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) ? <->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 = <->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 = <->def[i1];
2528 bp_mirr = <->def[i2];
2529
2530 sel = bp->f1 & SELECT;
2531 sel_mirr = bp_mirr->f1 & SELECT;
2532
2533 if (sel || sel_mirr) {
2534 dvert = <->dvert[i1];
2535 dvert_mirr = <->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(<->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