Blender V4.3
object_vgroup.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cmath>
10#include <cstddef>
11#include <cstring>
12
13#include "MEM_guardedalloc.h"
14
15#include "DNA_curve_types.h"
17#include "DNA_lattice_types.h"
18#include "DNA_mesh_types.h"
19#include "DNA_meshdata_types.h"
20#include "DNA_modifier_types.h"
21#include "DNA_object_types.h"
22#include "DNA_scene_types.h"
23
24#include "BLI_array.hh"
25#include "BLI_bitmap.h"
26#include "BLI_blenlib.h"
27#include "BLI_listbase.h"
28#include "BLI_utildefines.h"
30#include "BLI_vector.hh"
31
32#include "BKE_attribute.hh"
33#include "BKE_context.hh"
34#include "BKE_customdata.hh"
35#include "BKE_deform.hh"
36#include "BKE_editmesh.hh"
38#include "BKE_lattice.hh"
39#include "BKE_mesh.hh"
40#include "BKE_mesh_mapping.hh"
41#include "BKE_modifier.hh"
42#include "BKE_object.hh"
43#include "BKE_object_deform.h"
44#include "BKE_report.hh"
45
46#include "DEG_depsgraph.hh"
48
49#include "BLT_translation.hh"
50
51#include "DNA_armature_types.h"
52#include "RNA_access.hh"
53#include "RNA_define.hh"
54#include "RNA_enum_types.hh"
55
56#include "WM_api.hh"
57#include "WM_types.hh"
58
59#include "ED_grease_pencil.hh"
60#include "ED_mesh.hh"
61#include "ED_object.hh"
62#include "ED_object_vgroup.hh"
63#include "ED_screen.hh"
64
65#include "UI_resources.hh"
66
67#include "object_intern.hh"
68
69namespace blender::ed::object {
70
71static bool vertex_group_supported_poll_ex(bContext *C, const Object *ob);
72
73/* -------------------------------------------------------------------- */
77static bool object_array_for_wpaint_filter(const Object *ob, void *user_data)
78{
79 bContext *C = static_cast<bContext *>(user_data);
81 return true;
82 }
83 return false;
84}
85
90
92{
93 if (ob->mode == OB_MODE_EDIT) {
94 return true;
95 }
96 if ((ob->type == OB_MESH) &&
98 {
99 return true;
100 }
101 return false;
102}
103
105{
106 Lattice *lt = static_cast<Lattice *>(ob->data);
107 BLI_assert(ob->type == OB_LATTICE);
108 return (lt->editlatt) ? lt->editlatt->latt : lt;
109}
110
113/* -------------------------------------------------------------------- */
118{
120 if (armobj && (armobj->mode & OB_MODE_POSE)) {
121 bArmature *arm = static_cast<bArmature *>(armobj->data);
122 if (arm->act_bone) {
123 int def_num = BKE_object_defgroup_name_index(ob, arm->act_bone->name);
124 if (def_num != -1) {
126 return true;
127 }
128 }
129 }
130 return false;
131}
132
133void vgroup_data_clamp_range(ID *id, const int total)
134{
135 MDeformVert **dvert_arr;
136 int dvert_tot;
137
138 if (vgroup_parray_alloc(id, &dvert_arr, &dvert_tot, false)) {
139 for (int i = 0; i < dvert_tot; i++) {
140 MDeformVert *dv = dvert_arr[i];
141 for (int j = 0; j < dv->totweight; j++) {
142 if (dv->dw[j].def_nr >= total) {
143 BKE_defvert_remove_group(dv, &dv->dw[j]);
144 j--;
145 }
146 }
147 }
148 }
149}
150
151bool vgroup_parray_alloc(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, const bool use_vert_sel)
152{
153 *dvert_tot = 0;
154 *dvert_arr = nullptr;
155
156 if (id) {
157 switch (GS(id->name)) {
158 case ID_ME: {
159 Mesh *mesh = (Mesh *)id;
160
161 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
162 BMesh *bm = em->bm;
163 const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
164 BMIter iter;
165 BMVert *eve;
166 int i;
167
168 if (cd_dvert_offset == -1) {
169 return false;
170 }
171
172 i = em->bm->totvert;
173
174 *dvert_arr = static_cast<MDeformVert **>(MEM_mallocN(sizeof(void *) * i, __func__));
175 *dvert_tot = i;
176
177 i = 0;
178 if (use_vert_sel) {
179 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
180 (*dvert_arr)[i] = BM_elem_flag_test(eve, BM_ELEM_SELECT) ?
181 static_cast<MDeformVert *>(
182 BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)) :
183 nullptr;
184 i++;
185 }
186 }
187 else {
188 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
189 (*dvert_arr)[i] = static_cast<MDeformVert *>(
190 BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
191 i++;
192 }
193 }
194
195 return true;
196 }
197 if (!mesh->deform_verts().is_empty()) {
198 MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write();
199
200 *dvert_tot = mesh->verts_num;
201 *dvert_arr = static_cast<MDeformVert **>(
202 MEM_mallocN(sizeof(void *) * mesh->verts_num, __func__));
203
204 if (use_vert_sel) {
205 const bke::AttributeAccessor attributes = mesh->attributes();
206 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
207 ".select_vert", bke::AttrDomain::Point, false);
208
209 for (int i = 0; i < mesh->verts_num; i++) {
210 (*dvert_arr)[i] = select_vert[i] ? &dverts[i] : nullptr;
211 }
212 }
213 else {
214 for (int i = 0; i < mesh->verts_num; i++) {
215 (*dvert_arr)[i] = &dverts[i];
216 }
217 }
218
219 return true;
220 }
221 return false;
222 }
223 case ID_LT: {
224 Lattice *lt = (Lattice *)id;
225 lt = (lt->editlatt) ? lt->editlatt->latt : lt;
226
227 if (lt->dvert) {
228 BPoint *def = lt->def;
229 *dvert_tot = lt->pntsu * lt->pntsv * lt->pntsw;
230 *dvert_arr = static_cast<MDeformVert **>(
231 MEM_mallocN(sizeof(void *) * (*dvert_tot), __func__));
232
233 if (use_vert_sel) {
234 for (int i = 0; i < *dvert_tot; i++) {
235 (*dvert_arr)[i] = (def->f1 & SELECT) ? &lt->dvert[i] : nullptr;
236 }
237 }
238 else {
239 for (int i = 0; i < *dvert_tot; i++) {
240 (*dvert_arr)[i] = lt->dvert + i;
241 }
242 }
243
244 return true;
245 }
246 return false;
247 }
248
249 default:
250 break;
251 }
252 }
253
254 return false;
255}
256
258 MDeformVert **dvert_array,
259 const int dvert_tot,
260 const bool *vgroup_validmap,
261 const int vgroup_tot)
262{
264 MDeformVert **dvert_array_all = nullptr;
265 int dvert_tot_all;
266
267 /* get an array of all verts, not only selected */
268 if (vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array_all, &dvert_tot_all, false) ==
269 false)
270 {
271 BLI_assert(0);
272 return;
273 }
274 if (em) {
276 }
277
278 int flip_map_len;
279 const int *flip_map = BKE_object_defgroup_flip_map(ob, true, &flip_map_len);
280
281 for (int i_src = 0; i_src < dvert_tot; i_src++) {
282 if (dvert_array[i_src] != nullptr) {
283 /* its selected, check if its mirror exists */
284 int i_dst = ED_mesh_mirror_get_vert(ob, i_src);
285 if (i_dst != -1 && dvert_array_all[i_dst] != nullptr) {
286 /* we found a match! */
287 const MDeformVert *dv_src = dvert_array[i_src];
288 MDeformVert *dv_dst = dvert_array_all[i_dst];
289
291 dv_dst, dv_src, vgroup_validmap, vgroup_tot, flip_map, flip_map_len);
292
293 dvert_array[i_dst] = dvert_array_all[i_dst];
294 }
295 }
296 }
297
298 MEM_freeN((void *)flip_map);
299 MEM_freeN(dvert_array_all);
300}
301
302void vgroup_parray_mirror_assign(Object *ob, MDeformVert **dvert_array, const int dvert_tot)
303{
305 MDeformVert **dvert_array_all = nullptr;
306 int dvert_tot_all;
307
308 /* get an array of all verts, not only selected */
309 if (vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array_all, &dvert_tot_all, false) ==
310 false)
311 {
312 BLI_assert(0);
313 return;
314 }
315 BLI_assert(dvert_tot == dvert_tot_all);
316 if (em) {
318 }
319
320 for (int i = 0; i < dvert_tot; i++) {
321 if (dvert_array[i] == nullptr) {
322 /* its unselected, check if its mirror is */
323 int i_sel = ED_mesh_mirror_get_vert(ob, i);
324 if ((i_sel != -1) && (i_sel != i) && (dvert_array[i_sel])) {
325 /* we found a match! */
326 dvert_array[i] = dvert_array_all[i];
327 }
328 }
329 }
330
331 MEM_freeN(dvert_array_all);
332}
333
335 const int dvert_tot,
336 const bool *vgroup_validmap,
337 const int vgroup_tot,
338 const float epsilon,
339 const bool keep_single)
340{
341 MDeformVert *dv;
342
343 for (int i = 0; i < dvert_tot; i++) {
344 /* in case its not selected */
345 if (!(dv = dvert_array[i])) {
346 continue;
347 }
348
349 int j = dv->totweight;
350
351 while (j--) {
352 MDeformWeight *dw;
353
354 if (keep_single && dv->totweight == 1) {
355 break;
356 }
357
358 dw = dv->dw + j;
359 if ((dw->def_nr < vgroup_tot) && vgroup_validmap[dw->def_nr]) {
360 if (dw->weight <= epsilon) {
362 }
363 }
364 }
365 }
366}
367
368bool vgroup_array_copy(Object *ob, Object *ob_from)
369{
370 MDeformVert **dvert_array_from = nullptr, **dvf;
371 MDeformVert **dvert_array = nullptr, **dv;
372 int dvert_tot_from;
373 int dvert_tot;
374 int i;
376 const ListBase *defbase_src = BKE_object_defgroup_list(ob_from);
377
378 int defbase_tot_from = BLI_listbase_count(defbase_src);
379 int defbase_tot = BLI_listbase_count(defbase_dst);
380 bool new_vgroup = false;
381
382 BLI_assert(ob != ob_from);
383
384 if (ob->data == ob_from->data) {
385 return true;
386 }
387
388 /* In case we copy vgroup between two objects using same data,
389 * we only have to care about object side of things. */
390 if (ob->data != ob_from->data) {
392 static_cast<ID *>(ob_from->data), &dvert_array_from, &dvert_tot_from, false);
393 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, false);
394
395 if ((dvert_array == nullptr) && (dvert_array_from != nullptr) &&
396 BKE_object_defgroup_data_create(static_cast<ID *>(ob->data)))
397 {
398 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, false);
399 new_vgroup = true;
400 }
401
402 if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == nullptr ||
403 dvert_array == nullptr)
404 {
405 if (dvert_array) {
406 MEM_freeN(dvert_array);
407 }
408 if (dvert_array_from) {
409 MEM_freeN(dvert_array_from);
410 }
411
412 if (new_vgroup == true) {
413 /* free the newly added vgroup since it wasn't compatible */
415 }
416
417 /* if true: both are 0 and nothing needs changing, consider this a success */
418 return (dvert_tot == dvert_tot_from);
419 }
420 }
421
422 /* do the copy */
423 BLI_freelistN(defbase_dst);
424 BLI_duplicatelist(defbase_dst, defbase_src);
426
427 if (defbase_tot_from < defbase_tot) {
428 /* correct vgroup indices because the number of vgroups is being reduced. */
429 Array<int> remap(defbase_tot + 1);
430 for (i = 0; i <= defbase_tot_from; i++) {
431 remap[i] = i;
432 }
433 for (; i <= defbase_tot; i++) {
434 remap[i] = 0; /* can't use these, so disable */
435 }
436
438 }
439
440 if (dvert_array_from != nullptr && dvert_array != nullptr) {
441 dvf = dvert_array_from;
442 dv = dvert_array;
443
444 for (i = 0; i < dvert_tot; i++, dvf++, dv++) {
445 MEM_SAFE_FREE((*dv)->dw);
446 *(*dv) = *(*dvf);
447
448 if ((*dv)->dw) {
449 (*dv)->dw = static_cast<MDeformWeight *>(MEM_dupallocN((*dv)->dw));
450 }
451 }
452
453 MEM_freeN(dvert_array);
454 MEM_freeN(dvert_array_from);
455 }
456
457 return true;
458}
459
461 const int dvert_tot,
462 float *dvert_weights,
463 const int def_nr)
464{
465 for (int i = 0; i < dvert_tot; i++) {
466 const MDeformVert *dv = dvert_array[i];
467 dvert_weights[i] = dv ? BKE_defvert_find_weight(dv, def_nr) : 0.0f;
468 }
469}
470
472 const int dvert_tot,
473 const float *dvert_weights,
474 const int def_nr,
475 const bool remove_zero)
476{
477 int i;
478
479 for (i = 0; i < dvert_tot; i++) {
480 MDeformVert *dv = dvert_array[i];
481 if (dv) {
482 if (dvert_weights[i] > 0.0f) {
483 MDeformWeight *dw = BKE_defvert_ensure_index(dv, def_nr);
484 BLI_assert(IN_RANGE_INCL(dvert_weights[i], 0.0f, 1.0f));
485 dw->weight = dvert_weights[i];
486 }
487 else {
488 MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
489 if (dw) {
490 if (remove_zero) {
492 }
493 else {
494 dw->weight = 0.0f;
495 }
496 }
497 }
498 }
499 }
500}
501
502/* TODO: cache flip data to speedup calls within a loop. */
504 MDeformVert *dvert_dst,
505 MDeformVert *dvert_src,
506 const int def_nr)
507{
508 if (def_nr == -1) {
509 /* All vgroups, add groups where needed. */
510 int flip_map_len;
511 int *flip_map = BKE_object_defgroup_flip_map_unlocked(ob, true, &flip_map_len);
512 BKE_defvert_sync_mapped(dvert_dst, dvert_src, flip_map, flip_map_len, true);
513 MEM_freeN(flip_map);
514 }
515 else {
516 /* Single vgroup. */
518 BKE_object_defgroup_flip_index(ob, def_nr, true));
519 if (dw) {
520 dw->weight = BKE_defvert_find_weight(dvert_src, def_nr);
521 }
522 }
523}
524
526 Object *ob, BMVert *eve, int def_nr, int vidx, const int cd_dvert_offset)
527{
528 Mesh *mesh = static_cast<Mesh *>(ob->data);
529 BMEditMesh *em = mesh->runtime->edit_mesh.get();
530 BMVert *eve_mirr;
531 bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
532
533 eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, vidx, use_topology);
534
535 if (eve_mirr && eve_mirr != eve) {
536 MDeformVert *dvert_src = static_cast<MDeformVert *>(
537 BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
538 MDeformVert *dvert_dst = static_cast<MDeformVert *>(
539 BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset));
540 mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr);
541 }
542}
543
544static void ED_mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx)
545{
546 int vidx_mirr;
547 Mesh *mesh = static_cast<Mesh *>(ob->data);
548 bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
549
550 if (vidx == -1) {
551 return;
552 }
553
554 vidx_mirr = mesh_get_x_mirror_vert(ob, nullptr, vidx, use_topology);
555
556 MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write();
557 if ((vidx_mirr) >= 0 && (vidx_mirr != vidx)) {
558 MDeformVert *dvert_src = &dverts[vidx];
559 MDeformVert *dvert_dst = &dverts[vidx_mirr];
560 mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr);
561 }
562}
563
565{
566 Mesh *mesh = static_cast<Mesh *>(ob->data);
567 BMEditMesh *em = mesh->runtime->edit_mesh.get();
568 MDeformVert *dvert_act;
569
570 if (mesh->symmetry & ME_SYMMETRY_X) {
571 if (em) {
572 BMVert *eve_act;
573 dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
574 if (dvert_act) {
575 const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
576 ED_mesh_defvert_mirror_update_em(ob, eve_act, def_nr, -1, cd_dvert_offset);
577 }
578 }
579 else {
580 int v_act;
581 dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
582 if (dvert_act) {
583 ED_mesh_defvert_mirror_update_ob(ob, def_nr, v_act);
584 }
585 }
586 }
587}
588
589static void vgroup_remove_weight(Object *ob, const int def_nr)
590{
591 MDeformVert *dvert_act;
592 MDeformWeight *dw;
593
594 dvert_act = ED_mesh_active_dvert_get_only(ob);
595
596 dw = BKE_defvert_find_index(dvert_act, def_nr);
597 BKE_defvert_remove_group(dvert_act, dw);
598}
599
601{
602 Mesh *mesh = static_cast<Mesh *>(ob->data);
603 BMEditMesh *em = mesh->runtime->edit_mesh.get();
604 BMVert *eve_act;
605 int v_act;
606 MDeformVert *dvert_act;
607 int subset_count, vgroup_tot;
608 const bool *vgroup_validmap;
609
610 if (em) {
611 dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
612 }
613 else {
614 dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
615 }
616
617 if (dvert_act == nullptr) {
618 return false;
619 }
620
622 ob, subset_type, &vgroup_tot, &subset_count);
623 BKE_defvert_normalize_subset(dvert_act, vgroup_validmap, vgroup_tot);
624 MEM_freeN((void *)vgroup_validmap);
625
626 if (mesh->symmetry & ME_SYMMETRY_X) {
627 if (em) {
628 const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
629 ED_mesh_defvert_mirror_update_em(ob, eve_act, -1, -1, cd_dvert_offset);
630 }
631 else {
633 }
634 }
635
636 return true;
637}
638
639static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type)
640{
641 Mesh *mesh = static_cast<Mesh *>(ob->data);
642 MDeformVert *dvert_act;
643 int i, vgroup_tot, subset_count;
644 const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
645 ob, subset_type, &vgroup_tot, &subset_count);
646
647 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
648 BMIter iter;
649 BMVert *eve, *eve_act;
650 const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
651
652 dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
653 if (dvert_act) {
654 BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
655 if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve != eve_act) {
656 MDeformVert *dv = static_cast<MDeformVert *>(
657 BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
658 BKE_defvert_copy_subset(dv, dvert_act, vgroup_validmap, vgroup_tot);
659 if (mesh->symmetry & ME_SYMMETRY_X) {
660 ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
661 }
662 }
663 }
664 }
665 }
666 else {
667 const bke::AttributeAccessor attributes = mesh->attributes();
668 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
669 ".select_vert", bke::AttrDomain::Point, false);
670
671 int v_act;
672
673 dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
674 if (dvert_act) {
675 MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write();
676 for (i = 0; i < mesh->verts_num; i++) {
677 if (select_vert[i] && &dverts[i] != dvert_act) {
678 BKE_defvert_copy_subset(&dverts[i], dvert_act, vgroup_validmap, vgroup_tot);
679 if (mesh->symmetry & ME_SYMMETRY_X) {
681 }
682 }
683 }
684 }
685 }
686
687 MEM_freeN((void *)vgroup_validmap);
688}
689
692/* -------------------------------------------------------------------- */
697 {WT_VGROUP_ACTIVE, "ACTIVE", 0, "Active Group", "The active Vertex Group"},
699 "BONE_SELECT",
700 0,
701 "Selected Pose Bones",
702 "All Vertex Groups assigned to Selection"},
704 "BONE_DEFORM",
705 0,
706 "Deform Pose Bones",
707 "All Vertex Groups assigned to Deform Bones"},
708 {WT_VGROUP_ALL, "ALL", 0, "All Groups", "All Vertex Groups"},
709 {0, nullptr, 0, nullptr, nullptr},
710};
711
713 PointerRNA * /*ptr*/,
714 PropertyRNA * /*prop*/,
715 bool *r_free,
716 const uint selection_mask)
717{
718 Object *ob;
719 EnumPropertyItem *item = nullptr;
720 int totitem = 0;
721
722 if (C == nullptr) {
723 /* needed for docs and i18n tools */
725 }
726
728 if (selection_mask & (1 << WT_VGROUP_ACTIVE)) {
730 }
731
732 if (ob) {
734 if (selection_mask & (1 << WT_VGROUP_BONE_SELECT)) {
737 }
738 }
739
741 if (selection_mask & (1 << WT_VGROUP_BONE_DEFORM)) {
744 }
745 }
746 }
747
748 if (selection_mask & (1 << WT_VGROUP_ALL)) {
750 }
751
752 RNA_enum_item_end(&item, &totitem);
753 *r_free = true;
754
755 return item;
756}
757
760 PropertyRNA *prop,
761 bool *r_free)
762{
763 return vgroup_selection_itemf_helper(C, ptr, prop, r_free, WT_VGROUP_MASK_ALL);
764}
765
768 PropertyRNA *prop,
769 bool *r_free)
770{
772 C, ptr, prop, r_free, WT_VGROUP_MASK_ALL & ~(1 << WT_VGROUP_ACTIVE));
773}
774
776{
777 PropertyRNA *prop;
778
779 prop = RNA_def_enum(ot->srna,
780 "group_select_mode",
782 use_active ? WT_VGROUP_ACTIVE : WT_VGROUP_ALL,
783 "Subset",
784 "Define which subset of groups shall be used");
785
786 if (use_active) {
788 }
789 else {
791 }
793 ot->prop = prop;
794}
795
798/* -------------------------------------------------------------------- */
806/* for Mesh in Object mode */
807/* allows editmode for Lattice */
809 Object *ob, const int def_nr, const int vertnum, const float weight, const int assignmode)
810{
811 /* Add the vert to the deform group with the specified number. */
812 MDeformVert *dvert = nullptr;
813 int tot;
814
815 /* Get the vert. */
816 BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dvert, &tot);
817
818 if (dvert == nullptr) {
819 return;
820 }
821
822 /* Check that vertnum is valid before trying to get the relevant dvert. */
823 if ((vertnum < 0) || (vertnum >= tot)) {
824 return;
825 }
826
827 MDeformVert *dv = &dvert[vertnum];
828 MDeformWeight *dw;
829
830 /* Lets first check to see if this vert is already in the weight group - if so lets update it. */
831 dw = BKE_defvert_find_index(dv, def_nr);
832
833 if (dw) {
834 switch (assignmode) {
835 case WEIGHT_REPLACE:
836 dw->weight = weight;
837 break;
838 case WEIGHT_ADD:
839 dw->weight += weight;
840 if (dw->weight >= 1.0f) {
841 dw->weight = 1.0f;
842 }
843 break;
844 case WEIGHT_SUBTRACT:
845 dw->weight -= weight;
846 /* If the weight is zero or less than remove the vert from the deform group. */
847 if (dw->weight <= 0.0f) {
849 }
850 break;
851 }
852 }
853 else {
854 /* If the vert wasn't in the deform group then we must take a different form of action. */
855
856 switch (assignmode) {
857 case WEIGHT_SUBTRACT:
858 /* If we are subtracting then we don't need to do anything. */
859 return;
860
861 case WEIGHT_REPLACE:
862 case WEIGHT_ADD:
863 /* If we are doing an additive assignment, then we need to create the deform weight. */
864
865 /* We checked if the vertex was added before so no need to test again, simply add. */
866 BKE_defvert_add_index_notest(dv, def_nr, weight);
867 break;
868 }
869 }
870}
871
872void vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode)
873{
874 /* add the vert to the deform group with the
875 * specified assign mode
876 */
877 const ListBase *defbase = BKE_object_defgroup_list(ob);
878 const int def_nr = BLI_findindex(defbase, dg);
879
880 MDeformVert *dv = nullptr;
881 int tot;
882
883 /* get the deform group number, exit if
884 * it can't be found
885 */
886 if (def_nr != -1) {
887
888 /* if there's no deform verts then create some,
889 */
890 if (BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dv, &tot) && dv == nullptr) {
891 BKE_object_defgroup_data_create(static_cast<ID *>(ob->data));
892 }
893
894 /* call another function to do the work
895 */
896 vgroup_nr_vert_add(ob, def_nr, vertnum, weight, assignmode);
897 }
898}
899
900void vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
901{
902 /* This routine removes the vertex from the specified
903 * deform group.
904 */
905
906 /* TODO(@ideasman42): This is slow in a loop, better pass def_nr directly,
907 * but leave for later. */
908 const ListBase *defbase = BKE_object_defgroup_list(ob);
909 const int def_nr = BLI_findindex(defbase, dg);
910
911 if (def_nr != -1) {
912 MDeformVert *dvert = nullptr;
913 int tot;
914
915 /* get the deform vertices corresponding to the
916 * vertnum
917 */
918 BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dvert, &tot);
919
920 if (dvert) {
921 MDeformVert *dv = &dvert[vertnum];
922 MDeformWeight *dw;
923
924 dw = BKE_defvert_find_index(dv, def_nr);
925 BKE_defvert_remove_group(dv, dw); /* dw can be nullptr */
926 }
927 }
928}
929
930static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum)
931{
932 const MDeformVert *dv = nullptr;
933
934 /* get the deform vertices corresponding to the vertnum */
935 if (ob->type == OB_MESH) {
936 Mesh *mesh = static_cast<Mesh *>(ob->data);
937
938 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
939 const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
940 /* warning, this lookup is _not_ fast */
941
942 if (cd_dvert_offset != -1 && vertnum < em->bm->totvert) {
943 BMVert *eve;
945 eve = BM_vert_at_index(em->bm, vertnum);
946 dv = static_cast<const MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
947 }
948 else {
949 return 0.0f;
950 }
951 }
952 else {
953 const Span<MDeformVert> dverts = mesh->deform_verts();
954 if (!dverts.is_empty()) {
955 if (vertnum >= mesh->verts_num) {
956 return 0.0f;
957 }
958 dv = &dverts[vertnum];
959 }
960 }
961 }
962 else if (ob->type == OB_LATTICE) {
964
965 if (lt->dvert) {
966 if (vertnum >= lt->pntsu * lt->pntsv * lt->pntsw) {
967 return 0.0f;
968 }
969 dv = &lt->dvert[vertnum];
970 }
971 }
972
973 if (dv) {
974 MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
975 if (dw) {
976 return dw->weight;
977 }
978 }
979
980 return -1;
981}
982
983float vgroup_vert_weight(Object *ob, bDeformGroup *dg, int vertnum)
984{
985 const ListBase *defbase = BKE_object_defgroup_list(ob);
986 const int def_nr = BLI_findindex(defbase, dg);
987
988 if (def_nr == -1) {
989 return -1;
990 }
991
992 return get_vert_def_nr(ob, def_nr, vertnum);
993}
994
995void vgroup_select_by_name(Object *ob, const char *name)
996{
997 /* NOTE: `actdef == 0` signals on painting to create a new one,
998 * if a bone in pose-mode is selected. */
1000}
1001
1004/* -------------------------------------------------------------------- */
1008/* only in editmode */
1009static void vgroup_select_verts(const ToolSettings &tool_settings,
1010 Object *ob,
1011 Scene &scene,
1012 int select)
1013{
1014 const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
1015
1016 const ListBase *defbase = BKE_object_defgroup_list(ob);
1017 const bDeformGroup *def_group = static_cast<bDeformGroup *>(BLI_findlink(defbase, def_nr));
1018 if (!def_group) {
1019 return;
1020 }
1021
1022 if (ob->type == OB_MESH) {
1023 Mesh *mesh = static_cast<Mesh *>(ob->data);
1024
1025 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
1026 const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
1027
1028 if (cd_dvert_offset != -1) {
1029 BMIter iter;
1030 BMVert *eve;
1031
1032 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
1033 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
1034 MDeformVert *dv = static_cast<MDeformVert *>(
1035 BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
1036 if (BKE_defvert_find_index(dv, def_nr)) {
1037 BM_vert_select_set(em->bm, eve, select);
1038 }
1039 }
1040 }
1041
1042 /* this has to be called, because this function operates on vertices only */
1043 if (select) {
1044 EDBM_select_flush(em); /* vertices to edges/faces */
1045 }
1046 else {
1048 }
1049 }
1050 }
1051 else {
1052 const Span<MDeformVert> dverts = mesh->deform_verts();
1053 if (!dverts.is_empty()) {
1054 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
1055 const VArray<bool> hide_vert = *attributes.lookup_or_default<bool>(
1056 ".hide_vert", bke::AttrDomain::Point, false);
1057 bke::SpanAttributeWriter<bool> select_vert =
1058 attributes.lookup_or_add_for_write_only_span<bool>(".select_vert",
1060
1061 for (const int i : select_vert.span.index_range()) {
1062 if (!hide_vert[i]) {
1063 if (BKE_defvert_find_index(&dverts[i], def_nr)) {
1064 select_vert.span[i] = select;
1065 }
1066 }
1067 }
1068
1069 select_vert.finish();
1071 }
1072 }
1073 }
1074 else if (ob->type == OB_LATTICE) {
1075 Lattice *lt = vgroup_edit_lattice(ob);
1076
1077 if (lt->dvert) {
1078 MDeformVert *dv;
1079 BPoint *bp, *actbp = BKE_lattice_active_point_get(lt);
1080 int a, tot;
1081
1082 dv = lt->dvert;
1083
1084 tot = lt->pntsu * lt->pntsv * lt->pntsw;
1085 for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) {
1086 if (BKE_defvert_find_index(dv, def_nr)) {
1087 if (select) {
1088 bp->f1 |= SELECT;
1089 }
1090 else {
1091 bp->f1 &= ~SELECT;
1092 if (actbp && bp == actbp) {
1093 lt->actbp = LT_ACTBP_NONE;
1094 }
1095 }
1096 }
1097 }
1098 }
1099 }
1100 else if (ob->type == OB_GREASE_PENCIL) {
1102 &tool_settings);
1103 GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob->data);
1104 {
1105 using namespace ed::greasepencil;
1106 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, *grease_pencil);
1107 for (MutableDrawingInfo info : drawings) {
1109 info.drawing, selection_domain, def_group->name, bool(select));
1110 }
1111 }
1112 DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY);
1113 }
1114}
1115
1116static void vgroup_duplicate(Object *ob)
1117{
1118 bDeformGroup *dg, *cdg;
1119 char name[sizeof(dg->name)];
1120 MDeformWeight *dw_org, *dw_cpy;
1121 MDeformVert **dvert_array = nullptr;
1122 int i, idg, icdg, dvert_tot = 0;
1123
1125
1126 dg = static_cast<bDeformGroup *>(
1128 if (!dg) {
1129 return;
1130 }
1131
1132 if (!strstr(dg->name, "_copy")) {
1133 SNPRINTF(name, "%s_copy", dg->name);
1134 }
1135 else {
1136 STRNCPY(name, dg->name);
1137 }
1138
1139 cdg = BKE_defgroup_duplicate(dg);
1140 STRNCPY(cdg->name, name);
1142
1143 BLI_addtail(defbase, cdg);
1144
1148
1149 /* TODO(@ideasman42): we might want to allow only copy selected verts here? */
1150 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, false);
1151
1152 if (dvert_array) {
1153 for (i = 0; i < dvert_tot; i++) {
1154 MDeformVert *dv = dvert_array[i];
1155 dw_org = BKE_defvert_find_index(dv, idg);
1156 if (dw_org) {
1157 /* #BKE_defvert_ensure_index re-allocates org so need to store the weight first. */
1158 const float weight = dw_org->weight;
1159 dw_cpy = BKE_defvert_ensure_index(dv, icdg);
1160 dw_cpy->weight = weight;
1161 }
1162 }
1163
1164 MEM_freeN(dvert_array);
1165 }
1166}
1167
1168static bool vgroup_normalize(Object *ob)
1169{
1170 MDeformWeight *dw;
1171 MDeformVert *dv, **dvert_array = nullptr;
1172 int dvert_tot = 0;
1173 const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
1174
1175 const bool use_vert_sel = vertex_group_use_vert_sel(ob);
1176
1177 const ListBase *defbase = BKE_object_defgroup_list(ob);
1178 if (!BLI_findlink(defbase, def_nr)) {
1179 return false;
1180 }
1181
1182 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
1183
1184 if (dvert_array) {
1185 float weight_max = 0.0f;
1186
1187 for (int i = 0; i < dvert_tot; i++) {
1188
1189 /* in case its not selected */
1190 if (!(dv = dvert_array[i])) {
1191 continue;
1192 }
1193
1194 dw = BKE_defvert_find_index(dv, def_nr);
1195 if (dw) {
1196 weight_max = max_ff(dw->weight, weight_max);
1197 }
1198 }
1199
1200 if (weight_max > 0.0f) {
1201 for (int i = 0; i < dvert_tot; i++) {
1202
1203 /* in case its not selected */
1204 if (!(dv = dvert_array[i])) {
1205 continue;
1206 }
1207
1208 dw = BKE_defvert_find_index(dv, def_nr);
1209 if (dw) {
1210 dw->weight /= weight_max;
1211
1212 /* in case of division errors with very low weights */
1213 CLAMP(dw->weight, 0.0f, 1.0f);
1214 }
1215 }
1216 }
1217
1218 MEM_freeN(dvert_array);
1219
1220 return true;
1221 }
1222
1223 return false;
1224}
1225
1227 const bool *vgroup_validmap,
1228 const int vgroup_tot,
1229 const int /*subset_count*/,
1230 const float offset,
1231 const float gain)
1232{
1233 MDeformWeight *dw;
1234 MDeformVert *dv, **dvert_array = nullptr;
1235 int dvert_tot = 0;
1236
1237 const bool use_vert_sel = vertex_group_use_vert_sel(ob);
1238 const bool use_mirror = (ob->type == OB_MESH) ?
1239 (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
1240 false;
1241
1242 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
1243
1244 if (dvert_array) {
1245
1246 for (int i = 0; i < dvert_tot; i++) {
1247 /* in case its not selected */
1248 if (!(dv = dvert_array[i])) {
1249 continue;
1250 }
1251
1252 int j = vgroup_tot;
1253 while (j--) {
1254 if (vgroup_validmap[j]) {
1255 dw = BKE_defvert_find_index(dv, j);
1256 if (dw) {
1257 dw->weight = gain * (dw->weight + offset);
1258
1259 CLAMP(dw->weight, 0.0f, 1.0f);
1260 }
1261 }
1262 }
1263 }
1264
1265 if (use_mirror && use_vert_sel) {
1266 vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, vgroup_validmap, vgroup_tot);
1267 }
1268
1269 MEM_freeN(dvert_array);
1270 }
1271}
1272
1274 const bool *vgroup_validmap,
1275 const int vgroup_tot,
1276 const int subset_count,
1277 const bool lock_active,
1278 ReportList *reports)
1279{
1280 MDeformVert *dv, **dvert_array = nullptr;
1281 int i, dvert_tot = 0;
1282 const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
1283
1284 const bool use_vert_sel = vertex_group_use_vert_sel(ob);
1285
1286 if (subset_count == 0) {
1287 BKE_report(reports, RPT_ERROR, "No vertex groups to operate on");
1288 return false;
1289 }
1290
1291 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
1292
1293 if (dvert_array) {
1294 const ListBase *defbase = BKE_object_defgroup_list(ob);
1295 const int defbase_tot = BLI_listbase_count(defbase);
1296 bool *lock_flags = BKE_object_defgroup_lock_flags_get(ob, defbase_tot);
1297 bool changed = false;
1298
1299 if ((lock_active == true) && (lock_flags != nullptr) && (def_nr < defbase_tot)) {
1300 lock_flags[def_nr] = true;
1301 }
1302
1303 if (lock_flags) {
1304 for (i = 0; i < defbase_tot; i++) {
1305 if (lock_flags[i] == false) {
1306 break;
1307 }
1308 }
1309
1310 if (i == defbase_tot) {
1311 BKE_report(reports, RPT_ERROR, "All groups are locked");
1312 goto finally;
1313 }
1314 }
1315
1316 for (i = 0; i < dvert_tot; i++) {
1317 /* in case its not selected */
1318 if ((dv = dvert_array[i])) {
1319 if (lock_flags) {
1320 BKE_defvert_normalize_lock_map(dv, vgroup_validmap, vgroup_tot, lock_flags, defbase_tot);
1321 }
1322 else if (lock_active) {
1323 BKE_defvert_normalize_lock_single(dv, vgroup_validmap, vgroup_tot, def_nr);
1324 }
1325 else {
1326 BKE_defvert_normalize_subset(dv, vgroup_validmap, vgroup_tot);
1327 }
1328 }
1329 }
1330
1331 changed = true;
1332
1333 finally:
1334 if (lock_flags) {
1335 MEM_freeN(lock_flags);
1336 }
1337
1338 MEM_freeN(dvert_array);
1339
1340 return changed;
1341 }
1342
1343 return false;
1344}
1345
1346enum {
1351};
1352
1355 "TOGGLE",
1356 0,
1357 "Toggle",
1358 "Unlock all vertex groups if there is at least one locked group, lock all in other case"},
1359 {VGROUP_LOCK, "LOCK", 0, "Lock", "Lock all vertex groups"},
1360 {VGROUP_UNLOCK, "UNLOCK", 0, "Unlock", "Unlock all vertex groups"},
1361 {VGROUP_INVERT, "INVERT", 0, "Invert", "Invert the lock state of all vertex groups"},
1362 {0, nullptr, 0, nullptr, nullptr},
1363};
1364
1365enum {
1370};
1371
1373 {VGROUP_MASK_ALL, "ALL", 0, "All", "Apply action to all vertex groups"},
1374 {VGROUP_MASK_SELECTED, "SELECTED", 0, "Selected", "Apply to selected vertex groups"},
1375 {VGROUP_MASK_UNSELECTED, "UNSELECTED", 0, "Unselected", "Apply to unselected vertex groups"},
1377 "INVERT_UNSELECTED",
1378 0,
1379 "Invert Unselected",
1380 "Apply the opposite of Lock/Unlock to unselected vertex groups"},
1381 {0, nullptr, 0, nullptr, nullptr},
1382};
1383
1385{
1386 int sel_count = 0, defbase_tot = BKE_object_defgroup_count(ob);
1387 bool *mask;
1388
1389 if (ob->mode & OB_MODE_WEIGHT_PAINT) {
1390 mask = BKE_object_defgroup_selected_get(ob, defbase_tot, &sel_count);
1391
1392 /* Mirror the selection if X Mirror is enabled. */
1393 Mesh *mesh = BKE_mesh_from_object(ob);
1394
1395 if (mesh && ME_USING_MIRROR_X_VERTEX_GROUPS(mesh)) {
1396 BKE_object_defgroup_mirror_selection(ob, defbase_tot, mask, mask, &sel_count);
1397 }
1398 }
1399 else {
1400 mask = static_cast<bool *>(MEM_callocN(defbase_tot * sizeof(bool), __func__));
1401 }
1402
1403 const int actdef = BKE_object_defgroup_active_index_get(ob);
1404 if (sel_count == 0 && actdef >= 1 && actdef <= defbase_tot) {
1405 mask[actdef - 1] = true;
1406 }
1407
1408 return mask;
1409}
1410
1411static void vgroup_lock_all(Object *ob, int action, int mask)
1412{
1413 bDeformGroup *dg;
1414 bool *selected = nullptr;
1415 int i;
1416
1417 if (mask != VGROUP_MASK_ALL) {
1418 selected = vgroup_selected_get(ob);
1419 }
1420 const ListBase *defbase = BKE_object_defgroup_list(ob);
1421
1422 if (action == VGROUP_TOGGLE) {
1423 action = VGROUP_LOCK;
1424
1425 for (dg = static_cast<bDeformGroup *>(defbase->first), i = 0; dg; dg = dg->next, i++) {
1426 switch (mask) {
1429 if (!selected[i]) {
1430 continue;
1431 }
1432 break;
1434 if (selected[i]) {
1435 continue;
1436 }
1437 break;
1438 default:
1439 break;
1440 }
1441
1442 if (dg->flag & DG_LOCK_WEIGHT) {
1443 action = VGROUP_UNLOCK;
1444 break;
1445 }
1446 }
1447 }
1448
1449 for (dg = static_cast<bDeformGroup *>(defbase->first), i = 0; dg; dg = dg->next, i++) {
1450 switch (mask) {
1452 if (!selected[i]) {
1453 continue;
1454 }
1455 break;
1457 if (selected[i]) {
1458 continue;
1459 }
1460 break;
1461 default:
1462 break;
1463 }
1464
1465 switch (action) {
1466 case VGROUP_LOCK:
1467 dg->flag |= DG_LOCK_WEIGHT;
1468 break;
1469 case VGROUP_UNLOCK:
1470 dg->flag &= ~DG_LOCK_WEIGHT;
1471 break;
1472 case VGROUP_INVERT:
1473 dg->flag ^= DG_LOCK_WEIGHT;
1474 break;
1475 }
1476
1477 if (mask == VGROUP_MASK_INVERT_UNSELECTED && !selected[i]) {
1478 dg->flag ^= DG_LOCK_WEIGHT;
1479 }
1480 }
1481
1482 if (selected) {
1483 MEM_freeN(selected);
1484 }
1485}
1486
1488 const bool *vgroup_validmap,
1489 const int vgroup_tot,
1490 const int /*subset_count*/,
1491 const bool auto_assign,
1492 const bool auto_remove)
1493{
1494 MDeformWeight *dw;
1495 MDeformVert *dv, **dvert_array = nullptr;
1496 int dvert_tot = 0;
1497 const bool use_vert_sel = vertex_group_use_vert_sel(ob);
1498 const bool use_mirror = (ob->type == OB_MESH) ?
1499 (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
1500 false;
1501
1502 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
1503
1504 if (dvert_array) {
1505 for (int i = 0; i < dvert_tot; i++) {
1506 /* in case its not selected */
1507 if (!(dv = dvert_array[i])) {
1508 continue;
1509 }
1510
1511 int j = vgroup_tot;
1512 while (j--) {
1513
1514 if (vgroup_validmap[j]) {
1515 if (auto_assign) {
1516 dw = BKE_defvert_ensure_index(dv, j);
1517 }
1518 else {
1519 dw = BKE_defvert_find_index(dv, j);
1520 }
1521
1522 if (dw) {
1523 dw->weight = 1.0f - dw->weight;
1524 CLAMP(dw->weight, 0.0f, 1.0f);
1525 }
1526 }
1527 }
1528 }
1529
1530 if (use_mirror && use_vert_sel) {
1531 vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, vgroup_validmap, vgroup_tot);
1532 }
1533
1534 if (auto_remove) {
1535 vgroup_parray_remove_zero(dvert_array, dvert_tot, vgroup_validmap, vgroup_tot, 0.0f, false);
1536 }
1537
1538 MEM_freeN(dvert_array);
1539 }
1540}
1541
1543 const bool *vgroup_validmap,
1544 const int vgroup_tot,
1545 const int subset_count,
1546 const float fac,
1547 const int repeat,
1548 const float fac_expand)
1549{
1550 const float ifac = 1.0f - fac;
1551 MDeformVert **dvert_array = nullptr;
1552 int dvert_tot = 0;
1553 Array<int, 32> vgroup_subset_map(subset_count);
1554 Array<float, 32> vgroup_subset_weights(subset_count);
1555 const bool use_mirror = (ob->type == OB_MESH) ?
1556 (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
1557 false;
1558 const bool use_select = vertex_group_use_vert_sel(ob);
1559 const bool use_hide = use_select;
1560
1561 const int expand_sign = signum_i(fac_expand);
1562 const float expand = fabsf(fac_expand);
1563 const float iexpand = 1.0f - expand;
1564
1566 BMesh *bm = em ? em->bm : nullptr;
1567 Mesh *mesh = em ? nullptr : static_cast<Mesh *>(ob->data);
1568
1569 float *weight_accum_prev;
1570 float *weight_accum_curr;
1571
1572 uint subset_index;
1573
1574 /* vertex indices that will be smoothed, (only to avoid iterating over verts that do nothing) */
1575 uint *verts_used;
1576 STACK_DECLARE(verts_used);
1577
1578 BKE_object_defgroup_subset_to_index_array(vgroup_validmap, vgroup_tot, vgroup_subset_map.data());
1579 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, false);
1580 vgroup_subset_weights.fill(0.0f);
1581
1582 Array<int> vert_to_edge_offsets;
1583 Array<int> vert_to_edge_indices;
1584 GroupedSpan<int> emap;
1585 if (bm) {
1588 }
1589 else {
1591 mesh->edges(), mesh->verts_num, vert_to_edge_offsets, vert_to_edge_indices);
1592 }
1593
1594 weight_accum_prev = static_cast<float *>(
1595 MEM_mallocN(sizeof(*weight_accum_prev) * dvert_tot, __func__));
1596 weight_accum_curr = static_cast<float *>(
1597 MEM_mallocN(sizeof(*weight_accum_curr) * dvert_tot, __func__));
1598
1599 verts_used = static_cast<uint *>(MEM_mallocN(sizeof(*verts_used) * dvert_tot, __func__));
1600 STACK_INIT(verts_used, dvert_tot);
1601
1602#define IS_BM_VERT_READ(v) (use_hide ? (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == 0) : true)
1603#define IS_BM_VERT_WRITE(v) (use_select ? (BM_elem_flag_test(v, BM_ELEM_SELECT) != 0) : true)
1604
1605 const bool *hide_vert = mesh ? (const bool *)CustomData_get_layer_named(
1606 &mesh->vert_data, CD_PROP_BOOL, ".hide_vert") :
1607 nullptr;
1608
1609#define IS_ME_VERT_READ(v) (use_hide ? !(hide_vert && hide_vert[v]) : true)
1610#define IS_ME_VERT_WRITE(v) (use_select ? select_vert[v] : true)
1611
1612 /* initialize used verts */
1613 if (bm) {
1614 for (int i = 0; i < dvert_tot; i++) {
1615 BMVert *v = BM_vert_at_index(bm, i);
1616 if (IS_BM_VERT_WRITE(v)) {
1617 BMIter eiter;
1618 BMEdge *e;
1619 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
1620 BMVert *v_other = BM_edge_other_vert(e, v);
1621 if (IS_BM_VERT_READ(v_other)) {
1622 STACK_PUSH(verts_used, i);
1623 break;
1624 }
1625 }
1626 }
1627 }
1628 }
1629 else {
1630 const bke::AttributeAccessor attributes = mesh->attributes();
1631 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
1632 ".select_vert", bke::AttrDomain::Point, false);
1633
1634 const Span<int2> edges = mesh->edges();
1635 for (int i = 0; i < dvert_tot; i++) {
1636 if (IS_ME_VERT_WRITE(i)) {
1637 for (int j = 0; j < emap[i].size(); j++) {
1638 const int2 &edge = edges[emap[i][j]];
1639 const int i_other = (edge[0] == i) ? edge[1] : edge[0];
1640 if (IS_ME_VERT_READ(i_other)) {
1641 STACK_PUSH(verts_used, i);
1642 break;
1643 }
1644 }
1645 }
1646 }
1647 }
1648
1649 for (subset_index = 0; subset_index < subset_count; subset_index++) {
1650 const int def_nr = vgroup_subset_map[subset_index];
1651 int iter;
1652
1654 (const MDeformVert **)dvert_array, dvert_tot, weight_accum_prev, def_nr);
1655 memcpy(weight_accum_curr, weight_accum_prev, sizeof(*weight_accum_curr) * dvert_tot);
1656
1657 for (iter = 0; iter < repeat; iter++) {
1658 uint *vi_step, *vi_end = verts_used + STACK_SIZE(verts_used);
1659
1660 /* avoid looping over all verts */
1661 // for (i = 0; i < dvert_tot; i++)
1662 for (vi_step = verts_used; vi_step != vi_end; vi_step++) {
1663 const uint i = *vi_step;
1664 float weight_tot = 0.0f;
1665 float weight = 0.0f;
1666
1667#define WEIGHT_ACCUMULATE \
1668 { \
1669 float weight_other = weight_accum_prev[i_other]; \
1670 float tot_factor = 1.0f; \
1671 if (expand_sign == 1) { /* expand */ \
1672 if (weight_other < weight_accum_prev[i]) { \
1673 weight_other = (weight_accum_prev[i] * expand) + (weight_other * iexpand); \
1674 tot_factor = iexpand; \
1675 } \
1676 } \
1677 else if (expand_sign == -1) { /* contract */ \
1678 if (weight_other > weight_accum_prev[i]) { \
1679 weight_other = (weight_accum_prev[i] * expand) + (weight_other * iexpand); \
1680 tot_factor = iexpand; \
1681 } \
1682 } \
1683 weight += tot_factor * weight_other; \
1684 weight_tot += tot_factor; \
1685 } \
1686 ((void)0)
1687
1688 if (bm) {
1689 BMVert *v = BM_vert_at_index(bm, i);
1690 BMIter eiter;
1691 BMEdge *e;
1692
1693 /* checked already */
1695
1696 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
1697 BMVert *v_other = BM_edge_other_vert(e, v);
1698 if (IS_BM_VERT_READ(v_other)) {
1699 const int i_other = BM_elem_index_get(v_other);
1700
1702 }
1703 }
1704 }
1705 else {
1706 const bke::AttributeAccessor attributes = mesh->attributes();
1707 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
1708 ".select_vert", bke::AttrDomain::Point, false);
1709
1710 int j;
1711 const Span<int2> edges = mesh->edges();
1712
1713 /* checked already */
1715
1716 for (j = 0; j < emap[i].size(); j++) {
1717 const int2 &edge = edges[emap[i][j]];
1718 const int i_other = (edge[0] == i ? edge[1] : edge[0]);
1719 if (IS_ME_VERT_READ(i_other)) {
1721 }
1722 }
1723 }
1724
1725#undef WEIGHT_ACCUMULATE
1726
1727 if (weight_tot != 0.0f) {
1728 weight /= weight_tot;
1729 weight = (weight_accum_prev[i] * ifac) + (weight * fac);
1730
1731 /* should be within range, just clamp because of float precision */
1732 CLAMP(weight, 0.0f, 1.0f);
1733 weight_accum_curr[i] = weight;
1734 }
1735 }
1736
1737 std::swap(weight_accum_curr, weight_accum_prev);
1738 }
1739
1740 vgroup_parray_from_weight_array(dvert_array, dvert_tot, weight_accum_prev, def_nr, true);
1741 }
1742
1743#undef IS_BM_VERT_READ
1744#undef IS_BM_VERT_WRITE
1745#undef IS_ME_VERT_READ
1746#undef IS_ME_VERT_WRITE
1747
1748 MEM_freeN(weight_accum_curr);
1749 MEM_freeN(weight_accum_prev);
1750 MEM_freeN(verts_used);
1751
1752 if (dvert_array) {
1753 MEM_freeN(dvert_array);
1754 }
1755
1756 /* not so efficient to get 'dvert_array' again just so unselected verts are nullptr'd */
1757 if (use_mirror) {
1758 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, true);
1759 vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, vgroup_validmap, vgroup_tot);
1760 if (dvert_array) {
1761 MEM_freeN(dvert_array);
1762 }
1763 }
1764}
1765
1766static int inv_cmp_mdef_vert_weights(const void *a1, const void *a2)
1767{
1768 /* #qsort sorts in ascending order. We want descending order to save a #memcpy
1769 * so this compare function is inverted from the standard greater than comparison #qsort needs.
1770 * A normal compare function is called with two pointer arguments and should return an integer
1771 * less than, equal to, or greater than zero corresponding to whether its first argument is
1772 * considered less than, equal to, or greater than its second argument.
1773 * This does the opposite. */
1774 const MDeformWeight *dw1 = static_cast<const MDeformWeight *>(a1);
1775 const MDeformWeight *dw2 = static_cast<const MDeformWeight *>(a2);
1776
1777 if (dw1->weight < dw2->weight) {
1778 return 1;
1779 }
1780 if (dw1->weight > dw2->weight) {
1781 return -1;
1782 }
1783 if (&dw1 < &dw2) {
1784 return 1; /* compare address for stable sort algorithm */
1785 }
1786 return -1;
1787}
1788
1789/* Used for limiting the number of influencing bones per vertex when exporting
1790 * skinned meshes. if all_deform_weights is True, limit all deform modifiers
1791 * to max_weights regardless of type, otherwise,
1792 * only limit the number of influencing bones per vertex. */
1794 const bool *vgroup_validmap,
1795 const int vgroup_tot,
1796 const int subset_count,
1797 const int max_weights)
1798{
1799 MDeformVert *dv, **dvert_array = nullptr;
1800 int i, dvert_tot = 0;
1801 const bool use_vert_sel = vertex_group_use_vert_sel(ob);
1802 int remove_tot = 0;
1803
1804 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
1805
1806 if (dvert_array) {
1807 int num_to_drop = 0;
1808
1809 for (i = 0; i < dvert_tot; i++) {
1810
1811 MDeformWeight *dw_temp;
1812 int bone_count = 0, non_bone_count = 0;
1813 int j;
1814
1815 /* in case its not selected */
1816 if (!(dv = dvert_array[i])) {
1817 continue;
1818 }
1819
1820 num_to_drop = subset_count - max_weights;
1821
1822 /* first check if we even need to test further */
1823 if (num_to_drop > 0) {
1824 /* re-pack dw array so that non-bone weights are first, bone-weighted verts at end
1825 * sort the tail, then copy only the truncated array back to dv->dw */
1826 dw_temp = static_cast<MDeformWeight *>(
1827 MEM_mallocN(sizeof(MDeformWeight) * dv->totweight, __func__));
1828 bone_count = 0;
1829 non_bone_count = 0;
1830 for (j = 0; j < dv->totweight; j++) {
1831 if (LIKELY(dv->dw[j].def_nr < vgroup_tot) && vgroup_validmap[dv->dw[j].def_nr]) {
1832 dw_temp[dv->totweight - 1 - bone_count] = dv->dw[j];
1833 bone_count += 1;
1834 }
1835 else {
1836 dw_temp[non_bone_count] = dv->dw[j];
1837 non_bone_count += 1;
1838 }
1839 }
1840 BLI_assert(bone_count + non_bone_count == dv->totweight);
1841 num_to_drop = bone_count - max_weights;
1842 if (num_to_drop > 0) {
1843 qsort(&dw_temp[non_bone_count],
1844 bone_count,
1845 sizeof(MDeformWeight),
1847 dv->totweight -= num_to_drop;
1848 /* Do we want to clean/normalize here? */
1849 MEM_freeN(dv->dw);
1850 dv->dw = static_cast<MDeformWeight *>(
1851 MEM_reallocN(dw_temp, sizeof(MDeformWeight) * dv->totweight));
1852 remove_tot += num_to_drop;
1853 }
1854 else {
1855 MEM_freeN(dw_temp);
1856 }
1857 }
1858 }
1859 MEM_freeN(dvert_array);
1860 }
1861
1862 return remove_tot;
1863}
1864
1866 const bool *vgroup_validmap,
1867 const int vgroup_tot,
1868 const int /*subset_count*/,
1869 const float epsilon,
1870 const bool keep_single)
1871{
1872 MDeformVert **dvert_array = nullptr;
1873 int dvert_tot = 0;
1874 const bool use_vert_sel = vertex_group_use_vert_sel(ob);
1875 const bool use_mirror = (ob->type == OB_MESH) ?
1876 (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
1877 false;
1878
1879 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
1880
1881 if (dvert_array) {
1882 if (use_mirror && use_vert_sel) {
1883 /* correct behavior in this case isn't well defined
1884 * for now assume both sides are mirrored correctly,
1885 * so cleaning one side also cleans the other */
1886 vgroup_parray_mirror_assign(ob, dvert_array, dvert_tot);
1887 }
1888
1890 dvert_array, dvert_tot, vgroup_validmap, vgroup_tot, epsilon, keep_single);
1891
1892 MEM_freeN(dvert_array);
1893 }
1894}
1895
1897 const bool *vgroup_validmap,
1898 const int vgroup_tot,
1899 const int /*subset_count*/,
1900 const int steps)
1901{
1902 MDeformVert **dvert_array = nullptr;
1903 int dvert_tot = 0;
1904 const bool use_vert_sel = vertex_group_use_vert_sel(ob);
1905 const bool use_mirror = (ob->type == OB_MESH) ?
1906 (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
1907 false;
1908 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
1909
1910 if (dvert_array) {
1911 const float steps_fl = steps;
1912 MDeformVert *dv;
1913
1914 if (use_mirror && use_vert_sel) {
1915 vgroup_parray_mirror_assign(ob, dvert_array, dvert_tot);
1916 }
1917
1918 for (int i = 0; i < dvert_tot; i++) {
1919 MDeformWeight *dw;
1920
1921 /* in case its not selected */
1922 if (!(dv = dvert_array[i])) {
1923 continue;
1924 }
1925
1926 int j;
1927 for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) {
1928 if ((dw->def_nr < vgroup_tot) && vgroup_validmap[dw->def_nr]) {
1929 dw->weight = floorf((dw->weight * steps_fl) + 0.5f) / steps_fl;
1930 CLAMP(dw->weight, 0.0f, 1.0f);
1931 }
1932 }
1933 }
1934
1935 MEM_freeN(dvert_array);
1936 }
1937}
1938
1939static void dvert_mirror_op(MDeformVert *dvert,
1940 MDeformVert *dvert_mirr,
1941 const char sel,
1942 const char sel_mirr,
1943 const int *flip_map,
1944 const int flip_map_len,
1945 const bool mirror_weights,
1946 const bool flip_vgroups,
1947 const bool all_vgroups,
1948 const int act_vgroup)
1949{
1950 BLI_assert(sel || sel_mirr);
1951
1952 if (sel_mirr && sel) {
1953 /* swap */
1954 if (mirror_weights) {
1955 if (all_vgroups) {
1956 std::swap(*dvert, *dvert_mirr);
1957 }
1958 else {
1959 MDeformWeight *dw = BKE_defvert_find_index(dvert, act_vgroup);
1960 MDeformWeight *dw_mirr = BKE_defvert_find_index(dvert_mirr, act_vgroup);
1961
1962 if (dw && dw_mirr) {
1963 std::swap(dw->weight, dw_mirr->weight);
1964 }
1965 else if (dw) {
1966 dw_mirr = BKE_defvert_ensure_index(dvert_mirr, act_vgroup);
1967 dw_mirr->weight = dw->weight;
1968 BKE_defvert_remove_group(dvert, dw);
1969 }
1970 else if (dw_mirr) {
1971 dw = BKE_defvert_ensure_index(dvert, act_vgroup);
1972 dw->weight = dw_mirr->weight;
1973 BKE_defvert_remove_group(dvert_mirr, dw_mirr);
1974 }
1975 }
1976 }
1977
1978 if (flip_vgroups) {
1979 BKE_defvert_flip(dvert, flip_map, flip_map_len);
1980 BKE_defvert_flip(dvert_mirr, flip_map, flip_map_len);
1981 }
1982 }
1983 else {
1984 /* dvert should always be the target, only swaps pointer */
1985 if (sel_mirr) {
1986 std::swap(dvert, dvert_mirr);
1987 }
1988
1989 if (mirror_weights) {
1990 if (all_vgroups) {
1991 BKE_defvert_copy(dvert, dvert_mirr);
1992 }
1993 else {
1994 BKE_defvert_copy_index(dvert, act_vgroup, dvert_mirr, act_vgroup);
1995 }
1996 }
1997
1998 /* flip map already modified for 'all_vgroups' */
1999 if (flip_vgroups) {
2000 BKE_defvert_flip(dvert, flip_map, flip_map_len);
2001 }
2002 }
2003}
2004
2006 const bool mirror_weights,
2007 const bool flip_vgroups,
2008 const bool all_vgroups,
2009 const bool use_topology,
2010 int *r_totmirr,
2011 int *r_totfail)
2012{
2013 /* TODO: vgroup locking.
2014 * TODO: face masking. */
2015
2016 const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
2017 int totmirr = 0, totfail = 0;
2018
2019 *r_totmirr = *r_totfail = 0;
2020
2021 const ListBase *defbase = BKE_object_defgroup_list(ob);
2022
2023 if ((mirror_weights == false && flip_vgroups == false) ||
2024 (BLI_findlink(defbase, def_nr) == nullptr))
2025 {
2026 return;
2027 }
2028
2029 int *flip_map = nullptr;
2030 int flip_map_len;
2031 if (flip_vgroups) {
2032 flip_map = all_vgroups ? BKE_object_defgroup_flip_map(ob, false, &flip_map_len) :
2033 BKE_object_defgroup_flip_map_single(ob, false, def_nr, &flip_map_len);
2034
2035 BLI_assert(flip_map != nullptr);
2036
2037 if (flip_map == nullptr) {
2038 /* something went wrong!, possibly no groups */
2039 return;
2040 }
2041 }
2042 else {
2043 flip_map = nullptr;
2044 flip_map_len = 0;
2045 }
2046
2047 /* only the active group */
2048 if (ob->type == OB_MESH) {
2049 Mesh *mesh = static_cast<Mesh *>(ob->data);
2050
2051 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
2052 const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
2053 BMIter iter;
2054
2055 if (cd_dvert_offset == -1) {
2056 goto cleanup;
2057 }
2058
2059 EDBM_verts_mirror_cache_begin(em, 0, true, false, false, use_topology);
2060
2062
2063 /* Go through the list of edit-vertices and assign them. */
2064 BMVert *eve, *eve_mirr;
2065 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2066 if (!BM_elem_flag_test(eve, BM_ELEM_TAG)) {
2067 if ((eve_mirr = EDBM_verts_mirror_get(em, eve))) {
2068 if (eve_mirr != eve) {
2069 if (!BM_elem_flag_test(eve_mirr, BM_ELEM_TAG)) {
2070 const bool sel = BM_elem_flag_test(eve, BM_ELEM_SELECT);
2071 const bool sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT);
2072
2073 if ((sel || sel_mirr) && (eve != eve_mirr)) {
2075 static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)),
2076 static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset)),
2077 sel,
2078 sel_mirr,
2079 flip_map,
2080 flip_map_len,
2081 mirror_weights,
2082 flip_vgroups,
2083 all_vgroups,
2084 def_nr);
2085 totmirr++;
2086 }
2087
2088 /* don't use these again */
2091 }
2092 }
2093 }
2094 else {
2095 totfail++;
2096 }
2097 }
2098 }
2100 }
2101 else {
2102 /* object mode / weight paint */
2103 const bool use_vert_sel = (mesh->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
2104
2105 if (mesh->deform_verts().is_empty()) {
2106 goto cleanup;
2107 }
2108
2109 BLI_bitmap *vert_tag = BLI_BITMAP_NEW(mesh->verts_num, __func__);
2110 MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write();
2111 const bke::AttributeAccessor attributes = mesh->attributes();
2112 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
2113 ".select_vert", bke::AttrDomain::Point, false);
2114
2115 for (int vidx = 0; vidx < mesh->verts_num; vidx++) {
2116 if (!BLI_BITMAP_TEST(vert_tag, vidx)) {
2117 int vidx_mirr;
2118 if ((vidx_mirr = mesh_get_x_mirror_vert(ob, nullptr, vidx, use_topology)) != -1) {
2119 if (vidx != vidx_mirr) {
2120 if (!BLI_BITMAP_TEST(vert_tag, vidx_mirr)) {
2121 const bool sel = use_vert_sel ? select_vert[vidx] : true;
2122 const bool sel_mirr = use_vert_sel ? select_vert[vidx_mirr] : true;
2123
2124 if (sel || sel_mirr) {
2125 dvert_mirror_op(&dverts[vidx],
2126 &dverts[vidx_mirr],
2127 sel,
2128 sel_mirr,
2129 flip_map,
2130 flip_map_len,
2131 mirror_weights,
2132 flip_vgroups,
2133 all_vgroups,
2134 def_nr);
2135 totmirr++;
2136 }
2137
2138 BLI_BITMAP_ENABLE(vert_tag, vidx);
2139 BLI_BITMAP_ENABLE(vert_tag, vidx_mirr);
2140 }
2141 }
2142 }
2143 else {
2144 totfail++;
2145 }
2146 }
2147 }
2148
2149 MEM_freeN(vert_tag);
2150 }
2151 }
2152 else if (ob->type == OB_LATTICE) {
2153 Lattice *lt = vgroup_edit_lattice(ob);
2154 /* half but found up odd value */
2155
2156 if (lt->pntsu == 1 || lt->dvert == nullptr) {
2157 goto cleanup;
2158 }
2159
2160 /* unlike editmesh we know that by only looping over the first half of
2161 * the 'u' indices it will cover all points except the middle which is
2162 * ok in this case */
2163 int pntsu_half = lt->pntsu / 2;
2164
2165 for (int w = 0; w < lt->pntsw; w++) {
2166 for (int v = 0; v < lt->pntsv; v++) {
2167 for (int u = 0; u < pntsu_half; u++) {
2168 int u_inv = (lt->pntsu - 1) - u;
2169 if (u != u_inv) {
2170 const int i1 = BKE_lattice_index_from_uvw(lt, u, v, w);
2171 const int i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w);
2172
2173 const BPoint *bp = &lt->def[i1];
2174 const BPoint *bp_mirr = &lt->def[i2];
2175
2176 const bool sel = bp->f1 & SELECT;
2177 const bool sel_mirr = bp_mirr->f1 & SELECT;
2178
2179 if (sel || sel_mirr) {
2180 dvert_mirror_op(&lt->dvert[i1],
2181 &lt->dvert[i2],
2182 sel,
2183 sel_mirr,
2184 flip_map,
2185 flip_map_len,
2186 mirror_weights,
2187 flip_vgroups,
2188 all_vgroups,
2189 def_nr);
2190 totmirr++;
2191 }
2192 }
2193 }
2194 }
2195 }
2196 }
2197
2198 /* disabled, confusing when you have an active pose bone */
2199#if 0
2200 /* flip active group index */
2201 if (flip_vgroups && flip_map[def_nr] >= 0) {
2202 ob->actdef = flip_map[def_nr] + 1;
2203 }
2204#endif
2205
2206cleanup:
2207 *r_totmirr = totmirr;
2208 *r_totfail = totfail;
2209
2210 if (flip_map) {
2211 MEM_freeN(flip_map);
2212 }
2213
2214#undef VGROUP_MIRR_OP
2215}
2216
2218{
2219 const ListBase *defbase = BKE_object_defgroup_list(ob);
2220 bDeformGroup *dg = static_cast<bDeformGroup *>(
2222 if (!dg) {
2223 return;
2224 }
2225
2227}
2228
2229/* only in editmode */
2230static void vgroup_assign_verts(Object *ob, Scene &scene, const float weight)
2231{
2232 const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
2233
2234 const ListBase *defbase = BKE_object_defgroup_list(ob);
2235 if (!BLI_findlink(defbase, def_nr)) {
2236 return;
2237 }
2238
2239 if (ob->type == OB_MESH) {
2240 Mesh *mesh = static_cast<Mesh *>(ob->data);
2241
2242 if (mesh->runtime->edit_mesh) {
2243 BMEditMesh *em = mesh->runtime->edit_mesh.get();
2244 int cd_dvert_offset;
2245
2246 BMIter iter;
2247 BMVert *eve;
2248
2251 }
2252
2253 cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
2254
2255 /* Go through the list of edit-vertices and assign them. */
2256 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2258 MDeformVert *dv;
2259 MDeformWeight *dw;
2260 dv = static_cast<MDeformVert *>(
2261 BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)); /* can be nullptr */
2262 dw = BKE_defvert_ensure_index(dv, def_nr);
2263 if (dw) {
2264 dw->weight = weight;
2265 }
2266 }
2267 }
2268 }
2269 else {
2270 const bke::AttributeAccessor attributes = mesh->attributes();
2271 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
2272 ".select_vert", bke::AttrDomain::Point, false);
2273
2274 MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write();
2275
2276 for (int i = 0; i < mesh->verts_num; i++) {
2277 if (select_vert[i]) {
2278 MDeformWeight *dw;
2279 dw = BKE_defvert_ensure_index(&dverts[i], def_nr);
2280 if (dw) {
2281 dw->weight = weight;
2282 }
2283 }
2284 }
2285 }
2286 }
2287 else if (ob->type == OB_LATTICE) {
2288 Lattice *lt = vgroup_edit_lattice(ob);
2289 MDeformVert *dv;
2290 BPoint *bp;
2291 int a, tot;
2292
2293 if (lt->dvert == nullptr) {
2295 }
2296
2297 dv = lt->dvert;
2298
2299 tot = lt->pntsu * lt->pntsv * lt->pntsw;
2300 for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) {
2301 if (bp->f1 & SELECT) {
2302 MDeformWeight *dw;
2303
2304 dw = BKE_defvert_ensure_index(dv, def_nr);
2305 if (dw) {
2306 dw->weight = weight;
2307 }
2308 }
2309 }
2310 }
2311 else if (ob->type == OB_GREASE_PENCIL) {
2312 GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob->data);
2313 const bDeformGroup *defgroup = static_cast<const bDeformGroup *>(
2315
2316 {
2317 using namespace ed::greasepencil;
2318 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, *grease_pencil);
2319 for (MutableDrawingInfo info : drawings) {
2320 bke::greasepencil::assign_to_vertex_group(info.drawing, defgroup->name, weight);
2321 }
2322 }
2323 }
2324}
2325
2328/* -------------------------------------------------------------------- */
2333{
2335 CTX_wm_operator_poll_msg_set(C, "No active editable object");
2336 return false;
2337 }
2338
2339 if (!OB_TYPE_SUPPORT_VGROUP(ob->type)) {
2340 CTX_wm_operator_poll_msg_set(C, "Object type does not support vertex groups");
2341 return false;
2342 }
2343
2344 /* Data checks. */
2345 const ID *data = static_cast<const ID *>(ob->data);
2346 if (data == nullptr || !ID_IS_EDITABLE(data) || ID_IS_OVERRIDE_LIBRARY(data)) {
2347 CTX_wm_operator_poll_msg_set(C, "Object type \"%s\" does not have editable data");
2348 return false;
2349 }
2350
2351 return true;
2352}
2353
2355{
2356 Object *ob = context_object(C);
2357 return vertex_group_supported_poll_ex(C, ob);
2358}
2359
2361{
2362 if (!vertex_group_supported_poll_ex(C, ob)) {
2363 return false;
2364 }
2365
2366 const ListBase *defbase = BKE_object_defgroup_list(ob);
2367 if (BLI_listbase_is_empty(defbase)) {
2368 CTX_wm_operator_poll_msg_set(C, "Object has no vertex groups");
2369 return false;
2370 }
2371
2372 return true;
2373}
2374
2376{
2377 Object *ob = context_object(C);
2378 return vertex_group_poll_ex(C, ob);
2379}
2380
2382{
2383 Object *ob = context_object(C);
2384
2385 if (!vertex_group_supported_poll_ex(C, ob)) {
2386 return false;
2387 }
2388
2390}
2391
2392/* editmode _or_ weight paint vertex sel */
2394 const bool needs_select,
2395 const short ob_type_flag)
2396{
2397 Object *ob = context_object(C);
2398
2399 if (!vertex_group_supported_poll_ex(C, ob)) {
2400 return false;
2401 }
2402
2403 if (ob_type_flag && ((1 << ob->type) & ob_type_flag) == 0) {
2404 return false;
2405 }
2406
2408 return true;
2409 }
2410 if (ob->mode & OB_MODE_WEIGHT_PAINT) {
2411 if (needs_select) {
2413 return true;
2414 }
2415 CTX_wm_operator_poll_msg_set(C, "Vertex select needs to be enabled in weight paint mode");
2416 return false;
2417 }
2418 return true;
2419 }
2420 return false;
2421}
2422
2423#if 0
2424static bool vertex_group_vert_poll(bContext *C)
2425{
2426 return vertex_group_vert_poll_ex(C, false, 0);
2427}
2428#endif
2429
2431{
2432 return vertex_group_vert_poll_ex(C, false, (1 << OB_MESH));
2433}
2434
2436{
2437 return vertex_group_vert_poll_ex(C, true, 0);
2438}
2439
2440#if 0
2441static bool vertex_group_mesh_vert_select_poll(bContext *C)
2442{
2443 return vertex_group_vert_poll_ex(C, true, (1 << OB_MESH));
2444}
2445#endif
2446
2447/* editmode _or_ weight paint vertex sel and active group unlocked */
2449{
2450 Object *ob = context_object(C);
2451
2452 if (!vertex_group_supported_poll_ex(C, ob)) {
2453 return false;
2454 }
2455
2457 return false;
2458 }
2459
2460 const int def_nr = BKE_object_defgroup_active_index_get(ob);
2461 if (def_nr != 0) {
2462 const ListBase *defbase = BKE_object_defgroup_list(ob);
2463 const bDeformGroup *dg = static_cast<const bDeformGroup *>(BLI_findlink(defbase, def_nr - 1));
2464 if (dg && (dg->flag & DG_LOCK_WEIGHT)) {
2465 CTX_wm_operator_poll_msg_set(C, "The active vertex group is locked");
2466 return false;
2467 }
2468 }
2469 return true;
2470}
2471
2473{
2474 Object *ob = context_object(C);
2475
2476 if (!vertex_group_supported_poll_ex(C, ob)) {
2477 return false;
2478 }
2479
2480 /* only difference to #vertex_group_vert_select_poll */
2481 if (ob->type != OB_MESH) {
2482 return false;
2483 }
2484
2486}
2487
2490/* -------------------------------------------------------------------- */
2506
2508{
2509 /* identifiers */
2510 ot->name = "Add Vertex Group";
2511 ot->idname = "OBJECT_OT_vertex_group_add";
2512 ot->description = "Add a new vertex group to the active object";
2513
2514 /* api callbacks */
2517
2518 /* flags */
2520}
2521
2524/* -------------------------------------------------------------------- */
2529 Object &ob,
2530 bDeformGroup *dg,
2531 const bool use_selection,
2532 const bool all_drawings = false)
2533{
2534 using namespace ed::greasepencil;
2535 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob.data);
2536
2537 if (all_drawings) {
2538 /* When removing vgroup, iterate over all the drawing. */
2539 for (GreasePencilDrawingBase *base : grease_pencil.drawings()) {
2540 if (base->type != GP_DRAWING) {
2541 continue;
2542 }
2543 bke::greasepencil::Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(base)->wrap();
2544 bke::greasepencil::remove_from_vertex_group(drawing, dg->name, use_selection);
2545 }
2546 /* Remove vgroup from the list. */
2548 }
2549 else {
2550 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
2551 for (const MutableDrawingInfo &info : drawings) {
2552 bke::greasepencil::remove_from_vertex_group(info.drawing, dg->name, use_selection);
2553 }
2554 }
2555}
2556
2558 Object &ob,
2559 const bool use_selection,
2560 const bool all_drawings = false,
2561 const bool only_unlocked = false)
2562{
2563 const ListBase *defbase = BKE_object_defgroup_list(&ob);
2564
2565 bDeformGroup *dg = static_cast<bDeformGroup *>(defbase->first);
2566 while (dg) {
2567 bDeformGroup *next_group = dg->next;
2568 if (!only_unlocked || (dg->flag & DG_LOCK_WEIGHT) == 0) {
2569 grease_pencil_clear_from_vgroup(scene, ob, dg, use_selection, all_drawings);
2570 }
2571 dg = next_group;
2572 }
2573}
2574
2576{
2577 Object *ob = context_object(C);
2578 Scene &scene = *CTX_data_scene(C);
2579 const bool all_vgroup = RNA_boolean_get(op->ptr, "all");
2580 const bool only_unlocked = RNA_boolean_get(op->ptr, "all_unlocked");
2581
2582 if (ob->type == OB_GREASE_PENCIL) {
2583 if (all_vgroup || only_unlocked) {
2584 grease_pencil_clear_from_all_vgroup(scene, *ob, false, true, only_unlocked);
2585 }
2586 else {
2587 const ListBase *defbase = BKE_object_defgroup_list(ob);
2588 bDeformGroup *dg = static_cast<bDeformGroup *>(
2590
2591 if (!dg) {
2592 return OPERATOR_CANCELLED;
2593 }
2594 grease_pencil_clear_from_vgroup(scene, *ob, dg, false, true);
2595 }
2596 }
2597 else {
2598 if (all_vgroup || only_unlocked) {
2599 BKE_object_defgroup_remove_all_ex(ob, only_unlocked);
2600 }
2601 else {
2603 }
2604 }
2605
2610
2611 return OPERATOR_FINISHED;
2612}
2613
2615{
2616 /* identifiers */
2617 ot->name = "Remove Vertex Group";
2618 ot->idname = "OBJECT_OT_vertex_group_remove";
2619 ot->description = "Delete the active or all vertex groups from the active object";
2620
2621 /* api callbacks */
2624
2625 /* flags */
2626 /* redo operator will fail in this case because vertex groups aren't stored
2627 * in local edit mode stack and toggling "all" property will lead to
2628 * all groups deleted without way to restore them (see #29527, sergey) */
2629 ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
2630
2631 /* properties */
2632 PropertyRNA *prop = RNA_def_boolean(ot->srna, "all", false, "All", "Remove all vertex groups");
2634 prop = RNA_def_boolean(
2635 ot->srna, "all_unlocked", false, "All Unlocked", "Remove all unlocked vertex groups");
2637}
2638
2641/* -------------------------------------------------------------------- */
2646{
2648 Object *ob = context_object(C);
2649 Scene &scene = *CTX_data_scene(C);
2650
2651 vgroup_assign_verts(ob, scene, ts->vgroup_weight);
2654
2655 return OPERATOR_FINISHED;
2656}
2657
2659{
2660 /* identifiers */
2661 ot->name = "Assign to Vertex Group";
2662 ot->idname = "OBJECT_OT_vertex_group_assign";
2663 ot->description = "Assign the selected vertices to the active vertex group";
2664
2665 /* api callbacks */
2668
2669 /* flags */
2670 /* redo operator will fail in this case because vertex group assignment
2671 * isn't stored in local edit mode stack and toggling "new" property will
2672 * lead to creating plenty of new vertex groups (see #29527, sergey) */
2673 ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
2674}
2675
2678/* -------------------------------------------------------------------- */
2682/* NOTE: just a wrapper around vertex_group_assign_exec(), except we add these to a new group */
2684{
2685 /* create new group... */
2686 Object *ob = context_object(C);
2688
2689 /* assign selection to new group */
2690 return vertex_group_assign_exec(C, op);
2691}
2692
2694{
2695 /* identifiers */
2696 ot->name = "Assign to New Group";
2697 ot->idname = "OBJECT_OT_vertex_group_assign_new";
2698 ot->description = "Assign the selected vertices to a new vertex group";
2699
2700 /* api callbacks */
2703
2704 /* flags */
2705 /* redo operator will fail in this case because vertex group assignment
2706 * isn't stored in local edit mode stack and toggling "new" property will
2707 * lead to creating plenty of new vertex groups (see #29527, sergey) */
2708 ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
2709}
2710
2713/* -------------------------------------------------------------------- */
2718{
2719 const bool use_all_groups = RNA_boolean_get(op->ptr, "use_all_groups");
2720 const bool use_all_verts = RNA_boolean_get(op->ptr, "use_all_verts");
2721 Scene &scene = *CTX_data_scene(C);
2722
2723 Object *ob = context_object(C);
2724
2725 if (use_all_groups) {
2726 if (ob->type == OB_GREASE_PENCIL) {
2727 grease_pencil_clear_from_all_vgroup(scene, *ob, true);
2728 }
2729 else if (BKE_object_defgroup_clear_all(ob, true) == false) {
2730 return OPERATOR_CANCELLED;
2731 }
2732 }
2733 else {
2734 const ListBase *defbase = BKE_object_defgroup_list(ob);
2735 bDeformGroup *dg = static_cast<bDeformGroup *>(
2737 if (dg == nullptr) {
2738 return OPERATOR_CANCELLED;
2739 }
2740
2741 if (ob->type == OB_GREASE_PENCIL) {
2742 grease_pencil_clear_from_vgroup(scene, *ob, dg, !use_all_verts);
2743 }
2744 else if (BKE_object_defgroup_clear(ob, dg, !use_all_verts) == false) {
2745 return OPERATOR_CANCELLED;
2746 }
2747 }
2748
2751
2752 return OPERATOR_FINISHED;
2753}
2754
2756{
2757 PropertyRNA *prop;
2758 /* identifiers */
2759 ot->name = "Remove from Vertex Group";
2760 ot->idname = "OBJECT_OT_vertex_group_remove_from";
2761 ot->description = "Remove the selected vertices from active or all vertex group(s)";
2762
2763 /* api callbacks */
2766
2767 /* flags */
2768 /* redo operator will fail in this case because vertex groups assignment
2769 * isn't stored in local edit mode stack and toggling "all" property will lead to
2770 * removing vertices from all groups (see #29527, sergey) */
2771 ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
2772
2773 /* properties */
2774 prop = RNA_def_boolean(
2775 ot->srna, "use_all_groups", false, "All Groups", "Remove from all groups");
2777 prop = RNA_def_boolean(
2778 ot->srna, "use_all_verts", false, "All Vertices", "Clear the active group");
2780}
2781
2784/* -------------------------------------------------------------------- */
2789{
2790 const ToolSettings &tool_settings = *CTX_data_scene(C)->toolsettings;
2791 Object *ob = context_object(C);
2792 Scene &scene = *CTX_data_scene(C);
2793
2794 if (!ob || !ID_IS_EDITABLE(ob) || ID_IS_OVERRIDE_LIBRARY(ob)) {
2795 return OPERATOR_CANCELLED;
2796 }
2797
2798 vgroup_select_verts(tool_settings, ob, scene, 1);
2801
2802 return OPERATOR_FINISHED;
2803}
2804
2806{
2807 /* identifiers */
2808 ot->name = "Select Vertex Group";
2809 ot->idname = "OBJECT_OT_vertex_group_select";
2810 ot->description = "Select all the vertices assigned to the active vertex group";
2811
2812 /* api callbacks */
2815
2816 /* flags */
2818}
2819
2822/* -------------------------------------------------------------------- */
2827{
2828 const ToolSettings &tool_settings = *CTX_data_scene(C)->toolsettings;
2829 Object *ob = context_object(C);
2830 Scene &scene = *CTX_data_scene(C);
2831
2832 vgroup_select_verts(tool_settings, ob, scene, 0);
2835
2836 return OPERATOR_FINISHED;
2837}
2838
2840{
2841 /* identifiers */
2842 ot->name = "Deselect Vertex Group";
2843 ot->idname = "OBJECT_OT_vertex_group_deselect";
2844 ot->description = "Deselect all selected vertices assigned to the active vertex group";
2845
2846 /* api callbacks */
2849
2850 /* flags */
2852}
2853
2856/* -------------------------------------------------------------------- */
2872
2874{
2875 /* identifiers */
2876 ot->name = "Duplicate Vertex Group";
2877 ot->idname = "OBJECT_OT_vertex_group_copy";
2878 ot->description = "Make a copy of the active vertex group";
2879
2880 /* api callbacks */
2883
2884 /* flags */
2886}
2887
2890/* -------------------------------------------------------------------- */
2895{
2896 Object *ob = context_object(C);
2897
2898 float offset = RNA_float_get(op->ptr, "offset");
2899 float gain = RNA_float_get(op->ptr, "gain");
2900 eVGroupSelect subset_type = static_cast<eVGroupSelect>(
2901 RNA_enum_get(op->ptr, "group_select_mode"));
2902
2903 int subset_count, vgroup_tot;
2904
2905 const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
2906 ob, subset_type, &vgroup_tot, &subset_count);
2907 vgroup_levels_subset(ob, vgroup_validmap, vgroup_tot, subset_count, offset, gain);
2908 MEM_freeN((void *)vgroup_validmap);
2909
2913
2914 return OPERATOR_FINISHED;
2915}
2916
2918{
2919 /* identifiers */
2920 ot->name = "Vertex Group Levels";
2921 ot->idname = "OBJECT_OT_vertex_group_levels";
2922 ot->description =
2923 "Add some offset and multiply with some gain the weights of the active vertex group";
2924
2925 /* api callbacks */
2928
2929 /* flags */
2931
2934 ot->srna, "offset", 0.0f, -1.0, 1.0, "Offset", "Value to add to weights", -1.0f, 1.0f);
2936 ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply weights by", 0.0f, 10.0f);
2937}
2938
2941/* -------------------------------------------------------------------- */
2946{
2947 Object *ob = context_object(C);
2948 bool changed;
2949
2950 changed = vgroup_normalize(ob);
2951
2952 if (changed) {
2956
2957 return OPERATOR_FINISHED;
2958 }
2959 return OPERATOR_CANCELLED;
2960}
2961
2963{
2964 /* identifiers */
2965 ot->name = "Normalize Vertex Group";
2966 ot->idname = "OBJECT_OT_vertex_group_normalize";
2967 ot->description =
2968 "Normalize weights of the active vertex group, so that the highest ones are now 1.0";
2969
2970 /* api callbacks */
2973
2974 /* flags */
2976}
2977
2980/* -------------------------------------------------------------------- */
2984/*
2985 * For a given object, determine which target vertex group to normalize.
2986 */
2988{
2989 /* Default to All Groups. */
2990 eVGroupSelect target_group = WT_VGROUP_ALL;
2991
2992 /* If armature is present, and armature is actively deforming the object
2993 * (i.e armature modifier isn't disabled) use BONE DEFORM. */
2995
2996 int defgroup_tot = BKE_object_defgroup_count(ob);
2997 bool *defgroup_validmap = BKE_object_defgroup_validmap_get(ob, defgroup_tot);
2998
2999 for (int i = 0; i < defgroup_tot; i++) {
3000 if (defgroup_validmap[i] == true) {
3001 target_group = WT_VGROUP_BONE_DEFORM;
3002 break;
3003 }
3004 }
3005 MEM_freeN(defgroup_validmap);
3006 }
3007
3008 return target_group;
3009}
3010
3012{
3013 Object *ob = context_object(C);
3014
3016
3017 RNA_enum_set(op->ptr, "group_select_mode", target_group);
3018
3019 bool lock_active = RNA_boolean_get(op->ptr, "lock_active");
3020 eVGroupSelect subset_type = static_cast<eVGroupSelect>(
3021 RNA_enum_get(op->ptr, "group_select_mode"));
3022 bool changed;
3023 int subset_count, vgroup_tot;
3024 const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3025 ob, subset_type, &vgroup_tot, &subset_count);
3026
3027 changed = vgroup_normalize_all(
3028 ob, vgroup_validmap, vgroup_tot, subset_count, lock_active, op->reports);
3029 MEM_freeN((void *)vgroup_validmap);
3030
3031 if (changed) {
3035
3036 return OPERATOR_FINISHED;
3037 }
3038
3039 /* allow to adjust settings */
3040 return OPERATOR_FINISHED;
3041}
3042
3044{
3045 /* identifiers */
3046 ot->name = "Normalize All Vertex Groups";
3047 ot->idname = "OBJECT_OT_vertex_group_normalize_all";
3048 ot->description =
3049 "Normalize all weights of all vertex groups, "
3050 "so that for each vertex, the sum of all weights is 1.0";
3051
3052 /* api callbacks */
3055
3056 /* flags */
3058
3061 "lock_active",
3062 true,
3063 "Lock Active",
3064 "Keep the values of the active group while normalizing others");
3065}
3066
3069/* -------------------------------------------------------------------- */
3074{
3076
3077 int action = RNA_enum_get(op->ptr, "action");
3078 int mask = RNA_enum_get(op->ptr, "mask");
3079
3080 vgroup_lock_all(ob, action, mask);
3081
3083
3084 return OPERATOR_FINISHED;
3085}
3086
3088 wmOperatorType * /*ot*/,
3089 PointerRNA *ptr)
3090{
3091 int action = RNA_enum_get(ptr, "action");
3092 int mask = RNA_enum_get(ptr, "mask");
3093
3094 /* NOTE: constructing the following string literals can be done in a less verbose way,
3095 * however the resulting strings can't be usefully translated, (via `TIP_`). */
3096 switch (action) {
3097 case VGROUP_LOCK:
3098 switch (mask) {
3099 case VGROUP_MASK_ALL:
3100 return TIP_("Lock all vertex groups of the active object");
3102 return TIP_("Lock selected vertex groups of the active object");
3104 return TIP_("Lock unselected vertex groups of the active object");
3106 return TIP_("Lock selected and unlock unselected vertex groups of the active object");
3107 }
3108 break;
3109 case VGROUP_UNLOCK:
3110 switch (mask) {
3111 case VGROUP_MASK_ALL:
3112 return TIP_("Unlock all vertex groups of the active object");
3114 return TIP_("Unlock selected vertex groups of the active object");
3116 return TIP_("Unlock unselected vertex groups of the active object");
3118 return TIP_("Unlock selected and lock unselected vertex groups of the active object");
3119 }
3120 break;
3121 case VGROUP_TOGGLE:
3122 switch (mask) {
3123 case VGROUP_MASK_ALL:
3124 return TIP_("Toggle locks of all vertex groups of the active object");
3126 return TIP_("Toggle locks of selected vertex groups of the active object");
3128 return TIP_("Toggle locks of unselected vertex groups of the active object");
3130 return TIP_(
3131 "Toggle locks of all and invert unselected vertex groups of the active object");
3132 }
3133 break;
3134 case VGROUP_INVERT:
3135 switch (mask) {
3136 case VGROUP_MASK_ALL:
3137 return TIP_("Invert locks of all vertex groups of the active object");
3140 return TIP_("Invert locks of selected vertex groups of the active object");
3142 return TIP_("Invert locks of unselected vertex groups of the active object");
3143 }
3144 break;
3145 default:
3146 return {};
3147 }
3148 return {};
3149}
3150
3152{
3153 /* identifiers */
3154 ot->name = "Change the Lock On Vertex Groups";
3155 ot->idname = "OBJECT_OT_vertex_group_lock";
3156 ot->description = "Change the lock state of all or some vertex groups of active object";
3157
3158 /* api callbacks */
3162
3163 /* flags */
3165
3167 "action",
3170 "Action",
3171 "Lock action to execute on vertex groups");
3172
3174 "mask",
3177 "Mask",
3178 "Apply the action based on vertex group selection");
3179}
3180
3183/* -------------------------------------------------------------------- */
3188{
3189 Object *ob = context_object(C);
3190 bool auto_assign = RNA_boolean_get(op->ptr, "auto_assign");
3191 bool auto_remove = RNA_boolean_get(op->ptr, "auto_remove");
3192
3193 eVGroupSelect subset_type = static_cast<eVGroupSelect>(
3194 RNA_enum_get(op->ptr, "group_select_mode"));
3195
3196 int subset_count, vgroup_tot;
3197
3198 const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3199 ob, subset_type, &vgroup_tot, &subset_count);
3200 vgroup_invert_subset(ob, vgroup_validmap, vgroup_tot, subset_count, auto_assign, auto_remove);
3201 MEM_freeN((void *)vgroup_validmap);
3202
3206
3207 return OPERATOR_FINISHED;
3208}
3209
3211{
3212 /* identifiers */
3213 ot->name = "Invert Vertex Group";
3214 ot->idname = "OBJECT_OT_vertex_group_invert";
3215 ot->description = "Invert active vertex group's weights";
3216
3217 /* api callbacks */
3220
3221 /* flags */
3223
3226 "auto_assign",
3227 true,
3228 "Add Weights",
3229 "Add vertices from groups that have zero weight before inverting");
3231 "auto_remove",
3232 true,
3233 "Remove Weights",
3234 "Remove vertices from groups that have zero weight after inverting");
3235}
3236
3239/* -------------------------------------------------------------------- */
3244{
3245 const float fac = RNA_float_get(op->ptr, "factor");
3246 const int repeat = RNA_int_get(op->ptr, "repeat");
3247 const eVGroupSelect subset_type = static_cast<eVGroupSelect>(
3248 RNA_enum_get(op->ptr, "group_select_mode"));
3249 const float fac_expand = RNA_float_get(op->ptr, "expand");
3250
3251 const Vector<Object *> objects = object_array_for_wpaint(C);
3252 for (Object *ob : objects) {
3253 int subset_count, vgroup_tot;
3254
3255 const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3256 ob, subset_type, &vgroup_tot, &subset_count);
3257
3258 vgroup_smooth_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac, repeat, fac_expand);
3259 MEM_freeN((void *)vgroup_validmap);
3260
3263 WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
3264 }
3265
3266 return OPERATOR_FINISHED;
3267}
3268
3270{
3271 /* identifiers */
3272 ot->name = "Smooth Vertex Weights";
3273 ot->idname = "OBJECT_OT_vertex_group_smooth";
3274 ot->description = "Smooth weights for selected vertices";
3275
3276 /* api callbacks */
3279
3280 /* flags */
3282
3284 RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0, "Factor", "", 0.0f, 1.0f);
3285 RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
3286
3288 "expand",
3289 0.0f,
3290 -1.0f,
3291 1.0,
3292 "Expand/Contract",
3293 "Expand/contract weights",
3294 -1.0f,
3295 1.0f);
3296}
3297
3300/* -------------------------------------------------------------------- */
3305{
3306 const float limit = RNA_float_get(op->ptr, "limit");
3307 const bool keep_single = RNA_boolean_get(op->ptr, "keep_single");
3308 const eVGroupSelect subset_type = static_cast<eVGroupSelect>(
3309 RNA_enum_get(op->ptr, "group_select_mode"));
3310
3311 const Vector<Object *> objects = object_array_for_wpaint(C);
3312 for (Object *ob : objects) {
3313 int subset_count, vgroup_tot;
3314
3315 const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3316 ob, subset_type, &vgroup_tot, &subset_count);
3317
3318 vgroup_clean_subset(ob, vgroup_validmap, vgroup_tot, subset_count, limit, keep_single);
3319 MEM_freeN((void *)vgroup_validmap);
3320
3323 WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
3324 }
3325
3326 return OPERATOR_FINISHED;
3327}
3328
3330{
3331 /* identifiers */
3332 ot->name = "Clean Vertex Group Weights";
3333 ot->idname = "OBJECT_OT_vertex_group_clean";
3334 ot->description = "Remove vertex group assignments which are not required";
3335
3336 /* api callbacks */
3339
3340 /* flags */
3342
3345 "limit",
3346 0.0f,
3347 0.0f,
3348 1.0,
3349 "Limit",
3350 "Remove vertices which weight is below or equal to this limit",
3351 0.0f,
3352 0.99f);
3354 "keep_single",
3355 false,
3356 "Keep Single",
3357 "Keep verts assigned to at least one group when cleaning");
3358}
3359
3362/* -------------------------------------------------------------------- */
3367{
3368 Object *ob = context_object(C);
3369
3370 const int steps = RNA_int_get(op->ptr, "steps");
3371 eVGroupSelect subset_type = static_cast<eVGroupSelect>(
3372 RNA_enum_get(op->ptr, "group_select_mode"));
3373
3374 int subset_count, vgroup_tot;
3375
3376 const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3377 ob, subset_type, &vgroup_tot, &subset_count);
3378 vgroup_quantize_subset(ob, vgroup_validmap, vgroup_tot, subset_count, steps);
3379 MEM_freeN((void *)vgroup_validmap);
3380
3384
3385 return OPERATOR_FINISHED;
3386}
3387
3389{
3390 /* identifiers */
3391 ot->name = "Quantize Vertex Weights";
3392 ot->idname = "OBJECT_OT_vertex_group_quantize";
3393 ot->description = "Set weights to a fixed number of steps";
3394
3395 /* api callbacks */
3398
3399 /* flags */
3401
3403 RNA_def_int(ot->srna, "steps", 4, 1, 1000, "Steps", "Number of steps between 0 and 1", 1, 100);
3404}
3405
3408/* -------------------------------------------------------------------- */
3413{
3414 const int limit = RNA_int_get(op->ptr, "limit");
3415 const eVGroupSelect subset_type = static_cast<eVGroupSelect>(
3416 RNA_enum_get(op->ptr, "group_select_mode"));
3417 int remove_multi_count = 0;
3418
3419 const Vector<Object *> objects = object_array_for_wpaint(C);
3420 for (Object *ob : objects) {
3421
3422 int subset_count, vgroup_tot;
3423 const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3424 ob, subset_type, &vgroup_tot, &subset_count);
3425 const int remove_count = vgroup_limit_total_subset(
3426 ob, vgroup_validmap, vgroup_tot, subset_count, limit);
3427 MEM_freeN((void *)vgroup_validmap);
3428
3429 if (remove_count != 0) {
3432 WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
3433 }
3434 remove_multi_count += remove_count;
3435 }
3436
3437 if (remove_multi_count) {
3438 BKE_reportf(op->reports,
3439 remove_multi_count ? RPT_INFO : RPT_WARNING,
3440 "%d vertex weights limited",
3441 remove_multi_count);
3442
3443 return OPERATOR_FINISHED;
3444 }
3445
3446 /* NOTE: would normally return canceled, except we want the redo
3447 * UI to show up for users to change */
3448 return OPERATOR_FINISHED;
3449}
3450
3452{
3453 /* identifiers */
3454 ot->name = "Limit Number of Weights per Vertex";
3455 ot->idname = "OBJECT_OT_vertex_group_limit_total";
3456 ot->description =
3457 "Limit deform weights associated with a vertex to a specified number by removing lowest "
3458 "weights";
3459
3460 /* api callbacks */
3463
3464 /* flags */
3466
3468 RNA_def_int(ot->srna, "limit", 4, 1, 32, "Limit", "Maximum number of deform weights", 1, 32);
3469}
3470
3473/* -------------------------------------------------------------------- */
3478{
3479 Object *ob = context_object(C);
3480 int totmirr = 0, totfail = 0;
3481
3482 vgroup_mirror(ob,
3483 RNA_boolean_get(op->ptr, "mirror_weights"),
3484 RNA_boolean_get(op->ptr, "flip_group_names"),
3485 RNA_boolean_get(op->ptr, "all_groups"),
3486 RNA_boolean_get(op->ptr, "use_topology"),
3487 &totmirr,
3488 &totfail);
3489
3490 ED_mesh_report_mirror(op, totmirr, totfail);
3491
3496
3497 return OPERATOR_FINISHED;
3498}
3499
3501{
3502 /* identifiers */
3503 ot->name = "Mirror Vertex Group";
3504 ot->idname = "OBJECT_OT_vertex_group_mirror";
3505 ot->description =
3506 "Mirror vertex group, flip weights and/or names, editing only selected vertices, "
3507 "flipping when both sides are selected otherwise copy from unselected";
3508
3509 /* api callbacks */
3512
3513 /* flags */
3515
3516 /* properties */
3517 RNA_def_boolean(ot->srna, "mirror_weights", true, "Mirror Weights", "Mirror weights");
3519 ot->srna, "flip_group_names", true, "Flip Group Names", "Flip vertex group names");
3520 RNA_def_boolean(ot->srna, "all_groups", false, "All Groups", "Mirror all vertex groups weights");
3522 ot->srna,
3523 "use_topology",
3524 false,
3525 "Topology Mirror",
3526 "Use topology based mirroring (for when both sides of mesh have matching, unique topology)");
3527}
3528
3531/* -------------------------------------------------------------------- */
3536{
3537 Object *obact = context_object(C);
3538 int changed_tot = 0;
3539 int fail = 0;
3540
3541 CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
3542 if (obact != ob && BKE_object_supports_vertex_groups(ob)) {
3543 if (vgroup_array_copy(ob, obact)) {
3547 changed_tot++;
3548 }
3549 else {
3550 fail++;
3551 }
3552 }
3553 }
3555
3556 if ((changed_tot == 0 && fail == 0) || fail) {
3557 BKE_reportf(op->reports,
3558 RPT_ERROR,
3559 "Copy vertex groups to selected: %d done, %d failed (object data must support "
3560 "vertex groups and have matching indices)",
3561 changed_tot,
3562 fail);
3563 }
3564
3565 return OPERATOR_FINISHED;
3566}
3567
3569{
3570 /* identifiers */
3571 ot->name = "Copy Vertex Group to Selected";
3572 ot->idname = "OBJECT_OT_vertex_group_copy_to_selected";
3573 ot->description = "Replace vertex groups of selected objects by vertex groups of active object";
3574
3575 /* api callbacks */
3578
3579 /* flags */
3581}
3582
3585/* -------------------------------------------------------------------- */
3590{
3591 Object *ob = context_object(C);
3592 int nr = RNA_enum_get(op->ptr, "group");
3593
3594 BLI_assert(nr + 1 >= 0);
3596
3599
3600 return OPERATOR_FINISHED;
3601}
3602
3604 PointerRNA * /*ptr*/,
3605 PropertyRNA * /*prop*/,
3606 bool *r_free)
3607{
3608 if (C == nullptr) {
3610 }
3611
3612 Object *ob = context_object(C);
3613 EnumPropertyItem tmp = {0, "", 0, "", ""};
3614 EnumPropertyItem *item = nullptr;
3615 bDeformGroup *def;
3616 int a, totitem = 0;
3617
3618 if (!ob) {
3620 }
3621
3622 const ListBase *defbase = BKE_object_defgroup_list(ob);
3623 for (a = 0, def = static_cast<bDeformGroup *>(defbase->first); def; def = def->next, a++) {
3624 tmp.value = a;
3625 tmp.icon = ICON_GROUP_VERTEX;
3626 tmp.identifier = def->name;
3627 tmp.name = def->name;
3628 RNA_enum_item_add(&item, &totitem, &tmp);
3629 }
3630
3631 RNA_enum_item_end(&item, &totitem);
3632 *r_free = true;
3633
3634 return item;
3635}
3636
3638{
3639 PropertyRNA *prop;
3640
3641 /* identifiers */
3642 ot->name = "Set Active Vertex Group";
3643 ot->idname = "OBJECT_OT_vertex_group_set_active";
3644 ot->description = "Set the active vertex group";
3645
3646 /* api callbacks */
3650
3651 /* flags */
3653
3654 /* properties */
3655 prop = RNA_def_enum(
3656 ot->srna, "group", rna_enum_dummy_NULL_items, 0, "Group", "Vertex group to set as active");
3659 ot->prop = prop;
3660}
3661
3664/* -------------------------------------------------------------------- */
3668/* creates the name_array parameter for vgroup_do_remap, call this before fiddling
3669 * with the order of vgroups then call vgroup_do_remap after */
3670static char *vgroup_init_remap(Object *ob)
3671{
3672 const ListBase *defbase = BKE_object_defgroup_list(ob);
3673 int defbase_tot = BLI_listbase_count(defbase);
3674 char *name_array = static_cast<char *>(
3675 MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * defbase_tot, "sort vgroups"));
3676 char *name;
3677
3678 name = name_array;
3679 LISTBASE_FOREACH (const bDeformGroup *, def, defbase) {
3680 BLI_strncpy(name, def->name, MAX_VGROUP_NAME);
3681 name += MAX_VGROUP_NAME;
3682 }
3683
3684 return name_array;
3685}
3686
3687static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
3688{
3689 MDeformVert *dvert = nullptr;
3690 const bDeformGroup *def;
3691 const ListBase *defbase = BKE_object_defgroup_list(ob);
3692 int defbase_tot = BLI_listbase_count(defbase);
3693
3694 /* Needs a dummy index at the start. */
3695 int *sort_map_update = static_cast<int *>(
3696 MEM_mallocN(sizeof(int) * (defbase_tot + 1), __func__));
3697 int *sort_map = sort_map_update + 1;
3698
3699 const char *name;
3700 int i;
3701
3702 name = name_array;
3703 for (def = static_cast<const bDeformGroup *>(defbase->first), i = 0; def; def = def->next, i++) {
3704 sort_map[i] = BKE_defgroup_name_index(defbase, name);
3705 name += MAX_VGROUP_NAME;
3706
3707 BLI_assert(sort_map[i] != -1);
3708 }
3709
3710 if (ob->type == OB_GREASE_PENCIL) {
3711 /* For Grease Pencil objects we don't have to do anything, because all drawings in the object
3712 * store their own set of #vertex_group_names. So changing the vertex group order on object
3713 * level is just a UI matter, no remapping in drawings is needed. */
3714 }
3715 else if (ob->mode == OB_MODE_EDIT) {
3716 if (ob->type == OB_MESH) {
3718 const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
3719
3720 if (cd_dvert_offset != -1) {
3721 BMIter iter;
3722 BMVert *eve;
3723
3724 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
3725 dvert = static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
3726 if (dvert->totweight) {
3727 BKE_defvert_remap(dvert, sort_map, defbase_tot);
3728 }
3729 }
3730 }
3731 }
3732 else {
3733 BKE_report(op->reports, RPT_ERROR, "Editmode lattice is not supported yet");
3734 MEM_freeN(sort_map_update);
3735 return OPERATOR_CANCELLED;
3736 }
3737 }
3738 else {
3739 int dvert_tot = 0;
3740 /* Grease pencil stores vertex groups separately for each stroke,
3741 * so remap each stroke's weights separately. */
3742 if (ob->type == OB_GPENCIL_LEGACY) {
3743 bGPdata *gpd = static_cast<bGPdata *>(ob->data);
3744 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
3745 LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
3746 LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
3747 dvert = gps->dvert;
3748 dvert_tot = gps->totpoints;
3749 if (dvert) {
3750 while (dvert_tot--) {
3751 if (dvert->totweight) {
3752 BKE_defvert_remap(dvert, sort_map, defbase_tot);
3753 }
3754 dvert++;
3755 }
3756 }
3757 }
3758 }
3759 }
3760 }
3761 else {
3762 BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dvert, &dvert_tot);
3763
3764 /* Create as necessary. */
3765 if (dvert) {
3766 while (dvert_tot--) {
3767 if (dvert->totweight) {
3768 BKE_defvert_remap(dvert, sort_map, defbase_tot);
3769 }
3770 dvert++;
3771 }
3772 }
3773 }
3774 }
3775
3776 /* update users */
3777 for (i = 0; i < defbase_tot; i++) {
3778 sort_map[i]++;
3779 }
3780
3781 sort_map_update[0] = 0;
3782 BKE_object_defgroup_remap_update_users(ob, sort_map_update);
3783
3784 BLI_assert(sort_map_update[BKE_object_defgroup_active_index_get(ob)] >= 0);
3786 sort_map_update[BKE_object_defgroup_active_index_get(ob)]);
3787
3788 MEM_freeN(sort_map_update);
3789
3790 return OPERATOR_FINISHED;
3791}
3792
3793static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr)
3794{
3795 const bDeformGroup *def_a = static_cast<const bDeformGroup *>(def_a_ptr);
3796 const bDeformGroup *def_b = static_cast<const bDeformGroup *>(def_b_ptr);
3797
3798 return BLI_strcasecmp_natural(def_a->name, def_b->name);
3799}
3800
3805static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase)
3806{
3807 if (bonebase == nullptr) {
3809 if (armobj != nullptr) {
3810 bArmature *armature = static_cast<bArmature *>(armobj->data);
3811 bonebase = &armature->bonebase;
3812 }
3813 }
3815
3816 if (bonebase != nullptr) {
3817 LISTBASE_FOREACH_BACKWARD (Bone *, bone, bonebase) {
3819 vgroup_sort_bone_hierarchy(ob, &bone->childbase);
3820
3821 if (dg != nullptr) {
3822 BLI_remlink(defbase, dg);
3823 BLI_addhead(defbase, dg);
3824 }
3825 }
3826 }
3827}
3828
3829enum {
3832};
3833
3835{
3836 Object *ob = context_object(C);
3837 char *name_array;
3838 int ret;
3839 int sort_type = RNA_enum_get(op->ptr, "sort_type");
3840
3841 /* Init remapping. */
3842 name_array = vgroup_init_remap(ob);
3843
3845
3846 /* Sort vgroup names. */
3847 switch (sort_type) {
3848 case SORT_TYPE_NAME:
3850 break;
3852 vgroup_sort_bone_hierarchy(ob, nullptr);
3853 break;
3854 }
3855
3856 /* Remap vgroup data to map to correct names. */
3857 ret = vgroup_do_remap(ob, name_array, op);
3858
3859 if (ret != OPERATOR_CANCELLED) {
3862 }
3863
3864 if (name_array) {
3865 MEM_freeN(name_array);
3866 }
3867
3868 return ret;
3869}
3870
3872{
3873 static const EnumPropertyItem vgroup_sort_type[] = {
3874 {SORT_TYPE_NAME, "NAME", 0, "Name", ""},
3875 {SORT_TYPE_BONEHIERARCHY, "BONE_HIERARCHY", 0, "Bone Hierarchy", ""},
3876 {0, nullptr, 0, nullptr, nullptr},
3877 };
3878
3879 ot->name = "Sort Vertex Groups";
3880 ot->idname = "OBJECT_OT_vertex_group_sort";
3881 ot->description = "Sort vertex groups";
3882
3883 /* api callbacks */
3886
3887 /* flags */
3889
3890 RNA_def_enum(ot->srna, "sort_type", vgroup_sort_type, SORT_TYPE_NAME, "Sort Type", "Sort type");
3891}
3892
3895/* -------------------------------------------------------------------- */
3900{
3901 Object *ob = context_object(C);
3902 bDeformGroup *def;
3903 char *name_array;
3904 int dir = RNA_enum_get(op->ptr, "direction");
3905 int ret = OPERATOR_FINISHED;
3906
3908
3909 def = static_cast<bDeformGroup *>(
3911 if (!def) {
3912 return OPERATOR_CANCELLED;
3913 }
3914
3915 name_array = vgroup_init_remap(ob);
3916
3917 if (BLI_listbase_link_move(defbase, def, dir)) {
3918 ret = vgroup_do_remap(ob, name_array, op);
3919
3920 if (ret != OPERATOR_CANCELLED) {
3923 }
3924 }
3925
3926 if (name_array) {
3927 MEM_freeN(name_array);
3928 }
3929
3930 return ret;
3931}
3932
3934{
3935 static const EnumPropertyItem vgroup_slot_move[] = {
3936 {-1, "UP", 0, "Up", ""},
3937 {1, "DOWN", 0, "Down", ""},
3938 {0, nullptr, 0, nullptr, nullptr},
3939 };
3940
3941 /* identifiers */
3942 ot->name = "Move Vertex Group";
3943 ot->idname = "OBJECT_OT_vertex_group_move";
3944 ot->description = "Move the active vertex group up/down in the list";
3945
3946 /* api callbacks */
3949
3950 /* flags */
3952
3954 "direction",
3955 vgroup_slot_move,
3956 0,
3957 "Direction",
3958 "Direction to move the active vertex group towards");
3959}
3960
3963/* -------------------------------------------------------------------- */
3967static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
3968{
3969 MDeformVert *dvert_act;
3970
3971 Mesh *mesh = static_cast<Mesh *>(ob->data);
3972 int i;
3973
3974 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
3975 const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
3976 BMIter iter;
3977 BMVert *eve, *eve_act;
3978
3979 dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
3980 if (dvert_act == nullptr) {
3981 return;
3982 }
3983
3984 BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
3985 if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && (eve != eve_act)) {
3986 MDeformVert *dvert_dst = static_cast<MDeformVert *>(
3987 BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
3988
3989 BKE_defvert_copy_index(dvert_dst, def_nr, dvert_act, def_nr);
3990
3991 if (mesh->symmetry & ME_SYMMETRY_X) {
3992 ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
3993 }
3994 }
3995 }
3996
3997 if (mesh->symmetry & ME_SYMMETRY_X) {
3998 ED_mesh_defvert_mirror_update_em(ob, eve_act, -1, -1, cd_dvert_offset);
3999 }
4000 }
4001 else {
4002 int v_act;
4003
4004 dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
4005 if (dvert_act == nullptr) {
4006 return;
4007 }
4008
4009 MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write();
4010 const bke::AttributeAccessor attributes = mesh->attributes();
4011 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
4012 ".select_vert", bke::AttrDomain::Point, false);
4013
4014 for (i = 0; i < mesh->verts_num; i++) {
4015 if (select_vert[i] && (&dverts[i] != dvert_act)) {
4016 BKE_defvert_copy_index(&dverts[i], def_nr, dvert_act, def_nr);
4017
4018 if (mesh->symmetry & ME_SYMMETRY_X) {
4020 }
4021 }
4022 }
4023
4024 if (mesh->symmetry & ME_SYMMETRY_X) {
4025 ED_mesh_defvert_mirror_update_ob(ob, -1, v_act);
4026 }
4027 }
4028}
4029
4030static bool check_vertex_group_accessible(wmOperator *op, Object *ob, int def_nr)
4031{
4032 const ListBase *defbase = BKE_object_defgroup_list(ob);
4033 bDeformGroup *dg = static_cast<bDeformGroup *>(BLI_findlink(defbase, def_nr));
4034
4035 if (!dg) {
4036 BKE_report(op->reports, RPT_ERROR, "Invalid vertex group index");
4037 return false;
4038 }
4039
4040 if (dg->flag & DG_LOCK_WEIGHT) {
4041 BKE_report(op->reports, RPT_ERROR, "Vertex group is locked");
4042 return false;
4043 }
4044
4045 return true;
4046}
4047
4049{
4050 Object *ob = context_object(C);
4051 const int def_nr = RNA_int_get(op->ptr, "weight_group");
4052
4053 if (!check_vertex_group_accessible(op, ob, def_nr)) {
4054 return OPERATOR_CANCELLED;
4055 }
4056
4058
4061
4062 return OPERATOR_FINISHED;
4063}
4064
4066{
4067 PropertyRNA *prop;
4068
4069 ot->name = "Paste Weight to Selected";
4070 ot->idname = "OBJECT_OT_vertex_weight_paste";
4071 ot->description =
4072 "Copy this group's weight to other selected vertices (disabled if vertex group is locked)";
4073
4074 /* api callbacks */
4077
4078 /* flags */
4080
4081 prop = RNA_def_int(ot->srna,
4082 "weight_group",
4083 -1,
4084 -1,
4085 INT_MAX,
4086 "Weight Index",
4087 "Index of source weight in active vertex group",
4088 -1,
4089 INT_MAX);
4091}
4092
4095/* -------------------------------------------------------------------- */
4100{
4101 Object *ob = context_object(C);
4102 const int def_nr = RNA_int_get(op->ptr, "weight_group");
4103
4104 if (!check_vertex_group_accessible(op, ob, def_nr)) {
4105 return OPERATOR_CANCELLED;
4106 }
4107
4108 vgroup_remove_weight(ob, def_nr);
4109
4112
4113 return OPERATOR_FINISHED;
4114}
4115
4117{
4118 PropertyRNA *prop;
4119
4120 ot->name = "Delete Weight";
4121 ot->idname = "OBJECT_OT_vertex_weight_delete";
4122 ot->description = "Delete this weight from the vertex (disabled if vertex group is locked)";
4123
4124 /* api callbacks */
4127
4128 /* flags */
4130
4131 prop = RNA_def_int(ot->srna,
4132 "weight_group",
4133 -1,
4134 -1,
4135 INT_MAX,
4136 "Weight Index",
4137 "Index of source weight in active vertex group",
4138 -1,
4139 INT_MAX);
4141}
4142
4145/* -------------------------------------------------------------------- */
4150{
4151 Object *ob = context_object(C);
4152 const int wg_index = RNA_int_get(op->ptr, "weight_group");
4153
4154 if (wg_index != -1) {
4155 BKE_object_defgroup_active_index_set(ob, wg_index + 1);
4158 }
4159
4160 return OPERATOR_FINISHED;
4161}
4162
4164{
4165 PropertyRNA *prop;
4166
4167 ot->name = "Set Active Group";
4168 ot->idname = "OBJECT_OT_vertex_weight_set_active";
4169 ot->description = "Set as active vertex group";
4170
4171 /* api callbacks */
4174
4175 /* flags */
4177
4178 prop = RNA_def_int(ot->srna,
4179 "weight_group",
4180 -1,
4181 -1,
4182 INT_MAX,
4183 "Weight Index",
4184 "Index of source weight in active vertex group",
4185 -1,
4186 INT_MAX);
4188}
4189
4192/* -------------------------------------------------------------------- */
4197{
4198 Object *ob = context_object(C);
4200 eVGroupSelect subset_type = static_cast<eVGroupSelect>(ts->vgroupsubset);
4201 bool changed;
4202
4203 changed = vgroup_normalize_active_vertex(ob, subset_type);
4204
4205 if (changed) {
4208
4209 return OPERATOR_FINISHED;
4210 }
4211 return OPERATOR_CANCELLED;
4212}
4213
4215{
4216
4217 ot->name = "Normalize Active";
4218 ot->idname = "OBJECT_OT_vertex_weight_normalize_active_vertex";
4219 ot->description = "Normalize active vertex's weights";
4220
4221 /* api callbacks */
4224
4225 /* flags */
4227}
4228
4231/* -------------------------------------------------------------------- */
4236{
4237 Object *ob = context_object(C);
4239 eVGroupSelect subset_type = static_cast<eVGroupSelect>(ts->vgroupsubset);
4240
4241 vgroup_copy_active_to_sel(ob, subset_type);
4242
4245
4246 return OPERATOR_FINISHED;
4247}
4248
4250{
4251
4252 ot->name = "Copy Active";
4253 ot->idname = "OBJECT_OT_vertex_weight_copy";
4254 ot->description = "Copy weights from active to selected";
4255
4256 /* api callbacks */
4259
4260 /* flags */
4262}
4263
4266} // namespace blender::ed::object
#define CTX_DATA_BEGIN(C, Type, instance, member)
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
#define CTX_DATA_END
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
const void * CustomData_get_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
support for deformation groups and hooks.
void BKE_defvert_copy_index(MDeformVert *dvert_dst, int defgroup_dst, const MDeformVert *dvert_src, int defgroup_src)
Definition deform.cc:153
void BKE_object_defgroup_active_index_set(Object *ob, int new_index)
Definition deform.cc:606
void BKE_defvert_sync_mapped(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const int *flip_map, int flip_map_num, bool use_ensure)
Definition deform.cc:197
void BKE_defvert_normalize_lock_single(MDeformVert *dvert, const bool *vgroup_subset, int vgroup_num, uint def_nr_lock)
Definition deform.cc:301
int BKE_object_defgroup_active_index_get(const Object *ob)
Definition deform.cc:601
void BKE_defvert_flip(MDeformVert *dvert, const int *flip_map, int flip_map_num)
Definition deform.cc:410
bDeformGroup * BKE_defgroup_duplicate(const bDeformGroup *ingroup)
Definition deform.cc:85
bool BKE_object_supports_vertex_groups(const Object *ob)
Definition deform.cc:457
void BKE_defvert_add_index_notest(MDeformVert *dv, int defgroup, float weight)
Definition deform.cc:846
int BKE_object_defgroup_count(const Object *ob)
Definition deform.cc:596
void BKE_defvert_mirror_subset(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const bool *vgroup_subset, int vgroup_num, const int *flip_map, int flip_map_num)
Definition deform.cc:115
void BKE_defvert_remap(MDeformVert *dvert, const int *map, int map_len)
Definition deform.cc:223
void BKE_defvert_normalize_subset(MDeformVert *dvert, const bool *vgroup_subset, int vgroup_num)
Definition deform.cc:235
int BKE_defgroup_name_index(const ListBase *defbase, blender::StringRef name)
Definition deform.cc:534
const ListBase * BKE_object_defgroup_list(const Object *ob)
Definition deform.cc:579
int BKE_object_defgroup_flip_index(const Object *ob, int index, bool use_default)
Definition deform.cc:708
MDeformWeight * BKE_defvert_ensure_index(MDeformVert *dv, int defgroup)
Definition deform.cc:814
void BKE_object_defgroup_unique_name(bDeformGroup *dg, Object *ob)
Definition deform.cc:752
int * BKE_object_defgroup_flip_map_single(const Object *ob, bool use_default, int defgroup, int *r_flip_map_num)
Definition deform.cc:673
MDeformWeight * BKE_defvert_find_index(const MDeformVert *dv, int defgroup)
Definition deform.cc:795
ListBase * BKE_object_defgroup_list_mutable(Object *ob)
Definition deform.cc:590
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:770
bDeformGroup * BKE_object_defgroup_find_name(const Object *ob, blender::StringRef name)
Definition deform.cc:520
void BKE_defvert_copy_subset(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const bool *vgroup_subset, int vgroup_num)
Definition deform.cc:102
int * BKE_object_defgroup_flip_map_unlocked(const Object *ob, bool use_default, int *r_flip_map_num)
Definition deform.cc:666
void BKE_defvert_copy(MDeformVert *dvert_dst, const MDeformVert *dvert_src)
Definition deform.cc:130
void BKE_defvert_remove_group(MDeformVert *dvert, MDeformWeight *dw)
Definition deform.cc:871
void BKE_defvert_normalize_lock_map(MDeformVert *dvert, const bool *vgroup_subset, int vgroup_num, const bool *lock_flags, int defbase_num)
Definition deform.cc:355
int * BKE_object_defgroup_flip_map(const Object *ob, bool use_default, int *r_flip_map_num)
Definition deform.cc:661
int BKE_object_defgroup_name_index(const Object *ob, blender::StringRef name)
Definition deform.cc:585
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:63
Utility functions for vertex groups in grease pencil objects.
BPoint * BKE_lattice_active_point_get(Lattice *lt)
Definition lattice.cc:582
int BKE_lattice_index_from_uvw(const Lattice *lt, int u, int v, int w)
Definition lattice.cc:195
Mesh * BKE_mesh_from_object(Object *ob)
Object * BKE_modifiers_is_deformed_by_armature(Object *ob)
General operations, lookup, etc. for blender objects.
Object * BKE_object_pose_armature_get(Object *ob)
bool BKE_object_is_in_wpaint_select_vert(const Object *ob)
bool BKE_object_is_in_editmode_vgroup(const Object *ob)
Functions for dealing with objects and deform verts, used by painting and tools.
bool * BKE_object_defgroup_subset_from_select_type(struct Object *ob, enum eVGroupSelect subset_type, int *r_defgroup_tot, int *r_subset_count)
bool BKE_object_defgroup_clear_all(struct Object *ob, bool use_selection)
bool BKE_object_defgroup_array_get(struct ID *id, struct MDeformVert **dvert_arr, int *dvert_tot)
void BKE_object_defgroup_remove(struct Object *ob, struct bDeformGroup *defgroup)
bool * BKE_object_defgroup_validmap_get(struct Object *ob, int defbase_tot)
bool * BKE_object_defgroup_lock_flags_get(struct Object *ob, int defbase_tot)
void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
void BKE_object_defgroup_remap_update_users(struct Object *ob, const int *map)
void BKE_object_defgroup_mirror_selection(struct Object *ob, int defbase_tot, const bool *selection, bool *dg_flags_sel, int *r_dg_flags_sel_tot)
void BKE_object_defgroup_subset_to_index_array(const bool *defgroup_validmap, int defgroup_tot, int *r_defgroup_subset_map)
struct bDeformGroup * BKE_object_defgroup_add(struct Object *ob)
struct MDeformVert * BKE_object_defgroup_data_create(struct ID *id)
void BKE_object_defgroup_remove_all(struct Object *ob)
bool BKE_object_defgroup_clear(struct Object *ob, struct bDeformGroup *dg, bool use_selection)
bool * BKE_object_defgroup_selected_get(struct Object *ob, int defbase_tot, int *r_dg_flags_sel_tot)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition BLI_bitmap.h:41
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition BLI_bitmap.h:65
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition BLI_bitmap.h:82
unsigned int BLI_bitmap
Definition BLI_bitmap.h:17
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:90
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
void void void void void void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void void BLI_listbase_sort(struct ListBase *listbase, int(*cmp)(const void *, const void *)) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
void void void bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL()
Definition listbase.cc:435
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float max_ff(float a, float b)
MINLINE int signum_i(float a)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
int char char int int int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
unsigned int uint
#define CLAMP(a, b, c)
#define UNUSED_FUNCTION(x)
#define IN_RANGE_INCL(a, b, c)
#define LIKELY(x)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_SIZE(stack)
#define STACK_INIT(stack, stack_num)
#define TIP_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_SELECT
Definition DNA_ID.h:1068
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:683
@ ID_ME
@ ID_LT
@ CD_MDEFORMVERT
#define LT_ACTBP_NONE
@ ME_SYMMETRY_X
@ ME_EDIT_PAINT_VERT_SEL
@ ME_EDIT_PAINT_FACE_SEL
@ ME_EDIT_MIRROR_TOPO
#define ME_USING_MIRROR_X_VERTEX_GROUPS(_me)
@ OB_MODE_EDIT
@ OB_MODE_WEIGHT_PAINT
@ OB_MODE_POSE
Object is a sort of wrapper for general info.
@ OB_LATTICE
@ OB_GREASE_PENCIL
@ OB_MESH
@ OB_GPENCIL_LEGACY
#define MAX_VGROUP_NAME
@ DG_LOCK_WEIGHT
#define OB_TYPE_SUPPORT_VGROUP(_type)
eVGroupSelect
@ WT_VGROUP_BONE_SELECT
@ WT_VGROUP_ALL
@ WT_VGROUP_ACTIVE
@ WT_VGROUP_BONE_DEFORM
#define WT_VGROUP_MASK_ALL
MDeformVert * ED_mesh_active_dvert_get_em(Object *ob, BMVert **r_eve)
BMVert * EDBM_verts_mirror_get(BMEditMesh *em, BMVert *v)
void EDBM_verts_mirror_cache_begin(BMEditMesh *em, int axis, bool use_self, bool use_select, bool respecthide, bool use_topology)
void paintvert_flush_flags(Object *ob)
Definition editface.cc:822
int mesh_get_x_mirror_vert(Object *ob, Mesh *mesh_eval, int index, bool use_topology)
Definition meshtools.cc:901
void EDBM_deselect_flush(BMEditMesh *em)
int ED_mesh_mirror_get_vert(Object *ob, int index)
Definition meshtools.cc:971
void ED_mesh_report_mirror(wmOperator *op, int totmirr, int totfail)
void EDBM_verts_mirror_cache_end(BMEditMesh *em)
void EDBM_select_flush(BMEditMesh *em)
MDeformVert * ED_mesh_active_dvert_get_only(Object *ob)
MDeformVert * ED_mesh_active_dvert_get_ob(Object *ob, int *r_index)
BMVert * editbmesh_get_x_mirror_vert(Object *ob, BMEditMesh *em, BMVert *eve, const float co[3], int index, bool use_topology)
Definition meshtools.cc:962
#define WEIGHT_REPLACE
#define WEIGHT_ADD
#define WEIGHT_SUBTRACT
bool ED_operator_object_active_local_editable_ex(bContext *C, const Object *ob)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
def_group
PropertyFlag
Definition RNA_types.hh:201
@ PROP_ENUM_NO_TRANSLATE
Definition RNA_types.hh:321
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ PROP_HIDDEN
Definition RNA_types.hh:239
#define C
Definition RandGen.cpp:29
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_GEOM
Definition WM_types.hh:360
#define ND_DRAW
Definition WM_types.hh:428
#define ND_DATA
Definition WM_types.hh:475
#define ND_VERTEX_GROUP
Definition WM_types.hh:476
#define ND_SELECT
Definition WM_types.hh:474
#define NC_OBJECT
Definition WM_types.hh:346
@ BM_ELEM_HIDDEN
@ BM_ELEM_SELECT
@ BM_ELEM_TAG
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
#define BM_elem_index_get(ele)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_VERTS_OF_MESH
@ BM_EDGES_OF_VERT
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
#define BM_VERT
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
const T * data() const
Definition BLI_array.hh:301
void fill(const T &value) const
Definition BLI_array.hh:261
constexpr bool is_empty() const
Definition BLI_span.hh:261
#define SELECT
#define floorf(x)
#define fabsf(x)
blender::bke::AttrDomain ED_grease_pencil_edit_selection_domain_get(const ToolSettings *tool_settings)
#define GS(x)
Definition iris.cc:202
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
ccl_device_inline float4 mask(const int4 mask, const float4 a)
ccl_device_inline float4 select(const int4 mask, const float4 a, const float4 b)
bool remove_from_vertex_group(Drawing &drawing, StringRef name, bool use_selection)
void select_from_group(Drawing &drawing, const AttrDomain selection_domain, StringRef name, bool select)
void assign_to_vertex_group(Drawing &drawing, StringRef name, float weight)
GroupedSpan< int > build_vert_to_edge_map(Span< int2 > edges, int verts_num, Array< int > &r_offsets, Array< int > &r_indices)
void vgroup_parray_to_weight_array(const MDeformVert **dvert_array, int dvert_tot, float *dvert_weights, int def_nr)
void OBJECT_OT_vertex_weight_paste(wmOperatorType *ot)
static void grease_pencil_clear_from_all_vgroup(Scene &scene, Object &ob, const bool use_selection, const bool all_drawings=false, const bool only_unlocked=false)
void OBJECT_OT_vertex_group_normalize(wmOperatorType *ot)
void OBJECT_OT_vertex_group_sort(wmOperatorType *ot)
void OBJECT_OT_vertex_group_levels(wmOperatorType *ot)
static void vgroup_smooth_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int subset_count, const float fac, const int repeat, const float fac_expand)
static bool object_array_for_wpaint_filter(const Object *ob, void *user_data)
static int vertex_group_select_exec(bContext *C, wmOperator *)
void OBJECT_OT_vertex_weight_set_active(wmOperatorType *ot)
static void vgroup_quantize_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int, const int steps)
static int vertex_group_smooth_exec(bContext *C, wmOperator *op)
static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr)
static bool vgroup_normalize_active_vertex(Object *ob, eVGroupSelect subset_type)
static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
static bool vgroup_normalize(Object *ob)
void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot)
void OBJECT_OT_vertex_group_smooth(wmOperatorType *ot)
void OBJECT_OT_vertex_group_lock(wmOperatorType *ot)
static const EnumPropertyItem vgroup_lock_actions[]
static const EnumPropertyItem * rna_vertex_group_select_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free)
static void vgroup_nr_vert_add(Object *ob, const int def_nr, const int vertnum, const float weight, const int assignmode)
void vgroup_data_clamp_range(ID *id, int total)
void vgroup_parray_from_weight_array(MDeformVert **dvert_array, int dvert_tot, const float *dvert_weights, int def_nr, bool remove_zero)
bool vgroup_array_copy(Object *ob, Object *ob_from)
static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
void vgroup_parray_remove_zero(MDeformVert **dvert_array, int dvert_tot, const bool *vgroup_validmap, int vgroup_tot, float epsilon, bool keep_single)
static int vertex_group_normalize_exec(bContext *C, wmOperator *)
static const EnumPropertyItem * rna_vertex_group_with_single_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free)
bool vgroup_parray_alloc(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, bool use_vert_sel)
void OBJECT_OT_vertex_weight_normalize_active_vertex(wmOperatorType *ot)
static int vertex_group_limit_total_exec(bContext *C, wmOperator *op)
static void mesh_defvert_mirror_update_internal(Object *ob, MDeformVert *dvert_dst, MDeformVert *dvert_src, const int def_nr)
static int vertex_group_assign_new_exec(bContext *C, wmOperator *op)
void OBJECT_OT_vertex_group_assign(wmOperatorType *ot)
bool vgroup_sync_from_pose(Object *ob)
static int vertex_group_levels_exec(bContext *C, wmOperator *op)
void OBJECT_OT_vertex_group_limit_total(wmOperatorType *ot)
static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
static void ED_mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx)
static int vertex_weight_copy_exec(bContext *C, wmOperator *)
static int vertex_group_deselect_exec(bContext *C, wmOperator *)
static int vgroup_limit_total_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int subset_count, const int max_weights)
static void vgroup_duplicate(Object *ob)
static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase)
static const EnumPropertyItem vgroup_lock_mask[]
void OBJECT_OT_vertex_group_copy_to_selected(wmOperatorType *ot)
static bool vertex_group_supported_poll(bContext *C)
void OBJECT_OT_vertex_weight_copy(wmOperatorType *ot)
static int vertex_weight_delete_exec(bContext *C, wmOperator *op)
void vgroup_parray_mirror_assign(Object *ob, MDeformVert **dvert_array, int dvert_tot)
static bool UNUSED_FUNCTION vertex_group_poll_edit(bContext *C)
static int vertex_weight_set_active_exec(bContext *C, wmOperator *op)
static void vgroup_clean_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int, const float epsilon, const bool keep_single)
static int vertex_group_mirror_exec(bContext *C, wmOperator *op)
static int vertex_group_sort_exec(bContext *C, wmOperator *op)
static int vertex_group_quantize_exec(bContext *C, wmOperator *op)
Object * context_object(const bContext *C)
static int vertex_group_remove_from_exec(bContext *C, wmOperator *op)
static void dvert_mirror_op(MDeformVert *dvert, MDeformVert *dvert_mirr, const char sel, const char sel_mirr, const int *flip_map, const int flip_map_len, const bool mirror_weights, const bool flip_vgroups, const bool all_vgroups, const int act_vgroup)
static int vertex_weight_paste_exec(bContext *C, wmOperator *op)
static int vertex_weight_normalize_active_vertex_exec(bContext *C, wmOperator *)
static Lattice * vgroup_edit_lattice(Object *ob)
void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot)
float vgroup_vert_weight(Object *ob, bDeformGroup *dg, int vertnum)
static int vertex_group_clean_exec(bContext *C, wmOperator *op)
static char * vgroup_init_remap(Object *ob)
void OBJECT_OT_vertex_group_deselect(wmOperatorType *ot)
static bool vertex_group_vert_select_poll(bContext *C)
static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type)
static bool vertex_group_poll_ex(bContext *C, Object *ob)
static int vertex_group_lock_exec(bContext *C, wmOperator *op)
static void vgroup_delete_active(Object *ob)
static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op)
void OBJECT_OT_vertex_group_invert(wmOperatorType *ot)
void OBJECT_OT_vertex_group_move(wmOperatorType *ot)
static bool vgroup_normalize_all(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int subset_count, const bool lock_active, ReportList *reports)
static int vertex_group_copy_exec(bContext *C, wmOperator *)
static void grease_pencil_clear_from_vgroup(Scene &scene, Object &ob, bDeformGroup *dg, const bool use_selection, const bool all_drawings=false)
void vgroup_mirror(Object *ob, bool mirror_weights, bool flip_vgroups, bool all_vgroups, bool use_topology, int *r_totmirr, int *r_totfail)
static int vertex_group_invert_exec(bContext *C, wmOperator *op)
void OBJECT_OT_vertex_group_remove_from(wmOperatorType *ot)
const EnumPropertyItem * vgroup_selection_itemf_helper(const bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free, unsigned int selection_mask)
static int vertex_group_remove_exec(bContext *C, wmOperator *op)
static bool vertex_group_vert_select_unlocked_poll(bContext *C)
static int inv_cmp_mdef_vert_weights(const void *a1, const void *a2)
static const EnumPropertyItem * vgroup_itemf(bContext *C, PointerRNA *, PropertyRNA *, bool *r_free)
static void vgroup_invert_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int, const bool auto_assign, const bool auto_remove)
void vgroup_select_by_name(Object *ob, const char *name)
static eVGroupSelect normalize_vertex_group_target(Object *ob)
void OBJECT_OT_vertex_group_assign_new(wmOperatorType *ot)
static void vgroup_operator_subset_select_props(wmOperatorType *ot, bool use_active)
void OBJECT_OT_vertex_weight_delete(wmOperatorType *ot)
static bool vertex_group_vert_poll_ex(bContext *C, const bool needs_select, const short ob_type_flag)
static bool vertex_group_supported_poll_ex(bContext *C, const Object *ob)
static void ED_mesh_defvert_mirror_update_em(Object *ob, BMVert *eve, int def_nr, int vidx, const int cd_dvert_offset)
void OBJECT_OT_vertex_group_copy(wmOperatorType *ot)
void vgroup_parray_mirror_sync(Object *ob, MDeformVert **dvert_array, int dvert_tot, const bool *vgroup_validmap, int vgroup_tot)
static void vgroup_select_verts(const ToolSettings &tool_settings, Object *ob, Scene &scene, int select)
static bool vertex_group_mesh_vert_poll(bContext *C)
static int vgroup_move_exec(bContext *C, wmOperator *op)
static bool vertex_group_poll(bContext *C)
static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum)
void OBJECT_OT_vertex_group_quantize(wmOperatorType *ot)
static Vector< Object * > object_array_for_wpaint(bContext *C)
static void vgroup_levels_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int, const float offset, const float gain)
static std::string vertex_group_lock_get_description(bContext *, wmOperatorType *, PointerRNA *ptr)
void vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode)
static const EnumPropertyItem WT_vertex_group_select_item[]
void OBJECT_OT_vertex_group_remove(wmOperatorType *ot)
void vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
static bool vertex_group_use_vert_sel(Object *ob)
static bool check_vertex_group_accessible(wmOperator *op, Object *ob, int def_nr)
static int vertex_group_add_exec(bContext *C, wmOperator *)
void OBJECT_OT_vertex_group_add(wmOperatorType *ot)
static void vgroup_assign_verts(Object *ob, Scene &scene, const float weight)
blender::Vector< Object * > objects_in_mode_or_selected(bContext *C, bool(*filter_fn)(const Object *ob, void *user_data), void *filter_user_data)
void OBJECT_OT_vertex_group_clean(wmOperatorType *ot)
void OBJECT_OT_vertex_group_select(wmOperatorType *ot)
static void vgroup_remove_weight(Object *ob, const int def_nr)
void vgroup_vert_active_mirror(Object *ob, int def_nr)
static void vgroup_lock_all(Object *ob, int action, int mask)
static bool vertex_group_vert_select_mesh_poll(bContext *C)
static int vertex_group_assign_exec(bContext *C, wmOperator *)
static bool * vgroup_selected_get(Object *ob)
void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot)
static int set_active_group_exec(bContext *C, wmOperator *op)
float wrap(float value, float max, float min)
Definition node_math.h:71
#define IS_BM_VERT_READ(v)
#define IS_ME_VERT_READ(v)
#define IS_ME_VERT_WRITE(v)
#define IS_BM_VERT_WRITE(v)
#define WEIGHT_ACCUMULATE
return ret
int RNA_int_get(PointerRNA *ptr, const char *name)
float RNA_float_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
void RNA_enum_items_add_value(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item, int value)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
const EnumPropertyItem rna_enum_dummy_NULL_items[]
Definition rna_rna.cc:29
static const int steps
#define FLT_MAX
Definition stdcycles.h:14
float co[3]
int totvert
CustomData vdata
uint8_t f1
char name[64]
struct Lattice * latt
const char * identifier
Definition RNA_types.hh:506
const char * name
Definition RNA_types.hh:510
Definition DNA_ID.h:413
struct MDeformVert * dvert
struct EditLatt * editlatt
struct BPoint * def
void * first
struct MDeformWeight * dw
unsigned int def_nr
ustring name
Definition graph/node.h:177
struct ToolSettings * toolsettings
struct bDeformGroup * next
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
std::string(* get_description)(bContext *C, wmOperatorType *ot, PointerRNA *ptr)
Definition WM_types.hh:1074
const char * idname
Definition WM_types.hh:992
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
struct PointerRNA * ptr
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)