Blender  V3.3
object_vgroup.c
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 
8 #include <math.h>
9 #include <stddef.h>
10 #include <string.h>
11 
12 #include "MEM_guardedalloc.h"
13 
14 #include "DNA_curve_types.h"
15 #include "DNA_gpencil_types.h"
16 #include "DNA_lattice_types.h"
17 #include "DNA_mesh_types.h"
18 #include "DNA_meshdata_types.h"
19 #include "DNA_modifier_types.h"
20 #include "DNA_object_types.h"
21 #include "DNA_scene_types.h"
22 #include "DNA_workspace_types.h"
23 
24 #include "BLI_alloca.h"
25 #include "BLI_array.h"
26 #include "BLI_bitmap.h"
27 #include "BLI_blenlib.h"
28 #include "BLI_listbase.h"
29 #include "BLI_math.h"
30 #include "BLI_utildefines.h"
31 #include "BLI_utildefines_stack.h"
32 
33 #include "BKE_context.h"
34 #include "BKE_customdata.h"
35 #include "BKE_deform.h"
36 #include "BKE_editmesh.h"
37 #include "BKE_lattice.h"
38 #include "BKE_layer.h"
39 #include "BKE_mesh.h"
40 #include "BKE_mesh_mapping.h"
41 #include "BKE_mesh_runtime.h"
42 #include "BKE_modifier.h"
43 #include "BKE_object.h"
44 #include "BKE_object_deform.h"
45 #include "BKE_report.h"
46 
47 #include "DEG_depsgraph.h"
48 #include "DEG_depsgraph_build.h"
49 #include "DEG_depsgraph_query.h"
50 
51 #include "BLT_translation.h"
52 
53 #include "DNA_armature_types.h"
54 #include "RNA_access.h"
55 #include "RNA_define.h"
56 #include "RNA_enum_types.h"
57 
58 #include "WM_api.h"
59 #include "WM_types.h"
60 
61 #include "ED_mesh.h"
62 #include "ED_object.h"
63 #include "ED_screen.h"
64 
65 #include "UI_resources.h"
66 
67 #include "object_intern.h"
68 
69 static bool vertex_group_supported_poll_ex(bContext *C, const Object *ob);
70 
71 /* -------------------------------------------------------------------- */
75 static bool object_array_for_wpaint_filter(const Object *ob, void *user_data)
76 {
77  bContext *C = user_data;
79  return true;
80  }
81  return false;
82 }
83 
84 static Object **object_array_for_wpaint(bContext *C, uint *r_objects_len)
85 {
87 }
88 
90 {
91  if (ob->mode == OB_MODE_EDIT) {
92  return true;
93  }
94  if ((ob->type == OB_MESH) &&
95  ((Mesh *)ob->data)->editflag & (ME_EDIT_PAINT_VERT_SEL | ME_EDIT_PAINT_FACE_SEL)) {
96  return true;
97  }
98  return false;
99 }
100 
102 {
103  Lattice *lt = ob->data;
104  BLI_assert(ob->type == OB_LATTICE);
105  return (lt->editlatt) ? lt->editlatt->latt : lt;
106 }
107 
110 /* -------------------------------------------------------------------- */
115 {
116  Object *armobj = BKE_object_pose_armature_get(ob);
117  if (armobj && (armobj->mode & OB_MODE_POSE)) {
118  struct bArmature *arm = armobj->data;
119  if (arm->act_bone) {
120  int def_num = BKE_object_defgroup_name_index(ob, arm->act_bone->name);
121  if (def_num != -1) {
122  BKE_object_defgroup_active_index_set(ob, def_num + 1);
123  return true;
124  }
125  }
126  }
127  return false;
128 }
129 
130 void ED_vgroup_data_clamp_range(ID *id, const int total)
131 {
132  MDeformVert **dvert_arr;
133  int dvert_tot;
134 
135  if (ED_vgroup_parray_alloc(id, &dvert_arr, &dvert_tot, false)) {
136  for (int i = 0; i < dvert_tot; i++) {
137  MDeformVert *dv = dvert_arr[i];
138  for (int j = 0; j < dv->totweight; j++) {
139  if (dv->dw[j].def_nr >= total) {
140  BKE_defvert_remove_group(dv, &dv->dw[j]);
141  j--;
142  }
143  }
144  }
145  }
146 }
147 
149  MDeformVert ***dvert_arr,
150  int *dvert_tot,
151  const bool use_vert_sel)
152 {
153  *dvert_tot = 0;
154  *dvert_arr = NULL;
155 
156  if (id) {
157  switch (GS(id->name)) {
158  case ID_ME: {
159  Mesh *me = (Mesh *)id;
160 
161  if (me->edit_mesh) {
162  BMEditMesh *em = me->edit_mesh;
163  BMesh *bm = em->bm;
164  const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
165  BMIter iter;
166  BMVert *eve;
167  int i;
168 
169  if (cd_dvert_offset == -1) {
170  return false;
171  }
172 
173  i = em->bm->totvert;
174 
175  *dvert_arr = MEM_mallocN(sizeof(void *) * i, "vgroup parray from me");
176  *dvert_tot = i;
177 
178  i = 0;
179  if (use_vert_sel) {
180  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
181  (*dvert_arr)[i] = BM_elem_flag_test(eve, BM_ELEM_SELECT) ?
182  BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset) :
183  NULL;
184  i++;
185  }
186  }
187  else {
188  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
189  (*dvert_arr)[i] = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
190  i++;
191  }
192  }
193 
194  return true;
195  }
196  if (me->dvert) {
197  MVert *mvert = me->mvert;
198  MDeformVert *dvert = me->dvert;
199 
200  *dvert_tot = me->totvert;
201  *dvert_arr = MEM_mallocN(sizeof(void *) * me->totvert, "vgroup parray from me");
202 
203  if (use_vert_sel) {
204  for (int i = 0; i < me->totvert; i++) {
205  (*dvert_arr)[i] = (mvert[i].flag & SELECT) ? &dvert[i] : NULL;
206  }
207  }
208  else {
209  for (int i = 0; i < me->totvert; i++) {
210  (*dvert_arr)[i] = me->dvert + i;
211  }
212  }
213 
214  return true;
215  }
216  return false;
217  }
218  case ID_LT: {
219  Lattice *lt = (Lattice *)id;
220  lt = (lt->editlatt) ? lt->editlatt->latt : lt;
221 
222  if (lt->dvert) {
223  BPoint *def = lt->def;
224  *dvert_tot = lt->pntsu * lt->pntsv * lt->pntsw;
225  *dvert_arr = MEM_mallocN(sizeof(void *) * (*dvert_tot), "vgroup parray from me");
226 
227  if (use_vert_sel) {
228  for (int i = 0; i < *dvert_tot; i++) {
229  (*dvert_arr)[i] = (def->f1 & SELECT) ? &lt->dvert[i] : NULL;
230  }
231  }
232  else {
233  for (int i = 0; i < *dvert_tot; i++) {
234  (*dvert_arr)[i] = lt->dvert + i;
235  }
236  }
237 
238  return true;
239  }
240  return false;
241  }
242 
243  default:
244  break;
245  }
246  }
247 
248  return false;
249 }
250 
252  MDeformVert **dvert_array,
253  const int dvert_tot,
254  const bool *vgroup_validmap,
255  const int vgroup_tot)
256 {
258  MDeformVert **dvert_array_all = NULL;
259  int dvert_tot_all;
260 
261  /* get an array of all verts, not only selected */
262  if (ED_vgroup_parray_alloc(ob->data, &dvert_array_all, &dvert_tot_all, false) == false) {
263  BLI_assert(0);
264  return;
265  }
266  if (em) {
268  }
269 
270  int flip_map_len;
271  const int *flip_map = BKE_object_defgroup_flip_map(ob, &flip_map_len, true);
272 
273  for (int i_src = 0; i_src < dvert_tot; i_src++) {
274  if (dvert_array[i_src] != NULL) {
275  /* its selected, check if its mirror exists */
276  int i_dst = ED_mesh_mirror_get_vert(ob, i_src);
277  if (i_dst != -1 && dvert_array_all[i_dst] != NULL) {
278  /* we found a match! */
279  const MDeformVert *dv_src = dvert_array[i_src];
280  MDeformVert *dv_dst = dvert_array_all[i_dst];
281 
283  dv_dst, dv_src, vgroup_validmap, vgroup_tot, flip_map, flip_map_len);
284 
285  dvert_array[i_dst] = dvert_array_all[i_dst];
286  }
287  }
288  }
289 
290  MEM_freeN((void *)flip_map);
291  MEM_freeN(dvert_array_all);
292 }
293 
294 void ED_vgroup_parray_mirror_assign(Object *ob, MDeformVert **dvert_array, const int dvert_tot)
295 {
297  MDeformVert **dvert_array_all = NULL;
298  int dvert_tot_all;
299 
300  /* get an array of all verts, not only selected */
301  if (ED_vgroup_parray_alloc(ob->data, &dvert_array_all, &dvert_tot_all, false) == false) {
302  BLI_assert(0);
303  return;
304  }
305  BLI_assert(dvert_tot == dvert_tot_all);
306  if (em) {
308  }
309 
310  for (int i = 0; i < dvert_tot; i++) {
311  if (dvert_array[i] == NULL) {
312  /* its unselected, check if its mirror is */
313  int i_sel = ED_mesh_mirror_get_vert(ob, i);
314  if ((i_sel != -1) && (i_sel != i) && (dvert_array[i_sel])) {
315  /* we found a match! */
316  dvert_array[i] = dvert_array_all[i];
317  }
318  }
319  }
320 
321  MEM_freeN(dvert_array_all);
322 }
323 
325  const int dvert_tot,
326  const bool *vgroup_validmap,
327  const int vgroup_tot,
328  const float epsilon,
329  const bool keep_single)
330 {
331  MDeformVert *dv;
332 
333  for (int i = 0; i < dvert_tot; i++) {
334  /* in case its not selected */
335  if (!(dv = dvert_array[i])) {
336  continue;
337  }
338 
339  int j = dv->totweight;
340 
341  while (j--) {
342  MDeformWeight *dw;
343 
344  if (keep_single && dv->totweight == 1) {
345  break;
346  }
347 
348  dw = dv->dw + j;
349  if ((dw->def_nr < vgroup_tot) && vgroup_validmap[dw->def_nr]) {
350  if (dw->weight <= epsilon) {
351  BKE_defvert_remove_group(dv, dw);
352  }
353  }
354  }
355  }
356 }
357 
358 bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
359 {
360  MDeformVert **dvert_array_from = NULL, **dvf;
361  MDeformVert **dvert_array = NULL, **dv;
362  int dvert_tot_from;
363  int dvert_tot;
364  int i;
365  ListBase *defbase_dst = BKE_object_defgroup_list_mutable(ob);
366  const ListBase *defbase_src = BKE_object_defgroup_list(ob_from);
367 
368  int defbase_tot_from = BLI_listbase_count(defbase_src);
369  int defbase_tot = BLI_listbase_count(defbase_dst);
370  bool new_vgroup = false;
371 
372  BLI_assert(ob != ob_from);
373 
374  if (ob->data == ob_from->data) {
375  return true;
376  }
377 
378  /* In case we copy vgroup between two objects using same data,
379  * we only have to care about object side of things. */
380  if (ob->data != ob_from->data) {
381  ED_vgroup_parray_alloc(ob_from->data, &dvert_array_from, &dvert_tot_from, false);
382  ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
383 
384  if ((dvert_array == NULL) && (dvert_array_from != NULL) &&
386  ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
387  new_vgroup = true;
388  }
389 
390  if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == NULL ||
391  dvert_array == NULL) {
392  if (dvert_array) {
393  MEM_freeN(dvert_array);
394  }
395  if (dvert_array_from) {
396  MEM_freeN(dvert_array_from);
397  }
398 
399  if (new_vgroup == true) {
400  /* free the newly added vgroup since it wasn't compatible */
402  }
403 
404  /* if true: both are 0 and nothing needs changing, consider this a success */
405  return (dvert_tot == dvert_tot_from);
406  }
407  }
408 
409  /* do the copy */
410  BLI_freelistN(defbase_dst);
411  BLI_duplicatelist(defbase_dst, defbase_src);
413 
414  if (defbase_tot_from < defbase_tot) {
415  /* correct vgroup indices because the number of vgroups is being reduced. */
416  int *remap = MEM_mallocN(sizeof(int) * (defbase_tot + 1), __func__);
417  for (i = 0; i <= defbase_tot_from; i++) {
418  remap[i] = i;
419  }
420  for (; i <= defbase_tot; i++) {
421  remap[i] = 0; /* can't use these, so disable */
422  }
423 
425  MEM_freeN(remap);
426  }
427 
428  if (dvert_array_from != NULL && dvert_array != NULL) {
429  dvf = dvert_array_from;
430  dv = dvert_array;
431 
432  for (i = 0; i < dvert_tot; i++, dvf++, dv++) {
433  MEM_SAFE_FREE((*dv)->dw);
434  *(*dv) = *(*dvf);
435 
436  if ((*dv)->dw) {
437  (*dv)->dw = MEM_dupallocN((*dv)->dw);
438  }
439  }
440 
441  MEM_freeN(dvert_array);
442  MEM_freeN(dvert_array_from);
443  }
444 
445  return true;
446 }
447 
449  const int dvert_tot,
450  float *dvert_weights,
451  const int def_nr)
452 {
453  for (int i = 0; i < dvert_tot; i++) {
454  const MDeformVert *dv = dvert_array[i];
455  dvert_weights[i] = dv ? BKE_defvert_find_weight(dv, def_nr) : 0.0f;
456  }
457 }
458 
460  const int dvert_tot,
461  const float *dvert_weights,
462  const int def_nr,
463  const bool remove_zero)
464 {
465  int i;
466 
467  for (i = 0; i < dvert_tot; i++) {
468  MDeformVert *dv = dvert_array[i];
469  if (dv) {
470  if (dvert_weights[i] > 0.0f) {
471  MDeformWeight *dw = BKE_defvert_ensure_index(dv, def_nr);
472  BLI_assert(IN_RANGE_INCL(dvert_weights[i], 0.0f, 1.0f));
473  dw->weight = dvert_weights[i];
474  }
475  else {
476  MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
477  if (dw) {
478  if (remove_zero) {
479  BKE_defvert_remove_group(dv, dw);
480  }
481  else {
482  dw->weight = 0.0f;
483  }
484  }
485  }
486  }
487  }
488 }
489 
490 /* TODO: cache flip data to speedup calls within a loop. */
492  MDeformVert *dvert_dst,
493  MDeformVert *dvert_src,
494  const int def_nr)
495 {
496  if (def_nr == -1) {
497  /* All vgroups, add groups where needed. */
498  int flip_map_len;
499  int *flip_map = BKE_object_defgroup_flip_map(ob, &flip_map_len, true);
500  BKE_defvert_sync_mapped(dvert_dst, dvert_src, flip_map, flip_map_len, true);
501  MEM_freeN(flip_map);
502  }
503  else {
504  /* Single vgroup. */
505  MDeformWeight *dw = BKE_defvert_ensure_index(dvert_dst,
506  BKE_object_defgroup_flip_index(ob, def_nr, 1));
507  if (dw) {
508  dw->weight = BKE_defvert_find_weight(dvert_src, def_nr);
509  }
510  }
511 }
512 
514  Object *ob, BMVert *eve, int def_nr, int vidx, const int cd_dvert_offset)
515 {
516  Mesh *me = ob->data;
517  BMEditMesh *em = me->edit_mesh;
518  BMVert *eve_mirr;
519  bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
520 
521  eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, vidx, use_topology);
522 
523  if (eve_mirr && eve_mirr != eve) {
524  MDeformVert *dvert_src = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
525  MDeformVert *dvert_dst = BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset);
526  mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr);
527  }
528 }
529 
530 static void ED_mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx)
531 {
532  int vidx_mirr;
533  Mesh *me = ob->data;
534  bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
535 
536  if (vidx == -1) {
537  return;
538  }
539 
540  vidx_mirr = mesh_get_x_mirror_vert(ob, NULL, vidx, use_topology);
541 
542  if ((vidx_mirr) >= 0 && (vidx_mirr != vidx)) {
543  MDeformVert *dvert_src = &me->dvert[vidx];
544  MDeformVert *dvert_dst = &me->dvert[vidx_mirr];
545  mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr);
546  }
547 }
548 
550 {
551  Mesh *me = ob->data;
552  BMEditMesh *em = me->edit_mesh;
553  MDeformVert *dvert_act;
554 
555  if (me->symmetry & ME_SYMMETRY_X) {
556  if (em) {
557  BMVert *eve_act;
558  dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
559  if (dvert_act) {
560  const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
561  ED_mesh_defvert_mirror_update_em(ob, eve_act, def_nr, -1, cd_dvert_offset);
562  }
563  }
564  else {
565  int v_act;
566  dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
567  if (dvert_act) {
568  ED_mesh_defvert_mirror_update_ob(ob, def_nr, v_act);
569  }
570  }
571  }
572 }
573 
574 static void vgroup_remove_weight(Object *ob, const int def_nr)
575 {
576  MDeformVert *dvert_act;
577  MDeformWeight *dw;
578 
579  dvert_act = ED_mesh_active_dvert_get_only(ob);
580 
581  dw = BKE_defvert_find_index(dvert_act, def_nr);
582  BKE_defvert_remove_group(dvert_act, dw);
583 }
584 
586 {
587  Mesh *me = ob->data;
588  BMEditMesh *em = me->edit_mesh;
589  BMVert *eve_act;
590  int v_act;
591  MDeformVert *dvert_act;
592  int subset_count, vgroup_tot;
593  const bool *vgroup_validmap;
594 
595  if (em) {
596  dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
597  }
598  else {
599  dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
600  }
601 
602  if (dvert_act == NULL) {
603  return false;
604  }
605 
607  ob, subset_type, &vgroup_tot, &subset_count);
608  BKE_defvert_normalize_subset(dvert_act, vgroup_validmap, vgroup_tot);
609  MEM_freeN((void *)vgroup_validmap);
610 
611  if (me->symmetry & ME_SYMMETRY_X) {
612  if (em) {
613  const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
614  ED_mesh_defvert_mirror_update_em(ob, eve_act, -1, -1, cd_dvert_offset);
615  }
616  else {
617  ED_mesh_defvert_mirror_update_ob(ob, -1, v_act);
618  }
619  }
620 
621  return true;
622 }
623 
624 static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type)
625 {
626  Mesh *me = ob->data;
627  BMEditMesh *em = me->edit_mesh;
628  MDeformVert *dvert_act;
629  int i, vgroup_tot, subset_count;
630  const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
631  ob, subset_type, &vgroup_tot, &subset_count);
632 
633  if (em) {
634  BMIter iter;
635  BMVert *eve, *eve_act;
636  const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
637 
638  dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
639  if (dvert_act) {
640  BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
641  if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve != eve_act) {
642  MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
643  BKE_defvert_copy_subset(dv, dvert_act, vgroup_validmap, vgroup_tot);
644  if (me->symmetry & ME_SYMMETRY_X) {
645  ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
646  }
647  }
648  }
649  }
650  }
651  else {
652  MDeformVert *dv;
653  int v_act;
654 
655  dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
656  if (dvert_act) {
657  dv = me->dvert;
658  for (i = 0; i < me->totvert; i++, dv++) {
659  if ((me->mvert[i].flag & SELECT) && dv != dvert_act) {
660  BKE_defvert_copy_subset(dv, dvert_act, vgroup_validmap, vgroup_tot);
661  if (me->symmetry & ME_SYMMETRY_X) {
663  }
664  }
665  }
666  }
667  }
668 
669  MEM_freeN((void *)vgroup_validmap);
670 }
671 
674 /* -------------------------------------------------------------------- */
679  {WT_VGROUP_ACTIVE, "ACTIVE", 0, "Active Group", "The active Vertex Group"},
681  "BONE_SELECT",
682  0,
683  "Selected Pose Bones",
684  "All Vertex Groups assigned to Selection"},
686  "BONE_DEFORM",
687  0,
688  "Deform Pose Bones",
689  "All Vertex Groups assigned to Deform Bones"},
690  {WT_VGROUP_ALL, "ALL", 0, "All Groups", "All Vertex Groups"},
691  {0, NULL, 0, NULL, NULL},
692 };
693 
696  PropertyRNA *prop,
697  bool *r_free,
698  const uint selection_mask)
699 {
700  Object *ob;
701  EnumPropertyItem *item = NULL;
702  int totitem = 0;
703 
704  if (C == NULL) {
705  /* needed for docs and i18n tools */
707  }
708 
710  if (selection_mask & (1 << WT_VGROUP_ACTIVE)) {
712  }
713 
714  if (ob) {
716  if (selection_mask & (1 << WT_VGROUP_BONE_SELECT)) {
719  }
720  }
721 
723  if (selection_mask & (1 << WT_VGROUP_BONE_DEFORM)) {
726  }
727  }
728  }
729 
730  if (selection_mask & (1 << WT_VGROUP_ALL)) {
732  }
733 
734  /* Set `Deform Bone` as default selection if armature is present. */
735  if (ob) {
738  }
739 
740  RNA_enum_item_end(&item, &totitem);
741  *r_free = true;
742 
743  return item;
744 }
745 
747  PointerRNA *ptr,
748  PropertyRNA *prop,
749  bool *r_free)
750 {
752 }
753 
755  PointerRNA *ptr,
756  PropertyRNA *prop,
757  bool *r_free)
758 {
760  C, ptr, prop, r_free, WT_VGROUP_MASK_ALL & ~(1 << WT_VGROUP_ACTIVE));
761 }
762 
764 {
765  PropertyRNA *prop;
766 
767  prop = RNA_def_enum(ot->srna,
768  "group_select_mode",
770  use_active ? WT_VGROUP_ACTIVE : WT_VGROUP_ALL,
771  "Subset",
772  "Define which subset of groups shall be used");
773 
774  if (use_active) {
776  }
777  else {
779  }
781  ot->prop = prop;
782 }
783 
786 /* -------------------------------------------------------------------- */
794 /* for Mesh in Object mode */
795 /* allows editmode for Lattice */
797  Object *ob, const int def_nr, const int vertnum, const float weight, const int assignmode)
798 {
799  /* Add the vert to the deform group with the specified number. */
800  MDeformVert *dvert = NULL;
801  int tot;
802 
803  /* Get the vert. */
804  BKE_object_defgroup_array_get(ob->data, &dvert, &tot);
805 
806  if (dvert == NULL) {
807  return;
808  }
809 
810  /* Check that vertnum is valid before trying to get the relevant dvert. */
811  if ((vertnum < 0) || (vertnum >= tot)) {
812  return;
813  }
814 
815  MDeformVert *dv = &dvert[vertnum];
816  MDeformWeight *dw;
817 
818  /* Lets first check to see if this vert is already in the weight group - if so lets update it. */
819  dw = BKE_defvert_find_index(dv, def_nr);
820 
821  if (dw) {
822  switch (assignmode) {
823  case WEIGHT_REPLACE:
824  dw->weight = weight;
825  break;
826  case WEIGHT_ADD:
827  dw->weight += weight;
828  if (dw->weight >= 1.0f) {
829  dw->weight = 1.0f;
830  }
831  break;
832  case WEIGHT_SUBTRACT:
833  dw->weight -= weight;
834  /* If the weight is zero or less than remove the vert from the deform group. */
835  if (dw->weight <= 0.0f) {
836  BKE_defvert_remove_group(dv, dw);
837  }
838  break;
839  }
840  }
841  else {
842  /* If the vert wasn't in the deform group then we must take a different form of action. */
843 
844  switch (assignmode) {
845  case WEIGHT_SUBTRACT:
846  /* If we are subtracting then we don't need to do anything. */
847  return;
848 
849  case WEIGHT_REPLACE:
850  case WEIGHT_ADD:
851  /* If we are doing an additive assignment, then we need to create the deform weight. */
852 
853  /* We checked if the vertex was added before so no need to test again, simply add. */
854  BKE_defvert_add_index_notest(dv, def_nr, weight);
855  break;
856  }
857  }
858 }
859 
860 void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode)
861 {
862  /* add the vert to the deform group with the
863  * specified assign mode
864  */
865  const ListBase *defbase = BKE_object_defgroup_list(ob);
866  const int def_nr = BLI_findindex(defbase, dg);
867 
868  MDeformVert *dv = NULL;
869  int tot;
870 
871  /* get the deform group number, exit if
872  * it can't be found
873  */
874  if (def_nr != -1) {
875 
876  /* if there's no deform verts then create some,
877  */
878  if (BKE_object_defgroup_array_get(ob->data, &dv, &tot) && dv == NULL) {
880  }
881 
882  /* call another function to do the work
883  */
884  ED_vgroup_nr_vert_add(ob, def_nr, vertnum, weight, assignmode);
885  }
886 }
887 
888 void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
889 {
890  /* This routine removes the vertex from the specified
891  * deform group.
892  */
893 
894  /* TODO(campbell): This is slow in a loop, better pass def_nr directly,
895  * but leave for later. */
896  const ListBase *defbase = BKE_object_defgroup_list(ob);
897  const int def_nr = BLI_findindex(defbase, dg);
898 
899  if (def_nr != -1) {
900  MDeformVert *dvert = NULL;
901  int tot;
902 
903  /* get the deform vertices corresponding to the
904  * vertnum
905  */
906  BKE_object_defgroup_array_get(ob->data, &dvert, &tot);
907 
908  if (dvert) {
909  MDeformVert *dv = &dvert[vertnum];
910  MDeformWeight *dw;
911 
912  dw = BKE_defvert_find_index(dv, def_nr);
913  BKE_defvert_remove_group(dv, dw); /* dw can be NULL */
914  }
915  }
916 }
917 
918 static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum)
919 {
920  MDeformVert *dv = NULL;
921 
922  /* get the deform vertices corresponding to the vertnum */
923  if (ob->type == OB_MESH) {
924  Mesh *me = ob->data;
925 
926  if (me->edit_mesh) {
927  BMEditMesh *em = me->edit_mesh;
928  const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
929  /* warning, this lookup is _not_ fast */
930 
931  if (cd_dvert_offset != -1 && vertnum < em->bm->totvert) {
932  BMVert *eve;
934  eve = BM_vert_at_index(em->bm, vertnum);
935  dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
936  }
937  else {
938  return 0.0f;
939  }
940  }
941  else {
942  if (me->dvert) {
943  if (vertnum >= me->totvert) {
944  return 0.0f;
945  }
946  dv = &me->dvert[vertnum];
947  }
948  }
949  }
950  else if (ob->type == OB_LATTICE) {
951  Lattice *lt = vgroup_edit_lattice(ob);
952 
953  if (lt->dvert) {
954  if (vertnum >= lt->pntsu * lt->pntsv * lt->pntsw) {
955  return 0.0f;
956  }
957  dv = &lt->dvert[vertnum];
958  }
959  }
960 
961  if (dv) {
962  MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
963  if (dw) {
964  return dw->weight;
965  }
966  }
967 
968  return -1;
969 }
970 
971 float ED_vgroup_vert_weight(Object *ob, bDeformGroup *dg, int vertnum)
972 {
973  const ListBase *defbase = BKE_object_defgroup_list(ob);
974  const int def_nr = BLI_findindex(defbase, dg);
975 
976  if (def_nr == -1) {
977  return -1;
978  }
979 
980  return get_vert_def_nr(ob, def_nr, vertnum);
981 }
982 
983 void ED_vgroup_select_by_name(Object *ob, const char *name)
984 {
985  /* NOTE: actdef==0 signals on painting to create a new one,
986  * if a bone in posemode is selected */
988 }
989 
992 /* -------------------------------------------------------------------- */
996 /* only in editmode */
997 static void vgroup_select_verts(Object *ob, int select)
998 {
999  const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
1000 
1001  const ListBase *defbase = BKE_object_defgroup_list(ob);
1002  if (!BLI_findlink(defbase, def_nr)) {
1003  return;
1004  }
1005 
1006  if (ob->type == OB_MESH) {
1007  Mesh *me = ob->data;
1008 
1009  if (me->edit_mesh) {
1010  BMEditMesh *em = me->edit_mesh;
1011  const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
1012 
1013  if (cd_dvert_offset != -1) {
1014  BMIter iter;
1015  BMVert *eve;
1016 
1017  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
1018  if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
1019  MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
1020  if (BKE_defvert_find_index(dv, def_nr)) {
1021  BM_vert_select_set(em->bm, eve, select);
1022  }
1023  }
1024  }
1025 
1026  /* this has to be called, because this function operates on vertices only */
1027  if (select) {
1028  EDBM_select_flush(em); /* vertices to edges/faces */
1029  }
1030  else {
1031  EDBM_deselect_flush(em);
1032  }
1033  }
1034  }
1035  else {
1036  if (me->dvert) {
1037  MVert *mv;
1038  MDeformVert *dv;
1039  int i;
1040 
1041  mv = me->mvert;
1042  dv = me->dvert;
1043 
1044  for (i = 0; i < me->totvert; i++, mv++, dv++) {
1045  if (!(mv->flag & ME_HIDE)) {
1046  if (BKE_defvert_find_index(dv, def_nr)) {
1047  if (select) {
1048  mv->flag |= SELECT;
1049  }
1050  else {
1051  mv->flag &= ~SELECT;
1052  }
1053  }
1054  }
1055  }
1056 
1058  }
1059  }
1060  }
1061  else if (ob->type == OB_LATTICE) {
1062  Lattice *lt = vgroup_edit_lattice(ob);
1063 
1064  if (lt->dvert) {
1065  MDeformVert *dv;
1066  BPoint *bp, *actbp = BKE_lattice_active_point_get(lt);
1067  int a, tot;
1068 
1069  dv = lt->dvert;
1070 
1071  tot = lt->pntsu * lt->pntsv * lt->pntsw;
1072  for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) {
1073  if (BKE_defvert_find_index(dv, def_nr)) {
1074  if (select) {
1075  bp->f1 |= SELECT;
1076  }
1077  else {
1078  bp->f1 &= ~SELECT;
1079  if (actbp && bp == actbp) {
1080  lt->actbp = LT_ACTBP_NONE;
1081  }
1082  }
1083  }
1084  }
1085  }
1086  }
1087 }
1088 
1089 static void vgroup_duplicate(Object *ob)
1090 {
1091  bDeformGroup *dg, *cdg;
1092  char name[sizeof(dg->name)];
1093  MDeformWeight *dw_org, *dw_cpy;
1094  MDeformVert **dvert_array = NULL;
1095  int i, idg, icdg, dvert_tot = 0;
1096 
1098 
1099  dg = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1);
1100  if (!dg) {
1101  return;
1102  }
1103 
1104  if (!strstr(dg->name, "_copy")) {
1105  BLI_snprintf(name, sizeof(name), "%s_copy", dg->name);
1106  }
1107  else {
1108  BLI_strncpy(name, dg->name, sizeof(name));
1109  }
1110 
1111  cdg = BKE_defgroup_duplicate(dg);
1112  BLI_strncpy(cdg->name, name, sizeof(cdg->name));
1114 
1115  BLI_addtail(defbase, cdg);
1116 
1119  icdg = BKE_object_defgroup_active_index_get(ob) - 1;
1120 
1121  /* TODO(campbell): we might want to allow only copy selected verts here? */
1122  ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
1123 
1124  if (dvert_array) {
1125  for (i = 0; i < dvert_tot; i++) {
1126  MDeformVert *dv = dvert_array[i];
1127  dw_org = BKE_defvert_find_index(dv, idg);
1128  if (dw_org) {
1129  /* BKE_defvert_ensure_index re-allocs org so need to store the weight first */
1130  const float weight = dw_org->weight;
1131  dw_cpy = BKE_defvert_ensure_index(dv, icdg);
1132  dw_cpy->weight = weight;
1133  }
1134  }
1135 
1136  MEM_freeN(dvert_array);
1137  }
1138 }
1139 
1140 static bool vgroup_normalize(Object *ob)
1141 {
1142  MDeformWeight *dw;
1143  MDeformVert *dv, **dvert_array = NULL;
1144  int dvert_tot = 0;
1145  const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
1146 
1147  const bool use_vert_sel = vertex_group_use_vert_sel(ob);
1148 
1149  const ListBase *defbase = BKE_object_defgroup_list(ob);
1150  if (!BLI_findlink(defbase, def_nr)) {
1151  return false;
1152  }
1153 
1154  ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
1155 
1156  if (dvert_array) {
1157  float weight_max = 0.0f;
1158 
1159  for (int i = 0; i < dvert_tot; i++) {
1160 
1161  /* in case its not selected */
1162  if (!(dv = dvert_array[i])) {
1163  continue;
1164  }
1165 
1166  dw = BKE_defvert_find_index(dv, def_nr);
1167  if (dw) {
1168  weight_max = max_ff(dw->weight, weight_max);
1169  }
1170  }
1171 
1172  if (weight_max > 0.0f) {
1173  for (int i = 0; i < dvert_tot; i++) {
1174 
1175  /* in case its not selected */
1176  if (!(dv = dvert_array[i])) {
1177  continue;
1178  }
1179 
1180  dw = BKE_defvert_find_index(dv, def_nr);
1181  if (dw) {
1182  dw->weight /= weight_max;
1183 
1184  /* in case of division errors with very low weights */
1185  CLAMP(dw->weight, 0.0f, 1.0f);
1186  }
1187  }
1188  }
1189 
1190  MEM_freeN(dvert_array);
1191 
1192  return true;
1193  }
1194 
1195  return false;
1196 }
1197 
1198 /* This finds all of the vertices face-connected to vert by an edge and returns a
1199  * MEM_allocated array of indices of size count.
1200  * count is an int passed by reference so it can be assigned the value of the length here. */
1201 static int *getSurroundingVerts(Mesh *me, int vert, int *count)
1202 {
1203  MPoly *mp = me->mpoly;
1204  int i = me->totpoly;
1205  /* Instead of looping twice on all polys and loops, and use a temp array, let's rather
1206  * use a BLI_array, with a reasonable starting/reserved size (typically, there are not
1207  * many vertices face-linked to another one, even 8 might be too high...). */
1208  int *verts = NULL;
1210 
1212  while (i--) {
1213  int j = mp->totloop;
1214  int first_l = mp->totloop - 1;
1215  MLoop *ml = &me->mloop[mp->loopstart];
1216  while (j--) {
1217  /* XXX This assume a vert can only be once in a poly, even though
1218  * it seems logical to me, not totally sure of that. */
1219  if (ml->v == vert) {
1220  int a, b, k;
1221  if (j == first_l) {
1222  /* We are on the first corner. */
1223  a = ml[1].v;
1224  b = ml[j].v;
1225  }
1226  else if (!j) {
1227  /* We are on the last corner. */
1228  a = (ml - 1)->v;
1229  b = me->mloop[mp->loopstart].v;
1230  }
1231  else {
1232  a = (ml - 1)->v;
1233  b = (ml + 1)->v;
1234  }
1235 
1236  /* Append a and b verts to array, if not yet present. */
1237  k = BLI_array_len(verts);
1238  /* XXX Maybe a == b is enough? */
1239  while (k-- && !(a == b && a == -1)) {
1240  if (verts[k] == a) {
1241  a = -1;
1242  }
1243  else if (verts[k] == b) {
1244  b = -1;
1245  }
1246  }
1247  if (a != -1) {
1249  }
1250  if (b != -1) {
1252  }
1253 
1254  /* Vert found in this poly, we can go to next one! */
1255  break;
1256  }
1257  ml++;
1258  }
1259  mp++;
1260  }
1261 
1262  /* Do not free the array! */
1264  return verts;
1265 }
1266 
1267 /* Get a single point in space by averaging a point cloud (vectors of size 3)
1268  * coord is the place the average is stored,
1269  * points is the point cloud, count is the number of points in the cloud.
1270  */
1271 static void getSingleCoordinate(MVert *points, int count, float coord[3])
1272 {
1273  int i;
1274  zero_v3(coord);
1275  for (i = 0; i < count; i++) {
1276  add_v3_v3(coord, points[i].co);
1277  }
1278  mul_v3_fl(coord, 1.0f / count);
1279 }
1280 
1281 /* given a plane and a start and end position,
1282  * compute the amount of vertical distance relative to the plane and store it in dists,
1283  * then get the horizontal and vertical change and store them in changes
1284  */
1285 static void getVerticalAndHorizontalChange(const float norm[3],
1286  float d,
1287  const float coord[3],
1288  const float start[3],
1289  float distToStart,
1290  float *end,
1291  float (*changes)[2],
1292  float *dists,
1293  int index)
1294 {
1295  /* A = Q - ((Q - P).N)N
1296  * D = (a * x0 + b * y0 +c * z0 + d) */
1297  float projA[3], projB[3];
1298  float plane[4];
1299 
1300  plane_from_point_normal_v3(plane, coord, norm);
1301 
1302  closest_to_plane_normalized_v3(projA, plane, start);
1303  closest_to_plane_normalized_v3(projB, plane, end);
1304  /* (vertical and horizontal refer to the plane's y and xz respectively)
1305  * vertical distance */
1306  dists[index] = dot_v3v3(norm, end) + d;
1307  /* vertical change */
1308  changes[index][0] = dists[index] - distToStart;
1309  // printf("vc %f %f\n", distance(end, projB, 3) - distance(start, projA, 3), changes[index][0]);
1310  /* horizontal change */
1311  changes[index][1] = len_v3v3(projA, projB);
1312 }
1313 
1314 /* by changing nonzero weights, try to move a vertex in me->mverts with index 'index' to
1315  * distToBe distance away from the provided plane strength can change distToBe so that it moves
1316  * towards distToBe by that percentage cp changes how much the weights are adjusted
1317  * to check the distance
1318  *
1319  * index is the index of the vertex being moved
1320  * norm and d are the plane's properties for the equation: ax + by + cz + d = 0
1321  * coord is a point on the plane
1322  */
1324  Scene *UNUSED(scene),
1325  Object *ob,
1326  Mesh *me,
1327  int index,
1328  const float norm[3],
1329  const float coord[3],
1330  float d,
1331  float distToBe,
1332  float strength,
1333  float cp)
1334 {
1335  Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
1336  Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
1337  Mesh *mesh_eval = (Mesh *)object_eval->data;
1338 
1339  Mesh *me_deform;
1340  MDeformWeight *dw, *dw_eval;
1341  MVert m;
1342  MDeformVert *dvert = me->dvert + index;
1343  MDeformVert *dvert_eval = mesh_eval->dvert + index;
1344  int totweight = dvert->totweight;
1345  float oldw = 0;
1346  float oldPos[3] = {0};
1347  float vc, hc, dist = 0.0f;
1348  int i, k;
1349  float(*changes)[2] = MEM_mallocN(sizeof(float[2]) * totweight, "vertHorzChange");
1350  float *dists = MEM_mallocN(sizeof(float) * totweight, "distance");
1351 
1352  /* track if up or down moved it closer for each bone */
1353  bool *upDown = MEM_callocN(sizeof(bool) * totweight, "upDownTracker");
1354 
1355  int *dwIndices = MEM_callocN(sizeof(int) * totweight, "dwIndexTracker");
1356  float distToStart;
1357  int bestIndex = 0;
1358  bool wasChange;
1359  bool wasUp;
1360  int lastIndex = -1;
1361  float originalDistToBe = distToBe;
1362  do {
1363  wasChange = false;
1364  me_deform = mesh_get_eval_deform(depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH);
1365  m = me_deform->mvert[index];
1366  copy_v3_v3(oldPos, m.co);
1367  distToStart = dot_v3v3(norm, oldPos) + d;
1368 
1369  if (distToBe == originalDistToBe) {
1370  distToBe += distToStart - distToStart * strength;
1371  }
1372  for (i = 0; i < totweight; i++) {
1373  dwIndices[i] = i;
1374  dw = (dvert->dw + i);
1375  dw_eval = (dvert_eval->dw + i);
1376  vc = hc = 0;
1377  if (!dw->weight) {
1378  changes[i][0] = 0;
1379  changes[i][1] = 0;
1380  dists[i] = distToStart;
1381  continue;
1382  }
1383  for (k = 0; k < 2; k++) {
1384  if (me_deform) {
1385  /* DO NOT try to do own cleanup here, this is call for dramatic failures and bugs!
1386  * Better to over-free and recompute a bit. */
1387  BKE_object_free_derived_caches(object_eval);
1388  }
1389  oldw = dw->weight;
1390  if (k) {
1391  dw->weight *= 1 + cp;
1392  }
1393  else {
1394  dw->weight /= 1 + cp;
1395  }
1396  if (dw->weight == oldw) {
1397  changes[i][0] = 0;
1398  changes[i][1] = 0;
1399  dists[i] = distToStart;
1400  break;
1401  }
1402  if (dw->weight > 1) {
1403  dw->weight = 1;
1404  }
1405  dw_eval->weight = dw->weight;
1406  me_deform = mesh_get_eval_deform(depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH);
1407  m = me_deform->mvert[index];
1409  norm, d, coord, oldPos, distToStart, m.co, changes, dists, i);
1410  dw->weight = oldw;
1411  dw_eval->weight = oldw;
1412  if (!k) {
1413  vc = changes[i][0];
1414  hc = changes[i][1];
1415  dist = dists[i];
1416  }
1417  else {
1418  if (fabsf(dist - distToBe) < fabsf(dists[i] - distToBe)) {
1419  upDown[i] = false;
1420  changes[i][0] = vc;
1421  changes[i][1] = hc;
1422  dists[i] = dist;
1423  }
1424  else {
1425  upDown[i] = true;
1426  }
1427  if (fabsf(dists[i] - distToBe) > fabsf(distToStart - distToBe)) {
1428  changes[i][0] = 0;
1429  changes[i][1] = 0;
1430  dists[i] = distToStart;
1431  }
1432  }
1433  }
1434  }
1435  /* sort the changes by the vertical change */
1436  for (k = 0; k < totweight; k++) {
1437  bestIndex = k;
1438  for (i = k + 1; i < totweight; i++) {
1439  dist = dists[i];
1440 
1441  if (fabsf(dist) > fabsf(dists[i])) {
1442  bestIndex = i;
1443  }
1444  }
1445  /* switch with k */
1446  if (bestIndex != k) {
1447  SWAP(bool, upDown[k], upDown[bestIndex]);
1448  SWAP(int, dwIndices[k], dwIndices[bestIndex]);
1449  swap_v2_v2(changes[k], changes[bestIndex]);
1450  SWAP(float, dists[k], dists[bestIndex]);
1451  }
1452  }
1453  bestIndex = -1;
1454  /* find the best change with an acceptable horizontal change */
1455  for (i = 0; i < totweight; i++) {
1456  if (fabsf(changes[i][0]) > fabsf(changes[i][1] * 2.0f)) {
1457  bestIndex = i;
1458  break;
1459  }
1460  }
1461  if (bestIndex != -1) {
1462  wasChange = true;
1463  /* it is a good place to stop if it tries to move the opposite direction
1464  * (relative to the plane) of last time */
1465  if (lastIndex != -1) {
1466  if (wasUp != upDown[bestIndex]) {
1467  wasChange = false;
1468  }
1469  }
1470  lastIndex = bestIndex;
1471  wasUp = upDown[bestIndex];
1472  dw = (dvert->dw + dwIndices[bestIndex]);
1473  oldw = dw->weight;
1474  if (upDown[bestIndex]) {
1475  dw->weight *= 1 + cp;
1476  }
1477  else {
1478  dw->weight /= 1 + cp;
1479  }
1480  if (dw->weight > 1) {
1481  dw->weight = 1;
1482  }
1483  if (oldw == dw->weight) {
1484  wasChange = false;
1485  }
1486  if (me_deform) {
1487  /* DO NOT try to do own cleanup here, this is call for dramatic failures and bugs!
1488  * Better to over-free and recompute a bit. */
1489  BKE_object_free_derived_caches(object_eval);
1490  }
1491  }
1492  } while (wasChange && ((distToStart - distToBe) / fabsf(distToStart - distToBe) ==
1493  (dists[bestIndex] - distToBe) / fabsf(dists[bestIndex] - distToBe)));
1494 
1495  MEM_freeN(upDown);
1496  MEM_freeN(changes);
1497  MEM_freeN(dists);
1498  MEM_freeN(dwIndices);
1499 }
1500 
1501 /* this is used to try to smooth a surface by only adjusting the nonzero weights of a vertex
1502  * but it could be used to raise or lower an existing 'bump.' */
1503 static void vgroup_fix(
1504  const bContext *C, Scene *UNUSED(scene), Object *ob, float distToBe, float strength, float cp)
1505 {
1507  Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
1508  Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
1509  int i;
1510 
1511  Mesh *me = ob->data;
1512  MVert *mvert = me->mvert;
1513  int *verts = NULL;
1514  if (!(me->editflag & ME_EDIT_PAINT_VERT_SEL)) {
1515  return;
1516  }
1517  for (i = 0; i < me->totvert && mvert; i++, mvert++) {
1518  if (mvert->flag & SELECT) {
1519  int count = 0;
1520  if ((verts = getSurroundingVerts(me, i, &count))) {
1521  MVert m;
1522  MVert *p = MEM_callocN(sizeof(MVert) * (count), "deformedPoints");
1523  int k;
1524 
1525  Mesh *me_deform = mesh_get_eval_deform(
1526  depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH);
1527  k = count;
1528  while (k--) {
1529  p[k] = me_deform->mvert[verts[k]];
1530  }
1531 
1532  if (count >= 3) {
1533  float d /*, dist */ /* UNUSED */, mag;
1534  float coord[3];
1535  float norm[3];
1536  getSingleCoordinate(p, count, coord);
1537  m = me_deform->mvert[i];
1538  sub_v3_v3v3(norm, m.co, coord);
1539  mag = normalize_v3(norm);
1540  if (mag) { /* zeros fix */
1541  d = -dot_v3v3(norm, coord);
1542  // dist = (dot_v3v3(norm, m.co) + d); /* UNUSED */
1544  depsgraph, scene_eval, object_eval, me, i, norm, coord, d, distToBe, strength, cp);
1545  }
1546  }
1547 
1548  MEM_freeN(verts);
1549  MEM_freeN(p);
1550  }
1551  }
1552  }
1553 }
1554 
1556  const bool *vgroup_validmap,
1557  const int vgroup_tot,
1558  const int UNUSED(subset_count),
1559  const float offset,
1560  const float gain)
1561 {
1562  MDeformWeight *dw;
1563  MDeformVert *dv, **dvert_array = NULL;
1564  int dvert_tot = 0;
1565 
1566  const bool use_vert_sel = vertex_group_use_vert_sel(ob);
1567  const bool use_mirror = (ob->type == OB_MESH) ?
1568  (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
1569  false;
1570 
1571  ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
1572 
1573  if (dvert_array) {
1574 
1575  for (int i = 0; i < dvert_tot; i++) {
1576  /* in case its not selected */
1577  if (!(dv = dvert_array[i])) {
1578  continue;
1579  }
1580 
1581  int j = vgroup_tot;
1582  while (j--) {
1583  if (vgroup_validmap[j]) {
1584  dw = BKE_defvert_find_index(dv, j);
1585  if (dw) {
1586  dw->weight = gain * (dw->weight + offset);
1587 
1588  CLAMP(dw->weight, 0.0f, 1.0f);
1589  }
1590  }
1591  }
1592  }
1593 
1594  if (use_mirror && use_vert_sel) {
1595  ED_vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, vgroup_validmap, vgroup_tot);
1596  }
1597 
1598  MEM_freeN(dvert_array);
1599  }
1600 }
1601 
1603  const bool *vgroup_validmap,
1604  const int vgroup_tot,
1605  const int subset_count,
1606  const bool lock_active,
1607  ReportList *reports)
1608 {
1609  MDeformVert *dv, **dvert_array = NULL;
1610  int i, dvert_tot = 0;
1611  const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
1612 
1613  const bool use_vert_sel = vertex_group_use_vert_sel(ob);
1614 
1615  if (subset_count == 0) {
1616  BKE_report(reports, RPT_ERROR, "No vertex groups to operate on");
1617  return false;
1618  }
1619 
1620  ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
1621 
1622  if (dvert_array) {
1623  const ListBase *defbase = BKE_object_defgroup_list(ob);
1624  const int defbase_tot = BLI_listbase_count(defbase);
1625  bool *lock_flags = BKE_object_defgroup_lock_flags_get(ob, defbase_tot);
1626  bool changed = false;
1627 
1628  if ((lock_active == true) && (lock_flags != NULL) && (def_nr < defbase_tot)) {
1629  lock_flags[def_nr] = true;
1630  }
1631 
1632  if (lock_flags) {
1633  for (i = 0; i < defbase_tot; i++) {
1634  if (lock_flags[i] == false) {
1635  break;
1636  }
1637  }
1638 
1639  if (i == defbase_tot) {
1640  BKE_report(reports, RPT_ERROR, "All groups are locked");
1641  goto finally;
1642  }
1643  }
1644 
1645  for (i = 0; i < dvert_tot; i++) {
1646  /* in case its not selected */
1647  if ((dv = dvert_array[i])) {
1648  if (lock_flags) {
1649  BKE_defvert_normalize_lock_map(dv, vgroup_validmap, vgroup_tot, lock_flags, defbase_tot);
1650  }
1651  else if (lock_active) {
1652  BKE_defvert_normalize_lock_single(dv, vgroup_validmap, vgroup_tot, def_nr);
1653  }
1654  else {
1655  BKE_defvert_normalize_subset(dv, vgroup_validmap, vgroup_tot);
1656  }
1657  }
1658  }
1659 
1660  changed = true;
1661 
1662  finally:
1663  if (lock_flags) {
1664  MEM_freeN(lock_flags);
1665  }
1666 
1667  MEM_freeN(dvert_array);
1668 
1669  return changed;
1670  }
1671 
1672  return false;
1673 }
1674 
1675 enum {
1680 };
1681 
1683  {VGROUP_TOGGLE,
1684  "TOGGLE",
1685  0,
1686  "Toggle",
1687  "Unlock all vertex groups if there is at least one locked group, lock all in other case"},
1688  {VGROUP_LOCK, "LOCK", 0, "Lock", "Lock all vertex groups"},
1689  {VGROUP_UNLOCK, "UNLOCK", 0, "Unlock", "Unlock all vertex groups"},
1690  {VGROUP_INVERT, "INVERT", 0, "Invert", "Invert the lock state of all vertex groups"},
1691  {0, NULL, 0, NULL, NULL},
1692 };
1693 
1694 enum {
1699 };
1700 
1702  {VGROUP_MASK_ALL, "ALL", 0, "All", "Apply action to all vertex groups"},
1703  {VGROUP_MASK_SELECTED, "SELECTED", 0, "Selected", "Apply to selected vertex groups"},
1704  {VGROUP_MASK_UNSELECTED, "UNSELECTED", 0, "Unselected", "Apply to unselected vertex groups"},
1706  "INVERT_UNSELECTED",
1707  0,
1708  "Invert Unselected",
1709  "Apply the opposite of Lock/Unlock to unselected vertex groups"},
1710  {0, NULL, 0, NULL, NULL},
1711 };
1712 
1713 static bool *vgroup_selected_get(Object *ob)
1714 {
1715  int sel_count = 0, defbase_tot = BKE_object_defgroup_count(ob);
1716  bool *mask;
1717 
1718  if (ob->mode & OB_MODE_WEIGHT_PAINT) {
1719  mask = BKE_object_defgroup_selected_get(ob, defbase_tot, &sel_count);
1720 
1721  /* Mirror the selection if X Mirror is enabled. */
1722  Mesh *me = BKE_mesh_from_object(ob);
1723 
1724  if (me && ME_USING_MIRROR_X_VERTEX_GROUPS(me)) {
1725  BKE_object_defgroup_mirror_selection(ob, defbase_tot, mask, mask, &sel_count);
1726  }
1727  }
1728  else {
1729  mask = MEM_callocN(defbase_tot * sizeof(bool), __func__);
1730  }
1731 
1732  const int actdef = BKE_object_defgroup_active_index_get(ob);
1733  if (sel_count == 0 && actdef >= 1 && actdef <= defbase_tot) {
1734  mask[actdef - 1] = true;
1735  }
1736 
1737  return mask;
1738 }
1739 
1740 static void vgroup_lock_all(Object *ob, int action, int mask)
1741 {
1742  bDeformGroup *dg;
1743  bool *selected = NULL;
1744  int i;
1745 
1746  if (mask != VGROUP_MASK_ALL) {
1747  selected = vgroup_selected_get(ob);
1748  }
1749  const ListBase *defbase = BKE_object_defgroup_list(ob);
1750 
1751  if (action == VGROUP_TOGGLE) {
1752  action = VGROUP_LOCK;
1753 
1754  for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) {
1755  switch (mask) {
1757  case VGROUP_MASK_SELECTED:
1758  if (!selected[i]) {
1759  continue;
1760  }
1761  break;
1763  if (selected[i]) {
1764  continue;
1765  }
1766  break;
1767  default:;
1768  }
1769 
1770  if (dg->flag & DG_LOCK_WEIGHT) {
1771  action = VGROUP_UNLOCK;
1772  break;
1773  }
1774  }
1775  }
1776 
1777  for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) {
1778  switch (mask) {
1779  case VGROUP_MASK_SELECTED:
1780  if (!selected[i]) {
1781  continue;
1782  }
1783  break;
1785  if (selected[i]) {
1786  continue;
1787  }
1788  break;
1789  default:;
1790  }
1791 
1792  switch (action) {
1793  case VGROUP_LOCK:
1794  dg->flag |= DG_LOCK_WEIGHT;
1795  break;
1796  case VGROUP_UNLOCK:
1797  dg->flag &= ~DG_LOCK_WEIGHT;
1798  break;
1799  case VGROUP_INVERT:
1800  dg->flag ^= DG_LOCK_WEIGHT;
1801  break;
1802  }
1803 
1804  if (mask == VGROUP_MASK_INVERT_UNSELECTED && !selected[i]) {
1805  dg->flag ^= DG_LOCK_WEIGHT;
1806  }
1807  }
1808 
1809  if (selected) {
1810  MEM_freeN(selected);
1811  }
1812 }
1813 
1815  const bool *vgroup_validmap,
1816  const int vgroup_tot,
1817  const int UNUSED(subset_count),
1818  const bool auto_assign,
1819  const bool auto_remove)
1820 {
1821  MDeformWeight *dw;
1822  MDeformVert *dv, **dvert_array = NULL;
1823  int dvert_tot = 0;
1824  const bool use_vert_sel = vertex_group_use_vert_sel(ob);
1825  const bool use_mirror = (ob->type == OB_MESH) ?
1826  (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
1827  false;
1828 
1829  ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
1830 
1831  if (dvert_array) {
1832  for (int i = 0; i < dvert_tot; i++) {
1833  /* in case its not selected */
1834  if (!(dv = dvert_array[i])) {
1835  continue;
1836  }
1837 
1838  int j = vgroup_tot;
1839  while (j--) {
1840 
1841  if (vgroup_validmap[j]) {
1842  if (auto_assign) {
1843  dw = BKE_defvert_ensure_index(dv, j);
1844  }
1845  else {
1846  dw = BKE_defvert_find_index(dv, j);
1847  }
1848 
1849  if (dw) {
1850  dw->weight = 1.0f - dw->weight;
1851  CLAMP(dw->weight, 0.0f, 1.0f);
1852  }
1853  }
1854  }
1855  }
1856 
1857  if (use_mirror && use_vert_sel) {
1858  ED_vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, vgroup_validmap, vgroup_tot);
1859  }
1860 
1861  if (auto_remove) {
1863  dvert_array, dvert_tot, vgroup_validmap, vgroup_tot, 0.0f, false);
1864  }
1865 
1866  MEM_freeN(dvert_array);
1867  }
1868 }
1869 
1871  const bool *vgroup_validmap,
1872  const int vgroup_tot,
1873  const int subset_count,
1874  const float fac,
1875  const int repeat,
1876  const float fac_expand)
1877 {
1878  const float ifac = 1.0f - fac;
1879  MDeformVert **dvert_array = NULL;
1880  int dvert_tot = 0;
1881  int *vgroup_subset_map = BLI_array_alloca(vgroup_subset_map, subset_count);
1882  float *vgroup_subset_weights = BLI_array_alloca(vgroup_subset_weights, subset_count);
1883  const bool use_mirror = (ob->type == OB_MESH) ?
1884  (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
1885  false;
1886  const bool use_select = vertex_group_use_vert_sel(ob);
1887  const bool use_hide = use_select;
1888 
1889  const int expand_sign = signum_i(fac_expand);
1890  const float expand = fabsf(fac_expand);
1891  const float iexpand = 1.0f - expand;
1892 
1894  BMesh *bm = em ? em->bm : NULL;
1895  Mesh *me = em ? NULL : ob->data;
1896 
1897  MeshElemMap *emap;
1898  int *emap_mem;
1899 
1900  float *weight_accum_prev;
1901  float *weight_accum_curr;
1902 
1903  uint subset_index;
1904 
1905  /* vertex indices that will be smoothed, (only to avoid iterating over verts that do nothing) */
1906  uint *verts_used;
1907  STACK_DECLARE(verts_used);
1908 
1909  BKE_object_defgroup_subset_to_index_array(vgroup_validmap, vgroup_tot, vgroup_subset_map);
1910  ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
1911  memset(vgroup_subset_weights, 0, sizeof(*vgroup_subset_weights) * subset_count);
1912 
1913  if (bm) {
1916 
1917  emap = NULL;
1918  emap_mem = NULL;
1919  }
1920  else {
1921  BKE_mesh_vert_edge_map_create(&emap, &emap_mem, me->medge, me->totvert, me->totedge);
1922  }
1923 
1924  weight_accum_prev = MEM_mallocN(sizeof(*weight_accum_prev) * dvert_tot, __func__);
1925  weight_accum_curr = MEM_mallocN(sizeof(*weight_accum_curr) * dvert_tot, __func__);
1926 
1927  verts_used = MEM_mallocN(sizeof(*verts_used) * dvert_tot, __func__);
1928  STACK_INIT(verts_used, dvert_tot);
1929 
1930 #define IS_BM_VERT_READ(v) (use_hide ? (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == 0) : true)
1931 #define IS_BM_VERT_WRITE(v) (use_select ? (BM_elem_flag_test(v, BM_ELEM_SELECT) != 0) : true)
1932 
1933 #define IS_ME_VERT_READ(v) (use_hide ? (((v)->flag & ME_HIDE) == 0) : true)
1934 #define IS_ME_VERT_WRITE(v) (use_select ? (((v)->flag & SELECT) != 0) : true)
1935 
1936  /* initialize used verts */
1937  if (bm) {
1938  for (int i = 0; i < dvert_tot; i++) {
1939  BMVert *v = BM_vert_at_index(bm, i);
1940  if (IS_BM_VERT_WRITE(v)) {
1941  BMIter eiter;
1942  BMEdge *e;
1943  BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
1944  BMVert *v_other = BM_edge_other_vert(e, v);
1945  if (IS_BM_VERT_READ(v_other)) {
1946  STACK_PUSH(verts_used, i);
1947  break;
1948  }
1949  }
1950  }
1951  }
1952  }
1953  else {
1954  for (int i = 0; i < dvert_tot; i++) {
1955  const MVert *v = &me->mvert[i];
1956  if (IS_ME_VERT_WRITE(v)) {
1957  for (int j = 0; j < emap[i].count; j++) {
1958  const MEdge *e = &me->medge[emap[i].indices[j]];
1959  const MVert *v_other = &me->mvert[(e->v1 == i) ? e->v2 : e->v1];
1960  if (IS_ME_VERT_READ(v_other)) {
1961  STACK_PUSH(verts_used, i);
1962  break;
1963  }
1964  }
1965  }
1966  }
1967  }
1968 
1969  for (subset_index = 0; subset_index < subset_count; subset_index++) {
1970  const int def_nr = vgroup_subset_map[subset_index];
1971  int iter;
1972 
1974  (const MDeformVert **)dvert_array, dvert_tot, weight_accum_prev, def_nr);
1975  memcpy(weight_accum_curr, weight_accum_prev, sizeof(*weight_accum_curr) * dvert_tot);
1976 
1977  for (iter = 0; iter < repeat; iter++) {
1978  uint *vi_step, *vi_end = verts_used + STACK_SIZE(verts_used);
1979 
1980  /* avoid looping over all verts */
1981  // for (i = 0; i < dvert_tot; i++)
1982  for (vi_step = verts_used; vi_step != vi_end; vi_step++) {
1983  const uint i = *vi_step;
1984  float weight_tot = 0.0f;
1985  float weight = 0.0f;
1986 
1987 #define WEIGHT_ACCUMULATE \
1988  { \
1989  float weight_other = weight_accum_prev[i_other]; \
1990  float tot_factor = 1.0f; \
1991  if (expand_sign == 1) { /* expand */ \
1992  if (weight_other < weight_accum_prev[i]) { \
1993  weight_other = (weight_accum_prev[i] * expand) + (weight_other * iexpand); \
1994  tot_factor = iexpand; \
1995  } \
1996  } \
1997  else if (expand_sign == -1) { /* contract */ \
1998  if (weight_other > weight_accum_prev[i]) { \
1999  weight_other = (weight_accum_prev[i] * expand) + (weight_other * iexpand); \
2000  tot_factor = iexpand; \
2001  } \
2002  } \
2003  weight += tot_factor * weight_other; \
2004  weight_tot += tot_factor; \
2005  } \
2006  ((void)0)
2007 
2008  if (bm) {
2009  BMVert *v = BM_vert_at_index(bm, i);
2010  BMIter eiter;
2011  BMEdge *e;
2012 
2013  /* checked already */
2015 
2016  BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
2017  BMVert *v_other = BM_edge_other_vert(e, v);
2018  if (IS_BM_VERT_READ(v_other)) {
2019  const int i_other = BM_elem_index_get(v_other);
2020 
2022  }
2023  }
2024  }
2025  else {
2026  int j;
2027 
2028  /* checked already */
2029  BLI_assert(IS_ME_VERT_WRITE(&me->mvert[i]));
2030 
2031  for (j = 0; j < emap[i].count; j++) {
2032  MEdge *e = &me->medge[emap[i].indices[j]];
2033  const int i_other = (e->v1 == i ? e->v2 : e->v1);
2034  MVert *v_other = &me->mvert[i_other];
2035 
2036  if (IS_ME_VERT_READ(v_other)) {
2038  }
2039  }
2040  }
2041 
2042 #undef WEIGHT_ACCUMULATE
2043 
2044  if (weight_tot != 0.0f) {
2045  weight /= weight_tot;
2046  weight = (weight_accum_prev[i] * ifac) + (weight * fac);
2047 
2048  /* should be within range, just clamp because of float precision */
2049  CLAMP(weight, 0.0f, 1.0f);
2050  weight_accum_curr[i] = weight;
2051  }
2052  }
2053 
2054  SWAP(float *, weight_accum_curr, weight_accum_prev);
2055  }
2056 
2057  ED_vgroup_parray_from_weight_array(dvert_array, dvert_tot, weight_accum_prev, def_nr, true);
2058  }
2059 
2060 #undef IS_BM_VERT_READ
2061 #undef IS_BM_VERT_WRITE
2062 #undef IS_ME_VERT_READ
2063 #undef IS_ME_VERT_WRITE
2064 
2065  MEM_freeN(weight_accum_curr);
2066  MEM_freeN(weight_accum_prev);
2067  MEM_freeN(verts_used);
2068 
2069  if (bm) {
2070  /* pass */
2071  }
2072  else {
2073  MEM_freeN(emap);
2074  MEM_freeN(emap_mem);
2075  }
2076 
2077  if (dvert_array) {
2078  MEM_freeN(dvert_array);
2079  }
2080 
2081  /* not so efficient to get 'dvert_array' again just so unselected verts are NULL'd */
2082  if (use_mirror) {
2083  ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, true);
2084  ED_vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, vgroup_validmap, vgroup_tot);
2085  if (dvert_array) {
2086  MEM_freeN(dvert_array);
2087  }
2088  }
2089 }
2090 
2091 static int inv_cmp_mdef_vert_weights(const void *a1, const void *a2)
2092 {
2093  /* qsort sorts in ascending order. We want descending order to save a memcopy
2094  * so this compare function is inverted from the standard greater than comparison qsort needs.
2095  * A normal compare function is called with two pointer arguments and should return an integer
2096  * less than, equal to, or greater than zero corresponding to whether its first argument is
2097  * considered less than, equal to, or greater than its second argument.
2098  * This does the opposite. */
2099  const struct MDeformWeight *dw1 = a1, *dw2 = a2;
2100 
2101  if (dw1->weight < dw2->weight) {
2102  return 1;
2103  }
2104  if (dw1->weight > dw2->weight) {
2105  return -1;
2106  }
2107  if (&dw1 < &dw2) {
2108  return 1; /* compare address for stable sort algorithm */
2109  }
2110  return -1;
2111 }
2112 
2113 /* Used for limiting the number of influencing bones per vertex when exporting
2114  * skinned meshes. if all_deform_weights is True, limit all deform modifiers
2115  * to max_weights regardless of type, otherwise,
2116  * only limit the number of influencing bones per vertex. */
2118  const bool *vgroup_validmap,
2119  const int vgroup_tot,
2120  const int subset_count,
2121  const int max_weights)
2122 {
2123  MDeformVert *dv, **dvert_array = NULL;
2124  int i, dvert_tot = 0;
2125  const bool use_vert_sel = vertex_group_use_vert_sel(ob);
2126  int remove_tot = 0;
2127 
2128  ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
2129 
2130  if (dvert_array) {
2131  int num_to_drop = 0;
2132 
2133  for (i = 0; i < dvert_tot; i++) {
2134 
2135  MDeformWeight *dw_temp;
2136  int bone_count = 0, non_bone_count = 0;
2137  int j;
2138 
2139  /* in case its not selected */
2140  if (!(dv = dvert_array[i])) {
2141  continue;
2142  }
2143 
2144  num_to_drop = subset_count - max_weights;
2145 
2146  /* first check if we even need to test further */
2147  if (num_to_drop > 0) {
2148  /* re-pack dw array so that non-bone weights are first, bone-weighted verts at end
2149  * sort the tail, then copy only the truncated array back to dv->dw */
2150  dw_temp = MEM_mallocN(sizeof(MDeformWeight) * dv->totweight, __func__);
2151  bone_count = 0;
2152  non_bone_count = 0;
2153  for (j = 0; j < dv->totweight; j++) {
2154  if (LIKELY(dv->dw[j].def_nr < vgroup_tot) && vgroup_validmap[dv->dw[j].def_nr]) {
2155  dw_temp[dv->totweight - 1 - bone_count] = dv->dw[j];
2156  bone_count += 1;
2157  }
2158  else {
2159  dw_temp[non_bone_count] = dv->dw[j];
2160  non_bone_count += 1;
2161  }
2162  }
2163  BLI_assert(bone_count + non_bone_count == dv->totweight);
2164  num_to_drop = bone_count - max_weights;
2165  if (num_to_drop > 0) {
2166  qsort(&dw_temp[non_bone_count],
2167  bone_count,
2168  sizeof(MDeformWeight),
2170  dv->totweight -= num_to_drop;
2171  /* Do we want to clean/normalize here? */
2172  MEM_freeN(dv->dw);
2173  dv->dw = MEM_reallocN(dw_temp, sizeof(MDeformWeight) * dv->totweight);
2174  remove_tot += num_to_drop;
2175  }
2176  else {
2177  MEM_freeN(dw_temp);
2178  }
2179  }
2180  }
2181  MEM_freeN(dvert_array);
2182  }
2183 
2184  return remove_tot;
2185 }
2186 
2187 static void vgroup_clean_subset(Object *ob,
2188  const bool *vgroup_validmap,
2189  const int vgroup_tot,
2190  const int UNUSED(subset_count),
2191  const float epsilon,
2192  const bool keep_single)
2193 {
2194  MDeformVert **dvert_array = NULL;
2195  int dvert_tot = 0;
2196  const bool use_vert_sel = vertex_group_use_vert_sel(ob);
2197  const bool use_mirror = (ob->type == OB_MESH) ?
2198  (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
2199  false;
2200 
2201  ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
2202 
2203  if (dvert_array) {
2204  if (use_mirror && use_vert_sel) {
2205  /* correct behavior in this case isn't well defined
2206  * for now assume both sides are mirrored correctly,
2207  * so cleaning one side also cleans the other */
2208  ED_vgroup_parray_mirror_assign(ob, dvert_array, dvert_tot);
2209  }
2210 
2212  dvert_array, dvert_tot, vgroup_validmap, vgroup_tot, epsilon, keep_single);
2213 
2214  MEM_freeN(dvert_array);
2215  }
2216 }
2217 
2219  const bool *vgroup_validmap,
2220  const int vgroup_tot,
2221  const int UNUSED(subset_count),
2222  const int steps)
2223 {
2224  MDeformVert **dvert_array = NULL;
2225  int dvert_tot = 0;
2226  const bool use_vert_sel = vertex_group_use_vert_sel(ob);
2227  const bool use_mirror = (ob->type == OB_MESH) ?
2228  (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
2229  false;
2230  ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
2231 
2232  if (dvert_array) {
2233  const float steps_fl = steps;
2234  MDeformVert *dv;
2235 
2236  if (use_mirror && use_vert_sel) {
2237  ED_vgroup_parray_mirror_assign(ob, dvert_array, dvert_tot);
2238  }
2239 
2240  for (int i = 0; i < dvert_tot; i++) {
2241  MDeformWeight *dw;
2242 
2243  /* in case its not selected */
2244  if (!(dv = dvert_array[i])) {
2245  continue;
2246  }
2247 
2248  int j;
2249  for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) {
2250  if ((dw->def_nr < vgroup_tot) && vgroup_validmap[dw->def_nr]) {
2251  dw->weight = floorf((dw->weight * steps_fl) + 0.5f) / steps_fl;
2252  CLAMP(dw->weight, 0.0f, 1.0f);
2253  }
2254  }
2255  }
2256 
2257  MEM_freeN(dvert_array);
2258  }
2259 }
2260 
2261 static void dvert_mirror_op(MDeformVert *dvert,
2262  MDeformVert *dvert_mirr,
2263  const char sel,
2264  const char sel_mirr,
2265  const int *flip_map,
2266  const int flip_map_len,
2267  const bool mirror_weights,
2268  const bool flip_vgroups,
2269  const bool all_vgroups,
2270  const int act_vgroup)
2271 {
2272  BLI_assert(sel || sel_mirr);
2273 
2274  if (sel_mirr && sel) {
2275  /* swap */
2276  if (mirror_weights) {
2277  if (all_vgroups) {
2278  SWAP(MDeformVert, *dvert, *dvert_mirr);
2279  }
2280  else {
2281  MDeformWeight *dw = BKE_defvert_find_index(dvert, act_vgroup);
2282  MDeformWeight *dw_mirr = BKE_defvert_find_index(dvert_mirr, act_vgroup);
2283 
2284  if (dw && dw_mirr) {
2285  SWAP(float, dw->weight, dw_mirr->weight);
2286  }
2287  else if (dw) {
2288  dw_mirr = BKE_defvert_ensure_index(dvert_mirr, act_vgroup);
2289  dw_mirr->weight = dw->weight;
2290  BKE_defvert_remove_group(dvert, dw);
2291  }
2292  else if (dw_mirr) {
2293  dw = BKE_defvert_ensure_index(dvert, act_vgroup);
2294  dw->weight = dw_mirr->weight;
2295  BKE_defvert_remove_group(dvert_mirr, dw_mirr);
2296  }
2297  }
2298  }
2299 
2300  if (flip_vgroups) {
2301  BKE_defvert_flip(dvert, flip_map, flip_map_len);
2302  BKE_defvert_flip(dvert_mirr, flip_map, flip_map_len);
2303  }
2304  }
2305  else {
2306  /* dvert should always be the target, only swaps pointer */
2307  if (sel_mirr) {
2308  SWAP(MDeformVert *, dvert, dvert_mirr);
2309  }
2310 
2311  if (mirror_weights) {
2312  if (all_vgroups) {
2313  BKE_defvert_copy(dvert, dvert_mirr);
2314  }
2315  else {
2316  BKE_defvert_copy_index(dvert, act_vgroup, dvert_mirr, act_vgroup);
2317  }
2318  }
2319 
2320  /* flip map already modified for 'all_vgroups' */
2321  if (flip_vgroups) {
2322  BKE_defvert_flip(dvert, flip_map, flip_map_len);
2323  }
2324  }
2325 }
2326 
2328  const bool mirror_weights,
2329  const bool flip_vgroups,
2330  const bool all_vgroups,
2331  const bool use_topology,
2332  int *r_totmirr,
2333  int *r_totfail)
2334 {
2335  /* TODO: vgroup locking.
2336  * TODO: face masking. */
2337 
2338 #define VGROUP_MIRR_OP \
2339  dvert_mirror_op(dvert, \
2340  dvert_mirr, \
2341  sel, \
2342  sel_mirr, \
2343  flip_map, \
2344  flip_map_len, \
2345  mirror_weights, \
2346  flip_vgroups, \
2347  all_vgroups, \
2348  def_nr)
2349 
2350  BMVert *eve, *eve_mirr;
2351  MDeformVert *dvert, *dvert_mirr;
2352  char sel, sel_mirr;
2353  int *flip_map = NULL, flip_map_len;
2354  const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
2355  int totmirr = 0, totfail = 0;
2356 
2357  *r_totmirr = *r_totfail = 0;
2358 
2359  const ListBase *defbase = BKE_object_defgroup_list(ob);
2360 
2361  if ((mirror_weights == false && flip_vgroups == false) ||
2362  (BLI_findlink(defbase, def_nr) == NULL)) {
2363  return;
2364  }
2365 
2366  if (flip_vgroups) {
2367  flip_map = all_vgroups ? BKE_object_defgroup_flip_map(ob, &flip_map_len, false) :
2368  BKE_object_defgroup_flip_map_single(ob, &flip_map_len, false, def_nr);
2369 
2370  BLI_assert(flip_map != NULL);
2371 
2372  if (flip_map == NULL) {
2373  /* something went wrong!, possibly no groups */
2374  return;
2375  }
2376  }
2377  else {
2378  flip_map = NULL;
2379  flip_map_len = 0;
2380  }
2381 
2382  /* only the active group */
2383  if (ob->type == OB_MESH) {
2384  Mesh *me = ob->data;
2385  BMEditMesh *em = me->edit_mesh;
2386 
2387  if (em) {
2388  const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
2389  BMIter iter;
2390 
2391  if (cd_dvert_offset == -1) {
2392  goto cleanup;
2393  }
2394 
2395  EDBM_verts_mirror_cache_begin(em, 0, true, false, false, use_topology);
2396 
2398 
2399  /* Go through the list of edit-vertices and assign them. */
2400  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2401  if (!BM_elem_flag_test(eve, BM_ELEM_TAG)) {
2402  if ((eve_mirr = EDBM_verts_mirror_get(em, eve))) {
2403  if (eve_mirr != eve) {
2404  if (!BM_elem_flag_test(eve_mirr, BM_ELEM_TAG)) {
2405  sel = BM_elem_flag_test(eve, BM_ELEM_SELECT);
2406  sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT);
2407 
2408  if ((sel || sel_mirr) && (eve != eve_mirr)) {
2409  dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
2410  dvert_mirr = BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset);
2411 
2413  totmirr++;
2414  }
2415 
2416  /* don't use these again */
2418  BM_elem_flag_enable(eve_mirr, BM_ELEM_TAG);
2419  }
2420  }
2421  }
2422  else {
2423  totfail++;
2424  }
2425  }
2426  }
2428  }
2429  else {
2430  /* object mode / weight paint */
2431  MVert *mv, *mv_mirr;
2432  int vidx, vidx_mirr;
2433  const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
2434 
2435  if (me->dvert == NULL) {
2436  goto cleanup;
2437  }
2438 
2439  if (!use_vert_sel) {
2440  sel = sel_mirr = true;
2441  }
2442 
2443  BLI_bitmap *vert_tag = BLI_BITMAP_NEW(me->totvert, __func__);
2444 
2445  for (vidx = 0, mv = me->mvert; vidx < me->totvert; vidx++, mv++) {
2446  if (!BLI_BITMAP_TEST(vert_tag, vidx)) {
2447  if ((vidx_mirr = mesh_get_x_mirror_vert(ob, NULL, vidx, use_topology)) != -1) {
2448  if (vidx != vidx_mirr) {
2449  mv_mirr = &me->mvert[vidx_mirr];
2450  if (!BLI_BITMAP_TEST(vert_tag, vidx_mirr)) {
2451 
2452  if (use_vert_sel) {
2453  sel = mv->flag & SELECT;
2454  sel_mirr = mv_mirr->flag & SELECT;
2455  }
2456 
2457  if (sel || sel_mirr) {
2458  dvert = &me->dvert[vidx];
2459  dvert_mirr = &me->dvert[vidx_mirr];
2460 
2462  totmirr++;
2463  }
2464 
2465  BLI_BITMAP_ENABLE(vert_tag, vidx);
2466  BLI_BITMAP_ENABLE(vert_tag, vidx_mirr);
2467  }
2468  }
2469  }
2470  else {
2471  totfail++;
2472  }
2473  }
2474  }
2475 
2476  MEM_freeN(vert_tag);
2477  }
2478  }
2479  else if (ob->type == OB_LATTICE) {
2480  Lattice *lt = vgroup_edit_lattice(ob);
2481  int i1, i2;
2482  int u, v, w;
2483  int pntsu_half;
2484  /* half but found up odd value */
2485 
2486  if (lt->pntsu == 1 || lt->dvert == NULL) {
2487  goto cleanup;
2488  }
2489 
2490  /* unlike editmesh we know that by only looping over the first half of
2491  * the 'u' indices it will cover all points except the middle which is
2492  * ok in this case */
2493  pntsu_half = lt->pntsu / 2;
2494 
2495  for (w = 0; w < lt->pntsw; w++) {
2496  for (v = 0; v < lt->pntsv; v++) {
2497  for (u = 0; u < pntsu_half; u++) {
2498  int u_inv = (lt->pntsu - 1) - u;
2499  if (u != u_inv) {
2500  BPoint *bp, *bp_mirr;
2501 
2502  i1 = BKE_lattice_index_from_uvw(lt, u, v, w);
2503  i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w);
2504 
2505  bp = &lt->def[i1];
2506  bp_mirr = &lt->def[i2];
2507 
2508  sel = bp->f1 & SELECT;
2509  sel_mirr = bp_mirr->f1 & SELECT;
2510 
2511  if (sel || sel_mirr) {
2512  dvert = &lt->dvert[i1];
2513  dvert_mirr = &lt->dvert[i2];
2514 
2516  totmirr++;
2517  }
2518  }
2519  }
2520  }
2521  }
2522  }
2523 
2524  /* disabled, confusing when you have an active pose bone */
2525 #if 0
2526  /* flip active group index */
2527  if (flip_vgroups && flip_map[def_nr] >= 0) {
2528  ob->actdef = flip_map[def_nr] + 1;
2529  }
2530 #endif
2531 
2532 cleanup:
2533  *r_totmirr = totmirr;
2534  *r_totfail = totfail;
2535 
2536  if (flip_map) {
2537  MEM_freeN(flip_map);
2538  }
2539 
2540 #undef VGROUP_MIRR_OP
2541 }
2542 
2544 {
2545  const ListBase *defbase = BKE_object_defgroup_list(ob);
2547  if (!dg) {
2548  return;
2549  }
2550 
2552 }
2553 
2554 /* only in editmode */
2555 static void vgroup_assign_verts(Object *ob, const float weight)
2556 {
2557  const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
2558 
2559  const ListBase *defbase = BKE_object_defgroup_list(ob);
2560  if (!BLI_findlink(defbase, def_nr)) {
2561  return;
2562  }
2563 
2564  if (ob->type == OB_MESH) {
2565  Mesh *me = ob->data;
2566 
2567  if (me->edit_mesh) {
2568  BMEditMesh *em = me->edit_mesh;
2569  int cd_dvert_offset;
2570 
2571  BMIter iter;
2572  BMVert *eve;
2573 
2576  }
2577 
2578  cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
2579 
2580  /* Go through the list of edit-vertices and assign them. */
2581  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2582  if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
2583  MDeformVert *dv;
2584  MDeformWeight *dw;
2585  dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); /* can be NULL */
2586  dw = BKE_defvert_ensure_index(dv, def_nr);
2587  if (dw) {
2588  dw->weight = weight;
2589  }
2590  }
2591  }
2592  }
2593  else {
2594  if (!me->dvert) {
2596  }
2597 
2598  MVert *mv = me->mvert;
2599  MDeformVert *dv = me->dvert;
2600 
2601  for (int i = 0; i < me->totvert; i++, mv++, dv++) {
2602  if (mv->flag & SELECT) {
2603  MDeformWeight *dw;
2604  dw = BKE_defvert_ensure_index(dv, def_nr);
2605  if (dw) {
2606  dw->weight = weight;
2607  }
2608  }
2609  }
2610  }
2611  }
2612  else if (ob->type == OB_LATTICE) {
2613  Lattice *lt = vgroup_edit_lattice(ob);
2614  MDeformVert *dv;
2615  BPoint *bp;
2616  int a, tot;
2617 
2618  if (lt->dvert == NULL) {
2620  }
2621 
2622  dv = lt->dvert;
2623 
2624  tot = lt->pntsu * lt->pntsv * lt->pntsw;
2625  for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) {
2626  if (bp->f1 & SELECT) {
2627  MDeformWeight *dw;
2628 
2629  dw = BKE_defvert_ensure_index(dv, def_nr);
2630  if (dw) {
2631  dw->weight = weight;
2632  }
2633  }
2634  }
2635  }
2636 }
2637 
2640 /* -------------------------------------------------------------------- */
2645 {
2647  CTX_wm_operator_poll_msg_set(C, "No active editable object");
2648  return false;
2649  }
2650 
2651  if (!OB_TYPE_SUPPORT_VGROUP(ob->type)) {
2652  CTX_wm_operator_poll_msg_set(C, "Object type does not support vertex groups");
2653  return false;
2654  }
2655 
2656  /* Data checks. */
2657  const ID *data = ob->data;
2659  CTX_wm_operator_poll_msg_set(C, "Object type \"%s\" does not have editable data");
2660  return false;
2661  }
2662 
2663  return true;
2664 }
2665 
2667 {
2668  Object *ob = ED_object_context(C);
2669  return vertex_group_supported_poll_ex(C, ob);
2670 }
2671 
2673 {
2674  if (!vertex_group_supported_poll_ex(C, ob)) {
2675  return false;
2676  }
2677 
2678  const ListBase *defbase = BKE_object_defgroup_list(ob);
2679  if (BLI_listbase_is_empty(defbase)) {
2680  CTX_wm_operator_poll_msg_set(C, "Object has no vertex groups");
2681  return false;
2682  }
2683 
2684  return true;
2685 }
2686 
2688 {
2689  Object *ob = ED_object_context(C);
2690  return vertex_group_poll_ex(C, ob);
2691 }
2692 
2694 {
2695  if (!vertex_group_poll_ex(C, ob)) {
2696  return false;
2697  }
2698 
2699  if (ob->type != OB_MESH) {
2700  CTX_wm_operator_poll_msg_set(C, "Only mesh objects are supported");
2701  return false;
2702  }
2703 
2704  return true;
2705 }
2706 
2708 {
2709  Object *ob = ED_object_context(C);
2710  if (!vertex_group_mesh_poll_ex(C, ob)) {
2711  return false;
2712  }
2713 
2714  Mesh *me = ob->data;
2715  if (me->dvert == NULL) {
2716  CTX_wm_operator_poll_msg_set(C, "The active mesh object has no vertex group data");
2717  return false;
2718  }
2719 
2720  return true;
2721 }
2722 
2724 {
2725  Object *ob = ED_object_context(C);
2726 
2727  if (!vertex_group_supported_poll_ex(C, ob)) {
2728  return false;
2729  }
2730 
2732 }
2733 
2734 /* editmode _or_ weight paint vertex sel */
2736  const bool needs_select,
2737  const short ob_type_flag)
2738 {
2739  Object *ob = ED_object_context(C);
2740 
2741  if (!vertex_group_supported_poll_ex(C, ob)) {
2742  return false;
2743  }
2744 
2745  if (ob_type_flag && (((1 << ob->type) & ob_type_flag)) == 0) {
2746  return false;
2747  }
2748 
2750  return true;
2751  }
2752  if (ob->mode & OB_MODE_WEIGHT_PAINT) {
2753  if (needs_select) {
2755  return true;
2756  }
2757  CTX_wm_operator_poll_msg_set(C, "Vertex select needs to be enabled in weight paint mode");
2758  return false;
2759  }
2760  return true;
2761  }
2762  return false;
2763 }
2764 
2765 #if 0
2766 static bool vertex_group_vert_poll(bContext *C)
2767 {
2768  return vertex_group_vert_poll_ex(C, false, 0);
2769 }
2770 #endif
2771 
2773 {
2774  return vertex_group_vert_poll_ex(C, false, (1 << OB_MESH));
2775 }
2776 
2778 {
2779  return vertex_group_vert_poll_ex(C, true, 0);
2780 }
2781 
2782 #if 0
2783 static bool vertex_group_mesh_vert_select_poll(bContext *C)
2784 {
2785  return vertex_group_vert_poll_ex(C, true, (1 << OB_MESH));
2786 }
2787 #endif
2788 
2789 /* editmode _or_ weight paint vertex sel and active group unlocked */
2791 {
2792  Object *ob = ED_object_context(C);
2793 
2794  if (!vertex_group_supported_poll_ex(C, ob)) {
2795  return false;
2796  }
2797 
2799  return false;
2800  }
2801 
2803  if (def_nr != 0) {
2804  const ListBase *defbase = BKE_object_defgroup_list(ob);
2805  const bDeformGroup *dg = BLI_findlink(defbase, def_nr - 1);
2806  if (dg) {
2807  return !(dg->flag & DG_LOCK_WEIGHT);
2808  }
2809  }
2810  return true;
2811 }
2812 
2814 {
2815  Object *ob = ED_object_context(C);
2816 
2817  if (!vertex_group_supported_poll_ex(C, ob)) {
2818  return false;
2819  }
2820 
2821  /* only difference to #vertex_group_vert_select_poll */
2822  if (ob->type != OB_MESH) {
2823  return false;
2824  }
2825 
2827 }
2828 
2831 /* -------------------------------------------------------------------- */
2836 {
2837  Object *ob = ED_object_context(C);
2838 
2844 
2845  return OPERATOR_FINISHED;
2846 }
2847 
2849 {
2850  /* identifiers */
2851  ot->name = "Add Vertex Group";
2852  ot->idname = "OBJECT_OT_vertex_group_add";
2853  ot->description = "Add a new vertex group to the active object";
2854 
2855  /* api callbacks */
2858 
2859  /* flags */
2861 }
2862 
2865 /* -------------------------------------------------------------------- */
2870 {
2871  Object *ob = ED_object_context(C);
2872 
2873  if (RNA_boolean_get(op->ptr, "all")) {
2875  }
2876  else if (RNA_boolean_get(op->ptr, "all_unlocked")) {
2878  }
2879  else {
2881  }
2882 
2887 
2888  return OPERATOR_FINISHED;
2889 }
2890 
2892 {
2893  /* identifiers */
2894  ot->name = "Remove Vertex Group";
2895  ot->idname = "OBJECT_OT_vertex_group_remove";
2896  ot->description = "Delete the active or all vertex groups from the active object";
2897 
2898  /* api callbacks */
2901 
2902  /* flags */
2903  /* redo operator will fail in this case because vertex groups aren't stored
2904  * in local edit mode stack and toggling "all" property will lead to
2905  * all groups deleted without way to restore them (see T29527, sergey) */
2906  ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
2907 
2908  /* properties */
2909  PropertyRNA *prop = RNA_def_boolean(ot->srna, "all", 0, "All", "Remove all vertex groups");
2911  prop = RNA_def_boolean(
2912  ot->srna, "all_unlocked", 0, "All Unlocked", "Remove all unlocked vertex groups");
2914 }
2915 
2918 /* -------------------------------------------------------------------- */
2923 {
2925  Object *ob = ED_object_context(C);
2926 
2930 
2931  return OPERATOR_FINISHED;
2932 }
2933 
2935 {
2936  /* identifiers */
2937  ot->name = "Assign to Vertex Group";
2938  ot->idname = "OBJECT_OT_vertex_group_assign";
2939  ot->description = "Assign the selected vertices to the active vertex group";
2940 
2941  /* api callbacks */
2944 
2945  /* flags */
2946  /* redo operator will fail in this case because vertex group assignment
2947  * isn't stored in local edit mode stack and toggling "new" property will
2948  * lead to creating plenty of new vertex groups (see T29527, sergey) */
2949  ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
2950 }
2951 
2954 /* -------------------------------------------------------------------- */
2958 /* NOTE: just a wrapper around vertex_group_assign_exec(), except we add these to a new group */
2960 {
2961  /* create new group... */
2962  Object *ob = ED_object_context(C);
2964 
2965  /* assign selection to new group */
2966  return vertex_group_assign_exec(C, op);
2967 }
2968 
2970 {
2971  /* identifiers */
2972  ot->name = "Assign to New Group";
2973  ot->idname = "OBJECT_OT_vertex_group_assign_new";
2974  ot->description = "Assign the selected vertices to a new vertex group";
2975 
2976  /* api callbacks */
2979 
2980  /* flags */
2981  /* redo operator will fail in this case because vertex group assignment
2982  * isn't stored in local edit mode stack and toggling "new" property will
2983  * lead to creating plenty of new vertex groups (see T29527, sergey) */
2984  ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
2985 }
2986 
2989 /* -------------------------------------------------------------------- */
2994 {
2995  const bool use_all_groups = RNA_boolean_get(op->ptr, "use_all_groups");
2996  const bool use_all_verts = RNA_boolean_get(op->ptr, "use_all_verts");
2997 
2998  Object *ob = ED_object_context(C);
2999 
3000  if (use_all_groups) {
3001  if (BKE_object_defgroup_clear_all(ob, true) == false) {
3002  return OPERATOR_CANCELLED;
3003  }
3004  }
3005  else {
3006  const ListBase *defbase = BKE_object_defgroup_list(ob);
3008  if ((dg == NULL) || (BKE_object_defgroup_clear(ob, dg, !use_all_verts) == false)) {
3009  return OPERATOR_CANCELLED;
3010  }
3011  }
3012 
3015 
3016  return OPERATOR_FINISHED;
3017 }
3018 
3020 {
3021  PropertyRNA *prop;
3022  /* identifiers */
3023  ot->name = "Remove from Vertex Group";
3024  ot->idname = "OBJECT_OT_vertex_group_remove_from";
3025  ot->description = "Remove the selected vertices from active or all vertex group(s)";
3026 
3027  /* api callbacks */
3030 
3031  /* flags */
3032  /* redo operator will fail in this case because vertex groups assignment
3033  * isn't stored in local edit mode stack and toggling "all" property will lead to
3034  * removing vertices from all groups (see T29527, sergey) */
3035  ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
3036 
3037  /* properties */
3038  prop = RNA_def_boolean(ot->srna, "use_all_groups", 0, "All Groups", "Remove from all groups");
3040  prop = RNA_def_boolean(ot->srna, "use_all_verts", 0, "All Vertices", "Clear the active group");
3042 }
3043 
3046 /* -------------------------------------------------------------------- */
3051 {
3052  Object *ob = ED_object_context(C);
3053 
3054  if (!ob || ID_IS_LINKED(ob) || ID_IS_OVERRIDE_LIBRARY(ob)) {
3055  return OPERATOR_CANCELLED;
3056  }
3057 
3058  vgroup_select_verts(ob, 1);
3061 
3062  return OPERATOR_FINISHED;
3063 }
3064 
3066 {
3067  /* identifiers */
3068  ot->name = "Select Vertex Group";
3069  ot->idname = "OBJECT_OT_vertex_group_select";
3070  ot->description = "Select all the vertices assigned to the active vertex group";
3071 
3072  /* api callbacks */
3075 
3076  /* flags */
3078 }
3079 
3082 /* -------------------------------------------------------------------- */
3087 {
3088  Object *ob = ED_object_context(C);
3089 
3090  vgroup_select_verts(ob, 0);
3093 
3094  return OPERATOR_FINISHED;
3095 }
3096 
3098 {
3099  /* identifiers */
3100  ot->name = "Deselect Vertex Group";
3101  ot->idname = "OBJECT_OT_vertex_group_deselect";
3102  ot->description = "Deselect all selected vertices assigned to the active vertex group";
3103 
3104  /* api callbacks */
3107 
3108  /* flags */
3110 }
3111 
3114 /* -------------------------------------------------------------------- */
3119 {
3120  Object *ob = ED_object_context(C);
3121 
3122  vgroup_duplicate(ob);
3127 
3128  return OPERATOR_FINISHED;
3129 }
3130 
3132 {
3133  /* identifiers */
3134  ot->name = "Copy Vertex Group";
3135  ot->idname = "OBJECT_OT_vertex_group_copy";
3136  ot->description = "Make a copy of the active vertex group";
3137 
3138  /* api callbacks */
3141 
3142  /* flags */
3144 }
3145 
3148 /* -------------------------------------------------------------------- */
3153 {
3154  Object *ob = ED_object_context(C);
3155 
3156  float offset = RNA_float_get(op->ptr, "offset");
3157  float gain = RNA_float_get(op->ptr, "gain");
3158  eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
3159 
3160  int subset_count, vgroup_tot;
3161 
3162  const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3163  ob, subset_type, &vgroup_tot, &subset_count);
3164  vgroup_levels_subset(ob, vgroup_validmap, vgroup_tot, subset_count, offset, gain);
3165  MEM_freeN((void *)vgroup_validmap);
3166 
3170 
3171  return OPERATOR_FINISHED;
3172 }
3173 
3175 {
3176  /* identifiers */
3177  ot->name = "Vertex Group Levels";
3178  ot->idname = "OBJECT_OT_vertex_group_levels";
3179  ot->description =
3180  "Add some offset and multiply with some gain the weights of the active vertex group";
3181 
3182  /* api callbacks */
3185 
3186  /* flags */
3188 
3190  RNA_def_float(
3191  ot->srna, "offset", 0.0f, -1.0, 1.0, "Offset", "Value to add to weights", -1.0f, 1.0f);
3192  RNA_def_float(
3193  ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply weights by", 0.0f, 10.0f);
3194 }
3195 
3198 /* -------------------------------------------------------------------- */
3203 {
3204  Object *ob = ED_object_context(C);
3205  bool changed;
3206 
3207  changed = vgroup_normalize(ob);
3208 
3209  if (changed) {
3213 
3214  return OPERATOR_FINISHED;
3215  }
3216  return OPERATOR_CANCELLED;
3217 }
3218 
3220 {
3221  /* identifiers */
3222  ot->name = "Normalize Vertex Group";
3223  ot->idname = "OBJECT_OT_vertex_group_normalize";
3224  ot->description =
3225  "Normalize weights of the active vertex group, so that the highest ones are now 1.0";
3226 
3227  /* api callbacks */
3230 
3231  /* flags */
3233 }
3234 
3237 /* -------------------------------------------------------------------- */
3242 {
3243  Object *ob = ED_object_context(C);
3244  bool lock_active = RNA_boolean_get(op->ptr, "lock_active");
3245  eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
3246  bool changed;
3247  int subset_count, vgroup_tot;
3248  const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3249  ob, subset_type, &vgroup_tot, &subset_count);
3250 
3251  changed = vgroup_normalize_all(
3252  ob, vgroup_validmap, vgroup_tot, subset_count, lock_active, op->reports);
3253  MEM_freeN((void *)vgroup_validmap);
3254 
3255  if (changed) {
3259 
3260  return OPERATOR_FINISHED;
3261  }
3262 
3263  /* allow to adjust settings */
3264  return OPERATOR_FINISHED;
3265 }
3266 
3268 {
3269  /* identifiers */
3270  ot->name = "Normalize All Vertex Groups";
3271  ot->idname = "OBJECT_OT_vertex_group_normalize_all";
3272  ot->description =
3273  "Normalize all weights of all vertex groups, "
3274  "so that for each vertex, the sum of all weights is 1.0";
3275 
3276  /* api callbacks */
3279 
3280  /* flags */
3282 
3285  "lock_active",
3286  true,
3287  "Lock Active",
3288  "Keep the values of the active group while normalizing others");
3289 }
3290 
3293 /* -------------------------------------------------------------------- */
3298 {
3301 
3302  float distToBe = RNA_float_get(op->ptr, "dist");
3303  float strength = RNA_float_get(op->ptr, "strength");
3304  float cp = RNA_float_get(op->ptr, "accuracy");
3305  ModifierData *md = ob->modifiers.first;
3306 
3307  while (md) {
3308  if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
3309  break;
3310  }
3311  md = md->next;
3312  }
3313 
3314  if (md && md->type == eModifierType_Mirror) {
3315  BKE_report(op->reports,
3317  "This operator does not support an active mirror modifier");
3318  return OPERATOR_CANCELLED;
3319  }
3320  vgroup_fix(C, scene, ob, distToBe, strength, cp);
3321 
3325 
3326  return OPERATOR_FINISHED;
3327 }
3328 
3330 {
3331  /* identifiers */
3332  ot->name = "Fix Vertex Group Deform";
3333  ot->idname = "OBJECT_OT_vertex_group_fix";
3334  ot->description =
3335  "Modify the position of selected vertices by changing only their respective "
3336  "groups' weights (this tool may be slow for many vertices)";
3337 
3338  /* api callbacks */
3341 
3342  /* flags */
3345  "dist",
3346  0.0f,
3347  -FLT_MAX,
3348  FLT_MAX,
3349  "Distance",
3350  "The distance to move to",
3351  -10.0f,
3352  10.0f);
3354  "strength",
3355  1.0f,
3356  -2.0f,
3357  FLT_MAX,
3358  "Strength",
3359  "The distance moved can be changed by this multiplier",
3360  -2.0f,
3361  2.0f);
3362  RNA_def_float(
3363  ot->srna,
3364  "accuracy",
3365  1.0f,
3366  0.05f,
3367  FLT_MAX,
3368  "Change Sensitivity",
3369  "Change the amount weights are altered with each iteration: lower values are slower",
3370  0.05f,
3371  1.0f);
3372 }
3373 
3376 /* -------------------------------------------------------------------- */
3381 {
3383 
3384  int action = RNA_enum_get(op->ptr, "action");
3385  int mask = RNA_enum_get(op->ptr, "mask");
3386 
3387  vgroup_lock_all(ob, action, mask);
3388 
3390 
3391  return OPERATOR_FINISHED;
3392 }
3393 
3395  struct wmOperatorType *UNUSED(op),
3396  struct PointerRNA *params)
3397 {
3398  int action = RNA_enum_get(params, "action");
3399  int mask = RNA_enum_get(params, "mask");
3400 
3401  const char *action_str, *target_str;
3402 
3403  switch (action) {
3404  case VGROUP_LOCK:
3405  action_str = TIP_("Lock");
3406  break;
3407  case VGROUP_UNLOCK:
3408  action_str = TIP_("Unlock");
3409  break;
3410  case VGROUP_TOGGLE:
3411  action_str = TIP_("Toggle locks of");
3412  break;
3413  case VGROUP_INVERT:
3414  action_str = TIP_("Invert locks of");
3415  break;
3416  default:
3417  return NULL;
3418  }
3419 
3420  switch (mask) {
3421  case VGROUP_MASK_ALL:
3422  target_str = TIP_("all");
3423  break;
3424  case VGROUP_MASK_SELECTED:
3425  target_str = TIP_("selected");
3426  break;
3428  target_str = TIP_("unselected");
3429  break;
3431  switch (action) {
3432  case VGROUP_INVERT:
3433  target_str = TIP_("selected");
3434  break;
3435  case VGROUP_LOCK:
3436  target_str = TIP_("selected and unlock unselected");
3437  break;
3438  case VGROUP_UNLOCK:
3439  target_str = TIP_("selected and lock unselected");
3440  break;
3441  default:
3442  target_str = TIP_("all and invert unselected");
3443  }
3444  break;
3445  default:
3446  return NULL;
3447  }
3448 
3449  return BLI_sprintfN(TIP_("%s %s vertex groups of the active object"), action_str, target_str);
3450 }
3451 
3453 {
3454  /* identifiers */
3455  ot->name = "Change the Lock On Vertex Groups";
3456  ot->idname = "OBJECT_OT_vertex_group_lock";
3457  ot->description = "Change the lock state of all or some vertex groups of active object";
3458 
3459  /* api callbacks */
3463 
3464  /* flags */
3466 
3467  RNA_def_enum(ot->srna,
3468  "action",
3470  VGROUP_TOGGLE,
3471  "Action",
3472  "Lock action to execute on vertex groups");
3473 
3474  RNA_def_enum(ot->srna,
3475  "mask",
3478  "Mask",
3479  "Apply the action based on vertex group selection");
3480 }
3481 
3484 /* -------------------------------------------------------------------- */
3489 {
3490  Object *ob = ED_object_context(C);
3491  bool auto_assign = RNA_boolean_get(op->ptr, "auto_assign");
3492  bool auto_remove = RNA_boolean_get(op->ptr, "auto_remove");
3493 
3494  eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
3495 
3496  int subset_count, vgroup_tot;
3497 
3498  const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3499  ob, subset_type, &vgroup_tot, &subset_count);
3500  vgroup_invert_subset(ob, vgroup_validmap, vgroup_tot, subset_count, auto_assign, auto_remove);
3501  MEM_freeN((void *)vgroup_validmap);
3502 
3506 
3507  return OPERATOR_FINISHED;
3508 }
3509 
3511 {
3512  /* identifiers */
3513  ot->name = "Invert Vertex Group";
3514  ot->idname = "OBJECT_OT_vertex_group_invert";
3515  ot->description = "Invert active vertex group's weights";
3516 
3517  /* api callbacks */
3520 
3521  /* flags */
3523 
3526  "auto_assign",
3527  true,
3528  "Add Weights",
3529  "Add vertices from groups that have zero weight before inverting");
3531  "auto_remove",
3532  true,
3533  "Remove Weights",
3534  "Remove vertices from groups that have zero weight after inverting");
3535 }
3536 
3539 /* -------------------------------------------------------------------- */
3544 {
3545  const float fac = RNA_float_get(op->ptr, "factor");
3546  const int repeat = RNA_int_get(op->ptr, "repeat");
3547  const eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
3548  const float fac_expand = RNA_float_get(op->ptr, "expand");
3549 
3550  uint objects_len;
3551  Object **objects = object_array_for_wpaint(C, &objects_len);
3552 
3553  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3554  Object *ob = objects[ob_index];
3555 
3556  int subset_count, vgroup_tot;
3557 
3558  const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3559  ob, subset_type, &vgroup_tot, &subset_count);
3560 
3561  vgroup_smooth_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac, repeat, fac_expand);
3562  MEM_freeN((void *)vgroup_validmap);
3563 
3567  }
3568  MEM_freeN(objects);
3569 
3570  return OPERATOR_FINISHED;
3571 }
3572 
3574 {
3575  /* identifiers */
3576  ot->name = "Smooth Vertex Weights";
3577  ot->idname = "OBJECT_OT_vertex_group_smooth";
3578  ot->description = "Smooth weights for selected vertices";
3579 
3580  /* api callbacks */
3583 
3584  /* flags */
3586 
3588  RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0, "Factor", "", 0.0f, 1.0f);
3589  RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
3590 
3592  "expand",
3593  0.0f,
3594  -1.0f,
3595  1.0,
3596  "Expand/Contract",
3597  "Expand/contract weights",
3598  -1.0f,
3599  1.0f);
3600 }
3601 
3604 /* -------------------------------------------------------------------- */
3609 {
3610  const float limit = RNA_float_get(op->ptr, "limit");
3611  const bool keep_single = RNA_boolean_get(op->ptr, "keep_single");
3612  const eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
3613 
3614  uint objects_len;
3615  Object **objects = object_array_for_wpaint(C, &objects_len);
3616 
3617  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3618  Object *ob = objects[ob_index];
3619 
3620  int subset_count, vgroup_tot;
3621 
3622  const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3623  ob, subset_type, &vgroup_tot, &subset_count);
3624 
3625  vgroup_clean_subset(ob, vgroup_validmap, vgroup_tot, subset_count, limit, keep_single);
3626  MEM_freeN((void *)vgroup_validmap);
3627 
3631  }
3632  MEM_freeN(objects);
3633 
3634  return OPERATOR_FINISHED;
3635 }
3636 
3638 {
3639  /* identifiers */
3640  ot->name = "Clean Vertex Group Weights";
3641  ot->idname = "OBJECT_OT_vertex_group_clean";
3642  ot->description = "Remove vertex group assignments which are not required";
3643 
3644  /* api callbacks */
3647 
3648  /* flags */
3650 
3653  "limit",
3654  0.0f,
3655  0.0f,
3656  1.0,
3657  "Limit",
3658  "Remove vertices which weight is below or equal to this limit",
3659  0.0f,
3660  0.99f);
3662  "keep_single",
3663  false,
3664  "Keep Single",
3665  "Keep verts assigned to at least one group when cleaning");
3666 }
3667 
3670 /* -------------------------------------------------------------------- */
3675 {
3676  Object *ob = ED_object_context(C);
3677 
3678  const int steps = RNA_int_get(op->ptr, "steps");
3679  eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
3680 
3681  int subset_count, vgroup_tot;
3682 
3683  const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3684  ob, subset_type, &vgroup_tot, &subset_count);
3685  vgroup_quantize_subset(ob, vgroup_validmap, vgroup_tot, subset_count, steps);
3686  MEM_freeN((void *)vgroup_validmap);
3687 
3691 
3692  return OPERATOR_FINISHED;
3693 }
3694 
3696 {
3697  /* identifiers */
3698  ot->name = "Quantize Vertex Weights";
3699  ot->idname = "OBJECT_OT_vertex_group_quantize";
3700  ot->description = "Set weights to a fixed number of steps";
3701 
3702  /* api callbacks */
3705 
3706  /* flags */
3708 
3710  RNA_def_int(ot->srna, "steps", 4, 1, 1000, "Steps", "Number of steps between 0 and 1", 1, 100);
3711 }
3712 
3715 /* -------------------------------------------------------------------- */
3720 {
3721  const int limit = RNA_int_get(op->ptr, "limit");
3722  const eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
3723  int remove_multi_count = 0;
3724 
3725  uint objects_len;
3726  Object **objects = object_array_for_wpaint(C, &objects_len);
3727  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3728  Object *ob = objects[ob_index];
3729 
3730  int subset_count, vgroup_tot;
3731  const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3732  ob, subset_type, &vgroup_tot, &subset_count);
3733  const int remove_count = vgroup_limit_total_subset(
3734  ob, vgroup_validmap, vgroup_tot, subset_count, limit);
3735  MEM_freeN((void *)vgroup_validmap);
3736 
3737  if (remove_count != 0) {
3741  }
3742  remove_multi_count += remove_count;
3743  }
3744  MEM_freeN(objects);
3745 
3746  if (remove_multi_count) {
3747  BKE_reportf(op->reports,
3748  remove_multi_count ? RPT_INFO : RPT_WARNING,
3749  "%d vertex weights limited",
3750  remove_multi_count);
3751 
3752  return OPERATOR_FINISHED;
3753  }
3754 
3755  /* NOTE: would normally return canceled, except we want the redo
3756  * UI to show up for users to change */
3757  return OPERATOR_FINISHED;
3758 }
3759 
3761 {
3762  /* identifiers */
3763  ot->name = "Limit Number of Weights per Vertex";
3764  ot->idname = "OBJECT_OT_vertex_group_limit_total";
3765  ot->description =
3766  "Limit deform weights associated with a vertex to a specified number by removing lowest "
3767  "weights";
3768 
3769  /* api callbacks */
3772 
3773  /* flags */
3775 
3777  RNA_def_int(ot->srna, "limit", 4, 1, 32, "Limit", "Maximum number of deform weights", 1, 32);
3778 }
3779 
3782 /* -------------------------------------------------------------------- */
3787 {
3788  Object *ob = ED_object_context(C);
3789  int totmirr = 0, totfail = 0;
3790 
3791  ED_vgroup_mirror(ob,
3792  RNA_boolean_get(op->ptr, "mirror_weights"),
3793  RNA_boolean_get(op->ptr, "flip_group_names"),
3794  RNA_boolean_get(op->ptr, "all_groups"),
3795  RNA_boolean_get(op->ptr, "use_topology"),
3796  &totmirr,
3797  &totfail);
3798 
3799  ED_mesh_report_mirror(op, totmirr, totfail);
3800 
3805 
3806  return OPERATOR_FINISHED;
3807 }
3808 
3810 {
3811  /* identifiers */
3812  ot->name = "Mirror Vertex Group";
3813  ot->idname = "OBJECT_OT_vertex_group_mirror";
3814  ot->description =
3815  "Mirror vertex group, flip weights and/or names, editing only selected vertices, "
3816  "flipping when both sides are selected otherwise copy from unselected";
3817 
3818  /* api callbacks */
3821 
3822  /* flags */
3824 
3825  /* properties */
3826  RNA_def_boolean(ot->srna, "mirror_weights", true, "Mirror Weights", "Mirror weights");
3828  ot->srna, "flip_group_names", true, "Flip Group Names", "Flip vertex group names");
3829  RNA_def_boolean(ot->srna, "all_groups", false, "All Groups", "Mirror all vertex groups weights");
3831  ot->srna,
3832  "use_topology",
3833  0,
3834  "Topology Mirror",
3835  "Use topology based mirroring (for when both sides of mesh have matching, unique topology)");
3836 }
3837 
3840 /* -------------------------------------------------------------------- */
3845 {
3846  Object *obact = ED_object_context(C);
3847  int changed_tot = 0;
3848  int fail = 0;
3849 
3850  CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
3851  if (obact != ob && BKE_object_supports_vertex_groups(ob)) {
3852  if (ED_vgroup_array_copy(ob, obact)) {
3856  changed_tot++;
3857  }
3858  else {
3859  fail++;
3860  }
3861  }
3862  }
3863  CTX_DATA_END;
3864 
3865  if ((changed_tot == 0 && fail == 0) || fail) {
3866  BKE_reportf(op->reports,
3867  RPT_ERROR,
3868  "Copy vertex groups to selected: %d done, %d failed (object data must support "
3869  "vertex groups and have matching indices)",
3870  changed_tot,
3871  fail);
3872  }
3873 
3874  return OPERATOR_FINISHED;
3875 }
3876 
3878 {
3879  /* identifiers */
3880  ot->name = "Copy Vertex Group to Selected";
3881  ot->idname = "OBJECT_OT_vertex_group_copy_to_selected";
3882  ot->description = "Replace vertex groups of selected objects by vertex groups of active object";
3883 
3884  /* api callbacks */
3887 
3888  /* flags */
3890 }
3891 
3894 /* -------------------------------------------------------------------- */
3899 {
3900  Object *ob = ED_object_context(C);
3901  int nr = RNA_enum_get(op->ptr, "group");
3902 
3903  BLI_assert(nr + 1 >= 0);
3905 
3908 
3909  return OPERATOR_FINISHED;
3910 }
3911 
3913  PointerRNA *UNUSED(ptr),
3914  PropertyRNA *UNUSED(prop),
3915  bool *r_free)
3916 {
3917  if (C == NULL) {
3918  return DummyRNA_NULL_items;
3919  }
3920 
3921  Object *ob = ED_object_context(C);
3922  EnumPropertyItem tmp = {0, "", 0, "", ""};
3923  EnumPropertyItem *item = NULL;
3924  bDeformGroup *def;
3925  int a, totitem = 0;
3926 
3927  if (!ob) {
3928  return DummyRNA_NULL_items;
3929  }
3930 
3931  const ListBase *defbase = BKE_object_defgroup_list(ob);
3932  for (a = 0, def = defbase->first; def; def = def->next, a++) {
3933  tmp.value = a;
3934  tmp.icon = ICON_GROUP_VERTEX;
3935  tmp.identifier = def->name;
3936  tmp.name = def->name;
3937  RNA_enum_item_add(&item, &totitem, &tmp);
3938  }
3939 
3940  RNA_enum_item_end(&item, &totitem);
3941  *r_free = true;
3942 
3943  return item;
3944 }
3945 
3947 {
3948  PropertyRNA *prop;
3949 
3950  /* identifiers */
3951  ot->name = "Set Active Vertex Group";
3952  ot->idname = "OBJECT_OT_vertex_group_set_active";
3953  ot->description = "Set the active vertex group";
3954 
3955  /* api callbacks */
3959 
3960  /* flags */
3962 
3963  /* properties */
3964  prop = RNA_def_enum(
3965  ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "Vertex group to set as active");
3968  ot->prop = prop;
3969 }
3970 
3973 /* -------------------------------------------------------------------- */
3977 /* creates the name_array parameter for vgroup_do_remap, call this before fiddling
3978  * with the order of vgroups then call vgroup_do_remap after */
3979 static char *vgroup_init_remap(Object *ob)
3980 {
3981  const ListBase *defbase = BKE_object_defgroup_list(ob);
3982  int defbase_tot = BLI_listbase_count(defbase);
3983  char *name_array = MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * defbase_tot, "sort vgroups");
3984  char *name;
3985 
3986  name = name_array;
3987  for (const bDeformGroup *def = defbase->first; def; def = def->next) {
3988  BLI_strncpy(name, def->name, MAX_VGROUP_NAME);
3989  name += MAX_VGROUP_NAME;
3990  }
3991 
3992  return name_array;
3993 }
3994 
3995 static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
3996 {
3997  MDeformVert *dvert = NULL;
3998  const bDeformGroup *def;
3999  const ListBase *defbase = BKE_object_defgroup_list(ob);
4000  int defbase_tot = BLI_listbase_count(defbase);
4001 
4002  /* Needs a dummy index at the start. */
4003  int *sort_map_update = MEM_mallocN(sizeof(int) * (defbase_tot + 1), "sort vgroups");
4004  int *sort_map = sort_map_update + 1;
4005 
4006  const char *name;
4007  int i;
4008 
4009  name = name_array;
4010  for (def = defbase->first, i = 0; def; def = def->next, i++) {
4011  sort_map[i] = BLI_findstringindex(defbase, name, offsetof(bDeformGroup, name));
4012  name += MAX_VGROUP_NAME;
4013 
4014  BLI_assert(sort_map[i] != -1);
4015  }
4016 
4017  if (ob->mode == OB_MODE_EDIT) {
4018  if (ob->type == OB_MESH) {
4020  const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
4021 
4022  if (cd_dvert_offset != -1) {
4023  BMIter iter;
4024  BMVert *eve;
4025 
4026  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
4027  dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
4028  if (dvert->totweight) {
4029  BKE_defvert_remap(dvert, sort_map, defbase_tot);
4030  }
4031  }
4032  }
4033  }
4034  else {
4035  BKE_report(op->reports, RPT_ERROR, "Editmode lattice is not supported yet");
4036  MEM_freeN(sort_map_update);
4037  return OPERATOR_CANCELLED;
4038  }
4039  }
4040  else {
4041  int dvert_tot = 0;
4042  /* Grease pencil stores vertex groups separately for each stroke,
4043  * so remap each stroke's weights separately. */
4044  if (ob->type == OB_GPENCIL) {
4045  bGPdata *gpd = ob->data;
4046  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
4047  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
4048  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
4049  dvert = gps->dvert;
4050  dvert_tot = gps->totpoints;
4051  if (dvert) {
4052  while (dvert_tot--) {
4053  if (dvert->totweight) {
4054  BKE_defvert_remap(dvert, sort_map, defbase_tot);
4055  }
4056  dvert++;
4057  }
4058  }
4059  }
4060  }
4061  }
4062  }
4063  else {
4064  BKE_object_defgroup_array_get(ob->data, &dvert, &dvert_tot);
4065 
4066  /* Create as necessary. */
4067  if (dvert) {
4068  while (dvert_tot--) {
4069  if (dvert->totweight) {
4070  BKE_defvert_remap(dvert, sort_map, defbase_tot);
4071  }
4072  dvert++;
4073  }
4074  }
4075  }
4076  }
4077 
4078  /* update users */
4079  for (i = 0; i < defbase_tot; i++) {
4080  sort_map[i]++;
4081  }
4082 
4083  sort_map_update[0] = 0;
4084  BKE_object_defgroup_remap_update_users(ob, sort_map_update);
4085 
4086  BLI_assert(sort_map_update[BKE_object_defgroup_active_index_get(ob)] >= 0);
4088  sort_map_update[BKE_object_defgroup_active_index_get(ob)]);
4089 
4090  MEM_freeN(sort_map_update);
4091 
4092  return OPERATOR_FINISHED;
4093 }
4094 
4095 static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr)
4096 {
4097  const bDeformGroup *def_a = def_a_ptr;
4098  const bDeformGroup *def_b = def_b_ptr;
4099 
4100  return BLI_strcasecmp_natural(def_a->name, def_b->name);
4101 }
4102 
4107 static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase)
4108 {
4109  if (bonebase == NULL) {
4111  if (armobj != NULL) {
4112  bArmature *armature = armobj->data;
4113  bonebase = &armature->bonebase;
4114  }
4115  }
4117 
4118  if (bonebase != NULL) {
4119  Bone *bone;
4120  for (bone = bonebase->last; bone; bone = bone->prev) {
4123 
4124  if (dg != NULL) {
4125  BLI_remlink(defbase, dg);
4126  BLI_addhead(defbase, dg);
4127  }
4128  }
4129  }
4130 }
4131 
4132 enum {
4135 };
4136 
4138 {
4139  Object *ob = ED_object_context(C);
4140  char *name_array;
4141  int ret;
4142  int sort_type = RNA_enum_get(op->ptr, "sort_type");
4143 
4144  /* Init remapping. */
4145  name_array = vgroup_init_remap(ob);
4146 
4148 
4149  /* Sort vgroup names. */
4150  switch (sort_type) {
4151  case SORT_TYPE_NAME:
4153  break;
4156  break;
4157  }
4158 
4159  /* Remap vgroup data to map to correct names. */
4160  ret = vgroup_do_remap(ob, name_array, op);
4161 
4162  if (ret != OPERATOR_CANCELLED) {
4165  }
4166 
4167  if (name_array) {
4168  MEM_freeN(name_array);
4169  }
4170 
4171  return ret;
4172 }
4173 
4175 {
4176  static const EnumPropertyItem vgroup_sort_type[] = {
4177  {SORT_TYPE_NAME, "NAME", 0, "Name", ""},
4178  {SORT_TYPE_BONEHIERARCHY, "BONE_HIERARCHY", 0, "Bone Hierarchy", ""},
4179  {0, NULL, 0, NULL, NULL},
4180  };
4181 
4182  ot->name = "Sort Vertex Groups";
4183  ot->idname = "OBJECT_OT_vertex_group_sort";
4184  ot->description = "Sort vertex groups";
4185 
4186  /* api callbacks */
4189 
4190  /* flags */
4192 
4193  RNA_def_enum(ot->srna, "sort_type", vgroup_sort_type, SORT_TYPE_NAME, "Sort Type", "Sort type");
4194 }
4195 
4198 /* -------------------------------------------------------------------- */
4203 {
4204  Object *ob = ED_object_context(C);
4205  bDeformGroup *def;
4206  char *name_array;
4207  int dir = RNA_enum_get(op->ptr, "direction");
4208  int ret = OPERATOR_FINISHED;
4209 
4211 
4212  def = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1);
4213  if (!def) {
4214  return OPERATOR_CANCELLED;
4215  }
4216 
4217  name_array = vgroup_init_remap(ob);
4218 
4219  if (BLI_listbase_link_move(defbase, def, dir)) {
4220  ret = vgroup_do_remap(ob, name_array, op);
4221 
4222  if (ret != OPERATOR_CANCELLED) {
4225  }
4226  }
4227 
4228  if (name_array) {
4229  MEM_freeN(name_array);
4230  }
4231 
4232  return ret;
4233 }
4234 
4236 {
4237  static const EnumPropertyItem vgroup_slot_move[] = {
4238  {-1, "UP", 0, "Up", ""},
4239  {1, "DOWN", 0, "Down", ""},
4240  {0, NULL, 0, NULL, NULL},
4241  };
4242 
4243  /* identifiers */
4244  ot->name = "Move Vertex Group";
4245  ot->idname = "OBJECT_OT_vertex_group_move";
4246  ot->description = "Move the active vertex group up/down in the list";
4247 
4248  /* api callbacks */
4251 
4252  /* flags */
4254 
4255  RNA_def_enum(ot->srna,
4256  "direction",
4257  vgroup_slot_move,
4258  0,
4259  "Direction",
4260  "Direction to move the active vertex group towards");
4261 }
4262 
4265 /* -------------------------------------------------------------------- */
4270 {
4271  MDeformVert *dvert_act;
4272 
4273  Mesh *me = ob->data;
4274  BMEditMesh *em = me->edit_mesh;
4275  int i;
4276 
4277  if (em) {
4278  const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
4279  BMIter iter;
4280  BMVert *eve, *eve_act;
4281 
4282  dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
4283  if (dvert_act == NULL) {
4284  return;
4285  }
4286 
4287  BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
4288  if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && (eve != eve_act)) {
4289  MDeformVert *dvert_dst = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
4290 
4291  BKE_defvert_copy_index(dvert_dst, def_nr, dvert_act, def_nr);
4292 
4293  if (me->symmetry & ME_SYMMETRY_X) {
4294  ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
4295  }
4296  }
4297  }
4298 
4299  if (me->symmetry & ME_SYMMETRY_X) {
4300  ED_mesh_defvert_mirror_update_em(ob, eve_act, -1, -1, cd_dvert_offset);
4301  }
4302  }
4303  else {
4304  MDeformVert *dv;
4305  int v_act;
4306 
4307  dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
4308  if (dvert_act == NULL) {
4309  return;
4310  }
4311 
4312  dv = me->dvert;
4313  for (i = 0; i < me->totvert; i++, dv++) {
4314  if ((me->mvert[i].flag & SELECT) && (dv != dvert_act)) {
4315 
4316  BKE_defvert_copy_index(dv, def_nr, dvert_act, def_nr);
4317 
4318  if (me->symmetry & ME_SYMMETRY_X) {
4320  }
4321  }
4322  }
4323 
4324  if (me->symmetry & ME_SYMMETRY_X) {
4325  ED_mesh_defvert_mirror_update_ob(ob, -1, v_act);
4326  }
4327  }
4328 }
4329 
4331 {
4332  const ListBase *defbase = BKE_object_defgroup_list(ob);
4333  bDeformGroup *dg = BLI_findlink(defbase, def_nr);
4334 
4335  if (!dg) {
4336  BKE_report(op->reports, RPT_ERROR, "Invalid vertex group index");
4337  return false;
4338  }
4339 
4340  if (dg->flag & DG_LOCK_WEIGHT) {
4341  BKE_report(op->reports, RPT_ERROR, "Vertex group is locked");
4342  return false;
4343  }
4344 
4345  return true;
4346 }
4347 
4349 {
4350  Object *ob = ED_object_context(C);
4351  const int def_nr = RNA_int_get(op->ptr, "weight_group");
4352 
4353  if (!check_vertex_group_accessible(op, ob, def_nr)) {
4354  return OPERATOR_CANCELLED;
4355  }
4356 
4358 
4361 
4362  return OPERATOR_FINISHED;
4363 }
4364 
4366 {
4367  PropertyRNA *prop;
4368 
4369  ot->name = "Paste Weight to Selected";
4370  ot->idname = "OBJECT_OT_vertex_weight_paste";
4371  ot->description =
4372  "Copy this group's weight to other selected vertices (disabled if vertex group is locked)";
4373 
4374  /* api callbacks */
4377 
4378  /* flags */
4380 
4381  prop = RNA_def_int(ot->srna,
4382  "weight_group",
4383  -1,
4384  -1,
4385  INT_MAX,
4386  "Weight Index",
4387  "Index of source weight in active vertex group",
4388  -1,
4389  INT_MAX);
4391 }
4392 
4395 /* -------------------------------------------------------------------- */
4400 {
4401  Object *ob = ED_object_context(C);
4402  const int def_nr = RNA_int_get(op->ptr, "weight_group");
4403 
4404  if (!check_vertex_group_accessible(op, ob, def_nr)) {
4405  return OPERATOR_CANCELLED;
4406  }
4407 
4409 
4412 
4413  return OPERATOR_FINISHED;
4414 }
4415 
4417 {
4418  PropertyRNA *prop;
4419 
4420  ot->name = "Delete Weight";
4421  ot->idname = "OBJECT_OT_vertex_weight_delete";
4422  ot->description = "Delete this weight from the vertex (disabled if vertex group is locked)";
4423 
4424  /* api callbacks */
4427 
4428  /* flags */
4430 
4431  prop = RNA_def_int(ot->srna,
4432  "weight_group",
4433  -1,
4434  -1,
4435  INT_MAX,
4436  "Weight Index",
4437  "Index of source weight in active vertex group",
4438  -1,
4439  INT_MAX);
4441 }
4442 
4445 /* -------------------------------------------------------------------- */
4450 {
4451  Object *ob = ED_object_context(C);
4452  const int wg_index = RNA_int_get(op->ptr, "weight_group");
4453 
4454  if (wg_index != -1) {
4455  BKE_object_defgroup_active_index_set(ob, wg_index + 1);
4458  }
4459 
4460  return OPERATOR_FINISHED;
4461 }
4462 
4464 {
4465  PropertyRNA *prop;
4466 
4467  ot->name = "Set Active Group";
4468  ot->idname = "OBJECT_OT_vertex_weight_set_active";
4469  ot->description = "Set as active vertex group";
4470 
4471  /* api callbacks */
4474 
4475  /* flags */
4477 
4478  prop = RNA_def_int(ot->srna,
4479  "weight_group",
4480  -1,
4481  -1,
4482  INT_MAX,
4483  "Weight Index",
4484  "Index of source weight in active vertex group",
4485  -1,
4486  INT_MAX);
4488 }
4489 
4492 /* -------------------------------------------------------------------- */
4497 {
4498  Object *ob = ED_object_context(C);
4500  eVGroupSelect subset_type = ts->vgroupsubset;
4501  bool changed;
4502 
4503  changed = vgroup_normalize_active_vertex(ob, subset_type);
4504 
4505  if (changed) {
4508 
4509  return OPERATOR_FINISHED;
4510  }
4511  return OPERATOR_CANCELLED;
4512 }
4513 
4515 {
4516 
4517  ot->name = "Normalize Active";
4518  ot->idname = "OBJECT_OT_vertex_weight_normalize_active_vertex";
4519  ot->description = "Normalize active vertex's weights";
4520 
4521  /* api callbacks */
4524 
4525  /* flags */
4527 }
4528 
4531 /* -------------------------------------------------------------------- */
4536 {
4537  Object *ob = ED_object_context(C);
4539  eVGroupSelect subset_type = ts->vgroupsubset;
4540 
4541  vgroup_copy_active_to_sel(ob, subset_type);
4542 
4545 
4546  return OPERATOR_FINISHED;
4547 }
4548 
4550 {
4551 
4552  ot->name = "Copy Active";
4553  ot->idname = "OBJECT_OT_vertex_weight_copy";
4554  ot->description = "Copy weights from active to selected";
4555 
4556  /* api callbacks */
4559 
4560  /* flags */
4562 }
4563 
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
#define CTX_DATA_BEGIN(C, Type, instance, member)
Definition: BKE_context.h:269
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
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg)
Definition: context.c:1042
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
#define CTX_DATA_END
Definition: BKE_context.h:278
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_has_layer(const struct CustomData *data, int type)
const CustomData_MeshMasks CD_MASK_BAREMESH
Definition: customdata.cc:2051
int CustomData_get_offset(const struct CustomData *data, int type)
support for deformation groups and hooks.
bool BKE_object_supports_vertex_groups(const struct Object *ob)
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 ListBase * BKE_object_defgroup_list_mutable(struct Object *ob)
Definition: deform.c:552
void BKE_defvert_normalize_subset(struct MDeformVert *dvert, const bool *vgroup_subset, int vgroup_tot)
Definition: deform.c:227
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
int * BKE_object_defgroup_flip_map(const struct Object *ob, int *flip_map_len, bool use_default)
void BKE_defvert_copy_index(struct MDeformVert *dvert_dst, int defgroup_dst, const struct MDeformVert *dvert_src, int defgroup_src)
int BKE_object_defgroup_name_index(const struct Object *ob, const char *name)
void BKE_defvert_remap(struct MDeformVert *dvert, const int *map, int map_len)
Definition: deform.c:215
void BKE_defvert_copy_subset(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src, const bool *vgroup_subset, int vgroup_tot)
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
const struct ListBase * BKE_object_defgroup_list(const struct Object *ob)
void BKE_defvert_flip(struct MDeformVert *dvert, const int *flip_map, int flip_map_len)
Definition: deform.c:402
struct MDeformWeight * BKE_defvert_ensure_index(struct MDeformVert *dv, int defgroup)
Definition: deform.c:748
void BKE_defvert_sync_mapped(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src, const int *flip_map, int flip_map_len, bool use_ensure)
int BKE_object_defgroup_flip_index(const struct Object *ob, int index, bool use_default)
void BKE_object_defgroup_unique_name(struct bDeformGroup *dg, struct Object *ob)
Definition: deform.c:692
void BKE_defvert_remove_group(struct MDeformVert *dvert, struct MDeformWeight *dw)
Definition: deform.c:804
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
void BKE_defvert_mirror_subset(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src, const bool *vgroup_subset, int vgroup_tot, const int *flip_map, int flip_map_len)
void BKE_defvert_add_index_notest(struct MDeformVert *dv, int defgroup, float weight)
Definition: deform.c:779
struct bDeformGroup * BKE_object_defgroup_find_name(const struct Object *ob, const char *name)
int * BKE_object_defgroup_flip_map_single(const struct Object *ob, int *flip_map_len, bool use_default, int defgroup)
int BKE_object_defgroup_count(const struct Object *ob)
struct bDeformGroup * BKE_defgroup_duplicate(const struct bDeformGroup *ingroup)
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:58
struct BPoint * BKE_lattice_active_point_get(struct Lattice *lt)
Definition: lattice.c:597
int BKE_lattice_index_from_uvw(struct Lattice *lt, int u, int v, int w)
Definition: lattice.c:205
struct Mesh * BKE_mesh_from_object(struct Object *ob)
Definition: mesh.cc:1365
void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge)
struct Mesh * mesh_get_eval_deform(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)
General operations, lookup, etc. for blender objects.
struct Object * BKE_object_pose_armature_get(struct Object *ob)
Definition: object.cc:2511
bool BKE_object_is_in_wpaint_select_vert(const struct Object *ob)
bool BKE_object_is_in_editmode_vgroup(const struct Object *ob)
void BKE_object_free_derived_caches(struct Object *ob)
Definition: object.cc:1774
Functions for dealing with objects and deform verts, used by painting and tools.
struct MDeformVert * BKE_object_defgroup_data_create(struct ID *id)
bool BKE_object_defgroup_clear_all(struct Object *ob, bool use_selection)
bool BKE_object_defgroup_array_get(struct ID *id, struct MDeformVert **dvert_arr, int *dvert_tot)
void BKE_object_defgroup_remove(struct Object *ob, struct bDeformGroup *defgroup)
void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
void BKE_object_defgroup_remap_update_users(struct Object *ob, const int *map)
Definition: object_deform.c:52
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)
struct bDeformGroup * BKE_object_defgroup_add(struct Object *ob)
bool * BKE_object_defgroup_subset_from_select_type(struct Object *ob, enum eVGroupSelect subset_type, int *r_defgroup_tot, int *r_subset_count)
void BKE_object_defgroup_subset_to_index_array(const bool *defgroup_validmap, int defgroup_tot, int *r_defgroup_subset_map)
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_object_defgroup_remove_all(struct Object *ob)
bool BKE_object_defgroup_clear(struct Object *ob, struct bDeformGroup *dg, bool use_selection)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:22
A (mainly) macro array library.
#define BLI_array_append(arr, item)
Definition: BLI_array.h:98
#define BLI_array_reserve(arr, num)
Definition: BLI_array.h:71
#define BLI_array_declare(arr)
Definition: BLI_array.h:50
#define BLI_array_len(arr)
Definition: BLI_array.h:63
#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
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:60
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void void void void void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:466
void void BLI_listbase_sort(struct ListBase *listbase, int(*cmp)(const void *, const void *)) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
void void void bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL()
Definition: listbase.c:405
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_findstringindex(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
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)
MINLINE float max_ff(float a, float b)
MINLINE int signum_i(float a)
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition: math_geom.c:209
void closest_to_plane_normalized_v3(float r_close[3], const float plane[4], const float pt[3])
Definition: math_geom.c:408
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void swap_v2_v2(float a[2], float b[2])
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
size_t size_t char * BLI_sprintfN(const char *__restrict format,...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1
int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:719
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNUSED_FUNCTION(x)
#define SWAP(type, a, b)
#define UNUSED(x)
#define IN_RANGE_INCL(a, b, c)
#define LIKELY(x)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_SIZE(stack)
#define STACK_INIT(stack, stack_num)
#define TIP_(msgid)
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_COPY_ON_WRITE
Definition: DNA_ID.h:834
@ ID_RECALC_SELECT
Definition: DNA_ID.h:818
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:566
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition: DNA_ID.h:588
@ ID_ME
Definition: DNA_ID_enums.h:48
@ ID_LT
Definition: DNA_ID_enums.h:54
@ CD_MDEFORMVERT
#define LT_ACTBP_NONE
@ 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)
@ ME_HIDE
@ eModifierMode_Realtime
@ eModifierType_Mirror
@ OB_MODE_EDIT
@ OB_MODE_WEIGHT_PAINT
@ OB_MODE_POSE
Object is a sort of wrapper for general info.
@ OB_LATTICE
@ OB_MESH
@ OB_GPENCIL
#define MAX_VGROUP_NAME
#define OB_TYPE_SUPPORT_VGROUP(_type)
#define DG_LOCK_WEIGHT
#define WT_VGROUP_MASK_ALL
eVGroupSelect
@ WT_VGROUP_BONE_SELECT
@ WT_VGROUP_ALL
@ WT_VGROUP_ACTIVE
@ WT_VGROUP_BONE_DEFORM
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ RPT_ERROR_INVALID_CONTEXT
struct MDeformVert * ED_mesh_active_dvert_get_ob(struct Object *ob, int *r_index)
Definition: meshtools.cc:1459
#define WEIGHT_REPLACE
Definition: ED_mesh.h:449
struct BMVert * editbmesh_get_x_mirror_vert(struct Object *ob, struct BMEditMesh *em, struct BMVert *eve, const float co[3], int index, bool use_topology)
Definition: meshtools.cc:977
struct MDeformVert * ED_mesh_active_dvert_get_em(struct Object *ob, struct BMVert **r_eve)
Definition: meshtools.cc:1432
void paintvert_flush_flags(struct Object *ob)
Definition: editface.cc:412
void EDBM_select_flush(struct BMEditMesh *em)
struct BMVert * EDBM_verts_mirror_get(struct BMEditMesh *em, struct BMVert *v)
void EDBM_verts_mirror_cache_end(struct BMEditMesh *em)
void ED_mesh_report_mirror(struct wmOperator *op, int totmirr, int totfail)
Definition: mesh_data.cc:1401
#define WEIGHT_ADD
Definition: ED_mesh.h:450
struct MDeformVert * ED_mesh_active_dvert_get_only(struct Object *ob)
Definition: meshtools.cc:1472
#define WEIGHT_SUBTRACT
Definition: ED_mesh.h:451
int ED_mesh_mirror_get_vert(struct Object *ob, int index)
Definition: meshtools.cc:986
void EDBM_deselect_flush(struct BMEditMesh *em)
void EDBM_verts_mirror_cache_begin(struct BMEditMesh *em, int axis, bool use_self, bool use_select, bool respecthide, bool use_topology)
int mesh_get_x_mirror_vert(struct Object *ob, struct Mesh *me_eval, int index, bool use_topology)
Definition: meshtools.cc:916
struct Object * ED_object_context(const struct bContext *C)
Object ** ED_object_array_in_mode_or_selected(struct bContext *C, bool(*filter_fn)(const struct Object *ob, void *user_data), void *filter_user_data, uint *r_objects_len)
bool ED_operator_object_active_local_editable_ex(struct bContext *C, const Object *ob)
Definition: screen_ops.c:402
_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 i1
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
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
@ PROP_HIDDEN
Definition: RNA_types.h:216
#define C
Definition: RandGen.cpp:25
@ 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 ND_DATA
Definition: WM_types.h:456
#define ND_VERTEX_GROUP
Definition: WM_types.h:457
#define ND_SELECT
Definition: WM_types.h:455
#define NC_OBJECT
Definition: WM_types.h:329
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:541
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:14
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
Definition: bmesh_interp.c:839
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_VERTS_OF_MESH
@ BM_EDGES_OF_VERT
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:558
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:446
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:103
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
SIMD_FORCE_INLINE btScalar norm() const
Return the norm (length) of the vector.
Definition: btVector3.h:263
#define SELECT
Scene scene
const Depsgraph * depsgraph
void * user_data
static float verts[][3]
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
int count
#define GS(x)
Definition: iris.c:225
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
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
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
#define floorf(x)
Definition: metal/compat.h:224
#define fabsf(x)
Definition: metal/compat.h:219
static unsigned a[3]
Definition: RandGen.cpp:78
static double epsilon
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static int vertex_group_levels_exec(bContext *C, wmOperator *op)
void ED_vgroup_parray_remove_zero(MDeformVert **dvert_array, const int dvert_tot, const bool *vgroup_validmap, const int vgroup_tot, const float epsilon, const bool keep_single)
static bool vertex_group_poll_ex(bContext *C, Object *ob)
static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
static int vertex_group_assign_new_exec(bContext *C, wmOperator *op)
static void getVerticalAndHorizontalChange(const float norm[3], float d, const float coord[3], const float start[3], float distToStart, float *end, float(*changes)[2], float *dists, int index)
void OBJECT_OT_vertex_group_limit_total(wmOperatorType *ot)
static int set_active_group_exec(bContext *C, wmOperator *op)
void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot)
@ VGROUP_MASK_UNSELECTED
@ VGROUP_MASK_INVERT_UNSELECTED
@ VGROUP_MASK_SELECTED
@ VGROUP_MASK_ALL
static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op)
static int vertex_group_invert_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem vgroup_lock_actions[]
void OBJECT_OT_vertex_group_clean(wmOperatorType *ot)
static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
static int vertex_group_copy_exec(bContext *C, wmOperator *UNUSED(op))
void OBJECT_OT_vertex_group_assign_new(wmOperatorType *ot)
static bool vertex_group_vert_select_mesh_poll(bContext *C)
float ED_vgroup_vert_weight(Object *ob, bDeformGroup *dg, int vertnum)
void ED_vgroup_data_clamp_range(ID *id, const int total)
void OBJECT_OT_vertex_group_levels(wmOperatorType *ot)
static void vgroup_assign_verts(Object *ob, const float weight)
static const EnumPropertyItem vgroup_lock_mask[]
void OBJECT_OT_vertex_group_add(wmOperatorType *ot)
void OBJECT_OT_vertex_group_quantize(wmOperatorType *ot)
@ VGROUP_LOCK
@ VGROUP_TOGGLE
@ VGROUP_INVERT
@ VGROUP_UNLOCK
static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase)
void OBJECT_OT_vertex_group_select(wmOperatorType *ot)
void OBJECT_OT_vertex_weight_copy(wmOperatorType *ot)
static void vgroup_operator_subset_select_props(wmOperatorType *ot, bool use_active)
static void moveCloserToDistanceFromPlane(Depsgraph *depsgraph, Scene *UNUSED(scene), Object *ob, Mesh *me, int index, const float norm[3], const float coord[3], float d, float distToBe, float strength, float cp)
#define IS_BM_VERT_READ(v)
void OBJECT_OT_vertex_group_remove(wmOperatorType *ot)
static bool vertex_group_mesh_vert_poll(bContext *C)
void OBJECT_OT_vertex_group_move(wmOperatorType *ot)
static bool vertex_group_supported_poll_ex(bContext *C, const Object *ob)
static void dvert_mirror_op(MDeformVert *dvert, MDeformVert *dvert_mirr, const char sel, const char sel_mirr, const int *flip_map, const int flip_map_len, const bool mirror_weights, const bool flip_vgroups, const bool all_vgroups, const int act_vgroup)
static void vgroup_fix(const bContext *C, Scene *UNUSED(scene), Object *ob, float distToBe, float strength, float cp)
static void vgroup_remove_weight(Object *ob, const int def_nr)
static Lattice * vgroup_edit_lattice(Object *ob)
static bool check_vertex_group_accessible(wmOperator *op, Object *ob, int def_nr)
static bool vertex_group_poll(bContext *C)
void ED_vgroup_mirror(Object *ob, const bool mirror_weights, const bool flip_vgroups, const bool all_vgroups, const bool use_topology, int *r_totmirr, int *r_totfail)
void OBJECT_OT_vertex_group_invert(wmOperatorType *ot)
void ED_vgroup_parray_mirror_sync(Object *ob, MDeformVert **dvert_array, const int dvert_tot, const bool *vgroup_validmap, const int vgroup_tot)
void OBJECT_OT_vertex_weight_paste(wmOperatorType *ot)
static int vgroup_limit_total_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int subset_count, const int max_weights)
#define VGROUP_MIRR_OP
void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot)
static int vertex_weight_set_active_exec(bContext *C, wmOperator *op)
void OBJECT_OT_vertex_group_lock(wmOperatorType *ot)
static bool vertex_group_mesh_poll_ex(bContext *C, Object *ob)
void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
static void getSingleCoordinate(MVert *points, int count, float coord[3])
static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum)
static void vgroup_lock_all(Object *ob, int action, int mask)
#define IS_ME_VERT_READ(v)
void ED_vgroup_parray_to_weight_array(const MDeformVert **dvert_array, const int dvert_tot, float *dvert_weights, const int def_nr)
static bool * vgroup_selected_get(Object *ob)
static bool UNUSED_FUNCTION() vertex_group_poll_edit(bContext *C)
void OBJECT_OT_vertex_group_sort(wmOperatorType *ot)
static int vertex_weight_delete_exec(bContext *C, wmOperator *op)
static int vertex_weight_copy_exec(bContext *C, wmOperator *UNUSED(op))
void OBJECT_OT_vertex_group_assign(wmOperatorType *ot)
static void ED_mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx)
static const EnumPropertyItem * rna_vertex_group_select_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free)
static int vertex_group_normalize_exec(bContext *C, wmOperator *UNUSED(op))
static void vgroup_clean_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int UNUSED(subset_count), const float epsilon, const bool keep_single)
void OBJECT_OT_vertex_group_copy(wmOperatorType *ot)
static int inv_cmp_mdef_vert_weights(const void *a1, const void *a2)
void OBJECT_OT_vertex_weight_set_active(wmOperatorType *ot)
static bool vertex_group_mesh_with_dvert_poll(bContext *C)
static int vertex_group_remove_exec(bContext *C, wmOperator *op)
static void ED_vgroup_nr_vert_add(Object *ob, const int def_nr, const int vertnum, const float weight, const int assignmode)
static int vertex_group_fix_exec(bContext *C, wmOperator *op)
static char * vertex_group_lock_description(struct bContext *UNUSED(C), struct wmOperatorType *UNUSED(op), struct PointerRNA *params)
static bool object_array_for_wpaint_filter(const Object *ob, void *user_data)
Definition: object_vgroup.c:75
#define IS_ME_VERT_WRITE(v)
static const EnumPropertyItem * rna_vertex_group_with_single_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free)
static void mesh_defvert_mirror_update_internal(Object *ob, MDeformVert *dvert_dst, MDeformVert *dvert_src, const int def_nr)
static int vertex_weight_normalize_active_vertex_exec(bContext *C, wmOperator *UNUSED(op))
void OBJECT_OT_vertex_group_copy_to_selected(wmOperatorType *ot)
static int vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
@ SORT_TYPE_NAME
@ SORT_TYPE_BONEHIERARCHY
static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
#define IS_BM_VERT_WRITE(v)
void OBJECT_OT_vertex_group_smooth(wmOperatorType *ot)
static char * vgroup_init_remap(Object *ob)
void OBJECT_OT_vertex_group_fix(wmOperatorType *ot)
static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr)
static bool vertex_group_vert_select_poll(bContext *C)
bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
static void vgroup_select_verts(Object *ob, int select)
bool ED_vgroup_parray_alloc(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, const bool use_vert_sel)
static void vgroup_quantize_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int UNUSED(subset_count), const int steps)
static int vertex_group_remove_from_exec(bContext *C, wmOperator *op)
static bool vertex_group_vert_select_unlocked_poll(bContext *C)
void ED_vgroup_vert_active_mirror(Object *ob, int def_nr)
static int vertex_group_add_exec(bContext *C, wmOperator *UNUSED(op))
bool ED_vgroup_sync_from_pose(Object *ob)
static const EnumPropertyItem WT_vertex_group_select_item[]
static void vgroup_delete_active(Object *ob)
static int vertex_group_limit_total_exec(bContext *C, wmOperator *op)
static bool vgroup_normalize_all(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int subset_count, const bool lock_active, ReportList *reports)
static int vertex_group_smooth_exec(bContext *C, wmOperator *op)
void ED_vgroup_parray_from_weight_array(MDeformVert **dvert_array, const int dvert_tot, const float *dvert_weights, const int def_nr, const bool remove_zero)
static int vertex_group_quantize_exec(bContext *C, wmOperator *op)
void OBJECT_OT_vertex_weight_normalize_active_vertex(wmOperatorType *ot)
static int vertex_group_sort_exec(bContext *C, wmOperator *op)
static Object ** object_array_for_wpaint(bContext *C, uint *r_objects_len)
Definition: object_vgroup.c:84
static bool vertex_group_supported_poll(bContext *C)
static int * getSurroundingVerts(Mesh *me, int vert, int *count)
static void ED_mesh_defvert_mirror_update_em(Object *ob, BMVert *eve, int def_nr, int vidx, const int cd_dvert_offset)
void ED_vgroup_select_by_name(Object *ob, const char *name)
static bool vertex_group_vert_poll_ex(bContext *C, const bool needs_select, const short ob_type_flag)
void OBJECT_OT_vertex_weight_delete(wmOperatorType *ot)
static int vgroup_move_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem * vgroup_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
static bool vertex_group_use_vert_sel(Object *ob)
Definition: object_vgroup.c:89
void OBJECT_OT_vertex_group_deselect(wmOperatorType *ot)
void OBJECT_OT_vertex_group_remove_from(wmOperatorType *ot)
#define WEIGHT_ACCUMULATE
static int vertex_group_lock_exec(bContext *C, wmOperator *op)
static int vertex_weight_paste_exec(bContext *C, wmOperator *op)
static void vgroup_levels_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int UNUSED(subset_count), const float offset, const float gain)
static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type)
void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot)
static bool vgroup_normalize_active_vertex(Object *ob, eVGroupSelect subset_type)
static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
static int vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(op))
void ED_vgroup_parray_mirror_assign(Object *ob, MDeformVert **dvert_array, const int dvert_tot)
static int vertex_group_mirror_exec(bContext *C, wmOperator *op)
static void vgroup_invert_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int UNUSED(subset_count), const bool auto_assign, const bool auto_remove)
static void vgroup_duplicate(Object *ob)
void OBJECT_OT_vertex_group_normalize(wmOperatorType *ot)
void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode)
static int vertex_group_clean_exec(bContext *C, wmOperator *op)
const EnumPropertyItem * ED_object_vgroup_selection_itemf_helper(const bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *prop, bool *r_free, const uint selection_mask)
static bool vgroup_normalize(Object *ob)
static void vgroup_smooth_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int subset_count, const float fac, const int repeat, const float fac_expand)
return ret
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
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
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3836
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
void RNA_def_property_enum_default(PropertyRNA *prop, int value)
Definition: rna_define.c:2106
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
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3597
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
Definition: rna_define.c:3830
void RNA_enum_items_add_value(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item, int value)
Definition: rna_define.c:4472
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
static const int steps
Definition: sky_nishita.cpp:19
struct BMesh * bm
Definition: BKE_editmesh.h:40
float co[3]
Definition: bmesh_class.h:87
int totvert
Definition: bmesh_class.h:297
CustomData vdata
Definition: bmesh_class.h:337
uint8_t f1
char name[64]
ListBase childbase
struct Bone * prev
struct Lattice * latt
const char * identifier
Definition: RNA_types.h:461
const char * name
Definition: RNA_types.h:465
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
struct MDeformVert * dvert
struct EditLatt * editlatt
struct BPoint * def
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
struct MDeformWeight * dw
unsigned int def_nr
unsigned int v
float co[3]
struct MEdge * medge
struct BMEditMesh * edit_mesh
char symmetry
struct MVert * mvert
struct MDeformVert * dvert
int totedge
char editflag
int totvert
struct MLoop * mloop
int totpoly
struct MPoly * mpoly
struct ModifierData * next
ListBase modifiers
void * data
ListBase bonebase
struct bDeformGroup * next
ListBase layers
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
const char * idname
Definition: WM_types.h:890
char *(* get_description)(struct bContext *C, struct wmOperatorType *, struct PointerRNA *)
Definition: WM_types.h:966
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
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
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
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))