Blender  V3.3
paint_vertex.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
13 #include "MEM_guardedalloc.h"
14 
15 #include "BLI_array_utils.h"
16 #include "BLI_color.hh"
17 #include "BLI_color_mix.hh"
18 #include "BLI_listbase.h"
19 #include "BLI_math.h"
20 #include "BLI_rect.h"
21 #include "BLI_string.h"
22 #include "BLI_task.h"
23 #include "BLI_task.hh"
24 
25 #include "DNA_brush_types.h"
26 #include "DNA_mesh_types.h"
27 #include "DNA_object_types.h"
28 #include "DNA_particle_types.h"
29 #include "DNA_scene_types.h"
30 
31 #include "RNA_access.h"
32 #include "RNA_prototypes.h"
33 
34 #include "BKE_attribute.h"
35 #include "BKE_brush.h"
36 #include "BKE_colortools.h"
37 #include "BKE_context.h"
38 #include "BKE_deform.h"
39 #include "BKE_editmesh.h"
40 #include "BKE_layer.h"
41 #include "BKE_lib_id.h"
42 #include "BKE_main.h"
43 #include "BKE_mesh.h"
44 #include "BKE_mesh_mapping.h"
45 #include "BKE_modifier.h"
46 #include "BKE_object.h"
47 #include "BKE_object_deform.h"
48 #include "BKE_paint.h"
49 #include "BKE_report.h"
50 #include "BKE_subsurf.h"
51 
52 #include "DEG_depsgraph.h"
53 
54 #include "WM_api.h"
55 #include "WM_message.h"
56 #include "WM_toolsystem.h"
57 #include "WM_types.h"
58 
59 #include "ED_armature.h"
60 #include "ED_image.h"
61 #include "ED_mesh.h"
62 #include "ED_object.h"
63 #include "ED_screen.h"
64 #include "ED_view3d.h"
65 
66 /* For IMB_BlendMode only. */
67 #include "IMB_imbuf.h"
68 
69 #include "BKE_ccg.h"
70 #include "bmesh.h"
71 
72 #include "paint_intern.h" /* own include */
73 #include "sculpt_intern.h"
74 
76 using namespace blender;
77 using namespace blender::color;
78 
79 /* -------------------------------------------------------------------- */
84 {
85  return *(reinterpret_cast<uint *>(&c));
86 }
87 
88 static bool isZero(ColorPaint4f c)
89 {
90  return c.r == 0.0f && c.g == 0.0f && c.b == 0.0f && c.a == 0.0f;
91 }
92 
93 static bool isZero(ColorPaint4b c)
94 {
95  return c.r == 0 && c.g == 0 && c.b == 0 && c.a == 0;
96 }
97 
98 template<typename Color = ColorPaint4f> static ColorPaint4f toFloat(const Color &c)
99 {
100  if constexpr (std::is_same_v<Color, ColorPaint4b>) {
101  return c.decode();
102  }
103  else {
104  return c;
105  }
106 }
107 
108 template<typename Color = ColorPaint4f> static Color fromFloat(const ColorPaint4f &c)
109 {
110  if constexpr (std::is_same_v<Color, ColorPaint4b>) {
111  return c.encode();
112  }
113  else {
114  return c;
115  }
116 }
117 
118 /* Use for 'blur' brush, align with PBVH nodes, created and freed on each update. */
119 template<typename BlendType> struct VPaintAverageAccum {
120  BlendType len;
121  BlendType value[3];
122 };
123 
126  double value;
127 };
128 
131  /* what angle to mask at */
132  float angle;
133  /* cos(angle), faster to compare */
134  float angle__cos;
135  float angle_inner;
137  /* difference between angle and angle_inner, for easy access */
138  float angle_range;
139 };
140 
141 /* Returns number of elements. */
142 static int get_vcol_elements(Mesh *me, size_t *r_elem_size)
143 {
145  const eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
146 
147  if (r_elem_size) {
148  *r_elem_size = layer->type == CD_PROP_COLOR ? sizeof(float) * 4ULL : 4ULL;
149  }
150 
151  switch (domain) {
152  case ATTR_DOMAIN_POINT:
153  return me->totvert;
154  case ATTR_DOMAIN_CORNER:
155  return me->totloop;
156  default:
157  return 0;
158  }
159 }
160 
161 static void view_angle_limits_init(NormalAnglePrecalc *a, float angle, bool do_mask_normal)
162 {
163  angle = RAD2DEGF(angle);
164  a->do_mask_normal = do_mask_normal;
165  if (do_mask_normal) {
166  a->angle_inner = angle;
167  a->angle = (a->angle_inner + 90.0f) * 0.5f;
168  }
169  else {
170  a->angle_inner = a->angle = angle;
171  }
172 
173  a->angle_inner *= (float)(M_PI_2 / 90);
174  a->angle *= (float)(M_PI_2 / 90);
175  a->angle_range = a->angle - a->angle_inner;
176 
177  if (a->angle_range <= 0.0f) {
178  a->do_mask_normal = false; /* no need to do blending */
179  }
180 
181  a->angle__cos = cosf(a->angle);
182  a->angle_inner__cos = cosf(a->angle_inner);
183 }
184 
186  float angle_cos,
187  float *mask_p)
188 {
189  if (angle_cos <= a->angle__cos) {
190  /* outsize the normal limit */
191  return false;
192  }
193  if (angle_cos < a->angle_inner__cos) {
194  *mask_p *= (a->angle - acosf(angle_cos)) / a->angle_range;
195  return true;
196  }
197  return true;
198 }
199 
200 static bool vwpaint_use_normal(const VPaint *vp)
201 {
202  return ((vp->paint.brush->flag & BRUSH_FRONTFACE) != 0) ||
203  ((vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
204 }
205 
206 static bool brush_use_accumulate_ex(const Brush *brush, const int ob_mode)
207 {
208  return ((brush->flag & BRUSH_ACCUMULATE) != 0 ||
209  (ob_mode == OB_MODE_VERTEX_PAINT ? (brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) :
210  (brush->weightpaint_tool == WPAINT_TOOL_SMEAR)));
211 }
212 
213 static bool brush_use_accumulate(const VPaint *vp)
214 {
216 }
217 
219  MDeformVert *dvert_curr,
220  int index)
221 {
222  const MDeformVert *dv_curr = &dvert_curr[index];
223  MDeformVert *dv_prev = &dvert_prev[index];
224  if (dv_prev->flag == 1) {
225  dv_prev->flag = 0;
226  BKE_defvert_copy(dv_prev, dv_curr);
227  }
228  return dv_prev;
229 }
230 
231 static void paint_last_stroke_update(Scene *scene, const float location[3])
232 {
234  ups->average_stroke_counter++;
235  add_v3_v3(ups->average_stroke_accum, location);
236  ups->last_stroke_valid = true;
237 }
238 
240 {
241  const Object *ob = CTX_data_active_object(C);
242 
243  if (!(ob && ob->mode == OB_MODE_VERTEX_PAINT && ((const Mesh *)ob->data)->totpoly)) {
244  return false;
245  }
246 
248  static_cast<const ID *>(ob->data));
249 
250  return layer != nullptr;
251 }
252 
253 static bool vertex_paint_poll_ex(bContext *C, bool check_tool)
254 {
257  if (area && area->spacetype == SPACE_VIEW3D) {
258  ARegion *region = CTX_wm_region(C);
259  if (region->regiontype == RGN_TYPE_WINDOW) {
260  if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
261  return true;
262  }
263  }
264  }
265  }
266  return false;
267 }
268 
270 {
271  return vertex_paint_poll_ex(C, true);
272 }
273 
275 {
276  return vertex_paint_poll_ex(C, false);
277 }
278 
280 {
281  const Object *ob = CTX_data_active_object(C);
282 
283  return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((const Mesh *)ob->data)->totpoly;
284 }
285 
286 static bool weight_paint_poll_ex(bContext *C, bool check_tool)
287 {
288  const Object *ob = CTX_data_active_object(C);
289  const ScrArea *area;
290 
291  if ((ob != nullptr) && (ob->mode & OB_MODE_WEIGHT_PAINT) &&
292  (BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != nullptr) &&
293  (area = CTX_wm_area(C)) && (area->spacetype == SPACE_VIEW3D)) {
294  ARegion *region = CTX_wm_region(C);
295  if (ELEM(region->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_HUD)) {
296  if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
297  return true;
298  }
299  }
300  }
301  return false;
302 }
303 
305 {
306  return weight_paint_poll_ex(C, true);
307 }
308 
310 {
311  return weight_paint_poll_ex(C, false);
312 }
313 
314 template<typename Color, typename Traits, eAttrDomain domain>
315 static Color vpaint_get_current_col(Scene *scene, VPaint *vp, bool secondary)
316 {
317  const Brush *brush = BKE_paint_brush_for_read(&vp->paint);
318  float color[4];
319  const float *brush_color = secondary ? BKE_brush_secondary_color_get(scene, brush) :
320  BKE_brush_color_get(scene, brush);
322 
323  color[3] = 1.0f; /* alpha isn't used, could even be removed to speedup paint a little */
324 
325  return fromFloat<Color>(ColorPaint4f(color));
326 }
327 
329 {
330  ColorPaint4b col = vpaint_get_current_col<ColorPaint4b, ByteTraits, ATTR_DOMAIN_CORNER>(
331  scene, vp, secondary);
332 
333  return color2uint(col);
334 }
335 
336 /* wpaint has 'wpaint_blend' */
337 template<typename Color, typename Traits>
338 static Color vpaint_blend(const VPaint *vp,
339  Color color_curr,
340  Color color_orig,
341  Color color_paint,
342  const typename Traits::ValueType alpha,
343  const typename Traits::BlendType brush_alpha_value)
344 {
345  using Value = typename Traits::ValueType;
346 
347  const Brush *brush = vp->paint.brush;
348  const IMB_BlendMode blend = (IMB_BlendMode)brush->blend;
349 
350  const Color color_blend = BLI_mix_colors<Color, Traits>(blend, color_curr, color_paint, alpha);
351 
352  /* If no accumulate, clip color adding with `color_orig` & `color_test`. */
353  if (!brush_use_accumulate(vp)) {
354  uint a;
355  Color color_test;
356  Value *cp, *ct, *co;
357 
358  color_test = BLI_mix_colors<Color, Traits>(blend, color_orig, color_paint, brush_alpha_value);
359 
360  cp = (Value *)&color_blend;
361  ct = (Value *)&color_test;
362  co = (Value *)&color_orig;
363 
364  for (a = 0; a < 4; a++) {
365  if (ct[a] < co[a]) {
366  if (cp[a] < ct[a]) {
367  cp[a] = ct[a];
368  }
369  else if (cp[a] > co[a]) {
370  cp[a] = co[a];
371  }
372  }
373  else {
374  if (cp[a] < co[a]) {
375  cp[a] = co[a];
376  }
377  else if (cp[a] > ct[a]) {
378  cp[a] = ct[a];
379  }
380  }
381  }
382  }
383 
384  if ((brush->flag & BRUSH_LOCK_ALPHA) &&
386  Value *cp, *cc;
387  cp = (Value *)&color_blend;
388  cc = (Value *)&color_curr;
389  cp[3] = cc[3];
390  }
391 
392  return color_blend;
393 }
394 
395 /* vpaint has 'vpaint_blend' */
396 static float wpaint_blend(const VPaint *wp,
397  float weight,
398  const float alpha,
399  float paintval,
400  const float UNUSED(brush_alpha_value),
401  const bool do_flip)
402 {
403  const Brush *brush = wp->paint.brush;
405 
406  if (do_flip) {
407  switch (blend) {
408  case IMB_BLEND_MIX:
409  paintval = 1.0f - paintval;
410  break;
411  case IMB_BLEND_ADD:
413  break;
414  case IMB_BLEND_SUB:
416  break;
417  case IMB_BLEND_LIGHTEN:
419  break;
420  case IMB_BLEND_DARKEN:
422  break;
423  default:
424  break;
425  }
426  }
427 
428  weight = ED_wpaint_blend_tool(blend, weight, paintval, alpha);
429 
430  CLAMP(weight, 0.0f, 1.0f);
431 
432  return weight;
433 }
434 
436  const ViewContext *vc,
437  const float co[3],
438  float r_rgba[4])
439 {
440  const Brush *brush = BKE_paint_brush(&vp->paint);
441  BLI_assert(brush->mtex.tex != nullptr);
442  if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
443  BKE_brush_sample_tex_3d(vc->scene, brush, co, r_rgba, 0, nullptr);
444  }
445  else {
446  float co_ss[2]; /* screenspace */
448  vc->region,
449  co,
450  co_ss,
452  const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
453  BKE_brush_sample_tex_3d(vc->scene, brush, co_ss_3d, r_rgba, 0, nullptr);
454  }
455  else {
456  zero_v4(r_rgba);
457  }
458  }
459 }
460 
461 static float wpaint_clamp_monotonic(float oldval, float curval, float newval)
462 {
463  if (newval < oldval) {
464  return MIN2(newval, curval);
465  }
466  if (newval > oldval) {
467  return MAX2(newval, curval);
468  }
469  return newval;
470 }
471 
473  float weight, float old_weight, float locked_weight, float free_weight, bool auto_normalize)
474 {
475  /* In auto-normalize mode, or when there is no unlocked weight,
476  * compute based on locked weight. */
477  if (auto_normalize || free_weight <= 0.0f) {
478  if (locked_weight < 1.0f - VERTEX_WEIGHT_LOCK_EPSILON) {
479  weight *= (1.0f - locked_weight);
480  }
481  else {
482  weight = 0;
483  }
484  }
485  else {
486  /* When dealing with full unlocked weight, don't paint, as it is always displayed as 1. */
487  if (old_weight >= free_weight) {
488  weight = old_weight;
489  }
490  /* Try to compute a weight value that would produce the desired effect if normalized. */
491  else if (weight < 1.0f) {
492  weight = weight * (free_weight - old_weight) / (1 - weight);
493  }
494  else {
495  weight = 1.0f;
496  }
497  }
498 
499  return weight;
500 }
501 
502 /* ----------------------------------------------------- */
503 
505  const int defbase_tot,
506  const bool *vgroup_validmap)
507 {
508  float sum = 0.0f, fac;
509  uint i, tot = 0;
510  MDeformWeight *dw;
511 
512  for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
513  if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
514  tot++;
515  sum += dw->weight;
516  }
517  }
518 
519  if ((tot == 0) || (sum == 1.0f)) {
520  return;
521  }
522 
523  if (sum != 0.0f) {
524  fac = 1.0f / sum;
525 
526  for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
527  if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
528  dw->weight *= fac;
529  }
530  }
531  }
532  else {
533  /* hrmf, not a factor in this case */
534  fac = 1.0f / tot;
535 
536  for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
537  if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
538  dw->weight = fac;
539  }
540  }
541  }
542 }
543 
549  const int defbase_tot,
550  const bool *vgroup_validmap,
551  const bool *lock_flags)
552 {
553  float sum = 0.0f, fac;
554  float sum_unlock = 0.0f;
555  float lock_weight = 0.0f;
556  uint i, tot = 0;
557  MDeformWeight *dw;
558 
559  if (lock_flags == nullptr) {
560  do_weight_paint_normalize_all(dvert, defbase_tot, vgroup_validmap);
561  return true;
562  }
563 
564  for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
565  if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
566  sum += dw->weight;
567 
568  if (lock_flags[dw->def_nr]) {
569  lock_weight += dw->weight;
570  }
571  else {
572  tot++;
573  sum_unlock += dw->weight;
574  }
575  }
576  }
577 
578  if (sum == 1.0f) {
579  return true;
580  }
581 
582  if (tot == 0) {
583  return false;
584  }
585 
586  if (lock_weight >= 1.0f - VERTEX_WEIGHT_LOCK_EPSILON) {
587  /* locked groups make it impossible to fully normalize,
588  * zero out what we can and return false */
589  for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
590  if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
591  if (lock_flags[dw->def_nr] == false) {
592  dw->weight = 0.0f;
593  }
594  }
595  }
596 
597  return (lock_weight == 1.0f);
598  }
599  if (sum_unlock != 0.0f) {
600  fac = (1.0f - lock_weight) / sum_unlock;
601 
602  for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
603  if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
604  if (lock_flags[dw->def_nr] == false) {
605  dw->weight *= fac;
606  /* paranoid but possibly with float error */
607  CLAMP(dw->weight, 0.0f, 1.0f);
608  }
609  }
610  }
611  }
612  else {
613  /* hrmf, not a factor in this case */
614  fac = (1.0f - lock_weight) / tot;
615  /* paranoid but possibly with float error */
616  CLAMP(fac, 0.0f, 1.0f);
617 
618  for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
619  if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
620  if (lock_flags[dw->def_nr] == false) {
621  dw->weight = fac;
622  }
623  }
624  }
625  }
626 
627  return true;
628 }
629 
635  const int defbase_tot,
636  const bool *vgroup_validmap,
637  const bool *lock_flags,
638  const bool *lock_with_active)
639 {
640  /* first pass with both active and explicitly locked groups restricted from change */
641 
643  dvert, defbase_tot, vgroup_validmap, lock_with_active);
644 
645  if (!success) {
655  do_weight_paint_normalize_all_locked(dvert, defbase_tot, vgroup_validmap, lock_flags);
656  }
657 }
658 
659 #if 0 /* UNUSED */
660 static bool has_unselected_unlocked_bone_group(int defbase_tot,
661  bool *defbase_sel,
662  int selected,
663  const bool *lock_flags,
664  const bool *vgroup_validmap)
665 {
666  int i;
667  if (defbase_tot == selected) {
668  return false;
669  }
670  for (i = 0; i < defbase_tot; i++) {
671  if (vgroup_validmap[i] && !defbase_sel[i] && !lock_flags[i]) {
672  return true;
673  }
674  }
675  return false;
676 }
677 #endif
678 
680  const int defbase_tot,
681  const bool *defbase_sel,
682  float *change_p)
683 {
684  int i;
685  MDeformWeight *dw;
686  float val;
687  float change = *change_p;
688 
689  /* verify that the change does not cause values exceeding 1 and clamp it */
690  for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
691  if (dw->def_nr < defbase_tot && defbase_sel[dw->def_nr]) {
692  if (dw->weight) {
693  val = dw->weight * change;
694  if (val > 1) {
695  change = 1.0f / dw->weight;
696  }
697  }
698  }
699  }
700 
701  *change_p = change;
702 }
703 
705  const int defbase_tot,
706  float change,
707  const bool *defbase_sel)
708 {
709  int i;
710  MDeformWeight *dw;
711  float val;
712 
713  /* in case the change is reduced, you need to recheck
714  * the earlier values to make sure they are not 0
715  * (precision error) */
716  for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
717  if (dw->def_nr < defbase_tot && defbase_sel[dw->def_nr]) {
718  if (dw->weight) {
719  val = dw->weight * change;
720  /* the value should never reach zero while multi-painting if it
721  * was nonzero beforehand */
722  if (val <= 0) {
723  return false;
724  }
725  }
726  }
727  }
728 
729  return true;
730 }
731 
733  const int defbase_tot,
734  float change,
735  const bool *defbase_sel)
736 {
737  int i;
738  MDeformWeight *dw;
739 
740  /* apply the valid change */
741  for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
742  if (dw->def_nr < defbase_tot && defbase_sel[dw->def_nr]) {
743  if (dw->weight) {
744  dw->weight = dw->weight * change;
745  CLAMP(dw->weight, 0.0f, 1.0f);
746  }
747  }
748  }
749 }
750 
761  int index;
767  const bool *lock;
768 };
769 
770 /* struct to avoid passing many args each call to do_weight_paint_vertex()
771  * this _could_ be made a part of the operators 'WPaintData' struct, or at
772  * least a member, but for now keep its own struct, initialized on every
773  * paint stroke update - campbell */
775 
777 
778  /* both must add up to 'defbase_tot' */
781 
783 
784  /* boolean array for locked bones,
785  * length of defbase_tot */
786  const bool *lock_flags;
787  /* boolean array for selected bones,
788  * length of defbase_tot, can't be const because of how it's passed */
789  const bool *defbase_sel;
790  /* same as WeightPaintData.vgroup_validmap,
791  * only added here for convenience */
792  const bool *vgroup_validmap;
793  /* same as WeightPaintData.vgroup_locked/unlocked,
794  * only added here for convenience */
795  const bool *vgroup_locked;
796  const bool *vgroup_unlocked;
797 
798  bool do_flip;
803 
804  float brush_alpha_value; /* result of BKE_brush_alpha_get() */
805 };
806 
808  /* vars which remain the same for every vert */
809  const VPaint *wp,
810  Object *ob,
811  const WeightPaintInfo *wpi,
812  /* vars which change on each stroke */
813  const uint index,
814  float alpha,
815  float paintweight)
816 {
817  Mesh *me = (Mesh *)ob->data;
818  MDeformVert *dv = &me->dvert[index];
819  bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
820 
821  MDeformWeight *dw;
822  float weight_prev, weight_cur;
823  float dw_rel_locked = 0.0f, dw_rel_free = 1.0f;
824 
825  /* mirror vars */
826  int index_mirr;
827  int vgroup_mirr;
828 
829  MDeformVert *dv_mirr;
830  MDeformWeight *dw_mirr;
831 
832  /* Check if we should mirror vertex groups (X-axis). */
834  index_mirr = mesh_get_x_mirror_vert(ob, nullptr, index, topology);
835  vgroup_mirr = wpi->mirror.index;
836 
837  /* another possible error - mirror group _and_ active group are the same (which is fine),
838  * but we also are painting onto a center vertex - this would paint the same weight twice */
839  if (index_mirr == index && vgroup_mirr == wpi->active.index) {
840  index_mirr = vgroup_mirr = -1;
841  }
842  }
843  else {
844  index_mirr = vgroup_mirr = -1;
845  }
846 
847  /* Check if painting should create new deform weight entries. */
848  bool restrict_to_existing = (wp->flag & VP_FLAG_VGROUP_RESTRICT) != 0;
849 
850  if (wpi->do_lock_relative || wpi->do_auto_normalize) {
851  /* Without do_lock_relative only dw_rel_locked is reliable, while dw_rel_free may be fake 0. */
852  dw_rel_free = BKE_defvert_total_selected_weight(dv, wpi->defbase_tot, wpi->vgroup_unlocked);
853  dw_rel_locked = BKE_defvert_total_selected_weight(dv, wpi->defbase_tot, wpi->vgroup_locked);
854  CLAMP(dw_rel_locked, 0.0f, 1.0f);
855 
856  /* Do not create entries if there is not enough free weight to paint.
857  * This logic is the same as in wpaint_undo_lock_relative and auto-normalize. */
858  if (wpi->do_auto_normalize || dw_rel_free <= 0.0f) {
859  if (dw_rel_locked >= 1.0f - VERTEX_WEIGHT_LOCK_EPSILON) {
860  restrict_to_existing = true;
861  }
862  }
863  }
864 
865  if (restrict_to_existing) {
866  dw = BKE_defvert_find_index(dv, wpi->active.index);
867  }
868  else {
869  dw = BKE_defvert_ensure_index(dv, wpi->active.index);
870  }
871 
872  if (dw == nullptr) {
873  return;
874  }
875 
876  /* get the mirror def vars */
877  if (index_mirr != -1) {
878  dv_mirr = &me->dvert[index_mirr];
879  if (wp->flag & VP_FLAG_VGROUP_RESTRICT) {
880  dw_mirr = BKE_defvert_find_index(dv_mirr, vgroup_mirr);
881 
882  if (dw_mirr == nullptr) {
883  index_mirr = vgroup_mirr = -1;
884  dv_mirr = nullptr;
885  }
886  }
887  else {
888  if (index != index_mirr) {
889  dw_mirr = BKE_defvert_ensure_index(dv_mirr, vgroup_mirr);
890  }
891  else {
892  /* dv and dv_mirr are the same */
893  int totweight_prev = dv_mirr->totweight;
894  int dw_offset = (int)(dw - dv_mirr->dw);
895  dw_mirr = BKE_defvert_ensure_index(dv_mirr, vgroup_mirr);
896 
897  /* if we added another, get our old one back */
898  if (totweight_prev != dv_mirr->totweight) {
899  dw = &dv_mirr->dw[dw_offset];
900  }
901  }
902  }
903  }
904  else {
905  dv_mirr = nullptr;
906  dw_mirr = nullptr;
907  }
908 
909  weight_cur = dw->weight;
910 
911  /* Handle weight caught up in locked defgroups for Lock Relative. */
912  if (wpi->do_lock_relative) {
913  weight_cur = BKE_defvert_calc_lock_relative_weight(weight_cur, dw_rel_locked, dw_rel_free);
914  }
915 
916  if (!brush_use_accumulate(wp)) {
917  MDeformVert *dvert_prev = ob->sculpt->mode.wpaint.dvert_prev;
918  MDeformVert *dv_prev = defweight_prev_init(dvert_prev, me->dvert, index);
919  if (index_mirr != -1) {
920  defweight_prev_init(dvert_prev, me->dvert, index_mirr);
921  }
922 
923  weight_prev = BKE_defvert_find_weight(dv_prev, wpi->active.index);
924 
925  if (wpi->do_lock_relative) {
926  weight_prev = BKE_defvert_lock_relative_weight(
927  weight_prev, dv_prev, wpi->defbase_tot, wpi->vgroup_locked, wpi->vgroup_unlocked);
928  }
929  }
930  else {
931  weight_prev = weight_cur;
932  }
933 
934  /* If there are no normalize-locks or multipaint,
935  * then there is no need to run the more complicated checks */
936 
937  {
938  float new_weight = wpaint_blend(
939  wp, weight_prev, alpha, paintweight, wpi->brush_alpha_value, wpi->do_flip);
940 
941  float weight = wpaint_clamp_monotonic(weight_prev, weight_cur, new_weight);
942 
943  /* Undo the lock relative weight correction. */
944  if (wpi->do_lock_relative) {
945  if (index_mirr == index) {
946  /* When painting a center vertex with X Mirror and L/R pair,
947  * handle both groups together. This avoids weird fighting
948  * in the non-normalized weight mode. */
949  float orig_weight = dw->weight + dw_mirr->weight;
950  weight = 0.5f *
952  weight * 2, orig_weight, dw_rel_locked, dw_rel_free, wpi->do_auto_normalize);
953  }
954  else {
955  weight = wpaint_undo_lock_relative(
956  weight, dw->weight, dw_rel_locked, dw_rel_free, wpi->do_auto_normalize);
957  }
958 
959  CLAMP(weight, 0.0f, 1.0f);
960  }
961 
962  dw->weight = weight;
963 
964  /* WATCH IT: take care of the ordering of applying mirror -> normalize,
965  * can give wrong results T26193, least confusing if normalize is done last */
966 
967  /* apply mirror */
968  if (index_mirr != -1) {
969  /* copy, not paint again */
970  dw_mirr->weight = dw->weight;
971  }
972 
973  /* apply normalize */
974  if (wpi->do_auto_normalize) {
975  /* note on normalize - this used to be applied after painting and normalize all weights,
976  * in some ways this is good because there is feedback where the more weights involved would
977  * 'resist' so you couldn't instantly zero out other weights by painting 1.0 on the active.
978  *
979  * However this gave a problem since applying mirror, then normalize both verts
980  * the resulting weight won't match on both sides.
981  *
982  * If this 'resisting', slower normalize is nicer, we could call
983  * do_weight_paint_normalize_all() and only use...
984  * do_weight_paint_normalize_all_active() when normalizing the mirror vertex.
985  * - campbell
986  */
988  dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
989 
990  if (index_mirr != -1) {
991  /* only normalize if this is not a center vertex,
992  * else we get a conflict, normalizing twice */
993  if (index != index_mirr) {
995  dv_mirr, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->mirror.lock);
996  }
997  else {
998  /* This case accounts for:
999  * - Painting onto a center vertex of a mesh.
1000  * - X-mirror is enabled.
1001  * - Auto normalize is enabled.
1002  * - The group you are painting onto has a L / R version.
1003  *
1004  * We want L/R vgroups to have the same weight but this can't be if both are over 0.5,
1005  * We _could_ have special check for that, but this would need its own
1006  * normalize function which holds 2 groups from changing at once.
1007  *
1008  * So! just balance out the 2 weights, it keeps them equal and everything normalized.
1009  *
1010  * While it won't hit the desired weight immediately as the user waggles their mouse,
1011  * constant painting and re-normalizing will get there. this is also just simpler logic.
1012  * - campbell */
1013  dw_mirr->weight = dw->weight = (dw_mirr->weight + dw->weight) * 0.5f;
1014  }
1015  }
1016  }
1017  }
1018 }
1019 
1021  /* vars which remain the same for every vert */
1022  const VPaint *wp,
1023  Object *ob,
1024  const WeightPaintInfo *wpi,
1025  /* vars which change on each stroke */
1026  const uint index,
1027  float alpha,
1028  float paintweight)
1029 {
1030  Mesh *me = (Mesh *)ob->data;
1031  MDeformVert *dv = &me->dvert[index];
1032  bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
1033 
1034  /* mirror vars */
1035  int index_mirr = -1;
1036  MDeformVert *dv_mirr = nullptr;
1037 
1038  /* weights */
1039  float curw, curw_real, oldw, neww, change, curw_mirr, change_mirr;
1040  float dw_rel_free, dw_rel_locked;
1041 
1042  /* Check if we should mirror vertex groups (X-axis). */
1044  index_mirr = mesh_get_x_mirror_vert(ob, nullptr, index, topology);
1045 
1046  if (!ELEM(index_mirr, -1, index)) {
1047  dv_mirr = &me->dvert[index_mirr];
1048  }
1049  else {
1050  index_mirr = -1;
1051  }
1052  }
1053 
1054  /* compute weight change by applying the brush to average or sum of group weights */
1055  curw = curw_real = BKE_defvert_multipaint_collective_weight(
1056  dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->is_normalized);
1057 
1058  if (curw == 0.0f) {
1059  /* NOTE: no weight to assign to this vertex, could add all groups? */
1060  return;
1061  }
1062 
1063  /* Handle weight caught up in locked defgroups for Lock Relative. */
1064  if (wpi->do_lock_relative) {
1065  dw_rel_free = BKE_defvert_total_selected_weight(dv, wpi->defbase_tot, wpi->vgroup_unlocked);
1066  dw_rel_locked = BKE_defvert_total_selected_weight(dv, wpi->defbase_tot, wpi->vgroup_locked);
1067  CLAMP(dw_rel_locked, 0.0f, 1.0f);
1068 
1069  curw = BKE_defvert_calc_lock_relative_weight(curw, dw_rel_locked, dw_rel_free);
1070  }
1071 
1072  if (!brush_use_accumulate(wp)) {
1073  MDeformVert *dvert_prev = ob->sculpt->mode.wpaint.dvert_prev;
1074  MDeformVert *dv_prev = defweight_prev_init(dvert_prev, me->dvert, index);
1075  if (index_mirr != -1) {
1076  defweight_prev_init(dvert_prev, me->dvert, index_mirr);
1077  }
1078 
1080  dv_prev, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->is_normalized);
1081 
1082  if (wpi->do_lock_relative) {
1084  oldw, dv_prev, wpi->defbase_tot, wpi->vgroup_locked, wpi->vgroup_unlocked);
1085  }
1086  }
1087  else {
1088  oldw = curw;
1089  }
1090 
1091  neww = wpaint_blend(wp, oldw, alpha, paintweight, wpi->brush_alpha_value, wpi->do_flip);
1092  neww = wpaint_clamp_monotonic(oldw, curw, neww);
1093 
1094  if (wpi->do_lock_relative) {
1096  neww, curw_real, dw_rel_locked, dw_rel_free, wpi->do_auto_normalize);
1097  }
1098 
1099  change = neww / curw_real;
1100 
1101  /* verify for all groups that 0 < result <= 1 */
1102  multipaint_clamp_change(dv, wpi->defbase_tot, wpi->defbase_sel, &change);
1103 
1104  if (dv_mirr != nullptr) {
1106  dv_mirr, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->is_normalized);
1107 
1108  if (curw_mirr == 0.0f) {
1109  /* can't mirror into a zero weight vertex */
1110  dv_mirr = nullptr;
1111  }
1112  else {
1113  /* mirror is changed to achieve the same collective weight value */
1114  float orig = change_mirr = curw_real * change / curw_mirr;
1115 
1116  multipaint_clamp_change(dv_mirr, wpi->defbase_tot, wpi->defbase_sel, &change_mirr);
1117 
1118  if (!multipaint_verify_change(dv_mirr, wpi->defbase_tot, change_mirr, wpi->defbase_sel)) {
1119  return;
1120  }
1121 
1122  change *= change_mirr / orig;
1123  }
1124  }
1125 
1126  if (!multipaint_verify_change(dv, wpi->defbase_tot, change, wpi->defbase_sel)) {
1127  return;
1128  }
1129 
1130  /* apply validated change to vertex and mirror */
1131  multipaint_apply_change(dv, wpi->defbase_tot, change, wpi->defbase_sel);
1132 
1133  if (dv_mirr != nullptr) {
1134  multipaint_apply_change(dv_mirr, wpi->defbase_tot, change_mirr, wpi->defbase_sel);
1135  }
1136 
1137  /* normalize */
1138  if (wpi->do_auto_normalize) {
1140  dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
1141 
1142  if (dv_mirr != nullptr) {
1144  dv_mirr, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
1145  }
1146  }
1147 }
1148 
1150  /* vars which remain the same for every vert */
1151  const VPaint *wp,
1152  Object *ob,
1153  const WeightPaintInfo *wpi,
1154  /* vars which change on each stroke */
1155  const uint index,
1156  float alpha,
1157  float paintweight)
1158 {
1159  if (wpi->do_multipaint) {
1160  do_weight_paint_vertex_multi(wp, ob, wpi, index, alpha, paintweight);
1161  }
1162  else {
1163  do_weight_paint_vertex_single(wp, ob, wpi, index, alpha, paintweight);
1164  }
1165 }
1166 
1167 /* Toggle operator for turning vertex paint mode on or off (copied from sculpt.c) */
1169  Scene *scene,
1170  Object *ob,
1171  eObjectMode object_mode)
1172 {
1173  /* Create persistent sculpt mode data */
1175 
1176  BLI_assert(ob->sculpt == nullptr);
1177  ob->sculpt = (SculptSession *)MEM_callocN(sizeof(SculptSession), "sculpt session");
1178  ob->sculpt->mode_type = object_mode;
1179  BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, true);
1180 }
1181 
1183 {
1184  BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, true);
1185  SculptSession *ss = ob->sculpt;
1186 
1187  /* Ensure ss->cache is allocated. It will mostly be initialized in
1188  * vwpaint_update_cache_invariants and vwpaint_update_cache_variants.
1189  */
1190  if (!ss->cache) {
1191  ss->cache = (StrokeCache *)MEM_callocN(sizeof(StrokeCache), "stroke cache");
1192  }
1193 }
1194 
1196 {
1198 
1199  SculptSession *ss = ob->sculpt;
1201 
1202  /* Allocate scratch array for previous colors if needed. */
1203  if (!brush_use_accumulate(ts->vpaint)) {
1204  if (!ss->cache->prev_colors_vpaint) {
1206  size_t elem_size;
1207  int elem_num;
1208 
1209  elem_num = get_vcol_elements(me, &elem_size);
1210 
1211  ss->cache->prev_colors_vpaint = (uint *)MEM_callocN(elem_num * elem_size, __func__);
1212  }
1213  }
1214  else {
1216  }
1217 }
1218 
1220 {
1221  /* Create maps */
1222  SculptVertexPaintGeomMap *gmap = nullptr;
1223  if (ob->mode == OB_MODE_VERTEX_PAINT) {
1224  gmap = &ob->sculpt->mode.vpaint.gmap;
1226  }
1227  else if (ob->mode == OB_MODE_WEIGHT_PAINT) {
1228  gmap = &ob->sculpt->mode.wpaint.gmap;
1230  }
1231  else {
1232  ob->sculpt->mode_type = (eObjectMode)0;
1233  BLI_assert(0);
1234  return;
1235  }
1236 
1237  Mesh *me = (Mesh *)ob->data;
1238 
1239  if (gmap->vert_to_loop == nullptr) {
1240  gmap->vert_map_mem = nullptr;
1241  gmap->vert_to_loop = nullptr;
1242  gmap->poly_map_mem = nullptr;
1243  gmap->vert_to_poly = nullptr;
1245  &gmap->vert_map_mem,
1246  me->mpoly,
1247  me->mloop,
1248  me->totvert,
1249  me->totpoly,
1250  me->totloop);
1252  &gmap->poly_map_mem,
1253  me->mpoly,
1254  me->mloop,
1255  me->totvert,
1256  me->totpoly,
1257  me->totloop);
1258  }
1259 
1260  /* Create average brush arrays */
1261  if (ob->mode == OB_MODE_WEIGHT_PAINT) {
1262  if (!brush_use_accumulate(ts->wpaint)) {
1263  if (ob->sculpt->mode.wpaint.alpha_weight == nullptr) {
1264  ob->sculpt->mode.wpaint.alpha_weight = (float *)MEM_callocN(me->totvert * sizeof(float),
1265  __func__);
1266  }
1267  if (ob->sculpt->mode.wpaint.dvert_prev == nullptr) {
1268  ob->sculpt->mode.wpaint.dvert_prev = (MDeformVert *)MEM_callocN(
1269  me->totvert * sizeof(MDeformVert), __func__);
1270  MDeformVert *dv = ob->sculpt->mode.wpaint.dvert_prev;
1271  for (int i = 0; i < me->totvert; i++, dv++) {
1272  /* Use to show this isn't initialized, never apply to the mesh data. */
1273  dv->flag = 1;
1274  }
1275  }
1276  }
1277  else {
1278  MEM_SAFE_FREE(ob->sculpt->mode.wpaint.alpha_weight);
1279  if (ob->sculpt->mode.wpaint.dvert_prev != nullptr) {
1280  BKE_defvert_array_free_elems(ob->sculpt->mode.wpaint.dvert_prev, me->totvert);
1281  MEM_freeN(ob->sculpt->mode.wpaint.dvert_prev);
1282  ob->sculpt->mode.wpaint.dvert_prev = nullptr;
1283  }
1284  }
1285  }
1286 }
1287 
1290 /* -------------------------------------------------------------------- */
1295  Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob, const eObjectMode mode_flag)
1296 {
1297  ob->mode |= mode_flag;
1298  Mesh *me = BKE_mesh_from_object(ob);
1299 
1300  /* Same as sculpt mode, make sure we don't have cached derived mesh which
1301  * points to freed arrays.
1302  */
1304 
1305  if (mode_flag == OB_MODE_VERTEX_PAINT) {
1306  const ePaintMode paint_mode = PAINT_MODE_VERTEX;
1307  ED_mesh_color_ensure(me, nullptr);
1308 
1310  Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
1312  BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_VERTEX_PAINT);
1313  }
1314  else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
1315  const ePaintMode paint_mode = PAINT_MODE_WEIGHT;
1316 
1318  Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
1320  BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_WEIGHT_PAINT);
1321 
1322  /* weight paint specific */
1325  }
1326  else {
1327  BLI_assert(0);
1328  }
1329 
1330  /* Create vertex/weight paint mode session data */
1331  if (ob->sculpt) {
1332  if (ob->sculpt->cache) {
1334  ob->sculpt->cache = nullptr;
1335  }
1337  }
1338 
1339  vertex_paint_init_session(depsgraph, scene, ob, mode_flag);
1340 
1341  /* Flush object mode. */
1343 }
1344 
1346 {
1348 }
1350 {
1351  Main *bmain = CTX_data_main(C);
1355 }
1356 
1358 {
1360 }
1362 {
1363  Main *bmain = CTX_data_main(C);
1367 }
1368 
1371 /* -------------------------------------------------------------------- */
1375 static void ed_vwpaintmode_exit_generic(Object *ob, const eObjectMode mode_flag)
1376 {
1377  Mesh *me = BKE_mesh_from_object(ob);
1378  ob->mode &= ~mode_flag;
1379 
1380  if (mode_flag == OB_MODE_VERTEX_PAINT) {
1381  if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
1383  }
1384  else if (me->editflag & ME_EDIT_PAINT_VERT_SEL) {
1386  }
1387  }
1388  else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
1389  if (me->editflag & ME_EDIT_PAINT_VERT_SEL) {
1391  }
1392  else if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
1394  }
1395  }
1396  else {
1397  BLI_assert(0);
1398  }
1399 
1400  /* If the cache is not released by a cancel or a done, free it now. */
1401  if (ob->sculpt && ob->sculpt->cache) {
1403  ob->sculpt->cache = nullptr;
1404  }
1405 
1407 
1409 
1410  if (mode_flag == OB_MODE_WEIGHT_PAINT) {
1413  }
1414 
1415  /* Never leave derived meshes behind. */
1417 
1418  /* Flush object mode. */
1420 }
1421 
1423 {
1425 }
1427 {
1430 }
1431 
1433 {
1435 }
1437 {
1440 }
1441 
1444 /* -------------------------------------------------------------------- */
1452 {
1453  Main *bmain = CTX_data_main(C);
1454  struct wmMsgBus *mbus = CTX_wm_message_bus(C);
1456  const int mode_flag = OB_MODE_WEIGHT_PAINT;
1457  const bool is_mode_set = (ob->mode & mode_flag) != 0;
1460 
1461  if (!is_mode_set) {
1462  if (!ED_object_mode_compat_set(C, ob, (eObjectMode)mode_flag, op->reports)) {
1463  return OPERATOR_CANCELLED;
1464  }
1465  }
1466 
1467  Mesh *me = BKE_mesh_from_object(ob);
1468 
1469  if (is_mode_set) {
1471  }
1472  else {
1474  if (depsgraph) {
1476  }
1479  }
1480 
1481  /* Prepare armature posemode. */
1482  ED_object_posemode_set_for_weight_paint(C, bmain, ob, is_mode_set);
1483 
1484  /* Weight-paint works by overriding colors in mesh,
1485  * so need to make sure we recalculate on enter and
1486  * exit (exit needs doing regardless because we
1487  * should re-deform).
1488  */
1489  DEG_id_tag_update(&me->id, 0);
1490 
1492 
1493  WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
1494 
1496 
1497  return OPERATOR_FINISHED;
1498 }
1499 
1501 {
1503  if (ob == nullptr || ob->type != OB_MESH) {
1504  return false;
1505  }
1506  if (!ob->data || ID_IS_LINKED(ob->data)) {
1507  return false;
1508  }
1509  return true;
1510 }
1511 
1513 {
1514 
1515  /* identifiers */
1516  ot->name = "Weight Paint Mode";
1517  ot->idname = "PAINT_OT_weight_paint_toggle";
1518  ot->description = "Toggle weight paint mode in 3D view";
1519 
1520  /* api callbacks */
1523 
1524  /* flags */
1526 }
1527 
1530 /* -------------------------------------------------------------------- */
1534 struct WPaintData {
1537 
1539 
1540  /* variables for auto normalize */
1541  const bool *vgroup_validmap; /* stores if vgroups tie to deforming bones or not */
1542  const bool *lock_flags;
1543  const bool *vgroup_locked; /* mask of locked defbones */
1544  const bool *vgroup_unlocked; /* mask of unlocked defbones */
1545 
1546  /* variables for multipaint */
1547  const bool *defbase_sel; /* set of selected groups */
1548  int defbase_tot_sel; /* number of selected groups */
1549  bool do_multipaint; /* true if multipaint enabled and multiple groups selected */
1551 
1553 
1554  /* original weight values for use in blur/smear */
1557 };
1558 
1559 static void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache)
1560 {
1562  Brush *brush = paint->brush;
1563  int cur_brush_size = BKE_brush_size_get(scene, brush);
1564 
1565  BLI_strncpy(
1566  cache->saved_active_brush_name, brush->id.name + 2, sizeof(cache->saved_active_brush_name));
1567 
1568  /* Switch to the blur (smooth) brush. */
1570  if (brush) {
1571  BKE_paint_brush_set(paint, brush);
1572  cache->saved_smooth_size = BKE_brush_size_get(scene, brush);
1573  BKE_brush_size_set(scene, brush, cur_brush_size);
1574  BKE_curvemapping_init(brush->curve);
1575  }
1576 }
1577 
1578 static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache *cache)
1579 {
1580  Main *bmain = CTX_data_main(C);
1582  Brush *brush = BKE_paint_brush(paint);
1583  /* The current brush should match with what we have stored in the cache. */
1584  BLI_assert(brush == cache->brush);
1585 
1586  /* Try to switch back to the saved/previous brush. */
1587  BKE_brush_size_set(scene, brush, cache->saved_smooth_size);
1588  brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, cache->saved_active_brush_name);
1589  if (brush) {
1590  BKE_paint_brush_set(paint, brush);
1591  }
1592 }
1593 
1594 /* Initialize the stroke cache invariants from operator properties */
1596  bContext *C, VPaint *vp, SculptSession *ss, wmOperator *op, const float mval[2])
1597 {
1598  StrokeCache *cache;
1599  const Scene *scene = CTX_data_scene(C);
1603  float mat[3][3];
1604  float view_dir[3] = {0.0f, 0.0f, 1.0f};
1605  int mode;
1606 
1607  /* VW paint needs to allocate stroke cache before update is called. */
1608  if (!ss->cache) {
1609  cache = (StrokeCache *)MEM_callocN(sizeof(StrokeCache), "stroke cache");
1610  ss->cache = cache;
1611  }
1612  else {
1613  cache = ss->cache;
1614  }
1615 
1616  /* Initial mouse location */
1617  if (mval) {
1618  copy_v2_v2(cache->initial_mouse, mval);
1619  }
1620  else {
1621  zero_v2(cache->initial_mouse);
1622  }
1623 
1624  mode = RNA_enum_get(op->ptr, "mode");
1625  cache->invert = mode == BRUSH_STROKE_INVERT;
1626  cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH;
1627  /* not very nice, but with current events system implementation
1628  * we can't handle brush appearance inversion hotkey separately (sergey) */
1629  if (cache->invert) {
1630  ups->draw_inverted = true;
1631  }
1632  else {
1633  ups->draw_inverted = false;
1634  }
1635 
1636  if (cache->alt_smooth) {
1637  smooth_brush_toggle_on(C, &vp->paint, cache);
1638  }
1639 
1640  copy_v2_v2(cache->mouse, cache->initial_mouse);
1641  const Brush *brush = vp->paint.brush;
1642  /* Truly temporary data that isn't stored in properties */
1643  cache->vc = vc;
1644  cache->brush = brush;
1645  cache->first_time = true;
1646 
1647  /* cache projection matrix */
1648  ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat);
1649 
1650  invert_m4_m4(ob->imat, ob->obmat);
1651  copy_m3_m4(mat, cache->vc->rv3d->viewinv);
1652  mul_m3_v3(mat, view_dir);
1653  copy_m3_m4(mat, ob->imat);
1654  mul_m3_v3(mat, view_dir);
1655  normalize_v3_v3(cache->true_view_normal, view_dir);
1656 
1657  copy_v3_v3(cache->view_normal, cache->true_view_normal);
1658  cache->bstrength = BKE_brush_alpha_get(scene, brush);
1659  cache->is_last_valid = false;
1660 }
1661 
1662 /* Initialize the stroke cache variants from operator properties */
1664 {
1666  SculptSession *ss = ob->sculpt;
1667  StrokeCache *cache = ss->cache;
1668  Brush *brush = BKE_paint_brush(&vp->paint);
1669 
1670  /* This effects the actual brush radius, so things farther away
1671  * are compared with a larger radius and vice versa. */
1672  if (cache->first_time) {
1673  RNA_float_get_array(ptr, "location", cache->true_location);
1674  }
1675 
1676  RNA_float_get_array(ptr, "mouse", cache->mouse);
1677 
1678  /* XXX: Use pressure value from first brush step for brushes which don't
1679  * support strokes (grab, thumb). They depends on initial state and
1680  * brush coord/pressure/etc.
1681  * It's more an events design issue, which doesn't split coordinate/pressure/angle
1682  * changing events. We should avoid this after events system re-design */
1684  cache->pressure = RNA_float_get(ptr, "pressure");
1685  }
1686 
1687  /* Truly temporary data that isn't stored in properties */
1688  if (cache->first_time) {
1690  cache->vc, cache->true_location, BKE_brush_size_get(scene, brush));
1692  }
1693 
1694  if (BKE_brush_use_size_pressure(brush) &&
1696  cache->radius = cache->initial_radius * cache->pressure;
1697  }
1698  else {
1699  cache->radius = cache->initial_radius;
1700  }
1701 
1702  cache->radius_squared = cache->radius * cache->radius;
1703 
1704  if (ss->pbvh) {
1706  }
1707 }
1708 
1709 static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
1710 {
1712  PaintStroke *stroke = (PaintStroke *)op->customdata;
1715  Mesh *me = BKE_mesh_from_object(ob);
1716  WPaintData *wpd;
1717  WPaintVGroupIndex vgroup_index;
1718  int defbase_tot, defbase_tot_sel;
1719  bool *defbase_sel;
1720  SculptSession *ss = ob->sculpt;
1723 
1724  if (ED_wpaint_ensure_data(C, op->reports, WPAINT_ENSURE_MIRROR, &vgroup_index) == false) {
1725  return false;
1726  }
1727 
1728  {
1729  /* check if we are attempting to paint onto a locked vertex group,
1730  * and other options disallow it from doing anything useful */
1731  bDeformGroup *dg;
1732  dg = (bDeformGroup *)BLI_findlink(&me->vertex_group_names, vgroup_index.active);
1733  if (dg->flag & DG_LOCK_WEIGHT) {
1734  BKE_report(op->reports, RPT_WARNING, "Active group is locked, aborting");
1735  return false;
1736  }
1737  if (vgroup_index.mirror != -1) {
1738  dg = (bDeformGroup *)BLI_findlink(&me->vertex_group_names, vgroup_index.mirror);
1739  if (dg->flag & DG_LOCK_WEIGHT) {
1740  BKE_report(op->reports, RPT_WARNING, "Mirror group is locked, aborting");
1741  return false;
1742  }
1743  }
1744  }
1745 
1746  /* check that multipaint groups are unlocked */
1747  defbase_tot = BLI_listbase_count(&me->vertex_group_names);
1748  defbase_sel = BKE_object_defgroup_selected_get(ob, defbase_tot, &defbase_tot_sel);
1749 
1750  if (ts->multipaint && defbase_tot_sel > 1) {
1751  int i;
1752  bDeformGroup *dg;
1753 
1756  ob, defbase_tot, defbase_sel, defbase_sel, &defbase_tot_sel);
1757  }
1758 
1759  for (i = 0; i < defbase_tot; i++) {
1760  if (defbase_sel[i]) {
1761  dg = (bDeformGroup *)BLI_findlink(&me->vertex_group_names, i);
1762  if (dg->flag & DG_LOCK_WEIGHT) {
1763  BKE_report(op->reports, RPT_WARNING, "Multipaint group is locked, aborting");
1764  MEM_freeN(defbase_sel);
1765  return false;
1766  }
1767  }
1768  }
1769  }
1770 
1771  /* ALLOCATIONS! no return after this line */
1772  /* make mode data storage */
1773  wpd = (WPaintData *)MEM_callocN(sizeof(WPaintData), "WPaintData");
1774  paint_stroke_set_mode_data(stroke, wpd);
1777  vp->paint.brush->falloff_angle,
1778  (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
1779 
1780  wpd->active.index = vgroup_index.active;
1781  wpd->mirror.index = vgroup_index.mirror;
1782 
1783  /* multipaint */
1784  wpd->defbase_tot = defbase_tot;
1785  wpd->defbase_sel = defbase_sel;
1786  wpd->defbase_tot_sel = defbase_tot_sel > 1 ? defbase_tot_sel : 1;
1787  wpd->do_multipaint = (ts->multipaint && defbase_tot_sel > 1);
1788 
1789  /* set up auto-normalize, and generate map for detecting which
1790  * vgroups affect deform bones */
1792  if (ts->auto_normalize || ts->multipaint || wpd->lock_flags != nullptr ||
1793  ts->wpaint_lock_relative) {
1795  }
1796 
1797  /* Compute the set of all locked deform groups when Lock Relative is active. */
1798  if (ts->wpaint_lock_relative &&
1800  wpd->lock_flags, wpd->vgroup_validmap, wpd->active.index) &&
1802  defbase_tot, wpd->lock_flags, defbase_sel, defbase_tot_sel))) {
1803  wpd->do_lock_relative = true;
1804  }
1805 
1806  if (wpd->do_lock_relative || (ts->auto_normalize && wpd->lock_flags && !wpd->do_multipaint)) {
1807  bool *unlocked = (bool *)MEM_dupallocN(wpd->vgroup_validmap);
1808 
1809  if (wpd->lock_flags) {
1810  bool *locked = (bool *)MEM_mallocN(sizeof(bool) * wpd->defbase_tot, __func__);
1812  wpd->defbase_tot, wpd->lock_flags, wpd->vgroup_validmap, locked, unlocked);
1813  wpd->vgroup_locked = locked;
1814  }
1815 
1816  wpd->vgroup_unlocked = unlocked;
1817  }
1818 
1819  if (wpd->do_multipaint && ts->auto_normalize) {
1820  bool *tmpflags;
1821  tmpflags = (bool *)MEM_mallocN(sizeof(bool) * defbase_tot, __func__);
1822  if (wpd->lock_flags) {
1823  BLI_array_binary_or(tmpflags, wpd->defbase_sel, wpd->lock_flags, wpd->defbase_tot);
1824  }
1825  else {
1826  memcpy(tmpflags, wpd->defbase_sel, sizeof(*tmpflags) * wpd->defbase_tot);
1827  }
1828  wpd->active.lock = tmpflags;
1829  }
1830  else if (ts->auto_normalize) {
1831  bool *tmpflags;
1832 
1833  tmpflags = wpd->lock_flags ? (bool *)MEM_dupallocN(wpd->lock_flags) :
1834  (bool *)MEM_callocN(sizeof(bool) * defbase_tot, __func__);
1835  tmpflags[wpd->active.index] = true;
1836  wpd->active.lock = tmpflags;
1837 
1838  tmpflags = wpd->lock_flags ? (bool *)MEM_dupallocN(wpd->lock_flags) :
1839  (bool *)MEM_callocN(sizeof(bool) * defbase_tot, __func__);
1840  tmpflags[(wpd->mirror.index != -1) ? wpd->mirror.index : wpd->active.index] = true;
1841  wpd->mirror.lock = tmpflags;
1842  }
1843 
1844  /* If not previously created, create vertex/weight paint mode session data */
1846  vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
1848 
1850  wpd->precomputed_weight = (float *)MEM_mallocN(sizeof(float) * me->totvert, __func__);
1851  }
1852 
1853  if (ob->sculpt->mode.wpaint.dvert_prev != nullptr) {
1854  MDeformVert *dv = ob->sculpt->mode.wpaint.dvert_prev;
1855  for (int i = 0; i < me->totvert; i++, dv++) {
1856  /* Use to show this isn't initialized, never apply to the mesh data. */
1857  dv->flag = 1;
1858  }
1859  }
1860 
1861  return true;
1862 }
1863 
1864 static void get_brush_alpha_data(const Scene *scene,
1865  const SculptSession *ss,
1866  const Brush *brush,
1867  float *r_brush_size_pressure,
1868  float *r_brush_alpha_value,
1869  float *r_brush_alpha_pressure)
1870 {
1871  *r_brush_size_pressure = BKE_brush_size_get(scene, brush) *
1872  (BKE_brush_use_size_pressure(brush) ? ss->cache->pressure : 1.0f);
1873  *r_brush_alpha_value = BKE_brush_alpha_get(scene, brush);
1874  *r_brush_alpha_pressure = (BKE_brush_use_alpha_pressure(brush) ? ss->cache->pressure : 1.0f);
1875 }
1876 
1877 static float wpaint_get_active_weight(const MDeformVert *dv, const WeightPaintInfo *wpi)
1878 {
1879  float weight;
1880 
1881  if (wpi->do_multipaint) {
1883  dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->is_normalized);
1884  }
1885  else {
1886  weight = BKE_defvert_find_weight(dv, wpi->active.index);
1887  }
1888 
1889  if (wpi->do_lock_relative) {
1891  weight, dv, wpi->defbase_tot, wpi->vgroup_locked, wpi->vgroup_unlocked);
1892  }
1893 
1894  CLAMP(weight, 0.0f, 1.0f);
1895  return weight;
1896 }
1897 
1898 static void do_wpaint_precompute_weight_cb_ex(void *__restrict userdata,
1899  const int n,
1900  const TaskParallelTLS *__restrict UNUSED(tls))
1901 {
1903  const MDeformVert *dv = &data->me->dvert[n];
1904 
1905  data->wpd->precomputed_weight[n] = wpaint_get_active_weight(dv, data->wpi);
1906 }
1907 
1909  bContext *C, Object *ob, Brush *brush, WPaintData *wpd, WeightPaintInfo *wpi, Mesh *me)
1910 {
1911  if (wpd->precomputed_weight_ready && !brush_use_accumulate_ex(brush, ob->mode)) {
1912  return;
1913  }
1914 
1915  /* threaded loop over vertices */
1917  data.C = C;
1918  data.ob = ob;
1919  data.wpd = wpd;
1920  data.wpi = wpi;
1921  data.me = me;
1922 
1923  TaskParallelSettings settings;
1926 
1927  wpd->precomputed_weight_ready = true;
1928 }
1929 
1930 static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata,
1931  const int n,
1932  const TaskParallelTLS *__restrict UNUSED(tls))
1933 {
1935  SculptSession *ss = data->ob->sculpt;
1936  const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
1937  const bool has_grids = (pbvh_type == PBVH_GRIDS);
1938  const SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap;
1939 
1940  const Brush *brush = data->brush;
1941  const StrokeCache *cache = ss->cache;
1942  Scene *scene = CTX_data_scene(data->C);
1943 
1944  float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
1946  scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
1947  const bool use_normal = vwpaint_use_normal(data->vp);
1948  const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
1949  const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
1950 
1951  SculptBrushTest test;
1953  ss, &test, data->brush->falloff_shape);
1954  const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
1955  ss, data->brush->falloff_shape);
1956 
1957  /* For each vertex */
1958  PBVHVertexIter vd;
1959  BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
1960  /* Test to see if the vertex coordinates are within the spherical brush region. */
1961  if (sculpt_brush_test_sq_fn(&test, vd.co)) {
1962  /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
1963  * Otherwise, take the current vert. */
1964  const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
1965  vd.vert_indices[vd.i];
1966  const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
1967  const char v_flag = data->me->mvert[v_index].flag;
1968  /* If the vertex is selected */
1969  if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
1970  /* Get the average poly weight */
1971  int total_hit_loops = 0;
1972  float weight_final = 0.0f;
1973  for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
1974  const int p_index = gmap->vert_to_poly[v_index].indices[j];
1975  const MPoly *mp = &data->me->mpoly[p_index];
1976 
1977  total_hit_loops += mp->totloop;
1978  for (int k = 0; k < mp->totloop; k++) {
1979  const int l_index = mp->loopstart + k;
1980  const MLoop *ml = &data->me->mloop[l_index];
1981  weight_final += data->wpd->precomputed_weight[ml->v];
1982  }
1983  }
1984 
1985  /* Apply the weight to the vertex. */
1986  if (total_hit_loops != 0) {
1987  float brush_strength = cache->bstrength;
1988  const float angle_cos = (use_normal && vd.no) ?
1989  dot_v3v3(sculpt_normal_frontface, vd.no) :
1990  1.0f;
1991  if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
1992  ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
1994  &data->wpd->normal_angle_precalc, angle_cos, &brush_strength))) {
1995  const float brush_fade = BKE_brush_curve_strength(
1996  brush, sqrtf(test.dist), cache->radius);
1997  const float final_alpha = brush_fade * brush_strength * grid_alpha *
1998  brush_alpha_pressure;
1999 
2000  if ((brush->flag & BRUSH_ACCUMULATE) == 0) {
2001  if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) {
2002  ss->mode.wpaint.alpha_weight[v_index] = final_alpha;
2003  }
2004  else {
2005  continue;
2006  }
2007  }
2008 
2009  weight_final /= total_hit_loops;
2010  /* Only paint visible verts */
2012  data->vp, data->ob, data->wpi, v_index, final_alpha, weight_final);
2013  }
2014  }
2015  }
2016  }
2017  }
2019 }
2020 
2021 static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
2022  const int n,
2023  const TaskParallelTLS *__restrict UNUSED(tls))
2024 {
2026  SculptSession *ss = data->ob->sculpt;
2027  const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
2028  const bool has_grids = (pbvh_type == PBVH_GRIDS);
2029  const SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap;
2030 
2031  const Brush *brush = data->brush;
2032  const Scene *scene = CTX_data_scene(data->C);
2033  const StrokeCache *cache = ss->cache;
2034  float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
2036  scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
2037  const bool use_normal = vwpaint_use_normal(data->vp);
2038  const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
2039  const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
2040  float brush_dir[3];
2041 
2042  sub_v3_v3v3(brush_dir, cache->location, cache->last_location);
2043  project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal);
2044 
2045  if (cache->is_last_valid && (normalize_v3(brush_dir) != 0.0f)) {
2046 
2047  SculptBrushTest test;
2049  ss, &test, data->brush->falloff_shape);
2050  const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
2051  ss, data->brush->falloff_shape);
2052 
2053  /* For each vertex */
2054  PBVHVertexIter vd;
2055  BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
2056  /* Test to see if the vertex coordinates are within the spherical brush region. */
2057  if (sculpt_brush_test_sq_fn(&test, vd.co)) {
2058  /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
2059  * Otherwise, take the current vert. */
2060  const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
2061  vd.vert_indices[vd.i];
2062  const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
2063  const MVert *mv_curr = &data->me->mvert[v_index];
2064 
2065  /* If the vertex is selected */
2066  if (!(use_face_sel || use_vert_sel) || mv_curr->flag & SELECT) {
2067  float brush_strength = cache->bstrength;
2068  const float angle_cos = (use_normal && vd.no) ?
2069  dot_v3v3(sculpt_normal_frontface, vd.no) :
2070  1.0f;
2071  if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
2072  ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
2074  &data->wpd->normal_angle_precalc, angle_cos, &brush_strength))) {
2075  bool do_color = false;
2076  /* Minimum dot product between brush direction and current
2077  * to neighbor direction is 0.0, meaning orthogonal. */
2078  float stroke_dot_max = 0.0f;
2079 
2080  /* Get the color of the loop in the opposite direction of the brush movement
2081  * (this callback is specifically for smear.) */
2082  float weight_final = 0.0;
2083  for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
2084  const int p_index = gmap->vert_to_poly[v_index].indices[j];
2085  const MPoly *mp = &data->me->mpoly[p_index];
2086  const MLoop *ml_other = &data->me->mloop[mp->loopstart];
2087  for (int k = 0; k < mp->totloop; k++, ml_other++) {
2088  const uint v_other_index = ml_other->v;
2089  if (v_other_index != v_index) {
2090  const MVert *mv_other = &data->me->mvert[v_other_index];
2091 
2092  /* Get the direction from the selected vert to the neighbor. */
2093  float other_dir[3];
2094  sub_v3_v3v3(other_dir, mv_curr->co, mv_other->co);
2095  project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal);
2096 
2097  normalize_v3(other_dir);
2098 
2099  const float stroke_dot = dot_v3v3(other_dir, brush_dir);
2100 
2101  if (stroke_dot > stroke_dot_max) {
2102  stroke_dot_max = stroke_dot;
2103  weight_final = data->wpd->precomputed_weight[v_other_index];
2104  do_color = true;
2105  }
2106  }
2107  }
2108  }
2109  /* Apply weight to vertex */
2110  if (do_color) {
2111  const float brush_fade = BKE_brush_curve_strength(
2112  brush, sqrtf(test.dist), cache->radius);
2113  const float final_alpha = brush_fade * brush_strength * grid_alpha *
2114  brush_alpha_pressure;
2115 
2116  if (final_alpha <= 0.0f) {
2117  continue;
2118  }
2119 
2121  data->vp, data->ob, data->wpi, v_index, final_alpha, (float)weight_final);
2122  }
2123  }
2124  }
2125  }
2126  }
2128  }
2129 }
2130 
2131 static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata,
2132  const int n,
2133  const TaskParallelTLS *__restrict UNUSED(tls))
2134 {
2136  SculptSession *ss = data->ob->sculpt;
2137  const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
2138  const bool has_grids = (pbvh_type == PBVH_GRIDS);
2139  const Scene *scene = CTX_data_scene(data->C);
2140 
2141  const Brush *brush = data->brush;
2142  const StrokeCache *cache = ss->cache;
2143  /* NOTE: normally `BKE_brush_weight_get(scene, brush)` is used,
2144  * however in this case we calculate a new weight each time. */
2145  const float paintweight = data->strength;
2146  float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
2148  scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
2149  const bool use_normal = vwpaint_use_normal(data->vp);
2150  const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
2151  const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
2152 
2153  SculptBrushTest test;
2155  ss, &test, data->brush->falloff_shape);
2156  const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
2157  ss, data->brush->falloff_shape);
2158 
2159  /* For each vertex */
2160  PBVHVertexIter vd;
2161  BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
2162  /* Test to see if the vertex coordinates are within the spherical brush region. */
2163  if (sculpt_brush_test_sq_fn(&test, vd.co)) {
2164  /* NOTE: grids are 1:1 with corners (aka loops).
2165  * For multires, take the vert whose loop corresponds to the current grid.
2166  * Otherwise, take the current vert. */
2167  const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
2168  vd.vert_indices[vd.i];
2169  const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
2170 
2171  const char v_flag = data->me->mvert[v_index].flag;
2172  /* If the vertex is selected */
2173  if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
2174  float brush_strength = cache->bstrength;
2175  const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
2176  1.0f;
2177  if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
2178  ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
2180  &data->wpd->normal_angle_precalc, angle_cos, &brush_strength))) {
2181  const float brush_fade = BKE_brush_curve_strength(
2182  brush, sqrtf(test.dist), cache->radius);
2183  const float final_alpha = brush_fade * brush_strength * grid_alpha *
2184  brush_alpha_pressure;
2185 
2186  if ((brush->flag & BRUSH_ACCUMULATE) == 0) {
2187  if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) {
2188  ss->mode.wpaint.alpha_weight[v_index] = final_alpha;
2189  }
2190  else {
2191  continue;
2192  }
2193  }
2194 
2195  do_weight_paint_vertex(data->vp, data->ob, data->wpi, v_index, final_alpha, paintweight);
2196  }
2197  }
2198  }
2199  }
2201 }
2202 
2204  void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
2205 {
2207  SculptSession *ss = data->ob->sculpt;
2208  StrokeCache *cache = ss->cache;
2209  const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
2210  const bool has_grids = (pbvh_type == PBVH_GRIDS);
2211 
2212  const bool use_normal = vwpaint_use_normal(data->vp);
2213  const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
2214  const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
2215 
2216  WPaintAverageAccum *accum = (WPaintAverageAccum *)data->custom_data + n;
2217  accum->len = 0;
2218  accum->value = 0.0;
2219 
2220  SculptBrushTest test;
2222  ss, &test, data->brush->falloff_shape);
2223  const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
2224  ss, data->brush->falloff_shape);
2225 
2226  /* For each vertex */
2227  PBVHVertexIter vd;
2228  BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
2229  /* Test to see if the vertex coordinates are within the spherical brush region. */
2230  if (sculpt_brush_test_sq_fn(&test, vd.co)) {
2231  const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
2232  1.0f;
2233  if (angle_cos > 0.0 &&
2234  BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0) {
2235  const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
2236  vd.vert_indices[vd.i];
2237  const char v_flag = data->me->mvert[v_index].flag;
2238 
2239  /* If the vertex is selected. */
2240  if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
2241  const MDeformVert *dv = &data->me->dvert[v_index];
2242  accum->len += 1;
2243  accum->value += wpaint_get_active_weight(dv, data->wpi);
2244  }
2245  }
2246  }
2247  }
2249 }
2250 
2252  PBVHNode **UNUSED(nodes),
2253  int totnode)
2254 {
2255  WPaintAverageAccum *accum = (WPaintAverageAccum *)MEM_mallocN(sizeof(*accum) * totnode,
2256  __func__);
2257  data->custom_data = accum;
2258 
2259  TaskParallelSettings settings;
2260  BKE_pbvh_parallel_range_settings(&settings, true, totnode);
2262 
2263  uint accum_len = 0;
2264  double accum_weight = 0.0;
2265  for (int i = 0; i < totnode; i++) {
2266  accum_len += accum[i].len;
2267  accum_weight += accum[i].value;
2268  }
2269  if (accum_len != 0) {
2270  accum_weight /= accum_len;
2271  data->strength = (float)accum_weight;
2272  }
2273 
2274  MEM_SAFE_FREE(data->custom_data); /* 'accum' */
2275 }
2276 
2278  Object *ob,
2279  Sculpt *sd,
2280  VPaint *vp,
2281  WPaintData *wpd,
2282  WeightPaintInfo *wpi,
2283  Mesh *me,
2284  PBVHNode **nodes,
2285  int totnode)
2286 {
2288  const Brush *brush = ob->sculpt->cache->brush;
2289 
2290  /* threaded loop over nodes */
2291  SculptThreadedTaskData data = {nullptr};
2292  data.C = C;
2293  data.sd = sd;
2294  data.ob = ob;
2295  data.brush = brush;
2296  data.nodes = nodes;
2297  data.vp = vp;
2298  data.wpd = wpd;
2299  data.wpi = wpi;
2300  data.me = me;
2301 
2302  /* Use this so average can modify its weight without touching the brush. */
2303  data.strength = BKE_brush_weight_get(scene, brush);
2304 
2305  /* NOTE: current mirroring code cannot be run in parallel */
2306  TaskParallelSettings settings;
2307  const bool use_threading = !ME_USING_MIRROR_X_VERTEX_GROUPS(me);
2308  BKE_pbvh_parallel_range_settings(&settings, use_threading, totnode);
2309 
2310  switch ((eBrushWeightPaintTool)brush->weightpaint_tool) {
2311  case WPAINT_TOOL_AVERAGE:
2312  calculate_average_weight(&data, nodes, totnode);
2314  break;
2315  case WPAINT_TOOL_SMEAR:
2317  break;
2318  case WPAINT_TOOL_BLUR:
2320  break;
2321  case WPAINT_TOOL_DRAW:
2323  break;
2324  }
2325 }
2326 
2328  Object *ob, VPaint *wp, Sculpt *sd, Brush *brush, int *r_totnode)
2329 {
2330  SculptSession *ss = ob->sculpt;
2331  const bool use_normal = vwpaint_use_normal(wp);
2332  PBVHNode **nodes = nullptr;
2333 
2334  /* Build a list of all nodes that are potentially within the brush's area of influence */
2335  if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
2336  SculptSearchSphereData data = {nullptr};
2337  data.ss = ss;
2338  data.sd = sd;
2339  data.radius_squared = ss->cache->radius_squared;
2340  data.original = true;
2341 
2342  BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode);
2343  if (use_normal) {
2345  brush, ob, nodes, *r_totnode, true, ss->cache->sculpt_normal_symm);
2346  }
2347  else {
2349  }
2350  }
2351  else {
2352  DistRayAABB_Precalc dist_ray_to_aabb_precalc;
2354  &dist_ray_to_aabb_precalc, ss->cache->location, ss->cache->view_normal);
2355  SculptSearchCircleData data = {nullptr};
2356  data.ss = ss;
2357  data.sd = sd;
2358  data.radius_squared = ss->cache->radius_squared;
2359  data.original = true;
2360  data.dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc;
2361 
2362  BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_circle_cb, &data, &nodes, r_totnode);
2363  if (use_normal) {
2365  }
2366  else {
2368  }
2369  }
2370  return nodes;
2371 }
2372 
2373 static void wpaint_do_paint(bContext *C,
2374  Object *ob,
2375  VPaint *wp,
2376  Sculpt *sd,
2377  WPaintData *wpd,
2378  WeightPaintInfo *wpi,
2379  Mesh *me,
2380  Brush *brush,
2381  const char symm,
2382  const int axis,
2383  const int i,
2384  const float angle)
2385 {
2386  SculptSession *ss = ob->sculpt;
2387  ss->cache->radial_symmetry_pass = i;
2388  SCULPT_cache_calc_brushdata_symm(ss->cache, symm, axis, angle);
2389 
2390  int totnode;
2391  PBVHNode **nodes = vwpaint_pbvh_gather_generic(ob, wp, sd, brush, &totnode);
2392 
2393  wpaint_paint_leaves(C, ob, sd, wp, wpd, wpi, me, nodes, totnode);
2394 
2395  if (nodes) {
2396  MEM_freeN(nodes);
2397  }
2398 }
2399 
2401  Object *ob,
2402  VPaint *wp,
2403  Sculpt *sd,
2404  WPaintData *wpd,
2405  WeightPaintInfo *wpi,
2406  Mesh *me,
2407  Brush *brush,
2408  const char symm,
2409  const int axis)
2410 {
2411  for (int i = 1; i < wp->radial_symm[axis - 'X']; i++) {
2412  const float angle = (2.0 * M_PI) * i / wp->radial_symm[axis - 'X'];
2413  wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, symm, axis, i, angle);
2414  }
2415 }
2416 
2417 /* near duplicate of: sculpt.c's,
2418  * 'do_symmetrical_brush_actions' and 'vpaint_do_symmetrical_brush_actions'. */
2420  bContext *C, Object *ob, VPaint *wp, Sculpt *sd, WPaintData *wpd, WeightPaintInfo *wpi)
2421 {
2422  Brush *brush = BKE_paint_brush(&wp->paint);
2423  Mesh *me = (Mesh *)ob->data;
2424  SculptSession *ss = ob->sculpt;
2425  StrokeCache *cache = ss->cache;
2426  const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
2427  int i = 0;
2428 
2429  /* initial stroke */
2430  cache->mirror_symmetry_pass = 0;
2431  wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X', 0, 0);
2432  wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X');
2433  wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Y');
2434  wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Z');
2435 
2436  cache->symmetry = symm;
2437 
2439  /* We don't do any symmetry strokes when mirroring vertex groups. */
2440  copy_v3_v3(cache->true_last_location, cache->true_location);
2441  cache->is_last_valid = true;
2442  return;
2443  }
2444 
2445  /* symm is a bit combination of XYZ - 1 is mirror
2446  * X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
2447  for (i = 1; i <= symm; i++) {
2448  if ((symm & i && (symm != 5 || i != 3) && (symm != 6 || (!ELEM(i, 3, 5))))) {
2449  cache->mirror_symmetry_pass = i;
2450  cache->radial_symmetry_pass = 0;
2451  SCULPT_cache_calc_brushdata_symm(cache, i, 0, 0);
2452 
2453  if (i & (1 << 0)) {
2454  wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X', 0, 0);
2455  wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X');
2456  }
2457  if (i & (1 << 1)) {
2458  wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y', 0, 0);
2459  wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y');
2460  }
2461  if (i & (1 << 2)) {
2462  wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z', 0, 0);
2463  wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z');
2464  }
2465  }
2466  }
2467  copy_v3_v3(cache->true_last_location, cache->true_location);
2468  cache->is_last_valid = true;
2469 }
2470 
2472  wmOperator *UNUSED(op),
2473  PaintStroke *stroke,
2474  PointerRNA *itemptr)
2475 {
2478  VPaint *wp = ts->wpaint;
2479  Brush *brush = BKE_paint_brush(&wp->paint);
2480  WPaintData *wpd = (WPaintData *)paint_stroke_mode_data(stroke);
2481  ViewContext *vc;
2483 
2484  SculptSession *ss = ob->sculpt;
2486 
2487  vwpaint_update_cache_variants(C, wp, ob, itemptr);
2488 
2489  float mat[4][4];
2490 
2491  const float brush_alpha_value = BKE_brush_alpha_get(scene, brush);
2492 
2493  /* intentionally don't initialize as nullptr, make sure we initialize all members below */
2494  WeightPaintInfo wpi;
2495 
2496  /* cannot paint if there is no stroke data */
2497  if (wpd == nullptr) {
2498  /* XXX: force a redraw here, since even though we can't paint,
2499  * at least view won't freeze until stroke ends */
2501  return;
2502  }
2503 
2504  vc = &wpd->vc;
2505  ob = vc->obact;
2506 
2508  ED_view3d_init_mats_rv3d(ob, vc->rv3d);
2509 
2510  /* load projection matrix */
2511  mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat);
2512 
2513  /* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */
2514  wpi.defbase_tot = wpd->defbase_tot;
2515  wpi.defbase_sel = wpd->defbase_sel;
2516  wpi.defbase_tot_sel = wpd->defbase_tot_sel;
2517 
2519  wpi.active = wpd->active;
2520  wpi.mirror = wpd->mirror;
2521  wpi.lock_flags = wpd->lock_flags;
2522  wpi.vgroup_validmap = wpd->vgroup_validmap;
2523  wpi.vgroup_locked = wpd->vgroup_locked;
2524  wpi.vgroup_unlocked = wpd->vgroup_unlocked;
2525  wpi.do_flip = RNA_boolean_get(itemptr, "pen_flip") || ss->cache->invert;
2526  wpi.do_multipaint = wpd->do_multipaint;
2527  wpi.do_auto_normalize = ((ts->auto_normalize != 0) && (wpi.vgroup_validmap != nullptr) &&
2528  (wpi.do_multipaint || wpi.vgroup_validmap[wpi.active.index]));
2531  wpi.brush_alpha_value = brush_alpha_value;
2532  /* *** done setting up WeightPaintInfo *** */
2533 
2534  if (wpd->precomputed_weight) {
2535  precompute_weight_values(C, ob, brush, wpd, &wpi, (Mesh *)ob->data);
2536  }
2537 
2538  wpaint_do_symmetrical_brush_actions(C, ob, wp, sd, wpd, &wpi);
2539 
2540  swap_m4m4(vc->rv3d->persmat, mat);
2541 
2542  /* Calculate pivot for rotation around selection if needed.
2543  * also needed for "Frame Selected" on last stroke. */
2544  float loc_world[3];
2545  mul_v3_m4v3(loc_world, ob->obmat, ss->cache->true_location);
2546  paint_last_stroke_update(scene, loc_world);
2547 
2549 
2550  DEG_id_tag_update((ID *)ob->data, 0);
2552  swap_m4m4(wpd->vc.rv3d->persmat, mat);
2553 
2554  rcti r;
2556  if (ss->cache) {
2557  ss->cache->current_r = r;
2558  }
2559 
2560  /* previous is not set in the current cache else
2561  * the partial rect will always grow */
2562  if (ss->cache) {
2563  if (!BLI_rcti_is_empty(&ss->cache->previous_r)) {
2564  BLI_rcti_union(&r, &ss->cache->previous_r);
2565  }
2566  }
2567 
2568  r.xmin += vc->region->winrct.xmin - 2;
2569  r.xmax += vc->region->winrct.xmin + 2;
2570  r.ymin += vc->region->winrct.ymin - 2;
2571  r.ymax += vc->region->winrct.ymin + 2;
2572  }
2573  ED_region_tag_redraw_partial(vc->region, &r, true);
2574 }
2575 
2576 static void wpaint_stroke_done(const bContext *C, PaintStroke *stroke)
2577 {
2579  WPaintData *wpd = (WPaintData *)paint_stroke_mode_data(stroke);
2580 
2581  if (wpd) {
2582  MEM_SAFE_FREE(wpd->defbase_sel);
2586  MEM_SAFE_FREE(wpd->lock_flags);
2587  MEM_SAFE_FREE(wpd->active.lock);
2588  MEM_SAFE_FREE(wpd->mirror.lock);
2590  MEM_freeN(wpd);
2591  }
2592 
2593  SculptSession *ss = ob->sculpt;
2594 
2595  if (ss->cache->alt_smooth) {
2597  VPaint *vp = ts->wpaint;
2598  smooth_brush_toggle_off(C, &vp->paint, ss->cache);
2599  }
2600 
2601  /* and particles too */
2602  if (ob->particlesystem.first) {
2603  ParticleSystem *psys;
2604  int i;
2605 
2606  for (psys = (ParticleSystem *)ob->particlesystem.first; psys; psys = psys->next) {
2607  for (i = 0; i < PSYS_TOT_VG; i++) {
2608  if (psys->vgroup[i] == BKE_object_defgroup_active_index_get(ob)) {
2609  psys->recalc |= ID_RECALC_PSYS_RESET;
2610  break;
2611  }
2612  }
2613  }
2614  }
2615 
2616  DEG_id_tag_update((ID *)ob->data, 0);
2617 
2619 
2621  ob->sculpt->cache = nullptr;
2622 }
2623 
2624 static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2625 {
2626  int retval;
2627 
2629  op,
2633  nullptr,
2635  event->type);
2636 
2637  if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
2639  return OPERATOR_FINISHED;
2640  }
2641  /* add modal handler */
2643 
2644  OPERATOR_RETVAL_CHECK(retval);
2646 
2647  return OPERATOR_RUNNING_MODAL;
2648 }
2649 
2650 static int wpaint_exec(bContext *C, wmOperator *op)
2651 {
2653  op,
2657  nullptr,
2659  0);
2660 
2661  /* frees op->customdata */
2663 
2664  return OPERATOR_FINISHED;
2665 }
2666 
2667 static void wpaint_cancel(bContext *C, wmOperator *op)
2668 {
2670  if (ob->sculpt->cache) {
2672  ob->sculpt->cache = nullptr;
2673  }
2674 
2676 }
2677 
2678 static int wpaint_modal(bContext *C, wmOperator *op, const wmEvent *event)
2679 {
2680  return paint_stroke_modal(C, op, event, (PaintStroke **)&op->customdata);
2681 }
2682 
2684 {
2685  /* identifiers */
2686  ot->name = "Weight Paint";
2687  ot->idname = "PAINT_OT_weight_paint";
2688  ot->description = "Paint a stroke in the current vertex group's weights";
2689 
2690  /* api callbacks */
2691  ot->invoke = wpaint_invoke;
2692  ot->modal = wpaint_modal;
2693  ot->exec = wpaint_exec;
2695  ot->cancel = wpaint_cancel;
2696 
2697  /* flags */
2699 
2701 }
2702 
2705 /* -------------------------------------------------------------------- */
2713 {
2714  Main *bmain = CTX_data_main(C);
2715  struct wmMsgBus *mbus = CTX_wm_message_bus(C);
2717  const int mode_flag = OB_MODE_VERTEX_PAINT;
2718  const bool is_mode_set = (ob->mode & mode_flag) != 0;
2721 
2722  if (!is_mode_set) {
2723  if (!ED_object_mode_compat_set(C, ob, (eObjectMode)mode_flag, op->reports)) {
2724  return OPERATOR_CANCELLED;
2725  }
2726  }
2727 
2728  Mesh *me = BKE_mesh_from_object(ob);
2729 
2730  /* toggle: end vpaint */
2731  if (is_mode_set) {
2733  }
2734  else {
2736  if (depsgraph) {
2738  }
2741  }
2742 
2744 
2745  /* update modifier stack for mapping requirements */
2746  DEG_id_tag_update(&me->id, 0);
2747 
2749  WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
2750 
2752 
2753  return OPERATOR_FINISHED;
2754 }
2755 
2757 {
2758  /* identifiers */
2759  ot->name = "Vertex Paint Mode";
2760  ot->idname = "PAINT_OT_vertex_paint_toggle";
2761  ot->description = "Toggle the vertex paint mode in 3D view";
2762 
2763  /* api callbacks */
2766 
2767  /* flags */
2769 }
2770 
2773 /* -------------------------------------------------------------------- */
2777 /* Implementation notes:
2778  *
2779  * Operator->invoke()
2780  * - Validate context (add #Mesh.mloopcol).
2781  * - Create custom-data storage.
2782  * - Call paint once (mouse click).
2783  * - Add modal handler.
2784  *
2785  * Operator->modal()
2786  * - For every mouse-move, apply vertex paint.
2787  * - Exit on mouse release, free custom-data.
2788  * (return OPERATOR_FINISHED also removes handler and operator)
2789  *
2790  * For future:
2791  * - implement a stroke event (or mouse-move with past positions).
2792  * - revise whether op->customdata should be added in object, in set_vpaint.
2793  */
2794 
2799 };
2800 
2801 template<typename Color, typename Traits, eAttrDomain domain>
2802 struct VPaintData : public VPaintDataBase {
2804 
2806 
2809 
2811 
2812  /* Special storage for smear brush, avoid feedback loop - update each step. */
2813  struct {
2814  void *color_prev;
2815  void *color_curr;
2816  } smear;
2817 };
2818 
2819 template<typename Color, typename Traits, eAttrDomain domain>
2821  wmOperator *op,
2822  Scene *scene,
2824  VPaint *vp,
2825  Object *ob,
2826  Mesh *me,
2827  const Brush *brush)
2828 {
2830 
2831  size_t elem_size;
2832  int elem_num = get_vcol_elements(me, &elem_size);
2833  /* make mode data storage */
2834  vpd = MEM_new<VPaintData<Color, Traits, domain>>("VPaintData");
2835 
2836  if constexpr (std::is_same_v<Color, ColorPaint4f>) {
2837  vpd->type = CD_PROP_COLOR;
2838  }
2839  else {
2840  vpd->type = CD_PROP_BYTE_COLOR;
2841  }
2842 
2843  vpd->domain = domain;
2844 
2847  vp->paint.brush->falloff_angle,
2848  (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
2849 
2850  vpd->paintcol = vpaint_get_current_col<Color, Traits, domain>(
2851  scene, vp, (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT));
2852 
2853  vpd->is_texbrush = !(brush->vertexpaint_tool == VPAINT_TOOL_BLUR) && brush->mtex.tex;
2854 
2855  if (brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) {
2857 
2858  vpd->smear.color_prev = MEM_malloc_arrayN(elem_num, elem_size, __func__);
2859  memcpy(vpd->smear.color_prev, layer->data, elem_size * elem_num);
2860 
2862  }
2863 
2864  /* Create projection handle */
2865  if (vpd->is_texbrush) {
2866  ob->sculpt->building_vp_handle = true;
2868  ob->sculpt->building_vp_handle = false;
2869  }
2870 
2871  return static_cast<void *>(vpd);
2872 }
2873 
2874 static bool vpaint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
2875 {
2878  PaintStroke *stroke = (PaintStroke *)op->customdata;
2879  VPaint *vp = ts->vpaint;
2880  Brush *brush = BKE_paint_brush(&vp->paint);
2882  Mesh *me;
2883  SculptSession *ss = ob->sculpt;
2885 
2886  /* context checks could be a poll() */
2887  me = BKE_mesh_from_object(ob);
2888  if (me == nullptr || me->totpoly == 0) {
2889  return false;
2890  }
2891 
2892  ED_mesh_color_ensure(me, nullptr);
2893 
2895  if (!layer) {
2896  return false;
2897  }
2898 
2899  eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
2900  void *vpd = nullptr;
2901 
2902  if (domain == ATTR_DOMAIN_POINT) {
2903  if (layer->type == CD_PROP_COLOR) {
2904  vpd = vpaint_init_vpaint<ColorPaint4f, FloatTraits, ATTR_DOMAIN_POINT>(
2905  C, op, scene, depsgraph, vp, ob, me, brush);
2906  }
2907  else if (layer->type == CD_PROP_BYTE_COLOR) {
2908  vpd = vpaint_init_vpaint<ColorPaint4b, ByteTraits, ATTR_DOMAIN_POINT>(
2909  C, op, scene, depsgraph, vp, ob, me, brush);
2910  }
2911  }
2912  else if (domain == ATTR_DOMAIN_CORNER) {
2913  if (layer->type == CD_PROP_COLOR) {
2914  vpd = vpaint_init_vpaint<ColorPaint4f, FloatTraits, ATTR_DOMAIN_CORNER>(
2915  C, op, scene, depsgraph, vp, ob, me, brush);
2916  }
2917  else if (layer->type == CD_PROP_BYTE_COLOR) {
2918  vpd = vpaint_init_vpaint<ColorPaint4b, ByteTraits, ATTR_DOMAIN_CORNER>(
2919  C, op, scene, depsgraph, vp, ob, me, brush);
2920  }
2921  }
2922 
2923  BLI_assert(vpd != nullptr);
2924 
2925  paint_stroke_set_mode_data(stroke, vpd);
2926 
2927  /* If not previously created, create vertex/weight paint mode session data */
2929  vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
2931 
2932  return true;
2933 }
2934 
2935 template<class Color = ColorPaint4b, typename Traits = ByteTraits>
2937  Sculpt *UNUSED(sd),
2938  VPaint *vp,
2940  Object *ob,
2941  Mesh *me,
2942  PBVHNode **nodes,
2943  int totnode,
2944  Color *lcol)
2945 {
2946  using Blend = typename Traits::BlendType;
2947 
2948  SculptSession *ss = ob->sculpt;
2949 
2950  const Brush *brush = ob->sculpt->cache->brush;
2951  const Scene *scene = CTX_data_scene(C);
2952 
2953  Color *previous_color = static_cast<Color *>(ss->cache->prev_colors_vpaint);
2954 
2955  blender::threading::parallel_for(IndexRange(totnode), 1LL, [&](IndexRange range) {
2956  for (int n : range) {
2957  const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
2958  const bool has_grids = (pbvh_type == PBVH_GRIDS);
2959 
2960  const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
2961  const StrokeCache *cache = ss->cache;
2962  float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
2964  scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
2965  const bool use_normal = vwpaint_use_normal(vp);
2966  const bool use_vert_sel = (me->editflag &
2968  const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
2969 
2970  SculptBrushTest test;
2972  ss, &test, brush->falloff_shape);
2973  const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
2974  ss, brush->falloff_shape);
2975 
2976  /* For each vertex */
2977  PBVHVertexIter vd;
2978  BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
2979  /* Test to see if the vertex coordinates are within the spherical brush region. */
2980  if (sculpt_brush_test_sq_fn(&test, vd.co)) {
2981  /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
2982  * Otherwise, take the current vert. */
2983  const int v_index = has_grids ? me->mloop[vd.grid_indices[vd.g]].v :
2984  vd.vert_indices[vd.i];
2985  const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
2986  const MVert *mv = &me->mvert[v_index];
2987 
2988  /* If the vertex is selected for painting. */
2989  if (!use_vert_sel || mv->flag & SELECT) {
2990  float brush_strength = cache->bstrength;
2991  const float angle_cos = (use_normal && vd.no) ?
2992  dot_v3v3(sculpt_normal_frontface, vd.no) :
2993  1.0f;
2994  if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
2995  ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
2997  &vpd->normal_angle_precalc, angle_cos, &brush_strength))) {
2998  const float brush_fade = BKE_brush_curve_strength(
2999  brush, sqrtf(test.dist), cache->radius);
3000 
3001  /* Get the average poly color */
3002  Color color_final(0, 0, 0, 0);
3003 
3004  int total_hit_loops = 0;
3005  Blend blend[4] = {0};
3006 
3007  for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
3008  int p_index = gmap->vert_to_poly[v_index].indices[j];
3009  const MPoly *mp = &me->mpoly[p_index];
3010  if (!use_face_sel || mp->flag & ME_FACE_SEL) {
3011  total_hit_loops += mp->totloop;
3012  for (int k = 0; k < mp->totloop; k++) {
3013  const uint l_index = mp->loopstart + k;
3014  Color *col = lcol + l_index;
3015 
3016  /* Color is squared to compensate the sqrt color encoding. */
3017  blend[0] += (Blend)col->r * (Blend)col->r;
3018  blend[1] += (Blend)col->g * (Blend)col->g;
3019  blend[2] += (Blend)col->b * (Blend)col->b;
3020  blend[3] += (Blend)col->a * (Blend)col->a;
3021  }
3022  }
3023  }
3024 
3025  if (total_hit_loops != 0) {
3026  /* Use rgb^2 color averaging. */
3027  Color *col = &color_final;
3028 
3029  color_final.r = Traits::round(
3030  sqrtf(Traits::divide_round(blend[0], total_hit_loops)));
3031  color_final.g = Traits::round(
3032  sqrtf(Traits::divide_round(blend[1], total_hit_loops)));
3033  color_final.b = Traits::round(
3034  sqrtf(Traits::divide_round(blend[2], total_hit_loops)));
3035  color_final.a = Traits::round(
3036  sqrtf(Traits::divide_round(blend[3], total_hit_loops)));
3037 
3038  /* For each poly owning this vert,
3039  * paint each loop belonging to this vert. */
3040  for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
3041  const int p_index = gmap->vert_to_poly[v_index].indices[j];
3042  const int l_index = gmap->vert_to_loop[v_index].indices[j];
3043  BLI_assert(me->mloop[l_index].v == v_index);
3044  const MPoly *mp = &me->mpoly[p_index];
3045  if (!use_face_sel || mp->flag & ME_FACE_SEL) {
3046  Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
3047 
3048  if (previous_color != nullptr) {
3049  /* Get the previous loop color */
3050  if (isZero(previous_color[l_index])) {
3051  previous_color[l_index] = lcol[l_index];
3052  }
3053  color_orig = previous_color[l_index];
3054  }
3055  const float final_alpha = Traits::range * brush_fade * brush_strength *
3056  brush_alpha_pressure * grid_alpha;
3057  /* Mix the new color with the original
3058  * based on the brush strength and the curve. */
3059  lcol[l_index] = vpaint_blend<Color, Traits>(vp,
3060  lcol[l_index],
3061  color_orig,
3062  *col,
3063  final_alpha,
3064  Traits::range * brush_strength);
3065  }
3066  }
3067  }
3068  }
3069  }
3070  }
3071  }
3073  };
3074  });
3075 }
3076 
3077 template<class Color = ColorPaint4b, typename Traits = ByteTraits>
3079  Sculpt *UNUSED(sd),
3080  VPaint *vp,
3082  Object *ob,
3083  Mesh *me,
3084  PBVHNode **nodes,
3085  int totnode,
3086  Color *lcol)
3087 {
3088  using Blend = typename Traits::BlendType;
3089 
3090  SculptSession *ss = ob->sculpt;
3091 
3092  const Brush *brush = ob->sculpt->cache->brush;
3093  const Scene *scene = CTX_data_scene(C);
3094 
3095  Color *previous_color = static_cast<Color *>(ss->cache->prev_colors_vpaint);
3096 
3097  blender::threading::parallel_for(IndexRange(totnode), 1LL, [&](IndexRange range) {
3098  for (int n : range) {
3099  const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
3100  const bool has_grids = (pbvh_type == PBVH_GRIDS);
3101 
3102  const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
3103  const StrokeCache *cache = ss->cache;
3104  float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
3106  scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
3107  const bool use_normal = vwpaint_use_normal(vp);
3108  const bool use_vert_sel = (me->editflag &
3110  const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
3111 
3112  SculptBrushTest test;
3114  ss, &test, brush->falloff_shape);
3115  const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
3116  ss, brush->falloff_shape);
3117 
3118  /* For each vertex */
3119  PBVHVertexIter vd;
3120  BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
3121  /* Test to see if the vertex coordinates are within the spherical brush region. */
3122  if (sculpt_brush_test_sq_fn(&test, vd.co)) {
3123  /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
3124  * Otherwise, take the current vert. */
3125  const int v_index = has_grids ? me->mloop[vd.grid_indices[vd.g]].v :
3126  vd.vert_indices[vd.i];
3127  const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
3128  const MVert *mv = &me->mvert[v_index];
3129 
3130  /* If the vertex is selected for painting. */
3131  if (!use_vert_sel || mv->flag & SELECT) {
3132  float brush_strength = cache->bstrength;
3133  const float angle_cos = (use_normal && vd.no) ?
3134  dot_v3v3(sculpt_normal_frontface, vd.no) :
3135  1.0f;
3136  if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
3137  ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
3139  &vpd->normal_angle_precalc, angle_cos, &brush_strength))) {
3140  const float brush_fade = BKE_brush_curve_strength(
3141  brush, sqrtf(test.dist), cache->radius);
3142 
3143  /* Get the average poly color */
3144  Color color_final(0, 0, 0, 0);
3145 
3146  int total_hit_loops = 0;
3147  Blend blend[4] = {0};
3148 
3149  for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
3150  int p_index = gmap->vert_to_poly[v_index].indices[j];
3151  const MPoly *mp = &me->mpoly[p_index];
3152  if (!use_face_sel || mp->flag & ME_FACE_SEL) {
3153  total_hit_loops += mp->totloop;
3154  for (int k = 0; k < mp->totloop; k++) {
3155  const uint l_index = mp->loopstart + k;
3156  const uint v_index = me->mloop[l_index].v;
3157 
3158  Color *col = lcol + v_index;
3159 
3160  /* Color is squared to compensate the sqrt color encoding. */
3161  blend[0] += (Blend)col->r * (Blend)col->r;
3162  blend[1] += (Blend)col->g * (Blend)col->g;
3163  blend[2] += (Blend)col->b * (Blend)col->b;
3164  blend[3] += (Blend)col->a * (Blend)col->a;
3165  }
3166  }
3167  }
3168 
3169  if (total_hit_loops != 0) {
3170  /* Use rgb^2 color averaging. */
3171  Color *col = &color_final;
3172 
3173  color_final.r = Traits::round(
3174  sqrtf(Traits::divide_round(blend[0], total_hit_loops)));
3175  color_final.g = Traits::round(
3176  sqrtf(Traits::divide_round(blend[1], total_hit_loops)));
3177  color_final.b = Traits::round(
3178  sqrtf(Traits::divide_round(blend[2], total_hit_loops)));
3179  color_final.a = Traits::round(
3180  sqrtf(Traits::divide_round(blend[3], total_hit_loops)));
3181 
3182  /* For each poly owning this vert,
3183  * paint each loop belonging to this vert. */
3184  for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
3185  const int p_index = gmap->vert_to_poly[v_index].indices[j];
3186 
3187  BLI_assert(me->mloop[gmap->vert_to_loop[v_index].indices[j]].v == v_index);
3188 
3189  const MPoly *mp = &me->mpoly[p_index];
3190  if (!use_face_sel || mp->flag & ME_FACE_SEL) {
3191  Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
3192 
3193  if (previous_color != nullptr) {
3194  /* Get the previous loop color */
3195  if (isZero(previous_color[v_index])) {
3196  previous_color[v_index] = lcol[v_index];
3197  }
3198  color_orig = previous_color[v_index];
3199  }
3200  const float final_alpha = Traits::range * brush_fade * brush_strength *
3201  brush_alpha_pressure * grid_alpha;
3202  /* Mix the new color with the original
3203  * based on the brush strength and the curve. */
3204  lcol[v_index] = vpaint_blend<Color, Traits>(vp,
3205  lcol[v_index],
3206  color_orig,
3207  *col,
3208  final_alpha,
3209  Traits::range * brush_strength);
3210  }
3211  }
3212  }
3213  }
3214  }
3215  }
3216  }
3218  };
3219  });
3220 }
3221 
3222 template<typename Color = ColorPaint4b, typename Traits, eAttrDomain domain>
3224  Sculpt *UNUSED(sd),
3225  VPaint *vp,
3227  Object *ob,
3228  Mesh *me,
3229  PBVHNode **nodes,
3230  int totnode,
3231  Color *lcol)
3232 {
3233  SculptSession *ss = ob->sculpt;
3234 
3235  const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
3236  const StrokeCache *cache = ss->cache;
3237  const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
3238  const bool has_grids = (pbvh_type == PBVH_GRIDS);
3239 
3240  const Brush *brush = ob->sculpt->cache->brush;
3241  const Scene *scene = CTX_data_scene(C);
3242  Color *color_curr = static_cast<Color *>(vpd->smear.color_curr);
3243  Color *color_prev_smear = static_cast<Color *>(vpd->smear.color_prev);
3244  Color *color_prev = reinterpret_cast<Color *>(ss->cache->prev_colors_vpaint);
3245 
3246  blender::threading::parallel_for(IndexRange(totnode), 1LL, [&](IndexRange range) {
3247  for (int n : range) {
3248  float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
3249 
3251  scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
3252  float brush_dir[3];
3253  const bool use_normal = vwpaint_use_normal(vp);
3254  const bool use_vert_sel = (me->editflag &
3256  const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
3257 
3258  sub_v3_v3v3(brush_dir, cache->location, cache->last_location);
3259  project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal);
3260 
3261  if (cache->is_last_valid && (normalize_v3(brush_dir) != 0.0f)) {
3262 
3263  SculptBrushTest test;
3265  ss, &test, brush->falloff_shape);
3266  const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
3267  ss, brush->falloff_shape);
3268 
3269  /* For each vertex */
3270  PBVHVertexIter vd;
3271  BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
3272  /* Test to see if the vertex coordinates are within the spherical brush region. */
3273  if (sculpt_brush_test_sq_fn(&test, vd.co)) {
3274  /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
3275  * Otherwise, take the current vert. */
3276  const int v_index = has_grids ? me->mloop[vd.grid_indices[vd.g]].v :
3277  vd.vert_indices[vd.i];
3278  const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
3279  const MVert *mv_curr = &me->mvert[v_index];
3280 
3281  /* if the vertex is selected for painting. */
3282  if (!use_vert_sel || mv_curr->flag & SELECT) {
3283  /* Calc the dot prod. between ray norm on surf and current vert
3284  * (ie splash prevention factor), and only paint front facing verts. */
3285  float brush_strength = cache->bstrength;
3286  const float angle_cos = (use_normal && vd.no) ?
3287  dot_v3v3(sculpt_normal_frontface, vd.no) :
3288  1.0f;
3289  if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
3290  ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
3292  &vpd->normal_angle_precalc, angle_cos, &brush_strength))) {
3293  const float brush_fade = BKE_brush_curve_strength(
3294  brush, sqrtf(test.dist), cache->radius);
3295 
3296  bool do_color = false;
3297  /* Minimum dot product between brush direction and current
3298  * to neighbor direction is 0.0, meaning orthogonal. */
3299  float stroke_dot_max = 0.0f;
3300 
3301  /* Get the color of the loop in the opposite
3302  * direction of the brush movement */
3303  Color color_final(0, 0, 0, 0);
3304 
3305  for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
3306  const int p_index = gmap->vert_to_poly[v_index].indices[j];
3307  const int l_index = gmap->vert_to_loop[v_index].indices[j];
3308  BLI_assert(me->mloop[l_index].v == v_index);
3309  UNUSED_VARS_NDEBUG(l_index);
3310  const MPoly *mp = &me->mpoly[p_index];
3311  if (!use_face_sel || mp->flag & ME_FACE_SEL) {
3312  const MLoop *ml_other = &me->mloop[mp->loopstart];
3313  for (int k = 0; k < mp->totloop; k++, ml_other++) {
3314  const uint v_other_index = ml_other->v;
3315  if (v_other_index != v_index) {
3316  const MVert *mv_other = &me->mvert[v_other_index];
3317 
3318  /* Get the direction from the
3319  * selected vert to the neighbor. */
3320  float other_dir[3];
3321  sub_v3_v3v3(other_dir, mv_curr->co, mv_other->co);
3322  project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal);
3323 
3324  normalize_v3(other_dir);
3325 
3326  const float stroke_dot = dot_v3v3(other_dir, brush_dir);
3327  int elem_index;
3328 
3329  if constexpr (domain == ATTR_DOMAIN_POINT) {
3330  elem_index = ml_other->v;
3331  }
3332  else {
3333  elem_index = mp->loopstart + k;
3334  }
3335 
3336  if (stroke_dot > stroke_dot_max) {
3337  stroke_dot_max = stroke_dot;
3338  color_final = color_prev_smear[elem_index];
3339  do_color = true;
3340  }
3341  }
3342  }
3343  }
3344  }
3345 
3346  if (do_color) {
3347  const float final_alpha = Traits::range * brush_fade * brush_strength *
3348  brush_alpha_pressure * grid_alpha;
3349 
3350  /* For each poly owning this vert,
3351  * paint each loop belonging to this vert. */
3352  for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
3353  const int p_index = gmap->vert_to_poly[v_index].indices[j];
3354 
3355  int elem_index;
3356  if constexpr (domain == ATTR_DOMAIN_POINT) {
3357  elem_index = v_index;
3358  }
3359  else {
3360  const int l_index = gmap->vert_to_loop[v_index].indices[j];
3361  elem_index = l_index;
3362  BLI_assert(me->mloop[l_index].v == v_index);
3363  }
3364 
3365  const MPoly *mp = &me->mpoly[p_index];
3366  if (!use_face_sel || mp->flag & ME_FACE_SEL) {
3367  /* Get the previous element color */
3368  Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
3369 
3370  if (color_prev != nullptr) {
3371  /* Get the previous element color */
3372  if (isZero(color_prev[elem_index])) {
3373  color_prev[elem_index] = lcol[elem_index];
3374  }
3375  color_orig = color_prev[elem_index];
3376  }
3377  /* Mix the new color with the original
3378  * based on the brush strength and the curve. */
3379  lcol[elem_index] = vpaint_blend<Color, Traits>(vp,
3380  lcol[elem_index],
3381  color_orig,
3382  color_final,
3383  final_alpha,
3384  Traits::range *
3385  brush_strength);
3386 
3387  color_curr[elem_index] = lcol[elem_index];
3388  }
3389  }
3390  }
3391  }
3392  }
3393  }
3394  }
3396  }
3397  }
3398  });
3399 }
3400 
3401 template<typename Color, typename Traits, eAttrDomain domain>
3403  Object *ob,
3404  Mesh *me,
3405  const Brush *brush,
3406  Color *lcol,
3407  PBVHNode **nodes,
3408  int totnode)
3409 {
3410  using Blend = typename Traits::BlendType;
3411 
3413  sizeof(*accum) * totnode, __func__);
3414  blender::threading::parallel_for(IndexRange(totnode), 1LL, [&](IndexRange range) {
3415  for (int n : range) {
3416  SculptSession *ss = ob->sculpt;
3417  const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
3418  const bool has_grids = (pbvh_type == PBVH_GRIDS);
3419  const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
3420 
3421  StrokeCache *cache = ss->cache;
3422  const bool use_vert_sel = (me->editflag &
3424 
3425  VPaintAverageAccum<Blend> *accum2 = accum + n;
3426  accum2->len = 0;
3427  memset(accum2->value, 0, sizeof(accum2->value));
3428 
3429  SculptBrushTest test;
3431  ss, &test, brush->falloff_shape);
3432 
3433  /* For each vertex */
3434  PBVHVertexIter vd;
3435  BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
3436  /* Test to see if the vertex coordinates are within the spherical brush region. */
3437  if (sculpt_brush_test_sq_fn(&test, vd.co)) {
3438  const int v_index = has_grids ? me->mloop[vd.grid_indices[vd.g]].v :
3439  vd.vert_indices[vd.i];
3440  if (BKE_brush_curve_strength(brush, 0.0, cache->radius) > 0.0) {
3441  /* If the vertex is selected for painting. */
3442  const MVert *mv = &me->mvert[v_index];
3443  if (!use_vert_sel || mv->flag & SELECT) {
3444  accum2->len += gmap->vert_to_loop[v_index].count;
3445  /* if a vertex is within the brush region, then add its color to the blend. */
3446  for (int j = 0; j < gmap->vert_to_loop[v_index].count; j++) {
3447  int elem_index;
3448 
3449  if constexpr (domain == ATTR_DOMAIN_CORNER) {
3450  elem_index = gmap->vert_to_loop[v_index].indices[j];
3451  }
3452  else {
3453  elem_index = v_index;
3454  }
3455 
3456  Color *col = lcol + elem_index;
3457 
3458  /* Color is squared to compensate the sqrt color encoding. */
3459  accum2->value[0] += col->r * col->r;
3460  accum2->value[1] += col->g * col->g;
3461  accum2->value[2] += col->b * col->b;
3462  }
3463  }
3464  }
3465  }
3466  }
3468  }
3469  });
3470 
3471  Blend accum_len = 0;
3472  Blend accum_value[3] = {0};
3473  Color blend(0, 0, 0, 0);
3474 
3475  for (int i = 0; i < totnode; i++) {
3476  accum_len += accum[i].len;
3477  accum_value[0] += accum[i].value[0];
3478  accum_value[1] += accum[i].value[1];
3479  accum_value[2] += accum[i].value[2];
3480  }
3481  if (accum_len != 0) {
3482  blend.r = Traits::round(sqrtf(Traits::divide_round(accum_value[0], accum_len)));
3483  blend.g = Traits::round(sqrtf(Traits::divide_round(accum_value[1], accum_len)));
3484  blend.b = Traits::round(sqrtf(Traits::divide_round(accum_value[2], accum_len)));
3485  blend.a = Traits::range;
3486 
3487  vpd->paintcol = blend;
3488  }
3489 }
3490 
3491 template<typename Color, typename Traits, eAttrDomain domain>
3494  const float v_co[3],
3495  Color *r_color)
3496 {
3498  ColorPaint4f rgba_br = toFloat(*r_color);
3499 
3500  paint_and_tex_color_alpha_intern(vp, &vpd->vc, v_co, &rgba.r);
3501 
3502  rgb_uchar_to_float(&rgba_br.r, (const uchar *)&vpd->paintcol);
3503  mul_v3_v3(rgba_br, rgba);
3504 
3505  *r_color = fromFloat<Color>(rgba_br);
3506  return rgba[3];
3507 }
3508 
3509 template<typename Color, typename Traits, eAttrDomain domain>
3510 static void vpaint_do_draw(bContext *C,
3511  Sculpt *UNUSED(sd),
3512  VPaint *vp,
3514  Object *ob,
3515  Mesh *me,
3516  PBVHNode **nodes,
3517  int totnode,
3518  Color *lcol)
3519 {
3520  SculptSession *ss = ob->sculpt;
3521  const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
3522 
3523  const Brush *brush = ob->sculpt->cache->brush;
3524  const Scene *scene = CTX_data_scene(C);
3525 
3526  Color *previous_color = static_cast<Color *>(ss->cache->prev_colors_vpaint);
3527 
3528  blender::threading::parallel_for(IndexRange(totnode), 1LL, [&](IndexRange range) {
3529  for (int n : range) {
3530  const bool has_grids = (pbvh_type == PBVH_GRIDS);
3531  const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
3532 
3533  const StrokeCache *cache = ss->cache;
3534  float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
3536  scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
3537  const bool use_normal = vwpaint_use_normal(vp);
3538  const bool use_vert_sel = (me->editflag &
3540  const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
3541 
3542  SculptBrushTest test;
3544  ss, &test, brush->falloff_shape);
3545  const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
3546  ss, brush->falloff_shape);
3547 
3548  Color paintcol = vpd->paintcol;
3549 
3550  /* For each vertex */
3551  PBVHVertexIter vd;
3552  BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
3553  /* Test to see if the vertex coordinates are within the spherical brush region. */
3554  if (sculpt_brush_test_sq_fn(&test, vd.co)) {
3555  /* NOTE: Grids are 1:1 with corners (aka loops).
3556  * For grid based pbvh, take the vert whose loop corresponds to the current grid.
3557  * Otherwise, take the current vert. */
3558  const int v_index = has_grids ? me->mloop[vd.grid_indices[vd.g]].v :
3559  vd.vert_indices[vd.i];
3560  const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
3561  const MVert *mv = &me->mvert[v_index];
3562 
3563  /* If the vertex is selected for painting. */
3564  if (!use_vert_sel || mv->flag & SELECT) {
3565  /* Calc the dot prod. between ray norm on surf and current vert
3566  * (ie splash prevention factor), and only paint front facing verts. */
3567  float brush_strength = cache->bstrength;
3568  const float angle_cos = (use_normal && vd.no) ?
3569  dot_v3v3(sculpt_normal_frontface, vd.no) :
3570  1.0f;
3571  if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
3572  ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
3574  &vpd->normal_angle_precalc, angle_cos, &brush_strength))) {
3575  const float brush_fade = BKE_brush_curve_strength(
3576  brush, sqrtf(test.dist), cache->radius);
3577 
3578  Color color_final = paintcol;
3579 
3580  /* If we're painting with a texture, sample the texture color and alpha. */
3581  float tex_alpha = 1.0;
3582  if (vpd->is_texbrush) {
3583  /* NOTE: we may want to paint alpha as vertex color alpha. */
3584  tex_alpha = paint_and_tex_color_alpha<Color, Traits, domain>(
3585  vp, vpd, vpd->vertexcosnos[v_index].co, &color_final);
3586  }
3587 
3588  Color color_orig(0, 0, 0, 0);
3589 
3590  if constexpr (domain == ATTR_DOMAIN_POINT) {
3591  int v_index = vd.index;
3592 
3593  if (previous_color != nullptr) {
3594  /* Get the previous loop color */
3595  if (isZero(previous_color[v_index])) {
3596  previous_color[v_index] = lcol[v_index];
3597  }
3598  color_orig = previous_color[v_index];
3599  }
3600  const float final_alpha = Traits::frange * brush_fade * brush_strength *
3601  tex_alpha * brush_alpha_pressure * grid_alpha;
3602 
3603  lcol[v_index] = vpaint_blend<Color, Traits>(vp,
3604  lcol[v_index],
3605  color_orig,
3606  color_final,
3607  final_alpha,
3608  Traits::range * brush_strength);
3609  }
3610  else {
3611  /* For each poly owning this vert, paint each loop belonging to this vert. */
3612  for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
3613  const int p_index = gmap->vert_to_poly[v_index].indices[j];
3614  const int l_index = gmap->vert_to_loop[v_index].indices[j];
3615  BLI_assert(me->mloop[l_index].v == v_index);
3616  const MPoly *mp = &me->mpoly[p_index];
3617  if (!use_face_sel || mp->flag & ME_FACE_SEL) {
3618  Color color_orig = Color(0, 0, 0, 0); /* unused when array is nullptr */
3619 
3620  if (previous_color != nullptr) {
3621  /* Get the previous loop color */
3622  if (isZero(previous_color[l_index])) {
3623  previous_color[l_index] = lcol[l_index];
3624  }
3625  color_orig = previous_color[l_index];
3626  }
3627  const float final_alpha = Traits::frange * brush_fade * brush_strength *
3628  tex_alpha * brush_alpha_pressure * grid_alpha;
3629 
3630  /* Mix the new color with the original based on final_alpha. */
3631  lcol[l_index] = vpaint_blend<Color, Traits>(vp,
3632  lcol[l_index],
3633  color_orig,
3634  color_final,
3635  final_alpha,
3636  Traits::range * brush_strength);
3637  }
3638  }
3639  }
3640  }
3641  }
3642  }
3643  }
3645  }
3646  });
3647 }
3648 
3649 template<typename Color, typename Traits, eAttrDomain domain>
3650 static void vpaint_do_blur(bContext *C,
3651  Sculpt *sd,
3652  VPaint *vp,
3654  Object *ob,
3655  Mesh *me,
3656  PBVHNode **nodes,
3657  int totnode,
3658  Color *lcol)
3659 {
3660  if constexpr (domain == ATTR_DOMAIN_POINT) {
3661  do_vpaint_brush_blur_verts<Color, Traits>(C, sd, vp, vpd, ob, me, nodes, totnode, lcol);
3662  }
3663  else {
3664  do_vpaint_brush_blur_loops<Color, Traits>(C, sd, vp, vpd, ob, me, nodes, totnode, lcol);
3665  }
3666 }
3667 
3668 template<typename Color, typename Traits, eAttrDomain domain>
3670  Sculpt *sd,
3671  VPaint *vp,
3673  Object *ob,
3674  Mesh *me,
3675  Color *lcol,
3676  PBVHNode **nodes,
3677  int totnode)
3678 {
3679 
3680  for (int i : IndexRange(totnode)) {
3682  }
3683 
3684  const Brush *brush = ob->sculpt->cache->brush;
3685 
3686  switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) {
3687  case VPAINT_TOOL_AVERAGE:
3688  calculate_average_color<Color, Traits, domain>(vpd, ob, me, brush, lcol, nodes, totnode);
3689  vpaint_do_draw<Color, Traits, domain>(C, sd, vp, vpd, ob, me, nodes, totnode, lcol);
3690  break;
3691  case VPAINT_TOOL_DRAW:
3692  vpaint_do_draw<Color, Traits, domain>(C, sd, vp, vpd, ob, me, nodes, totnode, lcol);
3693  break;
3694  case VPAINT_TOOL_BLUR:
3695  vpaint_do_blur<Color, Traits, domain>(C, sd, vp, vpd, ob, me, nodes, totnode, lcol);
3696  break;
3697  case VPAINT_TOOL_SMEAR:
3698  do_vpaint_brush_smear<Color, Traits, domain>(C, sd, vp, vpd, ob, me, nodes, totnode, lcol);
3699  break;
3700  default:
3701  break;
3702  }
3703 }
3704 
3705 template<typename Color, typename Traits, eAttrDomain domain>
3706 static void vpaint_do_paint(bContext *C,
3707  Sculpt *sd,
3708  VPaint *vp,
3710  Object *ob,
3711  Mesh *me,
3712  Brush *brush,
3713  const char symm,
3714  const int axis,
3715  const int i,
3716  const float angle)
3717 {
3718  SculptSession *ss = ob->sculpt;
3719  ss->cache->radial_symmetry_pass = i;
3720  SCULPT_cache_calc_brushdata_symm(ss->cache, symm, axis, angle);
3721 
3722  int totnode;
3723  PBVHNode **nodes = vwpaint_pbvh_gather_generic(ob, vp, sd, brush, &totnode);
3724 
3726  Color *color_data = static_cast<Color *>(layer->data);
3727 
3728  /* Paint those leaves. */
3729  vpaint_paint_leaves<Color, Traits, domain>(C, sd, vp, vpd, ob, me, color_data, nodes, totnode);
3730 
3731  if (nodes) {
3732  MEM_freeN(nodes);
3733  }
3734 }
3735 
3736 template<typename Color, typename Traits, eAttrDomain domain>
3738  Sculpt *sd,
3739  VPaint *vp,
3741  Object *ob,
3742  Mesh *me,
3743  Brush *brush,
3744  const char symm,
3745  const int axis)
3746 {
3747  for (int i = 1; i < vp->radial_symm[axis - 'X']; i++) {
3748  const float angle = (2.0 * M_PI) * i / vp->radial_symm[axis - 'X'];
3749  vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, symm, axis, i, angle);
3750  }
3751 }
3752 
3753 /* near duplicate of: sculpt.c's,
3754  * 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */
3755 template<typename Color, typename Traits, eAttrDomain domain>
3758 {
3759  Brush *brush = BKE_paint_brush(&vp->paint);
3760  Mesh *me = (Mesh *)ob->data;
3761  SculptSession *ss = ob->sculpt;
3762  StrokeCache *cache = ss->cache;
3763  const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
3764  int i = 0;
3765 
3766  /* initial stroke */
3767  cache->mirror_symmetry_pass = 0;
3768  vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'X', 0, 0);
3769  vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'X');
3770  vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Y');
3771  vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Z');
3772 
3773  cache->symmetry = symm;
3774 
3775  /* symm is a bit combination of XYZ - 1 is mirror
3776  * X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
3777  for (i = 1; i <= symm; i++) {
3778  if (symm & i && (symm != 5 || i != 3) && (symm != 6 || (!ELEM(i, 3, 5)))) {
3779  cache->mirror_symmetry_pass = i;
3780  cache->radial_symmetry_pass = 0;
3781  SCULPT_cache_calc_brushdata_symm(cache, i, 0, 0);
3782 
3783  if (i & (1 << 0)) {
3784  vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'X', 0, 0);
3785  vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'X');
3786  }
3787  if (i & (1 << 1)) {
3788  vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Y', 0, 0);
3789  vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Y');
3790  }
3791  if (i & (1 << 2)) {
3792  vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Z', 0, 0);
3793  vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Z');
3794  }
3795  }
3796  }
3797 
3798  copy_v3_v3(cache->true_last_location, cache->true_location);
3799  cache->is_last_valid = true;
3800 }
3801 
3802 template<typename Color, typename Traits, eAttrDomain domain>
3804 {
3808  paint_stroke_mode_data(stroke));
3809  VPaint *vp = ts->vpaint;
3810  ViewContext *vc = &vpd->vc;
3811  Object *ob = vc->obact;
3812  SculptSession *ss = ob->sculpt;
3814 
3815  vwpaint_update_cache_variants(C, vp, ob, itemptr);
3816 
3817  float mat[4][4];
3818 
3819  ED_view3d_init_mats_rv3d(ob, vc->rv3d);
3820 
3821  /* load projection matrix */
3822  mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat);
3823 
3824  swap_m4m4(vc->rv3d->persmat, mat);
3825 
3826  vpaint_do_symmetrical_brush_actions<Color, Traits, domain>(C, sd, vp, vpd, ob);
3827 
3828  swap_m4m4(vc->rv3d->persmat, mat);
3829 
3831 
3832  if (vp->paint.brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) {
3834 
3835  size_t elem_size;
3836  int elem_num;
3837 
3838  elem_num = get_vcol_elements(me, &elem_size);
3839  memcpy(vpd->smear.color_prev, vpd->smear.color_curr, elem_size * elem_num);
3840  }
3841 
3842  /* Calculate pivot for rotation around selection if needed.
3843  * also needed for "Frame Selected" on last stroke. */
3844  float loc_world[3];
3845  mul_v3_m4v3(loc_world, ob->obmat, ss->cache->true_location);
3846  paint_last_stroke_update(scene, loc_world);
3847 
3849 
3851 }
3852 
3854  wmOperator *UNUSED(op),
3855  PaintStroke *stroke,
3856  PointerRNA *itemptr)
3857 {
3858  VPaintDataBase *vpd = static_cast<VPaintDataBase *>(paint_stroke_mode_data(stroke));
3859 
3860  if (vpd->domain == ATTR_DOMAIN_POINT) {
3861  if (vpd->type == CD_PROP_COLOR) {
3862  vpaint_stroke_update_step_intern<ColorPaint4f, FloatTraits, ATTR_DOMAIN_POINT>(
3863  C, stroke, itemptr);
3864  }
3865  else if (vpd->type == CD_PROP_BYTE_COLOR) {
3866  vpaint_stroke_update_step_intern<ColorPaint4b, ByteTraits, ATTR_DOMAIN_POINT>(
3867  C, stroke, itemptr);
3868  }
3869  }
3870  else if (vpd->domain == ATTR_DOMAIN_CORNER) {
3871  if (vpd->type == CD_PROP_COLOR) {
3872  vpaint_stroke_update_step_intern<ColorPaint4f, FloatTraits, ATTR_DOMAIN_CORNER>(
3873  C, stroke, itemptr);
3874  }
3875  else if (vpd->type == CD_PROP_BYTE_COLOR) {
3876  vpaint_stroke_update_step_intern<ColorPaint4b, ByteTraits, ATTR_DOMAIN_CORNER>(
3877  C, stroke, itemptr);
3878  }
3879  }
3880 }
3881 
3882 template<typename Color, typename Traits, eAttrDomain domain>
3883 static void vpaint_free_vpaintdata(Object *UNUSED(ob), void *_vpd)
3884 {
3886 
3887  if (vpd->is_texbrush) {
3889  }
3890 
3891  if (vpd->smear.color_prev) {
3892  MEM_freeN(vpd->smear.color_prev);
3893  }
3894  if (vpd->smear.color_curr) {
3895  MEM_freeN(vpd->smear.color_curr);
3896  }
3897 
3898  MEM_delete<VPaintData<Color, Traits, domain>>(vpd);
3899 }
3900 
3901 static void vpaint_stroke_done(const bContext *C, PaintStroke *stroke)
3902 {
3903  void *vpd_ptr = paint_stroke_mode_data(stroke);
3904  VPaintDataBase *vpd = static_cast<VPaintDataBase *>(vpd_ptr);
3905 
3906  ViewContext *vc = &vpd->vc;
3907  Object *ob = vc->obact;
3908 
3909  if (vpd->domain == ATTR_DOMAIN_POINT) {
3910  if (vpd->type == CD_PROP_COLOR) {
3911  vpaint_free_vpaintdata<ColorPaint4f, FloatTraits, ATTR_DOMAIN_POINT>(ob, vpd);
3912  }
3913  else if (vpd->type == CD_PROP_BYTE_COLOR) {
3914  vpaint_free_vpaintdata<ColorPaint4b, ByteTraits, ATTR_DOMAIN_POINT>(ob, vpd);
3915  }
3916  }
3917  else if (vpd->domain == ATTR_DOMAIN_CORNER) {
3918  if (vpd->type == CD_PROP_COLOR) {
3919  vpaint_free_vpaintdata<ColorPaint4f, FloatTraits, ATTR_DOMAIN_CORNER>(ob, vpd);
3920  }
3921  else if (vpd->type == CD_PROP_BYTE_COLOR) {
3922  vpaint_free_vpaintdata<ColorPaint4b, ByteTraits, ATTR_DOMAIN_CORNER>(ob, vpd);
3923  }
3924  }
3925 
3926  SculptSession *ss = ob->sculpt;
3927 
3928  if (ss->cache->alt_smooth) {
3930  VPaint *vp = ts->vpaint;
3931  smooth_brush_toggle_off(C, &vp->paint, ss->cache);
3932  }
3933 
3935 
3937 
3939  ob->sculpt->cache = nullptr;
3940 }
3941 
3942 static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3943 {
3944  int retval;
3945 
3947  op,
3951  nullptr,
3953  event->type);
3954 
3956 
3957  if (SCULPT_has_loop_colors(ob) && ob->sculpt->pbvh) {
3959  }
3960 
3961  SCULPT_undo_push_begin(ob, "Vertex Paint");
3962 
3963  if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
3965  return OPERATOR_FINISHED;
3966  }
3967 
3968  /* add modal handler */
3970 
3971  OPERATOR_RETVAL_CHECK(retval);
3973 
3974  return OPERATOR_RUNNING_MODAL;
3975 }
3976 
3977 static int vpaint_exec(bContext *C, wmOperator *op)
3978 {
3980  op,
3984  nullptr,
3986  0);
3987 
3988  /* frees op->customdata */
3990 
3991  return OPERATOR_FINISHED;
3992 }
3993 
3994 static void vpaint_cancel(bContext *C, wmOperator *op)
3995 {
3997  if (ob->sculpt->cache) {
3999  ob->sculpt->cache = nullptr;
4000  }
4001 
4003 }
4004 
4005 static int vpaint_modal(bContext *C, wmOperator *op, const wmEvent *event)
4006 {
4007  return paint_stroke_modal(C, op, event, (PaintStroke **)&op->customdata);
4008 }
4009 
4011 {
4012  /* identifiers */
4013  ot->name = "Vertex Paint";
4014  ot->idname = "PAINT_OT_vertex_paint";
4015  ot->description = "Paint a stroke in the active color attribute layer";
4016 
4017  /* api callbacks */
4018  ot->invoke = vpaint_invoke;
4019  ot->modal = vpaint_modal;
4020  ot->exec = vpaint_exec;
4022  ot->cancel = vpaint_cancel;
4023 
4024  /* flags */
4026 
4028 }
4029 
4032 /* -------------------------------------------------------------------- */
4036 template<typename Color, typename Traits, eAttrDomain domain>
4037 static bool vertex_color_set(Object *ob, ColorPaint4f paintcol_in, CustomDataLayer *layer)
4038 {
4039  Mesh *me;
4040  if (((me = BKE_mesh_from_object(ob)) == nullptr) ||
4041  (ED_mesh_color_ensure(me, nullptr) == false)) {
4042  return false;
4043  }
4044 
4045  Color paintcol = fromFloat<Color>(paintcol_in);
4046 
4047  const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
4048  const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
4049 
4050  if (me->edit_mesh) {
4051  BMesh *bm = me->edit_mesh->bm;
4052  BMFace *f;
4053  BMIter iter;
4054 
4055  int cd_offset = -1;
4056 
4057  /* Find customdata offset inside of bmesh. */
4058  CustomData *cdata = domain == ATTR_DOMAIN_POINT ? &bm->vdata : &bm->ldata;
4059 
4060  for (int i = 0; i < cdata->totlayer; i++) {
4061  if (STREQ(cdata->layers[i].name, layer->name)) {
4062  cd_offset = layer->offset;
4063  }
4064  }
4065 
4066  BLI_assert(cd_offset != -1);
4067 
4068  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
4069  Color *color;
4070  BMLoop *l = f->l_first;
4071 
4072  do {
4073  if (!(use_vert_sel && !(BM_elem_flag_test(l->v, BM_ELEM_SELECT)))) {
4074  if constexpr (domain == ATTR_DOMAIN_CORNER) {
4075  color = static_cast<Color *>(BM_ELEM_CD_GET_VOID_P(l, cd_offset));
4076  }
4077  else {
4078  color = static_cast<Color *>(BM_ELEM_CD_GET_VOID_P(l->v, cd_offset));
4079  }
4080 
4081  *color = paintcol;
4082  }
4083  } while ((l = l->next) != f->l_first);
4084  }
4085  }
4086  else {
4087  Color *color_layer = static_cast<Color *>(layer->data);
4088 
4089  const MPoly *mp = me->mpoly;
4090  for (int i = 0; i < me->totpoly; i++, mp++) {
4091  if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
4092  continue;
4093  }
4094 
4095  int j = 0;
4096  do {
4097  uint vidx = me->mloop[mp->loopstart + j].v;
4098 
4099  if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) {
4100  if constexpr (domain == ATTR_DOMAIN_CORNER) {
4101  color_layer[mp->loopstart + j] = paintcol;
4102  }
4103  else {
4104  color_layer[vidx] = paintcol;
4105  }
4106  }
4107  j++;
4108  } while (j < mp->totloop);
4109  }
4110 
4111  /* remove stale me->mcol, will be added later */
4113  }
4114 
4116 
4117  /* NOTE: Original mesh is used for display, so tag it directly here. */
4119 
4120  return true;
4121 }
4122 
4127  ColorPaint4f fill_color,
4128  bool only_selected = true)
4129 {
4131  if (!me) {
4132  return false;
4133  }
4135  if (!layer) {
4136  return false;
4137  }
4138  /* Store original #Mesh.editflag.*/
4139  const decltype(me->editflag) editflag = me->editflag;
4140  if (!only_selected) {
4143  }
4144  eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
4145  bool ok = false;
4146  if (domain == ATTR_DOMAIN_POINT) {
4147  if (layer->type == CD_PROP_COLOR) {
4148  ok = vertex_color_set<ColorPaint4f, FloatTraits, ATTR_DOMAIN_POINT>(ob, fill_color, layer);
4149  }
4150  else if (layer->type == CD_PROP_BYTE_COLOR) {
4151  ok = vertex_color_set<ColorPaint4b, ByteTraits, ATTR_DOMAIN_POINT>(ob, fill_color, layer);
4152  }
4153  }
4154  else {
4155  if (layer->type == CD_PROP_COLOR) {
4156  ok = vertex_color_set<ColorPaint4f, FloatTraits, ATTR_DOMAIN_CORNER>(ob, fill_color, layer);
4157  }
4158  else if (layer->type == CD_PROP_BYTE_COLOR) {
4159  ok = vertex_color_set<ColorPaint4b, ByteTraits, ATTR_DOMAIN_CORNER>(ob, fill_color, layer);
4160  }
4161  }
4162  /* Restore #Mesh.editflag. */
4163  me->editflag = editflag;
4164  return ok;
4165 }
4166 
4168  const float fill_color[4],
4169  bool only_selected)
4170 {
4171  return paint_object_attributes_active_color_fill_ex(ob, ColorPaint4f(fill_color), only_selected);
4172 }
4173 
4175 {
4177  Object *obact = CTX_data_active_object(C);
4178 
4179  // uint paintcol = vpaint_get_current_color(scene, scene->toolsettings->vpaint, false);
4180  ColorPaint4f paintcol = vpaint_get_current_col<ColorPaint4f, FloatTraits, ATTR_DOMAIN_POINT>(
4181  scene, scene->toolsettings->vpaint, false);
4182 
4183  if (paint_object_attributes_active_color_fill_ex(obact, paintcol)) {
4185  return OPERATOR_FINISHED;
4186  }
4187  return OPERATOR_CANCELLED;
4188 }
4189 
4191 {
4192  /* identifiers */
4193  ot->name = "Set Vertex Colors";
4194  ot->idname = "PAINT_OT_vertex_color_set";
4195  ot->description = "Fill the active vertex color layer with the current paint color";
4196 
4197  /* api callbacks */
4200 
4201  /* flags */
4203 }
4204 
typedef float(TangentPoint)[2]
Generic geometry attributes built on CustomData.
eAttrDomain
Definition: BKE_attribute.h:25
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:30
struct CustomDataLayer * BKE_id_attributes_active_color_get(const struct ID *id)
eAttrDomain BKE_id_attribute_domain(const struct ID *id, const struct CustomDataLayer *layer)
void BKE_brush_size_set(struct Scene *scene, struct Brush *brush, int size)
Definition: brush.cc:2234
float BKE_brush_curve_strength(const struct Brush *br, float p, float len)
float BKE_brush_sample_tex_3d(const struct Scene *scene, const struct Brush *br, const float point[3], float rgba[4], int thread, struct ImagePool *pool)
bool BKE_brush_use_size_pressure(const struct Brush *brush)
float BKE_brush_weight_get(const struct Scene *scene, const struct Brush *brush)
const float * BKE_brush_secondary_color_get(const struct Scene *scene, const struct Brush *brush)
Definition: brush.cc:2216
float BKE_brush_alpha_get(const struct Scene *scene, const struct Brush *brush)
const float * BKE_brush_color_get(const struct Scene *scene, const struct Brush *brush)
Definition: brush.cc:2210
int BKE_brush_size_get(const struct Scene *scene, const struct Brush *brush)
void BKE_brush_unprojected_radius_set(struct Scene *scene, struct Brush *brush, float unprojected_radius)
Definition: brush.cc:2294
bool BKE_brush_use_alpha_pressure(const struct Brush *brush)
void BKE_curvemapping_init(struct CurveMapping *cumap)
Definition: colortools.c:1235
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:738
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct Depsgraph * CTX_data_depsgraph_on_load(const bContext *C)
Definition: context.c:1536
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
struct wmMsgBus * CTX_wm_message_bus(const bContext *C)
Definition: context.c:770
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct ToolSettings * CTX_data_tool_settings(const bContext *C)
Definition: context.c:1282
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:793
support for deformation groups and hooks.
int BKE_object_defgroup_active_index_get(const struct Object *ob)
struct MDeformWeight * BKE_defvert_find_index(const struct MDeformVert *dv, int defgroup)
float BKE_defvert_total_selected_weight(const struct MDeformVert *dv, int defbase_tot, const bool *defbase_sel)
Definition: deform.c:872
struct MDeformWeight * BKE_defvert_ensure_index(struct MDeformVert *dv, int defgroup)
Definition: deform.c:748
float BKE_defvert_calc_lock_relative_weight(float weight, float locked_weight, float unlocked_weight)
Definition: deform.c:911
float BKE_defvert_lock_relative_weight(float weight, const struct MDeformVert *dv, int defbase_tot, const bool *defbase_locked, const bool *defbase_unlocked)
Definition: deform.c:939
void BKE_defvert_array_free_elems(struct MDeformVert *dvert, int totvert)
Definition: deform.c:978
void BKE_defvert_copy(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src)
float BKE_defvert_find_weight(const struct MDeformVert *dvert, int defgroup)
Definition: deform.c:704
float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv, int defbase_tot, const bool *defbase_sel, int defbase_tot_sel, bool is_normalized)
Definition: deform.c:894
#define VERTEX_WEIGHT_LOCK_EPSILON
Definition: BKE_deform.h:133
struct ID * BKE_libblock_find_name(struct Main *bmain, short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: lib_id.c:1297
void BKE_mesh_flush_select_from_verts(struct Mesh *me)
void BKE_mesh_tessface_clear(struct Mesh *mesh)
Definition: mesh.cc:1654
struct Mesh * BKE_mesh_from_object(struct Object *ob)
Definition: mesh.cc:1365
void BKE_mesh_batch_cache_dirty_tag(struct Mesh *me, eMeshBatchDirtyMode mode)
void BKE_mesh_flush_select_from_polys(struct Mesh *me)
void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map, int **r_mem, const struct MPoly *mpoly, const struct MLoop *mloop, int totvert, int totpoly, int totloop)
void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map, int **r_mem, const struct MPoly *mpoly, const struct MLoop *mloop, int totvert, int totpoly, int totloop)
@ BKE_MESH_BATCH_DIRTY_ALL
General operations, lookup, etc. for blender objects.
void BKE_object_free_derived_caches(struct Object *ob)
Definition: object.cc:1774
struct Mesh * BKE_object_get_original_mesh(const struct Object *object)
Functions for dealing with objects and deform verts, used by painting and tools.
bool BKE_object_defgroup_check_lock_relative(const bool *lock_flags, const bool *validmap, int index)
void BKE_object_defgroup_split_locked_validmap(int defbase_tot, const bool *locked, const bool *deform, bool *r_locked, bool *r_unlocked)
bool * BKE_object_defgroup_validmap_get(struct Object *ob, int defbase_tot)
void BKE_object_defgroup_mirror_selection(struct Object *ob, int defbase_tot, const bool *selection, bool *dg_flags_sel, int *r_dg_flags_sel_tot)
bool BKE_object_defgroup_check_lock_relative_multi(int defbase_tot, const bool *lock_flags, const bool *selected, int sel_tot)
bool * BKE_object_defgroup_lock_flags_get(struct Object *ob, int defbase_tot)
bool * BKE_object_defgroup_selected_get(struct Object *ob, int defbase_tot, int *r_dg_flags_sel_tot)
void BKE_paint_brush_set(struct Paint *paint, struct Brush *br)
Definition: paint.c:617
struct Paint * BKE_paint_get_active_from_paintmode(struct Scene *sce, ePaintMode mode)
Definition: paint.c:345
void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene)
Definition: paint.c:1992
const char PAINT_CURSOR_VERTEX_PAINT[3]
Definition: paint.c:221
void BKE_sculpt_update_object_for_edit(struct Depsgraph *depsgraph, struct Object *ob_orig, bool need_pmap, bool need_mask, bool is_paint_tool)
Definition: paint.c:1914
struct Brush * BKE_paint_toolslots_brush_get(struct Paint *paint, int slot_index)
struct Brush * BKE_paint_brush(struct Paint *paint)
Definition: paint.c:607
void BKE_paint_init(struct Main *bmain, struct Scene *sce, ePaintMode mode, const char col[3])
Definition: paint.c:1130
bool BKE_paint_ensure(struct ToolSettings *ts, struct Paint **r_paint)
Definition: paint.c:1042
void BKE_sculptsession_free(struct Object *ob)
Definition: paint.c:1469
const char PAINT_CURSOR_WEIGHT_PAINT[3]
Definition: paint.c:222
void BKE_paint_toolslots_brush_validate(struct Main *bmain, struct Paint *paint)
ePaintMode
Definition: BKE_paint.h:67
@ PAINT_MODE_SCULPT
Definition: BKE_paint.h:68
@ PAINT_MODE_WEIGHT
Definition: BKE_paint.h:71
@ PAINT_MODE_VERTEX
Definition: BKE_paint.h:70
const struct Brush * BKE_paint_brush_for_read(const struct Paint *p)
#define BKE_pbvh_vertex_iter_begin(pbvh, node, vi, mode)
Definition: BKE_pbvh.h:439
PBVHType BKE_pbvh_type(const PBVH *pbvh)
Definition: pbvh.c:1798
#define BKE_pbvh_vertex_iter_end
Definition: BKE_pbvh.h:509
#define PBVH_ITER_UNIQUE
Definition: BKE_pbvh.h:391
PBVHType
Definition: BKE_pbvh.h:233
@ PBVH_GRIDS
Definition: BKE_pbvh.h:235
void BKE_pbvh_ensure_node_loops(PBVH *pbvh)
Definition: pbvh.c:3280
void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings, bool use_threading, int totnode)
Definition: pbvh.c:3211
void BKE_pbvh_update_bounds(PBVH *pbvh, int flags)
Definition: pbvh.c:1545
void BKE_pbvh_search_gather(PBVH *pbvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***array, int *tot)
Definition: pbvh.c:838
@ PBVH_UpdateBB
Definition: BKE_pbvh.h:67
@ PBVH_UpdateRedraw
Definition: BKE_pbvh.h:70
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
Generic array manipulation API.
#define BLI_array_binary_or(arr, arr_a, arr_b, arr_len)
#define BLI_assert(a)
Definition: BLI_assert.h:46
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define M_PI_2
Definition: BLI_math_base.h:23
#define M_PI
Definition: BLI_math_base.h:20
void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3])
Definition: math_color.c:376
void dist_squared_ray_to_aabb_v3_precalc(struct DistRayAABB_Precalc *neasrest_precalc, const float ray_origin[3], const float ray_direction[3])
Definition: math_geom.c:651
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:926
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:87
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void swap_m4m4(float m1[4][4], float m2[4][4])
Definition: math_matrix.c:233
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
#define RAD2DEGF(_rad)
MINLINE float normalize_v3(float r[3])
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
Definition: math_vector.c:638
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v4(float r[4])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE void zero_v2(float r[2])
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
void BLI_rcti_union(struct rcti *rct_a, const struct rcti *rct_b)
bool BLI_rcti_is_empty(const struct rcti *rect)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
unsigned char uchar
Definition: BLI_sys_types.h:70
unsigned int uint
Definition: BLI_sys_types.h:67
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:94
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:293
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define MAX2(a, b)
#define ELEM(...)
#define MIN2(a, b)
#define STREQ(a, b)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:834
@ ID_RECALC_PSYS_RESET
Definition: DNA_ID.h:800
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:566
@ ID_BR
Definition: DNA_ID_enums.h:69
@ BRUSH_LOCK_ALPHA
@ BRUSH_FRONTFACE
@ BRUSH_ACCUMULATE
@ BRUSH_FRONTFACE_FALLOFF
eBrushWeightPaintTool
@ WPAINT_TOOL_BLUR
@ WPAINT_TOOL_AVERAGE
@ WPAINT_TOOL_SMEAR
@ WPAINT_TOOL_DRAW
eBrushVertexPaintTool
@ VPAINT_TOOL_BLUR
@ VPAINT_TOOL_DRAW
@ VPAINT_TOOL_SMEAR
@ VPAINT_TOOL_AVERAGE
@ PAINT_FALLOFF_SHAPE_SPHERE
eCustomDataType
@ CD_PROP_BYTE_COLOR
@ CD_PROP_COLOR
@ ME_EDIT_MIRROR_VERTEX_GROUPS
@ ME_EDIT_PAINT_VERT_SEL
@ ME_EDIT_PAINT_FACE_SEL
@ ME_EDIT_MIRROR_TOPO
#define ME_USING_MIRROR_X_VERTEX_GROUPS(_me)
@ ME_FACE_SEL
eObjectMode
@ OB_MODE_WEIGHT_PAINT
@ OB_MODE_VERTEX_PAINT
Object is a sort of wrapper for general info.
@ OB_MESH
#define DG_LOCK_WEIGHT
#define PSYS_TOT_VG
@ VP_FLAG_VGROUP_RESTRICT
@ RGN_TYPE_WINDOW
@ RGN_TYPE_HUD
@ SPACE_VIEW3D
#define MTEX_MAP_MODE_3D
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
#define OPERATOR_RETVAL_CHECK(ret)
void ED_paint_cursor_start(struct Paint *p, bool(*poll)(struct bContext *C))
void ED_mesh_mirror_topo_table_end(struct Object *ob)
bool ED_vgroup_sync_from_pose(struct Object *ob)
bool ED_mesh_color_ensure(struct Mesh *me, const char *name)
Definition: mesh_data.cc:423
void ED_mesh_mirror_spatial_table_end(struct Object *ob)
int mesh_get_x_mirror_vert(struct Object *ob, struct Mesh *me_eval, int index, bool use_topology)
Definition: meshtools.cc:916
void ED_object_posemode_set_for_weight_paint(struct bContext *C, struct Main *bmain, struct Object *ob, bool is_mode_set)
Definition: object_modes.c:357
bool ED_object_mode_compat_set(struct bContext *C, struct Object *ob, eObjectMode mode, struct ReportList *reports)
Definition: object_modes.c:161
void ED_region_tag_redraw_partial(struct ARegion *region, const struct rcti *rct, bool rebuild)
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
eV3DProjTest
Definition: ED_view3d.h:233
@ V3D_PROJ_TEST_CLIP_NEAR
Definition: ED_view3d.h:237
@ V3D_PROJ_TEST_CLIP_BB
Definition: ED_view3d.h:235
void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc, struct Depsgraph *depsgraph)
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:217
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, const struct Object *ob, float r_pmat[4][4])
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
void view3d_operator_needs_opengl(const struct bContext *C)
void ED_view3d_init_mats_rv3d(const struct Object *ob, struct RegionView3D *rv3d)
Definition: space_view3d.c:166
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
BLI_INLINE void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
IMB_BlendMode
Definition: IMB_imbuf.h:209
@ IMB_BLEND_ERASE_ALPHA
Definition: IMB_imbuf.h:216
@ IMB_BLEND_ADD_ALPHA
Definition: IMB_imbuf.h:217
@ IMB_BLEND_DARKEN
Definition: IMB_imbuf.h:215
@ IMB_BLEND_LIGHTEN
Definition: IMB_imbuf.h:214
@ IMB_BLEND_MIX
Definition: IMB_imbuf.h:210
@ IMB_BLEND_ADD
Definition: IMB_imbuf.h:211
@ IMB_BLEND_SUB
Definition: IMB_imbuf.h:212
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color or the default fallback if none is specified Separate Split a vector into its and Z components Generates normals with round corners and may slow down renders Vector Displace the surface along an arbitrary direction White Return a random value or color based on an input seed Float Map an input float to a curve and outputs a float value Separate Color
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a producing a negative Combine Generate a color from its and blue Hue Saturation Value
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a color
#define C
Definition: RandGen.cpp:25
@ OPTYPE_BLOCKING
Definition: WM_types.h:150
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define ND_DRAW
Definition: WM_types.h:410
#define ND_MODE
Definition: WM_types.h:393
#define NC_SCENE
Definition: WM_types.h:328
#define NC_OBJECT
Definition: WM_types.h:329
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:541
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_MESH
ATTR_WARN_UNUSED_RESULT BMesh * bm
ATTR_WARN_UNUSED_RESULT const BMLoop * l
static T sum(const btAlignedObjectArray< T > &items)
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
ChannelStorageType r
Definition: BLI_color.hh:85
#define cosf(x)
Definition: cuda/compat.h:101
#define SELECT
Scene scene
const Depsgraph * depsgraph
uint col
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
#define acosf(x)
Definition: metal/compat.h:222
#define sqrtf(x)
Definition: metal/compat.h:243
static unsigned c
Definition: RandGen.cpp:83
static unsigned a[3]
Definition: RandGen.cpp:78
static void area(int d1, int d2, int e1, int e2, float weights[2])
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
ColorSceneLinear4f< eAlpha::Straight > ColorPaint4f
Definition: BLI_color.hh:348
static const pxr::TfToken rgba("rgba", pxr::TfToken::Immortal)
void paint_cursor_delete_textures(void)
Definition: paint_cursor.c:88
void paint_stroke_cancel(struct bContext *C, struct wmOperator *op, struct PaintStroke *stroke)
float ED_wpaint_blend_tool(int tool, float weight, float paintval, float alpha)
int paint_stroke_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event, struct PaintStroke **stroke_p)
int paint_stroke_exec(struct bContext *C, struct wmOperator *op, struct PaintStroke *stroke)
bool ED_wpaint_ensure_data(struct bContext *C, struct ReportList *reports, enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index)
struct PaintStroke * paint_stroke_new(struct bContext *C, struct wmOperator *op, StrokeGetLocation get_location, StrokeTestStart test_start, StrokeUpdateStep update_step, StrokeRedraw redraw, StrokeDone done, int event_type)
Definition: paint_stroke.c:874
@ BRUSH_STROKE_SMOOTH
Definition: paint_intern.h:451
@ BRUSH_STROKE_INVERT
Definition: paint_intern.h:450
void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data)
@ WPAINT_ENSURE_MIRROR
Definition: paint_intern.h:158
float paint_calc_object_space_radius(struct ViewContext *vc, const float center[3], float pixel_radius)
Definition: paint_utils.c:130
void paint_stroke_free(struct bContext *C, struct wmOperator *op, struct PaintStroke *stroke)
void ED_vpaint_proj_handle_free(struct VertProjHandle *vp_handle)
struct VertProjHandle * ED_vpaint_proj_handle_create(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct CoNo **r_vcosnos)
bool paint_supports_dynamic_size(struct Brush *br, enum ePaintMode mode)
void * paint_stroke_mode_data(struct PaintStroke *stroke)
struct ViewContext * paint_stroke_view_context(struct PaintStroke *stroke)
void paint_stroke_operator_properties(struct wmOperatorType *ot)
Definition: paint_utils.c:188
static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
static int wpaint_exec(bContext *C, wmOperator *op)
void PAINT_OT_vertex_color_set(wmOperatorType *ot)
void ED_object_wpaintmode_exit_ex(Object *ob)
void ED_object_vpaintmode_exit_ex(Object *ob)
static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
static void vpaint_do_draw(bContext *C, Sculpt *UNUSED(sd), VPaint *vp, VPaintData< Color, Traits, domain > *vpd, Object *ob, Mesh *me, PBVHNode **nodes, int totnode, Color *lcol)
static void vpaint_stroke_update_step_intern(bContext *C, PaintStroke *stroke, PointerRNA *itemptr)
static bool vpaint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
static void do_weight_paint_normalize_all(MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap)
void ED_object_wpaintmode_enter_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
void ED_object_vpaintmode_enter(bContext *C, Depsgraph *depsgraph)
bool BKE_object_attributes_active_color_fill(Object *ob, const float fill_color[4], bool only_selected)
void PAINT_OT_weight_paint(wmOperatorType *ot)
static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob)
static float paint_and_tex_color_alpha(VPaint *vp, VPaintData< Color, Traits, domain > *vpd, const float v_co[3], Color *r_color)
static Color vpaint_get_current_col(Scene *scene, VPaint *vp, bool secondary)
static void wpaint_do_radial_symmetry(bContext *C, Object *ob, VPaint *wp, Sculpt *sd, WPaintData *wpd, WeightPaintInfo *wpi, Mesh *me, Brush *brush, const char symm, const int axis)
static PBVHNode ** vwpaint_pbvh_gather_generic(Object *ob, VPaint *wp, Sculpt *sd, Brush *brush, int *r_totnode)
void PAINT_OT_vertex_paint(wmOperatorType *ot)
static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op)
static float wpaint_get_active_weight(const MDeformVert *dv, const WeightPaintInfo *wpi)
static void get_brush_alpha_data(const Scene *scene, const SculptSession *ss, const Brush *brush, float *r_brush_size_pressure, float *r_brush_alpha_value, float *r_brush_alpha_pressure)
uint vpaint_get_current_color(Scene *scene, VPaint *vp, bool secondary)
static bool weight_paint_poll_ex(bContext *C, bool check_tool)
static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
bool weight_paint_mode_poll(bContext *C)
static void vpaint_paint_leaves(bContext *C, Sculpt *sd, VPaint *vp, VPaintData< Color, Traits, domain > *vpd, Object *ob, Mesh *me, Color *lcol, PBVHNode **nodes, int totnode)
static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bool vertex_paint_poll_ex(bContext *C, bool check_tool)
bool weight_paint_poll(bContext *C)
static void paint_and_tex_color_alpha_intern(VPaint *vp, const ViewContext *vc, const float co[3], float r_rgba[4])
static float wpaint_blend(const VPaint *wp, float weight, const float alpha, float paintval, const float UNUSED(brush_alpha_value), const bool do_flip)
static void vwpaint_update_cache_invariants(bContext *C, VPaint *vp, SculptSession *ss, wmOperator *op, const float mval[2])
static Color vpaint_blend(const VPaint *vp, Color color_curr, Color color_orig, Color color_paint, const typename Traits::ValueType alpha, const typename Traits::BlendType brush_alpha_value)
void ED_object_wpaintmode_exit(bContext *C)
static void vpaint_stroke_done(const bContext *C, PaintStroke *stroke)
static bool brush_use_accumulate_ex(const Brush *brush, const int ob_mode)
static bool multipaint_verify_change(MDeformVert *dvert, const int defbase_tot, float change, const bool *defbase_sel)
static void vpaint_do_blur(bContext *C, Sculpt *sd, VPaint *vp, VPaintData< Color, Traits, domain > *vpd, Object *ob, Mesh *me, PBVHNode **nodes, int totnode, Color *lcol)
static void vpaint_do_symmetrical_brush_actions(bContext *C, Sculpt *sd, VPaint *vp, VPaintData< Color, Traits, domain > *vpd, Object *ob)
static bool isZero(ColorPaint4f c)
Definition: paint_vertex.cc:88
static int vpaint_exec(bContext *C, wmOperator *op)
bool vertex_paint_poll_ignore_tool(bContext *C)
static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void precompute_weight_values(bContext *C, Object *ob, Brush *brush, WPaintData *wpd, WeightPaintInfo *wpi, Mesh *me)
void ED_object_vpaintmode_enter_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
static bool paint_object_attributes_active_color_fill_ex(Object *ob, ColorPaint4f fill_color, bool only_selected=true)
static void wpaint_do_symmetrical_brush_actions(bContext *C, Object *ob, VPaint *wp, Sculpt *sd, WPaintData *wpd, WeightPaintInfo *wpi)
static void vpaint_free_vpaintdata(Object *UNUSED(ob), void *_vpd)
static bool paint_mode_toggle_poll_test(bContext *C)
static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache *cache)
static void do_weight_paint_vertex(const VPaint *wp, Object *ob, const WeightPaintInfo *wpi, const uint index, float alpha, float paintweight)
static float wpaint_clamp_monotonic(float oldval, float curval, float newval)
static ColorPaint4f toFloat(const Color &c)
Definition: paint_vertex.cc:98
static void do_wpaint_precompute_weight_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
static void wpaint_paint_leaves(bContext *C, Object *ob, Sculpt *sd, VPaint *vp, WPaintData *wpd, WeightPaintInfo *wpi, Mesh *me, PBVHNode **nodes, int totnode)
static void vpaint_do_radial_symmetry(bContext *C, Sculpt *sd, VPaint *vp, VPaintData< Color, Traits, domain > *vpd, Object *ob, Mesh *me, Brush *brush, const char symm, const int axis)
static bool vwpaint_use_normal(const VPaint *vp)
static void paint_last_stroke_update(Scene *scene, const float location[3])
void ED_object_vpaintmode_exit(bContext *C)
static float wpaint_undo_lock_relative(float weight, float old_weight, float locked_weight, float free_weight, bool auto_normalize)
static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
bool vertex_paint_mode_poll(bContext *C)
static void vpaint_do_paint(bContext *C, Sculpt *sd, VPaint *vp, VPaintData< Color, Traits, domain > *vpd, Object *ob, Mesh *me, Brush *brush, const char symm, const int axis, const int i, const float angle)
bool weight_paint_poll_ignore_tool(bContext *C)
static void wpaint_stroke_done(const bContext *C, PaintStroke *stroke)
static void wpaint_cancel(bContext *C, wmOperator *op)
static void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache)
static int get_vcol_elements(Mesh *me, size_t *r_elem_size)
static bool vertex_color_set(Object *ob, ColorPaint4f paintcol_in, CustomDataLayer *layer)
static int wpaint_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void vpaint_stroke_update_step(bContext *C, wmOperator *UNUSED(op), PaintStroke *stroke, PointerRNA *itemptr)
static void vertex_paint_init_stroke(Scene *scene, Depsgraph *depsgraph, Object *ob)
static void vertex_paint_init_session(Depsgraph *depsgraph, Scene *scene, Object *ob, eObjectMode object_mode)
static bool brush_use_accumulate(const VPaint *vp)
void PAINT_OT_weight_paint_toggle(wmOperatorType *ot)
static void do_weight_paint_vertex_multi(const VPaint *wp, Object *ob, const WeightPaintInfo *wpi, const uint index, float alpha, float paintweight)
static void do_vpaint_brush_blur_loops(bContext *C, Sculpt *UNUSED(sd), VPaint *vp, VPaintData< Color, Traits, ATTR_DOMAIN_CORNER > *vpd, Object *ob, Mesh *me, PBVHNode **nodes, int totnode, Color *lcol)
static void do_vpaint_brush_smear(bContext *C, Sculpt *UNUSED(sd), VPaint *vp, VPaintData< Color, Traits, domain > *vpd, Object *ob, Mesh *me, PBVHNode **nodes, int totnode, Color *lcol)
static void multipaint_apply_change(MDeformVert *dvert, const int defbase_tot, float change, const bool *defbase_sel)
static void wpaint_do_paint(bContext *C, Object *ob, VPaint *wp, Sculpt *sd, WPaintData *wpd, WeightPaintInfo *wpi, Mesh *me, Brush *brush, const char symm, const int axis, const int i, const float angle)
static Color fromFloat(const ColorPaint4f &c)
static void view_angle_limits_init(NormalAnglePrecalc *a, float angle, bool do_mask_normal)
static void do_weight_paint_vertex_single(const VPaint *wp, Object *ob, const WeightPaintInfo *wpi, const uint index, float alpha, float paintweight)
static void calculate_average_weight(SculptThreadedTaskData *data, PBVHNode **UNUSED(nodes), int totnode)
static void multipaint_clamp_change(MDeformVert *dvert, const int defbase_tot, const bool *defbase_sel, float *change_p)
static float view_angle_limits_apply_falloff(const NormalAnglePrecalc *a, float angle_cos, float *mask_p)
void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
static void wpaint_stroke_update_step(bContext *C, wmOperator *UNUSED(op), PaintStroke *stroke, PointerRNA *itemptr)
static int vpaint_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void do_weight_paint_normalize_all_locked_try_active(MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap, const bool *lock_flags, const bool *lock_with_active)
static MDeformVert * defweight_prev_init(MDeformVert *dvert_prev, MDeformVert *dvert_curr, int index)
static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op))
static void ed_vwpaintmode_enter_generic(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob, const eObjectMode mode_flag)
static void do_wpaint_brush_calc_average_weight_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
static void vpaint_cancel(bContext *C, wmOperator *op)
static void calculate_average_color(VPaintData< Color, Traits, domain > *vpd, Object *ob, Mesh *me, const Brush *brush, Color *lcol, PBVHNode **nodes, int totnode)
void ED_object_wpaintmode_enter(bContext *C, Depsgraph *depsgraph)
static void vwpaint_init_stroke(Depsgraph *depsgraph, Object *ob)
static uint color2uint(ColorPaint4b c)
Definition: paint_vertex.cc:83
bool vertex_paint_poll(bContext *C)
static void do_vpaint_brush_blur_verts(bContext *C, Sculpt *UNUSED(sd), VPaint *vp, VPaintData< Color, Traits, ATTR_DOMAIN_POINT > *vpd, Object *ob, Mesh *me, PBVHNode **nodes, int totnode, Color *lcol)
static void ed_vwpaintmode_exit_generic(Object *ob, const eObjectMode mode_flag)
static void * vpaint_init_vpaint(bContext *C, wmOperator *op, Scene *scene, Depsgraph *depsgraph, VPaint *vp, Object *ob, Mesh *me, const Brush *brush)
static void vwpaint_update_cache_variants(bContext *C, VPaint *vp, Object *ob, PointerRNA *ptr)
static bool do_weight_paint_normalize_all_locked(MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap, const bool *lock_flags)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:4980
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
bool SCULPT_pbvh_calc_area_normal(const Brush *brush, Object *ob, PBVHNode **nodes, int totnode, bool use_threading, float r_area_no[3])
Definition: sculpt.c:2110
bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mval[2], bool force_original)
Definition: sculpt.c:4964
void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache, const char symm, const char axis, const float angle)
Definition: sculpt.c:3767
const float * SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss, char falloff_shape)
Definition: sculpt.c:1703
SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss, SculptBrushTest *test, char falloff_shape)
Definition: sculpt.c:1686
bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v)
Definition: sculpt.c:2467
bool SCULPT_has_loop_colors(const Object *ob)
Definition: sculpt.c:148
char SCULPT_mesh_symmetry_xyz_get(Object *object)
Definition: sculpt.c:317
bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v)
Definition: sculpt.c:2513
void SCULPT_cache_free(StrokeCache *cache)
Definition: sculpt.c:4055
bool SCULPT_get_redraw_rect(ARegion *region, RegionView3D *rv3d, Object *ob, rcti *rect)
Definition: sculpt.c:1489
static float brush_strength(const Sculpt *sd, const StrokeCache *cache, const float feather, const UnifiedPaintSettings *ups, const PaintModeSettings *UNUSED(paint_mode_settings))
Definition: sculpt.c:2219
void SCULPT_undo_push_begin(struct Object *ob, const char *name)
Definition: sculpt_undo.c:1545
void SCULPT_undo_push_end(struct Object *ob)
Definition: sculpt_undo.c:1575
bool(* SculptBrushTestFn)(SculptBrushTest *test, const float co[3])
SculptUndoNode * SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type)
Definition: sculpt_undo.c:1419
@ SCULPT_UNDO_COLOR
short regiontype
struct BMesh * bm
Definition: BKE_editmesh.h:40
BMLoop * l_first
Definition: bmesh_class.h:261
struct BMVert * v
Definition: bmesh_class.h:153
struct BMLoop * next
Definition: bmesh_class.h:233
CustomData vdata
Definition: bmesh_class.h:337
CustomData ldata
Definition: bmesh_class.h:337
float falloff_angle
struct MTex mtex
char vertexpaint_tool
struct CurveMapping * curve
char falloff_shape
short blend
char weightpaint_tool
float co[3]
Definition: paint_intern.h:43
CustomDataLayer * layers
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
void * first
Definition: DNA_listBase.h:31
struct MDeformWeight * dw
unsigned int def_nr
unsigned int v
char brush_map_mode
struct Tex * tex
float co[3]
Definition: BKE_main.h:121
struct BMEditMesh * edit_mesh
struct MVert * mvert
struct MDeformVert * dvert
ListBase vertex_group_names
char editflag
int totvert
struct MLoop * mloop
int totpoly
int totloop
struct MPoly * mpoly
ListBase particlesystem
float imat[4][4]
float obmat[4][4]
struct SculptSession * sculpt
void * data
int * grid_indices
Definition: BKE_pbvh.h:409
float * co
Definition: BKE_pbvh.h:430
float * no
Definition: BKE_pbvh.h:431
const int * vert_indices
Definition: BKE_pbvh.h:417
unsigned short ob_mode
struct Paint_Runtime runtime
struct Brush * brush
struct ParticleSystem * next
float persmat[4][4]
float viewinv[4][4]
struct ToolSettings * toolsettings
struct SculptSession::@53::@54 vpaint
struct SculptSession::@53::@55 wpaint
union SculptSession::@53 mode
eObjectMode mode_type
Definition: BKE_paint.h:642
struct StrokeCache * cache
Definition: BKE_paint.h:563
bool building_vp_handle
Definition: BKE_paint.h:645
struct PBVH * pbvh
Definition: BKE_paint.h:550
struct MeshElemMap * vert_to_loop
Definition: BKE_paint.h:272
struct MeshElemMap * vert_to_poly
Definition: BKE_paint.h:274
float true_location[3]
float initial_radius
float initial_mouse[2]
const struct Brush * brush
float mouse[2]
float true_view_normal[3]
float radius_squared
float projection_mat[4][4]
void * prev_colors_vpaint
float last_location[3]
char saved_active_brush_name[MAX_ID_NAME]
float view_normal[3]
struct ViewContext * vc
float sculpt_normal_symm[3]
float location[3]
int radial_symmetry_pass
int saved_smooth_size
bool is_last_valid
struct UnifiedPaintSettings unified_paint_settings
BlendType value[3]
ViewContext vc
eAttrDomain domain
eCustomDataType type
void * color_curr
struct VertProjHandle * vp_handle
NormalAnglePrecalc normal_angle_precalc
void * color_prev
struct VPaintData::@510 smear
CoNo * vertexcosnos
int radial_symm[3]
struct Scene * scene
Definition: ED_view3d.h:65
struct ARegion * region
Definition: ED_view3d.h:69
struct Object * obact
Definition: ED_view3d.h:67
struct RegionView3D * rv3d
Definition: ED_view3d.h:72
const bool * vgroup_unlocked
NormalAnglePrecalc normal_angle_precalc
const bool * lock_flags
ViewContext vc
WeightPaintGroupData active
bool do_lock_relative
const bool * vgroup_validmap
const bool * defbase_sel
const bool * vgroup_locked
bool do_multipaint
bool precomputed_weight_ready
float * precomputed_weight
WeightPaintGroupData mirror
const bool * lock_flags
const bool * vgroup_locked
WeightPaintGroupData mirror
const bool * vgroup_unlocked
const bool * defbase_sel
const bool * vgroup_validmap
WeightPaintGroupData active
int ymin
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
short type
Definition: WM_types.h:678
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:927
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition: wm_files.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_)
bool WM_toolsystem_active_tool_is_brush(const bContext *C)
void WM_toolsystem_update_from_context_view3d(bContext *C)