Blender  V3.3
paint_vertex_weight_ops.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "MEM_guardedalloc.h"
8 
9 #include "BLI_bitmap.h"
10 #include "BLI_blenlib.h"
11 #include "BLI_math.h"
12 
13 #include "DNA_brush_types.h"
14 #include "DNA_mesh_types.h"
15 #include "DNA_meshdata_types.h"
16 #include "DNA_object_types.h"
17 #include "DNA_scene_types.h"
18 
19 #include "RNA_access.h"
20 #include "RNA_define.h"
21 #include "RNA_enum_types.h"
22 
23 #include "BKE_brush.h"
24 #include "BKE_colortools.h"
25 #include "BKE_context.h"
26 #include "BKE_deform.h"
27 #include "BKE_mesh.h"
28 #include "BKE_mesh_iterators.h"
29 #include "BKE_mesh_runtime.h"
30 #include "BKE_modifier.h"
31 #include "BKE_object_deform.h"
32 #include "BKE_paint.h"
33 #include "BKE_report.h"
34 
35 #include "DEG_depsgraph.h"
36 #include "DEG_depsgraph_query.h"
37 
38 #include "WM_api.h"
39 #include "WM_types.h"
40 
41 #include "ED_armature.h"
42 #include "ED_mesh.h"
43 #include "ED_screen.h"
44 #include "ED_view3d.h"
45 
46 #include "paint_intern.h" /* own include */
47 
48 /* -------------------------------------------------------------------- */
54 struct WPaintPrev {
55  /* previous vertex weights */
57  /* allocation size of prev buffers */
58  int tot;
59 };
60 
61 static void wpaint_prev_init(struct WPaintPrev *wpp)
62 {
63  wpp->wpaint_prev = NULL;
64  wpp->tot = 0;
65 }
66 
67 static void wpaint_prev_create(struct WPaintPrev *wpp, MDeformVert *dverts, int dcount)
68 {
69  wpaint_prev_init(wpp);
70 
71  if (dverts && dcount) {
72  wpp->wpaint_prev = MEM_mallocN(sizeof(MDeformVert) * dcount, "wpaint prev");
73  wpp->tot = dcount;
74  BKE_defvert_array_copy(wpp->wpaint_prev, dverts, dcount);
75  }
76 }
77 
78 static void wpaint_prev_destroy(struct WPaintPrev *wpp)
79 {
80  if (wpp->wpaint_prev) {
82  }
83  wpp->wpaint_prev = NULL;
84  wpp->tot = 0;
85 }
86 
89 /* -------------------------------------------------------------------- */
94 {
96 
98 }
99 
101 {
106  Mesh *me = ob->data;
107  int type = RNA_enum_get(op->ptr, "type");
108 
110  op->reports, depsgraph, scene, ob, armob, type, (me->symmetry & ME_SYMMETRY_X));
111 
112  DEG_id_tag_update(&me->id, 0);
115 
116  return OPERATOR_FINISHED;
117 }
118 
120 {
121  static const EnumPropertyItem type_items[] = {
122  {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights from bones"},
124  "ENVELOPES",
125  0,
126  "From Envelopes",
127  "Weights from envelopes with user defined radius"},
128  {0, NULL, 0, NULL, NULL},
129  };
130 
131  /* identifiers */
132  ot->name = "Weight from Bones";
133  ot->idname = "PAINT_OT_weight_from_bones";
134  ot->description =
135  ("Set the weights of the groups matching the attached armature's selected bones, "
136  "using the distance between the vertices and the bones");
137 
138  /* api callbacks */
142 
143  /* flags */
145 
146  /* properties */
147  ot->prop = RNA_def_enum(
148  ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights");
149 }
150 
153 /* -------------------------------------------------------------------- */
162 static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
163 {
165  ViewContext vc;
166  Mesh *me;
167  bool changed = false;
168 
170  me = BKE_mesh_from_object(vc.obact);
171 
172  if (me && me->dvert && vc.v3d && vc.rv3d && (me->vertex_group_active_index != 0)) {
173  const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
174  int v_idx_best = -1;
175  uint index;
176 
179 
180  if (use_vert_sel) {
181  if (ED_mesh_pick_vert(
182  C, vc.obact, event->mval, ED_MESH_PICK_DEFAULT_VERT_DIST, true, &index)) {
183  v_idx_best = index;
184  }
185  }
186  else {
188  C, vc.obact, event->mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
189  v_idx_best = index;
190  }
191  else if (ED_mesh_pick_face(
192  C, vc.obact, event->mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
193  /* This relies on knowing the internal workings of #ED_mesh_pick_face_vert() */
194  BKE_report(
195  op->reports, RPT_WARNING, "The modifier used does not support deformed locations");
196  }
197  }
198 
199  if (v_idx_best != -1) { /* should always be valid */
200  ToolSettings *ts = vc.scene->toolsettings;
201  Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
202  const int vgroup_active = me->vertex_group_active_index - 1;
203  float vgroup_weight = BKE_defvert_find_weight(&me->dvert[v_idx_best], vgroup_active);
204  const int defbase_tot = BLI_listbase_count(&me->vertex_group_names);
205  bool use_lock_relative = ts->wpaint_lock_relative;
206  bool *defbase_locked = NULL, *defbase_unlocked = NULL;
207 
208  if (use_lock_relative) {
209  defbase_locked = BKE_object_defgroup_lock_flags_get(vc.obact, defbase_tot);
210  defbase_unlocked = BKE_object_defgroup_validmap_get(vc.obact, defbase_tot);
211 
212  use_lock_relative = BKE_object_defgroup_check_lock_relative(
213  defbase_locked, defbase_unlocked, vgroup_active);
214  }
215 
216  /* use combined weight in multipaint mode,
217  * since that's what is displayed to the user in the colors */
218  if (ts->multipaint) {
219  int defbase_tot_sel;
220  bool *defbase_sel = BKE_object_defgroup_selected_get(
221  vc.obact, defbase_tot, &defbase_tot_sel);
222 
223  if (defbase_tot_sel > 1) {
226  vc.obact, defbase_tot, defbase_sel, defbase_sel, &defbase_tot_sel);
227  }
228 
229  use_lock_relative = use_lock_relative &&
231  defbase_tot, defbase_locked, defbase_sel, defbase_tot_sel);
232 
233  bool is_normalized = ts->auto_normalize || use_lock_relative;
235  &me->dvert[v_idx_best], defbase_tot, defbase_sel, defbase_tot_sel, is_normalized);
236  }
237 
238  MEM_freeN(defbase_sel);
239  }
240 
241  if (use_lock_relative) {
243  defbase_tot, defbase_locked, defbase_unlocked, defbase_locked, defbase_unlocked);
244 
245  vgroup_weight = BKE_defvert_lock_relative_weight(
246  vgroup_weight, &me->dvert[v_idx_best], defbase_tot, defbase_locked, defbase_unlocked);
247  }
248 
249  MEM_SAFE_FREE(defbase_locked);
250  MEM_SAFE_FREE(defbase_unlocked);
251 
252  CLAMP(vgroup_weight, 0.0f, 1.0f);
253  BKE_brush_weight_set(vc.scene, brush, vgroup_weight);
254  changed = true;
255  }
256  }
257 
258  if (changed) {
259  /* not really correct since the brush didn't change, but redraws the toolbar */
260  WM_main_add_notifier(NC_BRUSH | NA_EDITED, NULL); /* ts->wpaint->paint.brush */
261 
262  return OPERATOR_FINISHED;
263  }
264  return OPERATOR_CANCELLED;
265 }
266 
268 {
269  /* identifiers */
270  ot->name = "Weight Paint Sample Weight";
271  ot->idname = "PAINT_OT_weight_sample";
272  ot->description = "Use the mouse to sample a weight in the 3D view";
273 
274  /* api callbacks */
277 
278  /* flags */
279  ot->flag = OPTYPE_UNDO;
280 }
281 
284 /* -------------------------------------------------------------------- */
288 /* samples cursor location, and gives menu with vertex groups to activate */
290  const int defbase_tot,
291  int *groups)
292 {
293  /* this func fills in used vgroup's */
294  bool found = false;
295  int i = dvert->totweight;
296  MDeformWeight *dw;
297  for (dw = dvert->dw; i > 0; dw++, i--) {
298  if (dw->def_nr < defbase_tot) {
299  groups[dw->def_nr] = true;
300  found = true;
301  }
302  }
303  return found;
304 }
307  PropertyRNA *UNUSED(prop),
308  bool *r_free)
309 {
310  if (C) {
311  wmWindow *win = CTX_wm_window(C);
312  if (win && win->eventstate) {
314  ViewContext vc;
315  Mesh *me;
316 
318  me = BKE_mesh_from_object(vc.obact);
319 
320  if (me && me->dvert && vc.v3d && vc.rv3d && me->vertex_group_names.first) {
321  const int defbase_tot = BLI_listbase_count(&me->vertex_group_names);
322  const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
323  int *groups = MEM_callocN(defbase_tot * sizeof(int), "groups");
324  bool found = false;
325  uint index;
326 
327  const int mval[2] = {
328  win->eventstate->xy[0] - vc.region->winrct.xmin,
329  win->eventstate->xy[1] - vc.region->winrct.ymin,
330  };
331 
334 
335  if (use_vert_sel) {
336  if (ED_mesh_pick_vert(C, vc.obact, mval, ED_MESH_PICK_DEFAULT_VERT_DIST, true, &index)) {
337  MDeformVert *dvert = &me->dvert[index];
338  found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups);
339  }
340  }
341  else {
342  if (ED_mesh_pick_face(C, vc.obact, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
343  const MPoly *mp = &me->mpoly[index];
344  uint fidx = mp->totloop - 1;
345 
346  do {
347  MDeformVert *dvert = &me->dvert[me->mloop[mp->loopstart + fidx].v];
348  found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups);
349  } while (fidx--);
350  }
351  }
352 
353  if (found == false) {
354  MEM_freeN(groups);
355  }
356  else {
357  EnumPropertyItem *item = NULL, item_tmp = {0};
358  int totitem = 0;
359  int i = 0;
360  bDeformGroup *dg;
361  for (dg = me->vertex_group_names.first; dg && i < defbase_tot; i++, dg = dg->next) {
362  if (groups[i]) {
363  item_tmp.identifier = item_tmp.name = dg->name;
364  item_tmp.value = i;
365  RNA_enum_item_add(&item, &totitem, &item_tmp);
366  }
367  }
368 
369  RNA_enum_item_end(&item, &totitem);
370  *r_free = true;
371 
372  MEM_freeN(groups);
373  return item;
374  }
375  }
376  }
377  }
378 
379  return DummyRNA_NULL_items;
380 }
381 
383 {
384  int type = RNA_enum_get(op->ptr, "group");
386  ViewContext vc;
388 
389  BLI_assert(type + 1 >= 0);
391 
394  return OPERATOR_FINISHED;
395 }
396 
398 {
399  /* TODO: we could make this a menu into #OBJECT_OT_vertex_group_set_active
400  * rather than its own operator */
401 
402  PropertyRNA *prop = NULL;
403 
404  /* identifiers */
405  ot->name = "Weight Paint Sample Group";
406  ot->idname = "PAINT_OT_weight_sample_group";
407  ot->description = "Select one of the vertex groups available under current mouse position";
408 
409  /* api callbacks */
413 
414  /* flags */
415  ot->flag = OPTYPE_UNDO;
416 
417  /* Group to use (dynamic enum). */
418  prop = RNA_def_enum(
419  ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "Vertex group to set as active");
422  ot->prop = prop;
423 }
424 
427 /* -------------------------------------------------------------------- */
431 /* fills in the selected faces with the current weight and vertex group */
432 static bool weight_paint_set(Object *ob, float paintweight)
433 {
434  Mesh *me = ob->data;
435  const MPoly *mp;
436  MDeformWeight *dw, *dw_prev;
437  int vgroup_active, vgroup_mirror = -1;
438  uint index;
439  const bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
440 
441  /* mutually exclusive, could be made into a */
442  const short paint_selmode = ME_EDIT_PAINT_SEL_MODE(me);
443 
444  if (me->totpoly == 0 || me->dvert == NULL || !me->mpoly) {
445  return false;
446  }
447 
448  vgroup_active = BKE_object_defgroup_active_index_get(ob) - 1;
449 
450  /* if mirror painting, find the other group */
452  vgroup_mirror = ED_wpaint_mirror_vgroup_ensure(ob, vgroup_active);
453  }
454 
455  struct WPaintPrev wpp;
456  wpaint_prev_create(&wpp, me->dvert, me->totvert);
457 
458  for (index = 0, mp = me->mpoly; index < me->totpoly; index++, mp++) {
459  uint fidx = mp->totloop - 1;
460 
461  if ((paint_selmode == SCE_SELECT_FACE) && !(mp->flag & ME_FACE_SEL)) {
462  continue;
463  }
464 
465  do {
466  uint vidx = me->mloop[mp->loopstart + fidx].v;
467 
468  if (!me->dvert[vidx].flag) {
469  if ((paint_selmode == SCE_SELECT_VERTEX) && !(me->mvert[vidx].flag & SELECT)) {
470  continue;
471  }
472 
473  dw = BKE_defvert_ensure_index(&me->dvert[vidx], vgroup_active);
474  if (dw) {
475  dw_prev = BKE_defvert_ensure_index(wpp.wpaint_prev + vidx, vgroup_active);
476  dw_prev->weight = dw->weight; /* set the undo weight */
477  dw->weight = paintweight;
478 
479  if (me->symmetry & ME_SYMMETRY_X) {
480  /* x mirror painting */
481  int j = mesh_get_x_mirror_vert(ob, NULL, vidx, topology);
482  if (j >= 0) {
483  /* copy, not paint again */
484  if (vgroup_mirror != -1) {
485  dw = BKE_defvert_ensure_index(me->dvert + j, vgroup_mirror);
486  dw_prev = BKE_defvert_ensure_index(wpp.wpaint_prev + j, vgroup_mirror);
487  }
488  else {
489  dw = BKE_defvert_ensure_index(me->dvert + j, vgroup_active);
490  dw_prev = BKE_defvert_ensure_index(wpp.wpaint_prev + j, vgroup_active);
491  }
492  dw_prev->weight = dw->weight; /* set the undo weight */
493  dw->weight = paintweight;
494  }
495  }
496  }
497  me->dvert[vidx].flag = 1;
498  }
499 
500  } while (fidx--);
501  }
502 
503  {
504  MDeformVert *dv = me->dvert;
505  for (index = me->totvert; index != 0; index--, dv++) {
506  dv->flag = 0;
507  }
508  }
509 
510  wpaint_prev_destroy(&wpp);
511 
512  DEG_id_tag_update(&me->id, 0);
513 
514  return true;
515 }
516 
518 {
519  struct Scene *scene = CTX_data_scene(C);
520  Object *obact = CTX_data_active_object(C);
522  Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
523  float vgroup_weight = BKE_brush_weight_get(scene, brush);
524 
526  return OPERATOR_CANCELLED;
527  }
528 
529  if (weight_paint_set(obact, vgroup_weight)) {
530  ED_region_tag_redraw(CTX_wm_region(C)); /* XXX: should redraw all 3D views. */
531  return OPERATOR_FINISHED;
532  }
533  return OPERATOR_CANCELLED;
534 }
535 
537 {
538  /* identifiers */
539  ot->name = "Set Weight";
540  ot->idname = "PAINT_OT_weight_set";
541  ot->description = "Fill the active vertex group with the current paint weight";
542 
543  /* api callbacks */
546 
547  /* flags */
549 }
550 
553 /* -------------------------------------------------------------------- */
557 /* *** VGroups Gradient *** */
558 typedef struct WPGradient_vertStore {
559  float sco[2];
560  float weight_orig;
561  enum {
564  VGRAD_STORE_IS_MODIFIED = (1 << 1)
565  } flag;
567 
568 typedef struct WPGradient_vertStoreBase {
569  struct WPaintPrev wpp;
572 
573 typedef struct WPGradient_userData {
574  struct ARegion *region;
578  const float *sco_start; /* [2] */
579  const float *sco_end; /* [2] */
580  float sco_line_div; /* store (1.0f / len_v2v2(sco_start, sco_end)) */
581  int def_nr;
582  bool is_init;
584  /* only for init */
586 
587  /* options */
590  short type;
591  float weightpaint;
593 
594 static void gradientVert_update(WPGradient_userData *grad_data, int index)
595 {
596  Mesh *me = grad_data->me;
597  WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
598 
599  /* Optionally restrict to assigned vertices only. */
600  if (grad_data->use_vgroup_restrict && ((vs->flag & VGRAD_STORE_DW_EXIST) == 0)) {
601  /* In this case the vertex will never have been touched. */
602  BLI_assert((vs->flag & VGRAD_STORE_IS_MODIFIED) == 0);
603  return;
604  }
605 
606  float alpha;
607  if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) {
608  alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end);
609  }
610  else {
612  alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div;
613  }
614  /* no need to clamp 'alpha' yet */
615 
616  /* adjust weight */
617  alpha = BKE_brush_curve_strength_clamped(grad_data->brush, alpha, 1.0f);
618 
619  if (alpha != 0.0f) {
620  MDeformVert *dv = &me->dvert[index];
621  MDeformWeight *dw = BKE_defvert_ensure_index(dv, grad_data->def_nr);
622  // dw->weight = alpha; // testing
623  int tool = grad_data->brush->blend;
624  float testw;
625 
626  /* init if we just added */
627  testw = ED_wpaint_blend_tool(
628  tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha);
629  CLAMP(testw, 0.0f, 1.0f);
630  dw->weight = testw;
631  vs->flag |= VGRAD_STORE_IS_MODIFIED;
632  }
633  else {
634  MDeformVert *dv = &me->dvert[index];
635  if (vs->flag & VGRAD_STORE_DW_EXIST) {
636  /* normally we NULL check, but in this case we know it exists */
637  MDeformWeight *dw = BKE_defvert_find_index(dv, grad_data->def_nr);
638  dw->weight = vs->weight_orig;
639  }
640  else {
641  /* wasn't originally existing, remove */
642  MDeformWeight *dw = BKE_defvert_find_index(dv, grad_data->def_nr);
643  if (dw) {
644  BKE_defvert_remove_group(dv, dw);
645  }
646  }
647  vs->flag &= ~VGRAD_STORE_IS_MODIFIED;
648  }
649 }
650 
651 static void gradientVertUpdate__mapFunc(void *userData,
652  int index,
653  const float UNUSED(co[3]),
654  const float UNUSED(no[3]))
655 {
656  WPGradient_userData *grad_data = userData;
657  WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
658 
659  if (vs->sco[0] == FLT_MAX) {
660  return;
661  }
662 
663  gradientVert_update(grad_data, index);
664 }
665 
666 static void gradientVertInit__mapFunc(void *userData,
667  int index,
668  const float co[3],
669  const float UNUSED(no[3]))
670 {
671  WPGradient_userData *grad_data = userData;
672  Mesh *me = grad_data->me;
673  WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
674 
675  if (grad_data->use_select && !(me->mvert[index].flag & SELECT)) {
676  copy_v2_fl(vs->sco, FLT_MAX);
677  return;
678  }
679 
680  /* run first pass only,
681  * the screen coords of the verts need to be cached because
682  * updating the mesh may move them about (entering feedback loop) */
683  if (BLI_BITMAP_TEST(grad_data->vert_visit, index)) {
684  /* Do not copy FLT_MAX here, for generative modifiers we are getting here
685  * multiple times with the same orig index. */
686  return;
687  }
688 
690  grad_data->region, co, vs->sco, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) !=
691  V3D_PROJ_RET_OK) {
692  copy_v2_fl(vs->sco, FLT_MAX);
693  return;
694  }
695 
696  MDeformVert *dv = &me->dvert[index];
697  const MDeformWeight *dw = BKE_defvert_find_index(dv, grad_data->def_nr);
698  if (dw) {
699  vs->weight_orig = dw->weight;
700  vs->flag = VGRAD_STORE_DW_EXIST;
701  }
702  else {
703  vs->weight_orig = 0.0f;
704  vs->flag = VGRAD_STORE_NOP;
705  }
706  BLI_BITMAP_ENABLE(grad_data->vert_visit, index);
707  gradientVert_update(grad_data, index);
708 }
709 
710 static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event)
711 {
712  wmGesture *gesture = op->customdata;
713  WPGradient_vertStoreBase *vert_cache = gesture->user_data.data;
714  int ret = WM_gesture_straightline_modal(C, op, event);
715 
716  if (ret & OPERATOR_RUNNING_MODAL) {
717  if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { /* XXX, hardcoded */
718  /* generally crap! redo! */
722  }
723  }
724 
725  if (ret & OPERATOR_CANCELLED) {
727  if (vert_cache != NULL) {
728  Mesh *me = ob->data;
729  if (vert_cache->wpp.wpaint_prev) {
731  BKE_defvert_array_copy(me->dvert, vert_cache->wpp.wpaint_prev, me->totvert);
732  wpaint_prev_destroy(&vert_cache->wpp);
733  }
734  MEM_freeN(vert_cache);
735  }
736 
739  }
740  else if (ret & OPERATOR_FINISHED) {
741  wpaint_prev_destroy(&vert_cache->wpp);
742  MEM_freeN(vert_cache);
743  }
744 
745  return ret;
746 }
747 
749 {
750  wmGesture *gesture = op->customdata;
751  WPGradient_vertStoreBase *vert_cache;
752  struct ARegion *region = CTX_wm_region(C);
755  Mesh *me = ob->data;
756  int x_start = RNA_int_get(op->ptr, "xstart");
757  int y_start = RNA_int_get(op->ptr, "ystart");
758  int x_end = RNA_int_get(op->ptr, "xend");
759  int y_end = RNA_int_get(op->ptr, "yend");
760  const float sco_start[2] = {x_start, y_start};
761  const float sco_end[2] = {x_end, y_end};
762  const bool is_interactive = (gesture != NULL);
763 
765 
767 
768  if (is_interactive) {
769  if (gesture->user_data.data == NULL) {
771  (sizeof(WPGradient_vertStore) * me->totvert),
772  __func__);
773  gesture->user_data.use_free = false;
774  data.is_init = true;
775 
777  &((WPGradient_vertStoreBase *)gesture->user_data.data)->wpp, me->dvert, me->totvert);
778 
779  /* On initialization only, convert face -> vert sel. */
780  if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
782  }
783  }
784 
785  vert_cache = gesture->user_data.data;
786  }
787  else {
788  if (ED_wpaint_ensure_data(C, op->reports, 0, NULL) == false) {
789  return OPERATOR_CANCELLED;
790  }
791 
792  data.is_init = true;
793  vert_cache = MEM_mallocN(
794  sizeof(WPGradient_vertStoreBase) + (sizeof(WPGradient_vertStore) * me->totvert), __func__);
795  }
796 
797  data.region = region;
798  data.scene = scene;
799  data.me = ob->data;
800  data.sco_start = sco_start;
801  data.sco_end = sco_end;
802  data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end);
804  data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
805  data.vert_cache = vert_cache;
806  data.vert_visit = NULL;
807  data.type = RNA_enum_get(op->ptr, "type");
808 
809  {
811  VPaint *wp = ts->wpaint;
812  struct Brush *brush = BKE_paint_brush(&wp->paint);
813 
815 
816  data.brush = brush;
817  data.weightpaint = BKE_brush_weight_get(scene, brush);
818  data.use_vgroup_restrict = (ts->wpaint->flag & VP_FLAG_VGROUP_RESTRICT) != 0;
819  }
820 
822 
823  Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
824  Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
825 
827  cddata_masks.vmask |= CD_MASK_ORIGINDEX;
828  cddata_masks.emask |= CD_MASK_ORIGINDEX;
829  cddata_masks.pmask |= CD_MASK_ORIGINDEX;
830  Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &cddata_masks);
831  if (data.is_init) {
832  data.vert_visit = BLI_BITMAP_NEW(me->totvert, __func__);
833 
835 
836  MEM_freeN(data.vert_visit);
837  data.vert_visit = NULL;
838  }
839  else {
841  }
842 
845 
846  if (is_interactive == false) {
847  MEM_freeN(vert_cache);
848  }
849 
851  const int vgroup_num = BLI_listbase_count(&me->vertex_group_names);
852  bool *lock_flags = BKE_object_defgroup_lock_flags_get(ob, vgroup_num);
853  bool *vgroup_validmap = BKE_object_defgroup_validmap_get(ob, vgroup_num);
854  if (vgroup_validmap != NULL) {
855  MDeformVert *dvert = me->dvert;
856  for (int i = 0; i < me->totvert; i++) {
857  if ((data.vert_cache->elem[i].flag & VGRAD_STORE_IS_MODIFIED) != 0) {
858  if (lock_flags != NULL) {
860  &dvert[i], vgroup_validmap, vgroup_num, lock_flags, vgroup_num);
861  }
862  else {
863  BKE_defvert_normalize_lock_single(&dvert[i], vgroup_validmap, vgroup_num, data.def_nr);
864  }
865  }
866  }
867  MEM_freeN(vgroup_validmap);
868  }
869  }
870 
871  return OPERATOR_FINISHED;
872 }
873 
875 {
876  int ret;
877 
878  if (ED_wpaint_ensure_data(C, op->reports, 0, NULL) == false) {
879  return OPERATOR_CANCELLED;
880  }
881 
882  ret = WM_gesture_straightline_invoke(C, op, event);
883  if (ret & OPERATOR_RUNNING_MODAL) {
884  struct ARegion *region = CTX_wm_region(C);
885  if (region->regiontype == RGN_TYPE_WINDOW) {
886  /* TODO: hard-coded, extend `WM_gesture_straightline_*`. */
887  if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
888  wmGesture *gesture = op->customdata;
889  gesture->is_active = true;
890  }
891  }
892  }
893  return ret;
894 }
895 
897 {
898  /* defined in DNA_space_types.h */
899  static const EnumPropertyItem gradient_types[] = {
900  {WPAINT_GRADIENT_TYPE_LINEAR, "LINEAR", 0, "Linear", ""},
901  {WPAINT_GRADIENT_TYPE_RADIAL, "RADIAL", 0, "Radial", ""},
902  {0, NULL, 0, NULL, NULL},
903  };
904 
905  PropertyRNA *prop;
906 
907  /* identifiers */
908  ot->name = "Weight Gradient";
909  ot->idname = "PAINT_OT_weight_gradient";
910  ot->description = "Draw a line to apply a weight gradient to selected vertices";
911 
912  /* api callbacks */
918 
919  /* flags */
921 
922  prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", "");
924 
926 }
927 
float BKE_brush_curve_strength_clamped(const struct Brush *br, float p, float len)
float BKE_brush_weight_get(const struct Scene *scene, const struct Brush *brush)
void BKE_brush_weight_set(const struct Scene *scene, struct Brush *brush, float value)
void BKE_curvemapping_init(struct CurveMapping *cumap)
Definition: colortools.c:1235
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 Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Definition: context.c:1505
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 wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
support for deformation groups and hooks.
void BKE_defvert_normalize_lock_single(struct MDeformVert *dvert, const bool *vgroup_subset, int vgroup_tot, uint def_nr_lock)
Definition: deform.c:293
int BKE_object_defgroup_active_index_get(const struct Object *ob)
struct MDeformWeight * BKE_defvert_find_index(const struct MDeformVert *dv, int defgroup)
void BKE_object_defgroup_active_index_set(struct Object *ob, int new_index)
Definition: deform.c:568
void BKE_defvert_array_free(struct MDeformVert *dvert, int totvert)
Definition: deform.c:996
void BKE_defvert_normalize_lock_map(struct MDeformVert *dvert, const bool *vgroup_subset, int vgroup_tot, const bool *lock_flags, int defbase_tot)
Definition: deform.c:347
struct MDeformWeight * BKE_defvert_ensure_index(struct MDeformVert *dv, int defgroup)
Definition: deform.c:748
void BKE_defvert_array_copy(struct MDeformVert *dst, const struct MDeformVert *src, int totvert)
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_remove_group(struct MDeformVert *dvert, struct MDeformWeight *dw)
Definition: deform.c:804
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
struct Mesh * BKE_mesh_from_object(struct Object *ob)
Definition: mesh.cc:1365
void BKE_mesh_flush_select_from_polys(struct Mesh *me)
void BKE_mesh_foreach_mapped_vert(struct Mesh *mesh, void(*func)(void *userData, int index, const float co[3], const float no[3]), void *userData, MeshForeachFlag flag)
@ MESH_FOREACH_NOP
struct Mesh * mesh_get_eval_final(struct Depsgraph *depsgraph, const struct Scene *scene, struct Object *ob, const struct CustomData_MeshMasks *dataMask)
struct Object * BKE_modifiers_is_deformed_by_armature(struct Object *ob)
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)
struct Brush * BKE_paint_brush(struct Paint *paint)
Definition: paint.c:607
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition: BLI_bitmap.h:40
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition: BLI_bitmap.h:64
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:81
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:16
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:3274
MINLINE float len_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_fl(float r[2], float f)
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNUSED(x)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
void DEG_relations_tag_update(struct Main *bmain)
struct Object * DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object)
struct Scene * DEG_get_evaluated_scene(const struct Depsgraph *graph)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
#define CD_MASK_ORIGINDEX
@ ME_EDIT_PAINT_VERT_SEL
@ ME_EDIT_PAINT_FACE_SEL
@ ME_EDIT_MIRROR_TOPO
@ ME_SYMMETRY_X
#define ME_USING_MIRROR_X_VERTEX_GROUPS(_me)
#define ME_EDIT_PAINT_SEL_MODE(_me)
@ ME_FACE_SEL
@ OB_MODE_WEIGHT_PAINT
Object is a sort of wrapper for general info.
#define SCE_SELECT_FACE
@ VP_FLAG_VGROUP_RESTRICT
#define SCE_SELECT_VERTEX
@ RGN_TYPE_WINDOW
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
#define ARM_GROUPS_ENVELOPE
Definition: ED_armature.h:199
#define ARM_GROUPS_AUTO
Definition: ED_armature.h:200
bool ED_mesh_pick_face_vert(struct bContext *C, struct Object *ob, const int mval[2], uint dist_px, uint *r_index)
Definition: meshtools.cc:1241
#define ED_MESH_PICK_DEFAULT_VERT_DIST
Definition: ED_mesh.h:677
bool ED_mesh_pick_face(struct bContext *C, struct Object *ob, const int mval[2], uint dist_px, uint *r_index)
Definition: meshtools.cc:1179
#define ED_MESH_PICK_DEFAULT_FACE_DIST
Definition: ED_mesh.h:678
bool ED_mesh_pick_vert(struct bContext *C, struct Object *ob, const int mval[2], uint dist_px, bool use_zbuf, uint *r_index)
Definition: meshtools.cc:1359
int mesh_get_x_mirror_vert(struct Object *ob, struct Mesh *me_eval, int index, bool use_topology)
Definition: meshtools.cc:916
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
@ 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
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 type
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
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
@ PROP_ENUM_NO_TRANSLATE
Definition: RNA_types.h:294
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
#define C
Definition: RandGen.cpp:25
@ KM_PRESS
Definition: WM_types.h:267
@ KM_RELEASE
Definition: WM_types.h:268
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NC_GEOM
Definition: WM_types.h:343
#define ND_DRAW
Definition: WM_types.h:410
#define NC_BRUSH
Definition: WM_types.h:335
#define ND_DATA
Definition: WM_types.h:456
#define NA_EDITED
Definition: WM_types.h:523
#define NC_OBJECT
Definition: WM_types.h:329
void ED_object_vgroup_calc_from_armature(ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, Object *par, const int mode, const bool mirror)
#define SELECT
Scene scene
const Depsgraph * depsgraph
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
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
static ulong * next
bool mask_paint_poll(bContext *C)
float ED_wpaint_blend_tool(int tool, float weight, float paintval, float alpha)
@ WPAINT_GRADIENT_TYPE_RADIAL
Definition: paint_intern.h:131
@ WPAINT_GRADIENT_TYPE_LINEAR
Definition: paint_intern.h:130
bool ED_wpaint_ensure_data(struct bContext *C, struct ReportList *reports, enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index)
bool weight_paint_mode_poll(struct bContext *C)
@ WPAINT_ENSURE_MIRROR
Definition: paint_intern.h:158
bool weight_paint_poll_ignore_tool(bContext *C)
int ED_wpaint_mirror_vgroup_ensure(struct Object *ob, int vgroup_active)
void PAINT_OT_weight_set(wmOperatorType *ot)
static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
static bool weight_paint_set(Object *ob, float paintweight)
static void wpaint_prev_create(struct WPaintPrev *wpp, MDeformVert *dverts, int dcount)
struct WPGradient_userData WPGradient_userData
struct WPGradient_vertStore WPGradient_vertStore
struct WPGradient_vertStoreBase WPGradient_vertStoreBase
static int weight_from_bones_exec(bContext *C, wmOperator *op)
static int weight_paint_set_exec(bContext *C, wmOperator *op)
static void gradientVertInit__mapFunc(void *userData, int index, const float co[3], const float UNUSED(no[3]))
static bool weight_paint_sample_enum_itemf__helper(const MDeformVert *dvert, const int defbase_tot, int *groups)
static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event)
void PAINT_OT_weight_sample(wmOperatorType *ot)
static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void gradientVert_update(WPGradient_userData *grad_data, int index)
static void wpaint_prev_destroy(struct WPaintPrev *wpp)
static bool weight_from_bones_poll(bContext *C)
static void wpaint_prev_init(struct WPaintPrev *wpp)
void PAINT_OT_weight_from_bones(wmOperatorType *ot)
void PAINT_OT_weight_gradient(wmOperatorType *ot)
void PAINT_OT_weight_sample_group(wmOperatorType *ot)
static const EnumPropertyItem * weight_paint_sample_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void gradientVertUpdate__mapFunc(void *userData, int index, const float UNUSED(co[3]), const float UNUSED(no[3]))
static int weight_sample_group_exec(bContext *C, wmOperator *op)
return ret
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
Definition: rna_define.c:4487
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
Definition: rna_define.c:4436
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
Definition: rna_define.c:3830
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3783
const EnumPropertyItem DummyRNA_NULL_items[]
Definition: rna_rna.c:26
void * regiondata
short regiontype
float alpha
struct CurveMapping * curve
short blend
void * first
Definition: DNA_listBase.h:31
struct MDeformWeight * dw
unsigned int def_nr
unsigned int v
char symmetry
struct MVert * mvert
struct MDeformVert * dvert
ListBase vertex_group_names
char editflag
int totvert
struct MLoop * mloop
int totpoly
int vertex_group_active_index
struct MPoly * mpoly
void * data
struct CustomData_MeshMasks customdata_mask
struct ToolSettings * toolsettings
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 View3D * v3d
Definition: ED_view3d.h:70
struct RegionView3D * rv3d
Definition: ED_view3d.h:72
WPGradient_vertStoreBase * vert_cache
WPGradient_vertStore elem[0]
enum WPGradient_vertStore::@511 flag
struct MDeformVert * wpaint_prev
int ymin
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
short val
Definition: WM_types.h:680
int xy[2]
Definition: WM_types.h:682
int mval[2]
Definition: WM_types.h:684
short type
Definition: WM_types.h:678
wmGenericUserData user_data
Definition: WM_types.h:595
uint is_active
Definition: WM_types.h:571
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
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
PropertyRNA * prop
Definition: WM_types.h:981
struct ReportList * reports
struct PointerRNA * ptr
struct wmEvent * eventstate
@ WM_CURSOR_EDIT
Definition: wm_cursors.h:22
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ LEFTMOUSE
PointerRNA * ptr
Definition: wm_files.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
int WM_gesture_straightline_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_gesture_straightline_cancel(bContext *C, wmOperator *op)
int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))