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