Blender V4.5
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
8
9#include <algorithm>
10#include <cmath>
11#include <cstring>
12
13#include "MEM_guardedalloc.h"
14
15#include "DNA_curve_types.h"
16#include "DNA_lattice_types.h"
17#include "DNA_mesh_types.h"
18#include "DNA_meshdata_types.h"
19#include "DNA_object_types.h"
20#include "DNA_scene_types.h"
21
22#include "BLI_array.hh"
23#include "BLI_bitmap.h"
24#include "BLI_listbase.h"
25#include "BLI_string.h"
26#include "BLI_utildefines.h"
28#include "BLI_vector.hh"
29
30#include "BKE_attribute.hh"
31#include "BKE_context.hh"
32#include "BKE_curves.hh"
33#include "BKE_customdata.hh"
34#include "BKE_deform.hh"
35#include "BKE_editmesh.hh"
37#include "BKE_lattice.hh"
38#include "BKE_library.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_curves.hh"
60#include "ED_grease_pencil.hh"
61#include "ED_mesh.hh"
62#include "ED_object.hh"
63#include "ED_object_vgroup.hh"
64#include "ED_screen.hh"
65
66#include "UI_resources.hh"
67
68#include "object_intern.hh"
69
70namespace blender::ed::object {
71
72static bool vertex_group_supported_poll_ex(bContext *C, const Object *ob);
73
74/* -------------------------------------------------------------------- */
77
78static bool object_array_for_wpaint_filter(const Object *ob, void *user_data)
79{
80 bContext *C = static_cast<bContext *>(user_data);
82 return true;
83 }
84 return false;
85}
86
91
93{
94 if (ob->mode == OB_MODE_EDIT) {
95 return true;
96 }
97 if ((ob->type == OB_MESH) &&
99 {
100 return true;
101 }
102 return false;
103}
104
106{
107 Lattice *lt = static_cast<Lattice *>(ob->data);
108 BLI_assert(ob->type == OB_LATTICE);
109 return (lt->editlatt) ? lt->editlatt->latt : lt;
110}
111
113
114/* -------------------------------------------------------------------- */
117
119{
121 if (armobj && (armobj->mode & OB_MODE_POSE)) {
122 bArmature *arm = static_cast<bArmature *>(armobj->data);
123 if (arm->act_bone) {
124 int def_num = BKE_object_defgroup_name_index(ob, arm->act_bone->name);
125 if (def_num != -1) {
127 return true;
128 }
129 }
130 }
131 return false;
132}
133
134void vgroup_data_clamp_range(ID *id, const int total)
135{
136 MDeformVert **dvert_arr;
137 int dvert_tot;
138
139 if (vgroup_parray_alloc(id, &dvert_arr, &dvert_tot, false)) {
140 for (int i = 0; i < dvert_tot; i++) {
141 MDeformVert *dv = dvert_arr[i];
142 for (int j = 0; j < dv->totweight; j++) {
143 if (dv->dw[j].def_nr >= total) {
144 BKE_defvert_remove_group(dv, &dv->dw[j]);
145 j--;
146 }
147 }
148 }
149 }
150}
151
153 MDeformVert ***dvert_arr,
154 int *dvert_tot,
155 const bool use_vert_sel,
156 std::optional<int> current_frame)
157{
158 *dvert_tot = 0;
159 *dvert_arr = nullptr;
160
161 if (id) {
162 switch (GS(id->name)) {
163 case ID_ME: {
164 Mesh *mesh = (Mesh *)id;
165
166 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
167 BMesh *bm = em->bm;
168 const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
169 BMIter iter;
170 BMVert *eve;
171 int i;
172
173 if (cd_dvert_offset == -1) {
174 return false;
175 }
176
177 i = em->bm->totvert;
178
179 *dvert_arr = MEM_malloc_arrayN<MDeformVert *>(i, __func__);
180 *dvert_tot = i;
181
182 i = 0;
183 if (use_vert_sel) {
184 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
185 (*dvert_arr)[i] = BM_elem_flag_test(eve, BM_ELEM_SELECT) ?
186 static_cast<MDeformVert *>(
187 BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)) :
188 nullptr;
189 i++;
190 }
191 }
192 else {
193 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
194 (*dvert_arr)[i] = static_cast<MDeformVert *>(
195 BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
196 i++;
197 }
198 }
199
200 return true;
201 }
202 if (!mesh->deform_verts().is_empty()) {
203 MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write();
204
205 *dvert_tot = mesh->verts_num;
206 *dvert_arr = MEM_malloc_arrayN<MDeformVert *>(mesh->verts_num, __func__);
207
208 if (use_vert_sel) {
209 const bke::AttributeAccessor attributes = mesh->attributes();
210 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
211 ".select_vert", bke::AttrDomain::Point, false);
212
213 for (int i = 0; i < mesh->verts_num; i++) {
214 (*dvert_arr)[i] = select_vert[i] ? &dverts[i] : nullptr;
215 }
216 }
217 else {
218 for (int i = 0; i < mesh->verts_num; i++) {
219 (*dvert_arr)[i] = &dverts[i];
220 }
221 }
222
223 return true;
224 }
225 return false;
226 }
227 case ID_LT: {
228 Lattice *lt = (Lattice *)id;
229 lt = (lt->editlatt) ? lt->editlatt->latt : lt;
230
231 if (lt->dvert) {
232 BPoint *def = lt->def;
233 *dvert_tot = lt->pntsu * lt->pntsv * lt->pntsw;
234 *dvert_arr = MEM_malloc_arrayN<MDeformVert *>((*dvert_tot), __func__);
235
236 if (use_vert_sel) {
237 for (int i = 0; i < *dvert_tot; i++) {
238 (*dvert_arr)[i] = (def->f1 & SELECT) ? &lt->dvert[i] : nullptr;
239 }
240 }
241 else {
242 for (int i = 0; i < *dvert_tot; i++) {
243 (*dvert_arr)[i] = lt->dvert + i;
244 }
245 }
246
247 return true;
248 }
249 return false;
250 }
251 case ID_GP: {
252 if (!current_frame) {
253 return false;
254 }
255 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(id);
256 bke::greasepencil::Layer *layer = grease_pencil->get_active_layer();
257 if (!layer) {
258 return false;
259 }
260 bke::greasepencil::Drawing *drawing = grease_pencil->get_editable_drawing_at(
261 *layer, *current_frame);
262 if (!drawing) {
263 return false;
264 }
266 MutableSpan<MDeformVert> dverts = curves.deform_verts_for_write();
267
268 if (!dverts.is_empty()) {
269 const int points_num = curves.points_num();
270 *dvert_tot = points_num;
271 *dvert_arr = MEM_malloc_arrayN<MDeformVert *>(points_num, __func__);
272
273 for (int i = 0; i < points_num; i++) {
274 (*dvert_arr)[i] = &dverts[i];
275 }
276
277 return true;
278 }
279 return false;
280 }
281
282 default:
283 break;
284 }
285 }
286
287 return false;
288}
289
291 MDeformVert **dvert_array,
292 const int dvert_tot,
293 const bool *vgroup_validmap,
294 const int vgroup_tot)
295{
297 MDeformVert **dvert_array_all = nullptr;
298 int dvert_tot_all;
299
300 /* get an array of all verts, not only selected */
301 if (vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array_all, &dvert_tot_all, false) ==
302 false)
303 {
304 BLI_assert(0);
305 return;
306 }
307 if (em) {
309 }
310
311 int flip_map_len;
312 const int *flip_map = BKE_object_defgroup_flip_map(ob, true, &flip_map_len);
313
314 for (int i_src = 0; i_src < dvert_tot; i_src++) {
315 if (dvert_array[i_src] != nullptr) {
316 /* its selected, check if its mirror exists */
317 int i_dst = ED_mesh_mirror_get_vert(ob, i_src);
318 if (i_dst != -1 && dvert_array_all[i_dst] != nullptr) {
319 /* we found a match! */
320 const MDeformVert *dv_src = dvert_array[i_src];
321 MDeformVert *dv_dst = dvert_array_all[i_dst];
322
324 dv_dst, dv_src, vgroup_validmap, vgroup_tot, flip_map, flip_map_len);
325
326 dvert_array[i_dst] = dvert_array_all[i_dst];
327 }
328 }
329 }
330
331 MEM_freeN(flip_map);
332 MEM_freeN(dvert_array_all);
333}
334
335void vgroup_parray_mirror_assign(Object *ob, MDeformVert **dvert_array, const int dvert_tot)
336{
338 MDeformVert **dvert_array_all = nullptr;
339 int dvert_tot_all;
340
341 /* get an array of all verts, not only selected */
342 if (vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array_all, &dvert_tot_all, false) ==
343 false)
344 {
345 BLI_assert(0);
346 return;
347 }
348 BLI_assert(dvert_tot == dvert_tot_all);
349 if (em) {
351 }
352
353 for (int i = 0; i < dvert_tot; i++) {
354 if (dvert_array[i] == nullptr) {
355 /* its unselected, check if its mirror is */
356 int i_sel = ED_mesh_mirror_get_vert(ob, i);
357 if ((i_sel != -1) && (i_sel != i) && (dvert_array[i_sel])) {
358 /* we found a match! */
359 dvert_array[i] = dvert_array_all[i];
360 }
361 }
362 }
363
364 MEM_freeN(dvert_array_all);
365}
366
368 const int dvert_tot,
369 const bool *vgroup_validmap,
370 const int vgroup_tot,
371 const float epsilon,
372 const bool keep_single)
373{
374 MDeformVert *dv;
375
376 for (int i = 0; i < dvert_tot; i++) {
377 /* in case its not selected */
378 if (!(dv = dvert_array[i])) {
379 continue;
380 }
381
382 int j = dv->totweight;
383
384 while (j--) {
385 MDeformWeight *dw;
386
387 if (keep_single && dv->totweight == 1) {
388 break;
389 }
390
391 dw = dv->dw + j;
392 if ((dw->def_nr < vgroup_tot) && vgroup_validmap[dw->def_nr]) {
393 if (dw->weight <= epsilon) {
395 }
396 }
397 }
398 }
399}
400
401bool vgroup_array_copy(Object *ob, Object *ob_from)
402{
403 MDeformVert **dvert_array_from = nullptr, **dvf;
404 MDeformVert **dvert_array = nullptr, **dv;
405 int dvert_tot_from;
406 int dvert_tot;
407 int i;
409 const ListBase *defbase_src = BKE_object_defgroup_list(ob_from);
410
411 int defbase_tot_from = BLI_listbase_count(defbase_src);
412 int defbase_tot = BLI_listbase_count(defbase_dst);
413 bool new_vgroup = false;
414
415 BLI_assert(ob != ob_from);
416
417 if (ob->data == ob_from->data) {
418 return true;
419 }
420
421 /* In case we copy vgroup between two objects using same data,
422 * we only have to care about object side of things. */
423 if (ob->data != ob_from->data) {
425 static_cast<ID *>(ob_from->data), &dvert_array_from, &dvert_tot_from, false);
426 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, false);
427
428 if ((dvert_array == nullptr) && (dvert_array_from != nullptr) &&
429 BKE_object_defgroup_data_create(static_cast<ID *>(ob->data)))
430 {
431 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, false);
432 new_vgroup = true;
433 }
434
435 if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == nullptr ||
436 dvert_array == nullptr)
437 {
438 if (dvert_array) {
439 MEM_freeN(dvert_array);
440 }
441 if (dvert_array_from) {
442 MEM_freeN(dvert_array_from);
443 }
444
445 if (new_vgroup == true) {
446 /* free the newly added vgroup since it wasn't compatible */
448 }
449
450 /* if true: both are 0 and nothing needs changing, consider this a success */
451 return (dvert_tot == dvert_tot_from);
452 }
453 }
454
455 /* do the copy */
456 BLI_freelistN(defbase_dst);
457 BLI_duplicatelist(defbase_dst, defbase_src);
459
460 if (defbase_tot_from < defbase_tot) {
461 /* correct vgroup indices because the number of vgroups is being reduced. */
462 Array<int> remap(defbase_tot + 1);
463 for (i = 0; i <= defbase_tot_from; i++) {
464 remap[i] = i;
465 }
466 for (; i <= defbase_tot; i++) {
467 remap[i] = 0; /* can't use these, so disable */
468 }
469
471 }
472
473 if (dvert_array_from != nullptr && dvert_array != nullptr) {
474 dvf = dvert_array_from;
475 dv = dvert_array;
476
477 for (i = 0; i < dvert_tot; i++, dvf++, dv++) {
478 MEM_SAFE_FREE((*dv)->dw);
479 *(*dv) = *(*dvf);
480
481 if ((*dv)->dw) {
482 (*dv)->dw = static_cast<MDeformWeight *>(MEM_dupallocN((*dv)->dw));
483 }
484 }
485
486 MEM_freeN(dvert_array);
487 MEM_freeN(dvert_array_from);
488 }
489
490 return true;
491}
492
494 const int dvert_tot,
495 float *dvert_weights,
496 const int def_nr)
497{
498 for (int i = 0; i < dvert_tot; i++) {
499 const MDeformVert *dv = dvert_array[i];
500 dvert_weights[i] = dv ? BKE_defvert_find_weight(dv, def_nr) : 0.0f;
501 }
502}
503
505 const int dvert_tot,
506 const float *dvert_weights,
507 const int def_nr,
508 const bool remove_zero)
509{
510 int i;
511
512 for (i = 0; i < dvert_tot; i++) {
513 MDeformVert *dv = dvert_array[i];
514 if (dv) {
515 if (dvert_weights[i] > 0.0f) {
516 MDeformWeight *dw = BKE_defvert_ensure_index(dv, def_nr);
517 BLI_assert(IN_RANGE_INCL(dvert_weights[i], 0.0f, 1.0f));
518 dw->weight = dvert_weights[i];
519 }
520 else {
521 MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
522 if (dw) {
523 if (remove_zero) {
525 }
526 else {
527 dw->weight = 0.0f;
528 }
529 }
530 }
531 }
532 }
533}
534
535/* TODO: cache flip data to speedup calls within a loop. */
537 MDeformVert *dvert_dst,
538 MDeformVert *dvert_src,
539 const int def_nr)
540{
541 if (def_nr == -1) {
542 /* All vgroups, add groups where needed. */
543 int flip_map_len;
544 int *flip_map = BKE_object_defgroup_flip_map_unlocked(ob, true, &flip_map_len);
545 BKE_defvert_sync_mapped(dvert_dst, dvert_src, flip_map, flip_map_len, true);
546 MEM_freeN(flip_map);
547 }
548 else {
549 /* Single vgroup. */
551 BKE_object_defgroup_flip_index(ob, def_nr, true));
552 if (dw) {
553 dw->weight = BKE_defvert_find_weight(dvert_src, def_nr);
554 }
555 }
556}
557
559 Object *ob, BMVert *eve, int def_nr, int vidx, const int cd_dvert_offset)
560{
561 Mesh *mesh = static_cast<Mesh *>(ob->data);
562 BMEditMesh *em = mesh->runtime->edit_mesh.get();
563 BMVert *eve_mirr;
564 bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
565
566 eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, vidx, use_topology);
567
568 if (eve_mirr && eve_mirr != eve) {
569 MDeformVert *dvert_src = static_cast<MDeformVert *>(
570 BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
571 MDeformVert *dvert_dst = static_cast<MDeformVert *>(
572 BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset));
573 mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr);
574 }
575}
576
577static void mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx)
578{
579 int vidx_mirr;
580 Mesh *mesh = static_cast<Mesh *>(ob->data);
581 bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
582
583 if (vidx == -1) {
584 return;
585 }
586
587 vidx_mirr = mesh_get_x_mirror_vert(ob, nullptr, vidx, use_topology);
588
589 MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write();
590 if ((vidx_mirr) >= 0 && (vidx_mirr != vidx)) {
591 MDeformVert *dvert_src = &dverts[vidx];
592 MDeformVert *dvert_dst = &dverts[vidx_mirr];
593 mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr);
594 }
595}
596
598{
599 Mesh *mesh = static_cast<Mesh *>(ob->data);
600 BMEditMesh *em = mesh->runtime->edit_mesh.get();
601 MDeformVert *dvert_act;
602
603 if (mesh->symmetry & ME_SYMMETRY_X) {
604 if (em) {
605 BMVert *eve_act;
606 dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
607 if (dvert_act) {
608 const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
609 mesh_defvert_mirror_update_em(ob, eve_act, def_nr, -1, cd_dvert_offset);
610 }
611 }
612 else {
613 int v_act;
614 dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
615 if (dvert_act) {
616 mesh_defvert_mirror_update_ob(ob, def_nr, v_act);
617 }
618 }
619 }
620}
621
622static void vgroup_remove_weight(Object *ob, const int def_nr)
623{
624 MDeformVert *dvert_act;
625 MDeformWeight *dw;
626
627 dvert_act = ED_mesh_active_dvert_get_only(ob);
628
629 dw = BKE_defvert_find_index(dvert_act, def_nr);
630 BKE_defvert_remove_group(dvert_act, dw);
631}
632
634{
635 Mesh *mesh = static_cast<Mesh *>(ob->data);
636 BMEditMesh *em = mesh->runtime->edit_mesh.get();
637 BMVert *eve_act;
638 int v_act;
639 MDeformVert *dvert_act;
640 int subset_count, vgroup_tot;
641 const bool *vgroup_validmap;
642
643 if (em) {
644 dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
645 }
646 else {
647 dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
648 }
649
650 if (dvert_act == nullptr) {
651 return false;
652 }
653
655 ob, subset_type, &vgroup_tot, &subset_count);
656
657 bool *lock_flags = BKE_object_defgroup_lock_flags_get(ob, vgroup_tot);
658
659 if (lock_flags) {
660 const ListBase *defbase = BKE_object_defgroup_list(ob);
661 const int defbase_tot = BLI_listbase_count(defbase);
663 dvert_act, vgroup_validmap, vgroup_tot, lock_flags, defbase_tot);
664 MEM_freeN(lock_flags);
665 }
666 else {
667 BKE_defvert_normalize_subset(dvert_act, vgroup_validmap, vgroup_tot);
668 }
669
670 MEM_freeN(vgroup_validmap);
671
672 if (mesh->symmetry & ME_SYMMETRY_X) {
673 if (em) {
674 const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
675 mesh_defvert_mirror_update_em(ob, eve_act, -1, -1, cd_dvert_offset);
676 }
677 else {
678 mesh_defvert_mirror_update_ob(ob, -1, v_act);
679 }
680 }
681
682 return true;
683}
684
685static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type)
686{
687 Mesh *mesh = static_cast<Mesh *>(ob->data);
688 MDeformVert *dvert_act;
689 int i, vgroup_tot, subset_count;
690 const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
691 ob, subset_type, &vgroup_tot, &subset_count);
692
693 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
694 BMIter iter;
695 BMVert *eve, *eve_act;
696 const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
697
698 dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
699 if (dvert_act) {
700 BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
701 if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve != eve_act) {
702 MDeformVert *dv = static_cast<MDeformVert *>(
703 BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
704 BKE_defvert_copy_subset(dv, dvert_act, vgroup_validmap, vgroup_tot);
705 if (mesh->symmetry & ME_SYMMETRY_X) {
706 mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
707 }
708 }
709 }
710 }
711 }
712 else {
713 const bke::AttributeAccessor attributes = mesh->attributes();
714 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
715 ".select_vert", bke::AttrDomain::Point, false);
716
717 int v_act;
718
719 dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
720 if (dvert_act) {
721 MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write();
722 for (i = 0; i < mesh->verts_num; i++) {
723 if (select_vert[i] && &dverts[i] != dvert_act) {
724 BKE_defvert_copy_subset(&dverts[i], dvert_act, vgroup_validmap, vgroup_tot);
725 if (mesh->symmetry & ME_SYMMETRY_X) {
727 }
728 }
729 }
730 }
731 }
732
733 MEM_freeN(vgroup_validmap);
734}
735
737
738/* -------------------------------------------------------------------- */
741
743 {WT_VGROUP_ACTIVE, "ACTIVE", 0, "Active Group", "The active Vertex Group"},
745 "BONE_SELECT",
746 0,
747 "Selected Pose Bones",
748 "All Vertex Groups assigned to Selection"},
750 "BONE_DEFORM",
751 0,
752 "Deform Pose Bones",
753 "All Vertex Groups assigned to Deform Bones"},
754 {WT_VGROUP_ALL, "ALL", 0, "All Groups", "All Vertex Groups"},
755 {0, nullptr, 0, nullptr, nullptr},
756};
757
759 PointerRNA * /*ptr*/,
760 PropertyRNA * /*prop*/,
761 bool *r_free,
762 const uint selection_mask)
763{
764 Object *ob;
765 EnumPropertyItem *item = nullptr;
766 int totitem = 0;
767
768 if (C == nullptr) {
769 /* needed for docs and i18n tools */
771 }
772
773 ob = context_object(C);
774 if (selection_mask & (1 << WT_VGROUP_ACTIVE)) {
776 }
777
778 if (ob) {
780 if (selection_mask & (1 << WT_VGROUP_BONE_SELECT)) {
783 }
784 }
785
787 if (selection_mask & (1 << WT_VGROUP_BONE_DEFORM)) {
790 }
791 }
792 }
793
794 if (selection_mask & (1 << WT_VGROUP_ALL)) {
796 }
797
798 RNA_enum_item_end(&item, &totitem);
799 *r_free = true;
800
801 return item;
802}
803
806 PropertyRNA *prop,
807 bool *r_free)
808{
810}
811
814 PropertyRNA *prop,
815 bool *r_free)
816{
818 C, ptr, prop, r_free, WT_VGROUP_MASK_ALL & ~(1 << WT_VGROUP_ACTIVE));
819}
820
822{
823 PropertyRNA *prop;
824
825 prop = RNA_def_enum(ot->srna,
826 "group_select_mode",
828 use_active ? WT_VGROUP_ACTIVE : WT_VGROUP_ALL,
829 "Subset",
830 "Define which subset of groups shall be used");
831
832 if (use_active) {
834 }
835 else {
837 }
839 ot->prop = prop;
840}
841
843
844/* -------------------------------------------------------------------- */
851
852/* for Mesh in Object mode */
853/* allows editmode for Lattice */
855 Object *ob, const int def_nr, const int vertnum, const float weight, const int assignmode)
856{
857 /* Add the vert to the deform group with the specified number. */
858 MDeformVert *dvert = nullptr;
859 int tot;
860
861 /* Get the vert. */
862 BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dvert, &tot);
863
864 if (dvert == nullptr) {
865 return;
866 }
867
868 /* Check that vertnum is valid before trying to get the relevant dvert. */
869 if ((vertnum < 0) || (vertnum >= tot)) {
870 return;
871 }
872
873 MDeformVert *dv = &dvert[vertnum];
874 MDeformWeight *dw;
875
876 /* Lets first check to see if this vert is already in the weight group - if so lets update it. */
877 dw = BKE_defvert_find_index(dv, def_nr);
878
879 if (dw) {
880 switch (assignmode) {
881 case WEIGHT_REPLACE:
882 dw->weight = weight;
883 break;
884 case WEIGHT_ADD:
885 dw->weight += weight;
886 dw->weight = std::min(dw->weight, 1.0f);
887 break;
888 case WEIGHT_SUBTRACT:
889 dw->weight -= weight;
890 /* If the weight is zero or less than remove the vert from the deform group. */
891 if (dw->weight <= 0.0f) {
893 }
894 break;
895 }
896 }
897 else {
898 /* If the vert wasn't in the deform group then we must take a different form of action. */
899
900 switch (assignmode) {
901 case WEIGHT_SUBTRACT:
902 /* If we are subtracting then we don't need to do anything. */
903 return;
904
905 case WEIGHT_REPLACE:
906 case WEIGHT_ADD:
907 /* If we are doing an additive assignment, then we need to create the deform weight. */
908
909 /* We checked if the vertex was added before so no need to test again, simply add. */
910 BKE_defvert_add_index_notest(dv, def_nr, weight);
911 break;
912 }
913 }
914}
915
916void vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode)
917{
918 /* add the vert to the deform group with the
919 * specified assign mode
920 */
921 const ListBase *defbase = BKE_object_defgroup_list(ob);
922 const int def_nr = BLI_findindex(defbase, dg);
923
924 MDeformVert *dv = nullptr;
925 int tot;
926
927 /* get the deform group number, exit if
928 * it can't be found
929 */
930 if (def_nr != -1) {
931
932 /* if there's no deform verts then create some,
933 */
934 if (BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dv, &tot) && dv == nullptr) {
935 BKE_object_defgroup_data_create(static_cast<ID *>(ob->data));
936 }
937
938 /* call another function to do the work
939 */
940 vgroup_nr_vert_add(ob, def_nr, vertnum, weight, assignmode);
941 }
942}
943
944void vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
945{
946 /* This routine removes the vertex from the specified
947 * deform group.
948 */
949
950 /* TODO(@ideasman42): This is slow in a loop, better pass def_nr directly,
951 * but leave for later. */
952 const ListBase *defbase = BKE_object_defgroup_list(ob);
953 const int def_nr = BLI_findindex(defbase, dg);
954
955 if (def_nr != -1) {
956 MDeformVert *dvert = nullptr;
957 int tot;
958
959 /* get the deform vertices corresponding to the
960 * vertnum
961 */
962 BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dvert, &tot);
963
964 if (dvert) {
965 MDeformVert *dv = &dvert[vertnum];
966 MDeformWeight *dw;
967
968 dw = BKE_defvert_find_index(dv, def_nr);
969 BKE_defvert_remove_group(dv, dw); /* dw can be nullptr */
970 }
971 }
972}
973
974static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum)
975{
976 const MDeformVert *dv = nullptr;
977
978 /* get the deform vertices corresponding to the vertnum */
979 if (ob->type == OB_MESH) {
980 Mesh *mesh = static_cast<Mesh *>(ob->data);
981
982 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
983 const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
984 /* warning, this lookup is _not_ fast */
985
986 if (cd_dvert_offset != -1 && vertnum < em->bm->totvert) {
987 BMVert *eve;
989 eve = BM_vert_at_index(em->bm, vertnum);
990 dv = static_cast<const MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
991 }
992 else {
993 return 0.0f;
994 }
995 }
996 else {
997 const Span<MDeformVert> dverts = mesh->deform_verts();
998 if (!dverts.is_empty()) {
999 if (vertnum >= mesh->verts_num) {
1000 return 0.0f;
1001 }
1002 dv = &dverts[vertnum];
1003 }
1004 }
1005 }
1006 else if (ob->type == OB_LATTICE) {
1007 Lattice *lt = vgroup_edit_lattice(ob);
1008
1009 if (lt->dvert) {
1010 if (vertnum >= lt->pntsu * lt->pntsv * lt->pntsw) {
1011 return 0.0f;
1012 }
1013 dv = &lt->dvert[vertnum];
1014 }
1015 }
1016
1017 if (dv) {
1018 MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
1019 if (dw) {
1020 return dw->weight;
1021 }
1022 }
1023
1024 return -1;
1025}
1026
1027float vgroup_vert_weight(Object *ob, bDeformGroup *dg, int vertnum)
1028{
1029 const ListBase *defbase = BKE_object_defgroup_list(ob);
1030 const int def_nr = BLI_findindex(defbase, dg);
1031
1032 if (def_nr == -1) {
1033 return -1;
1034 }
1035
1036 return get_vert_def_nr(ob, def_nr, vertnum);
1037}
1038
1039void vgroup_select_by_name(Object *ob, const char *name)
1040{
1041 /* NOTE: `actdef == 0` signals on painting to create a new one,
1042 * if a bone in pose-mode is selected. */
1044}
1045
1047
1048/* -------------------------------------------------------------------- */
1051
1053 const ToolSettings &tool_settings,
1054 const bDeformGroup *def_group,
1055 const bool select,
1056 Object &object)
1057{
1058 using namespace bke;
1059 using namespace ed::greasepencil;
1061 &tool_settings);
1062 GreasePencil *grease_pencil = static_cast<GreasePencil *>(object.data);
1063
1064 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, *grease_pencil);
1065 for (MutableDrawingInfo &info : drawings) {
1066 bke::CurvesGeometry &curves = info.drawing.strokes_for_write();
1067 ListBase &vertex_group_names = curves.vertex_group_names;
1068
1069 const int def_nr = BKE_defgroup_name_index(&vertex_group_names, def_group->name);
1070 if (def_nr < 0) {
1071 /* No vertices assigned to the group in this drawing. */
1072 continue;
1073 }
1074
1075 const Span<MDeformVert> dverts = curves.deform_verts();
1076 if (dverts.is_empty()) {
1077 continue;
1078 }
1079
1080 GSpanAttributeWriter selection = ed::curves::ensure_selection_attribute(
1081 curves, selection_domain, CD_PROP_BOOL);
1082 switch (selection_domain) {
1083 case AttrDomain::Point:
1084 threading::parallel_for(curves.points_range(), 4096, [&](const IndexRange range) {
1085 for (const int point_i : range) {
1086 if (BKE_defvert_find_index(&dverts[point_i], def_nr)) {
1087 selection.span.typed<bool>()[point_i] = select;
1088 }
1089 }
1090 });
1091 break;
1092 case AttrDomain::Curve: {
1093 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
1094 threading::parallel_for(curves.curves_range(), 1024, [&](const IndexRange range) {
1095 for (const int curve_i : range) {
1096 const IndexRange points = points_by_curve[curve_i];
1097 bool any_point_in_group = false;
1098 for (const int point_i : points) {
1099 if (BKE_defvert_find_index(&dverts[point_i], def_nr)) {
1100 any_point_in_group = true;
1101 break;
1102 }
1103 }
1104 if (any_point_in_group) {
1105 selection.span.typed<bool>()[curve_i] = select;
1106 }
1107 }
1108 });
1109 break;
1110 }
1111 default:
1113 break;
1114 }
1115 selection.finish();
1116 }
1117
1118 DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY);
1119}
1120
1121/* only in editmode */
1122static void vgroup_select_verts(const ToolSettings &tool_settings,
1123 Object *ob,
1124 Scene &scene,
1125 int select)
1126{
1127 const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
1128
1129 const ListBase *defbase = BKE_object_defgroup_list(ob);
1130 const bDeformGroup *def_group = static_cast<bDeformGroup *>(BLI_findlink(defbase, def_nr));
1131 if (!def_group) {
1132 return;
1133 }
1134
1135 if (ob->type == OB_MESH) {
1136 Mesh *mesh = static_cast<Mesh *>(ob->data);
1137
1138 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
1139 const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
1140
1141 if (cd_dvert_offset != -1) {
1142 BMIter iter;
1143 BMVert *eve;
1144
1145 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
1146 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
1147 MDeformVert *dv = static_cast<MDeformVert *>(
1148 BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
1149 if (BKE_defvert_find_index(dv, def_nr)) {
1150 BM_vert_select_set(em->bm, eve, select);
1151 }
1152 }
1153 }
1154
1155 /* this has to be called, because this function operates on vertices only */
1156 if (select) {
1157 EDBM_select_flush(em); /* vertices to edges/faces */
1158 }
1159 else {
1161 }
1162 }
1163 }
1164 else {
1165 const Span<MDeformVert> dverts = mesh->deform_verts();
1166 if (!dverts.is_empty()) {
1167 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
1168 const VArray<bool> hide_vert = *attributes.lookup_or_default<bool>(
1169 ".hide_vert", bke::AttrDomain::Point, false);
1170 bke::SpanAttributeWriter<bool> select_vert =
1171 attributes.lookup_or_add_for_write_only_span<bool>(".select_vert",
1173
1174 for (const int i : select_vert.span.index_range()) {
1175 if (!hide_vert[i]) {
1176 if (BKE_defvert_find_index(&dverts[i], def_nr)) {
1177 select_vert.span[i] = select;
1178 }
1179 }
1180 }
1181
1182 select_vert.finish();
1184 }
1185 }
1186 }
1187 else if (ob->type == OB_LATTICE) {
1188 Lattice *lt = vgroup_edit_lattice(ob);
1189
1190 if (lt->dvert) {
1191 MDeformVert *dv;
1192 BPoint *bp, *actbp = BKE_lattice_active_point_get(lt);
1193 int a, tot;
1194
1195 dv = lt->dvert;
1196
1197 tot = lt->pntsu * lt->pntsv * lt->pntsw;
1198 for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) {
1199 if (BKE_defvert_find_index(dv, def_nr)) {
1200 if (select) {
1201 bp->f1 |= SELECT;
1202 }
1203 else {
1204 bp->f1 &= ~SELECT;
1205 if (actbp && bp == actbp) {
1206 lt->actbp = LT_ACTBP_NONE;
1207 }
1208 }
1209 }
1210 }
1211 }
1212 }
1213 else if (ob->type == OB_GREASE_PENCIL) {
1214 vgroup_grease_pencil_select_verts(scene, tool_settings, def_group, select, *ob);
1215 }
1216}
1217
1218static void vgroup_duplicate(Object *ob)
1219{
1220 bDeformGroup *dg, *cdg;
1221 char name[sizeof(dg->name)];
1222 MDeformWeight *dw_org, *dw_cpy;
1223 MDeformVert **dvert_array = nullptr;
1224 int i, idg, icdg, dvert_tot = 0;
1225
1227
1228 dg = static_cast<bDeformGroup *>(
1230 if (!dg) {
1231 return;
1232 }
1233
1234 if (!strstr(dg->name, "_copy")) {
1235 SNPRINTF(name, "%s_copy", dg->name);
1236 }
1237 else {
1238 STRNCPY(name, dg->name);
1239 }
1240
1241 cdg = BKE_defgroup_duplicate(dg);
1242 STRNCPY(cdg->name, name);
1244
1245 BLI_addtail(defbase, cdg);
1246
1250
1251 /* TODO(@ideasman42): we might want to allow only copy selected verts here? */
1252 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, false);
1253
1254 if (dvert_array) {
1255 for (i = 0; i < dvert_tot; i++) {
1256 MDeformVert *dv = dvert_array[i];
1257 dw_org = BKE_defvert_find_index(dv, idg);
1258 if (dw_org) {
1259 /* #BKE_defvert_ensure_index re-allocates org so need to store the weight first. */
1260 const float weight = dw_org->weight;
1261 dw_cpy = BKE_defvert_ensure_index(dv, icdg);
1262 dw_cpy->weight = weight;
1263 }
1264 }
1265
1266 MEM_freeN(dvert_array);
1267 }
1268}
1269
1270static bool vgroup_normalize(Object *ob)
1271{
1272 MDeformWeight *dw;
1273 MDeformVert *dv, **dvert_array = nullptr;
1274 int dvert_tot = 0;
1275 const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
1276
1277 const bool use_vert_sel = vertex_group_use_vert_sel(ob);
1278
1279 const ListBase *defbase = BKE_object_defgroup_list(ob);
1280 if (!BLI_findlink(defbase, def_nr)) {
1281 return false;
1282 }
1283
1284 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
1285
1286 if (dvert_array) {
1287 float weight_max = 0.0f;
1288
1289 for (int i = 0; i < dvert_tot; i++) {
1290
1291 /* in case its not selected */
1292 if (!(dv = dvert_array[i])) {
1293 continue;
1294 }
1295
1296 dw = BKE_defvert_find_index(dv, def_nr);
1297 if (dw) {
1298 weight_max = max_ff(dw->weight, weight_max);
1299 }
1300 }
1301
1302 if (weight_max > 0.0f) {
1303 for (int i = 0; i < dvert_tot; i++) {
1304
1305 /* in case its not selected */
1306 if (!(dv = dvert_array[i])) {
1307 continue;
1308 }
1309
1310 dw = BKE_defvert_find_index(dv, def_nr);
1311 if (dw) {
1312 dw->weight /= weight_max;
1313
1314 /* in case of division errors with very low weights */
1315 CLAMP(dw->weight, 0.0f, 1.0f);
1316 }
1317 }
1318 }
1319
1320 MEM_freeN(dvert_array);
1321
1322 return true;
1323 }
1324
1325 return false;
1326}
1327
1329 const bool *vgroup_validmap,
1330 const int vgroup_tot,
1331 const int /*subset_count*/,
1332 const float offset,
1333 const float gain)
1334{
1335 MDeformWeight *dw;
1336 MDeformVert *dv, **dvert_array = nullptr;
1337 int dvert_tot = 0;
1338
1339 const bool use_vert_sel = vertex_group_use_vert_sel(ob);
1340 const bool use_mirror = (ob->type == OB_MESH) ?
1341 (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
1342 false;
1343
1344 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
1345
1346 if (dvert_array) {
1347
1348 for (int i = 0; i < dvert_tot; i++) {
1349 /* in case its not selected */
1350 if (!(dv = dvert_array[i])) {
1351 continue;
1352 }
1353
1354 int j = vgroup_tot;
1355 while (j--) {
1356 if (vgroup_validmap[j]) {
1357 dw = BKE_defvert_find_index(dv, j);
1358 if (dw) {
1359 dw->weight = gain * (dw->weight + offset);
1360
1361 CLAMP(dw->weight, 0.0f, 1.0f);
1362 }
1363 }
1364 }
1365 }
1366
1367 if (use_mirror && use_vert_sel) {
1368 vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, vgroup_validmap, vgroup_tot);
1369 }
1370
1371 MEM_freeN(dvert_array);
1372 }
1373}
1374
1376 const bool *vgroup_validmap,
1377 const int vgroup_tot,
1378 const bool lock_active,
1380 std::optional<int> current_frame = {})
1381{
1382 MDeformVert *dv, **dvert_array = nullptr;
1383 int i, dvert_tot = 0;
1384 const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
1385 const bool use_vert_sel = vertex_group_use_vert_sel(ob);
1386
1387 vgroup_parray_alloc(
1388 static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel, current_frame);
1389
1390 if (dvert_array) {
1391 const ListBase *defbase = BKE_object_defgroup_list(ob);
1392 const int defbase_tot = BLI_listbase_count(defbase);
1393 bool *lock_flags = BKE_object_defgroup_lock_flags_get(ob, defbase_tot);
1394 bool changed = false;
1395
1396 if ((lock_active == true) && (lock_flags != nullptr) && (def_nr < defbase_tot)) {
1397 lock_flags[def_nr] = true;
1398 }
1399
1400 if (lock_flags) {
1401 for (i = 0; i < defbase_tot; i++) {
1402 if (lock_flags[i] == false) {
1403 break;
1404 }
1405 }
1406
1407 if (i == defbase_tot) {
1408 BKE_report(reports, RPT_ERROR, "All groups are locked");
1409 goto finally;
1410 }
1411 }
1412
1413 for (i = 0; i < dvert_tot; i++) {
1414 /* in case its not selected */
1415 if ((dv = dvert_array[i])) {
1416 if (lock_flags) {
1417 BKE_defvert_normalize_lock_map(dv, vgroup_validmap, vgroup_tot, lock_flags, defbase_tot);
1418 }
1419 else if (lock_active) {
1420 BKE_defvert_normalize_lock_single(dv, vgroup_validmap, vgroup_tot, def_nr);
1421 }
1422 else {
1423 BKE_defvert_normalize_subset(dv, vgroup_validmap, vgroup_tot);
1424 }
1425 }
1426 }
1427
1428 changed = true;
1429
1430 finally:
1431 if (lock_flags) {
1432 MEM_freeN(lock_flags);
1433 }
1434
1435 MEM_freeN(dvert_array);
1436
1437 return changed;
1438 }
1439
1440 return false;
1441}
1442
1452 const bool lock_active,
1454 std::optional<int> current_frame = {})
1455{
1456 int r_defgroup_tot = BKE_object_defgroup_count(ob);
1457 bool *defgroup_validmap = BKE_object_defgroup_validmap_get(ob, r_defgroup_tot);
1458 const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
1459
1460 /* Only auto-normalize if the active group is bone-deforming. */
1461 if (defgroup_validmap[def_nr] == true) {
1462 int subset_count, vgroup_tot;
1463 const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
1464 ob, WT_VGROUP_BONE_DEFORM, &vgroup_tot, &subset_count);
1465
1466 vgroup_normalize_all(ob, vgroup_validmap, vgroup_tot, lock_active, reports, current_frame);
1467 MEM_SAFE_FREE(vgroup_validmap);
1468 }
1469
1470 MEM_SAFE_FREE(defgroup_validmap);
1471}
1472
1473enum {
1478};
1479
1482 "TOGGLE",
1483 0,
1484 "Toggle",
1485 "Unlock all vertex groups if there is at least one locked group, lock all in other case"},
1486 {VGROUP_LOCK, "LOCK", 0, "Lock", "Lock all vertex groups"},
1487 {VGROUP_UNLOCK, "UNLOCK", 0, "Unlock", "Unlock all vertex groups"},
1488 {VGROUP_INVERT, "INVERT", 0, "Invert", "Invert the lock state of all vertex groups"},
1489 {0, nullptr, 0, nullptr, nullptr},
1490};
1491
1492enum {
1497};
1498
1500 {VGROUP_MASK_ALL, "ALL", 0, "All", "Apply action to all vertex groups"},
1501 {VGROUP_MASK_SELECTED, "SELECTED", 0, "Selected", "Apply to selected vertex groups"},
1502 {VGROUP_MASK_UNSELECTED, "UNSELECTED", 0, "Unselected", "Apply to unselected vertex groups"},
1504 "INVERT_UNSELECTED",
1505 0,
1506 "Invert Unselected",
1507 "Apply the opposite of Lock/Unlock to unselected vertex groups"},
1508 {0, nullptr, 0, nullptr, nullptr},
1509};
1510
1512{
1513 int sel_count = 0, defbase_tot = BKE_object_defgroup_count(ob);
1514 bool *mask;
1515
1516 if (ob->mode & OB_MODE_WEIGHT_PAINT) {
1517 mask = BKE_object_defgroup_selected_get(ob, defbase_tot, &sel_count);
1518
1519 /* Mirror the selection if X Mirror is enabled. */
1521
1523 BKE_object_defgroup_mirror_selection(ob, defbase_tot, mask, mask, &sel_count);
1524 }
1525 }
1526 else {
1527 mask = MEM_calloc_arrayN<bool>(defbase_tot, __func__);
1528 }
1529
1530 const int actdef = BKE_object_defgroup_active_index_get(ob);
1531 if (sel_count == 0 && actdef >= 1 && actdef <= defbase_tot) {
1532 mask[actdef - 1] = true;
1533 }
1534
1535 return mask;
1536}
1537
1538static void vgroup_lock_all(Object *ob, int action, int mask)
1539{
1540 bDeformGroup *dg;
1541 bool *selected = nullptr;
1542 int i;
1543
1544 if (mask != VGROUP_MASK_ALL) {
1545 selected = vgroup_selected_get(ob);
1546 }
1547 const ListBase *defbase = BKE_object_defgroup_list(ob);
1548
1549 if (action == VGROUP_TOGGLE) {
1550 action = VGROUP_LOCK;
1551
1552 for (dg = static_cast<bDeformGroup *>(defbase->first), i = 0; dg; dg = dg->next, i++) {
1553 switch (mask) {
1556 if (!selected[i]) {
1557 continue;
1558 }
1559 break;
1561 if (selected[i]) {
1562 continue;
1563 }
1564 break;
1565 default:
1566 break;
1567 }
1568
1569 if (dg->flag & DG_LOCK_WEIGHT) {
1570 action = VGROUP_UNLOCK;
1571 break;
1572 }
1573 }
1574 }
1575
1576 for (dg = static_cast<bDeformGroup *>(defbase->first), i = 0; dg; dg = dg->next, i++) {
1577 switch (mask) {
1579 if (!selected[i]) {
1580 continue;
1581 }
1582 break;
1584 if (selected[i]) {
1585 continue;
1586 }
1587 break;
1588 default:
1589 break;
1590 }
1591
1592 switch (action) {
1593 case VGROUP_LOCK:
1594 dg->flag |= DG_LOCK_WEIGHT;
1595 break;
1596 case VGROUP_UNLOCK:
1597 dg->flag &= ~DG_LOCK_WEIGHT;
1598 break;
1599 case VGROUP_INVERT:
1600 dg->flag ^= DG_LOCK_WEIGHT;
1601 break;
1602 }
1603
1604 if (mask == VGROUP_MASK_INVERT_UNSELECTED && !selected[i]) {
1605 dg->flag ^= DG_LOCK_WEIGHT;
1606 }
1607 }
1608
1609 if (selected) {
1610 MEM_freeN(selected);
1611 }
1612}
1613
1615 const bool *vgroup_validmap,
1616 const int vgroup_tot,
1617 const int /*subset_count*/,
1618 const bool auto_assign,
1619 const bool auto_remove)
1620{
1621 MDeformWeight *dw;
1622 MDeformVert *dv, **dvert_array = nullptr;
1623 int dvert_tot = 0;
1624 const bool use_vert_sel = vertex_group_use_vert_sel(ob);
1625 const bool use_mirror = (ob->type == OB_MESH) ?
1626 (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
1627 false;
1628
1629 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
1630
1631 if (dvert_array) {
1632 for (int i = 0; i < dvert_tot; i++) {
1633 /* in case its not selected */
1634 if (!(dv = dvert_array[i])) {
1635 continue;
1636 }
1637
1638 int j = vgroup_tot;
1639 while (j--) {
1640
1641 if (vgroup_validmap[j]) {
1642 if (auto_assign) {
1643 dw = BKE_defvert_ensure_index(dv, j);
1644 }
1645 else {
1646 dw = BKE_defvert_find_index(dv, j);
1647 }
1648
1649 if (dw) {
1650 dw->weight = 1.0f - dw->weight;
1651 CLAMP(dw->weight, 0.0f, 1.0f);
1652 }
1653 }
1654 }
1655 }
1656
1657 if (use_mirror && use_vert_sel) {
1658 vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, vgroup_validmap, vgroup_tot);
1659 }
1660
1661 if (auto_remove) {
1662 vgroup_parray_remove_zero(dvert_array, dvert_tot, vgroup_validmap, vgroup_tot, 0.0f, false);
1663 }
1664
1665 MEM_freeN(dvert_array);
1666 }
1667}
1668
1670 const bool *vgroup_validmap,
1671 const int vgroup_tot,
1672 const int subset_count,
1673 const float fac,
1674 const int repeat,
1675 const float fac_expand)
1676{
1677 /* Caller must check, while it's not an error it will do nothing. */
1678 BLI_assert(vgroup_tot > 0 && subset_count > 0);
1679
1680 const float ifac = 1.0f - fac;
1681 MDeformVert **dvert_array = nullptr;
1682 int dvert_tot = 0;
1683 Array<int, 32> vgroup_subset_map(subset_count);
1684 Array<float, 32> vgroup_subset_weights(subset_count);
1685 const bool use_mirror = (ob->type == OB_MESH) ?
1686 (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
1687 false;
1688 const bool use_select = vertex_group_use_vert_sel(ob);
1689 const bool use_hide = use_select;
1690
1691 const int expand_sign = signum_i(fac_expand);
1692 const float expand = fabsf(fac_expand);
1693 const float iexpand = 1.0f - expand;
1694
1696 BMesh *bm = em ? em->bm : nullptr;
1697 Mesh *mesh = em ? nullptr : static_cast<Mesh *>(ob->data);
1698
1699 float *weight_accum_prev;
1700 float *weight_accum_curr;
1701
1702 uint subset_index;
1703
1704 /* vertex indices that will be smoothed, (only to avoid iterating over verts that do nothing) */
1705 uint *verts_used;
1706 STACK_DECLARE(verts_used);
1707
1708 BKE_object_defgroup_subset_to_index_array(vgroup_validmap, vgroup_tot, vgroup_subset_map.data());
1709 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, false);
1710 vgroup_subset_weights.fill(0.0f);
1711
1712 Array<int> vert_to_edge_offsets;
1713 Array<int> vert_to_edge_indices;
1714 GroupedSpan<int> emap;
1715 if (bm) {
1718 }
1719 else {
1721 mesh->edges(), mesh->verts_num, vert_to_edge_offsets, vert_to_edge_indices);
1722 }
1723
1724 weight_accum_prev = MEM_malloc_arrayN<float>(dvert_tot, __func__);
1725 weight_accum_curr = MEM_malloc_arrayN<float>(dvert_tot, __func__);
1726
1727 verts_used = MEM_malloc_arrayN<uint>(dvert_tot, __func__);
1728 STACK_INIT(verts_used, dvert_tot);
1729
1730#define IS_BM_VERT_READ(v) (use_hide ? (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == 0) : true)
1731#define IS_BM_VERT_WRITE(v) (use_select ? (BM_elem_flag_test(v, BM_ELEM_SELECT) != 0) : true)
1732
1733 const bool *hide_vert = mesh ? (const bool *)CustomData_get_layer_named(
1734 &mesh->vert_data, CD_PROP_BOOL, ".hide_vert") :
1735 nullptr;
1736
1737#define IS_ME_VERT_READ(v) (use_hide ? !(hide_vert && hide_vert[v]) : true)
1738#define IS_ME_VERT_WRITE(v) (use_select ? select_vert[v] : true)
1739
1740 /* initialize used verts */
1741 if (bm) {
1742 for (int i = 0; i < dvert_tot; i++) {
1744 if (IS_BM_VERT_WRITE(v)) {
1745 BMIter eiter;
1746 BMEdge *e;
1747 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
1748 BMVert *v_other = BM_edge_other_vert(e, v);
1749 if (IS_BM_VERT_READ(v_other)) {
1750 STACK_PUSH(verts_used, i);
1751 break;
1752 }
1753 }
1754 }
1755 }
1756 }
1757 else {
1758 const bke::AttributeAccessor attributes = mesh->attributes();
1759 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
1760 ".select_vert", bke::AttrDomain::Point, false);
1761
1762 const Span<int2> edges = mesh->edges();
1763 for (int i = 0; i < dvert_tot; i++) {
1764 if (IS_ME_VERT_WRITE(i)) {
1765 for (int j = 0; j < emap[i].size(); j++) {
1766 const int2 &edge = edges[emap[i][j]];
1767 const int i_other = (edge[0] == i) ? edge[1] : edge[0];
1768 if (IS_ME_VERT_READ(i_other)) {
1769 STACK_PUSH(verts_used, i);
1770 break;
1771 }
1772 }
1773 }
1774 }
1775 }
1776
1777 for (subset_index = 0; subset_index < subset_count; subset_index++) {
1778 const int def_nr = vgroup_subset_map[subset_index];
1779 int iter;
1780
1782 (const MDeformVert **)dvert_array, dvert_tot, weight_accum_prev, def_nr);
1783 memcpy(weight_accum_curr, weight_accum_prev, sizeof(*weight_accum_curr) * dvert_tot);
1784
1785 for (iter = 0; iter < repeat; iter++) {
1786 uint *vi_step, *vi_end = verts_used + STACK_SIZE(verts_used);
1787
1788 /* avoid looping over all verts */
1789 // for (i = 0; i < dvert_tot; i++)
1790 for (vi_step = verts_used; vi_step != vi_end; vi_step++) {
1791 const uint i = *vi_step;
1792 float weight_tot = 0.0f;
1793 float weight = 0.0f;
1794
1795#define WEIGHT_ACCUMULATE \
1796 { \
1797 float weight_other = weight_accum_prev[i_other]; \
1798 float tot_factor = 1.0f; \
1799 if (expand_sign == 1) { /* expand */ \
1800 if (weight_other < weight_accum_prev[i]) { \
1801 weight_other = (weight_accum_prev[i] * expand) + (weight_other * iexpand); \
1802 tot_factor = iexpand; \
1803 } \
1804 } \
1805 else if (expand_sign == -1) { /* contract */ \
1806 if (weight_other > weight_accum_prev[i]) { \
1807 weight_other = (weight_accum_prev[i] * expand) + (weight_other * iexpand); \
1808 tot_factor = iexpand; \
1809 } \
1810 } \
1811 weight += tot_factor * weight_other; \
1812 weight_tot += tot_factor; \
1813 } \
1814 ((void)0)
1815
1816 if (bm) {
1818 BMIter eiter;
1819 BMEdge *e;
1820
1821 /* checked already */
1823
1824 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
1825 BMVert *v_other = BM_edge_other_vert(e, v);
1826 if (IS_BM_VERT_READ(v_other)) {
1827 const int i_other = BM_elem_index_get(v_other);
1828
1830 }
1831 }
1832 }
1833 else {
1834 const bke::AttributeAccessor attributes = mesh->attributes();
1835 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
1836 ".select_vert", bke::AttrDomain::Point, false);
1837
1838 int j;
1839 const Span<int2> edges = mesh->edges();
1840
1841 /* checked already */
1843
1844 for (j = 0; j < emap[i].size(); j++) {
1845 const int2 &edge = edges[emap[i][j]];
1846 const int i_other = (edge[0] == i ? edge[1] : edge[0]);
1847 if (IS_ME_VERT_READ(i_other)) {
1849 }
1850 }
1851 }
1852
1853#undef WEIGHT_ACCUMULATE
1854
1855 if (weight_tot != 0.0f) {
1856 weight /= weight_tot;
1857 weight = (weight_accum_prev[i] * ifac) + (weight * fac);
1858
1859 /* should be within range, just clamp because of float precision */
1860 CLAMP(weight, 0.0f, 1.0f);
1861 weight_accum_curr[i] = weight;
1862 }
1863 }
1864
1865 std::swap(weight_accum_curr, weight_accum_prev);
1866 }
1867
1868 vgroup_parray_from_weight_array(dvert_array, dvert_tot, weight_accum_prev, def_nr, true);
1869 }
1870
1871#undef IS_BM_VERT_READ
1872#undef IS_BM_VERT_WRITE
1873#undef IS_ME_VERT_READ
1874#undef IS_ME_VERT_WRITE
1875
1876 MEM_freeN(weight_accum_curr);
1877 MEM_freeN(weight_accum_prev);
1878 MEM_freeN(verts_used);
1879
1880 if (dvert_array) {
1881 MEM_freeN(dvert_array);
1882 }
1883
1884 /* not so efficient to get 'dvert_array' again just so unselected verts are nullptr'd */
1885 if (use_mirror) {
1886 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, true);
1887 vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, vgroup_validmap, vgroup_tot);
1888 if (dvert_array) {
1889 MEM_freeN(dvert_array);
1890 }
1891 }
1892}
1893
1894static int inv_cmp_mdef_vert_weights(const void *a1, const void *a2)
1895{
1896 /* #qsort sorts in ascending order. We want descending order to save a #memcpy
1897 * so this compare function is inverted from the standard greater than comparison #qsort needs.
1898 * A normal compare function is called with two pointer arguments and should return an integer
1899 * less than, equal to, or greater than zero corresponding to whether its first argument is
1900 * considered less than, equal to, or greater than its second argument.
1901 * This does the opposite. */
1902 const MDeformWeight *dw1 = static_cast<const MDeformWeight *>(a1);
1903 const MDeformWeight *dw2 = static_cast<const MDeformWeight *>(a2);
1904
1905 if (dw1->weight < dw2->weight) {
1906 return 1;
1907 }
1908 if (dw1->weight > dw2->weight) {
1909 return -1;
1910 }
1911
1912 /* Compare address for stable sort algorithm. */
1913 if (&dw1 < &dw2) {
1914 return 1;
1915 }
1916 if (&dw1 > &dw2) {
1917 return -1;
1918 }
1919 return 0;
1920}
1921
1922/* Used for limiting the number of influencing bones per vertex when exporting
1923 * skinned meshes. if all_deform_weights is True, limit all deform modifiers
1924 * to max_weights regardless of type, otherwise,
1925 * only limit the number of influencing bones per vertex. */
1927 const bool *vgroup_validmap,
1928 const int vgroup_tot,
1929 const int subset_count,
1930 const int max_weights)
1931{
1932 MDeformVert *dv, **dvert_array = nullptr;
1933 int i, dvert_tot = 0;
1934 const bool use_vert_sel = vertex_group_use_vert_sel(ob);
1935 int remove_tot = 0;
1936
1937 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
1938
1939 if (dvert_array) {
1940 int num_to_drop = 0;
1941
1942 for (i = 0; i < dvert_tot; i++) {
1943
1944 MDeformWeight *dw_temp;
1945 int bone_count = 0, non_bone_count = 0;
1946 int j;
1947
1948 /* in case its not selected */
1949 if (!(dv = dvert_array[i])) {
1950 continue;
1951 }
1952
1953 num_to_drop = subset_count - max_weights;
1954
1955 /* first check if we even need to test further */
1956 if (num_to_drop > 0) {
1957 /* re-pack dw array so that non-bone weights are first, bone-weighted verts at end
1958 * sort the tail, then copy only the truncated array back to dv->dw */
1959 dw_temp = MEM_malloc_arrayN<MDeformWeight>(dv->totweight, __func__);
1960 bone_count = 0;
1961 non_bone_count = 0;
1962 for (j = 0; j < dv->totweight; j++) {
1963 if (LIKELY(dv->dw[j].def_nr < vgroup_tot) && vgroup_validmap[dv->dw[j].def_nr]) {
1964 dw_temp[dv->totweight - 1 - bone_count] = dv->dw[j];
1965 bone_count += 1;
1966 }
1967 else {
1968 dw_temp[non_bone_count] = dv->dw[j];
1969 non_bone_count += 1;
1970 }
1971 }
1972 BLI_assert(bone_count + non_bone_count == dv->totweight);
1973 num_to_drop = bone_count - max_weights;
1974 if (num_to_drop > 0) {
1975 qsort(&dw_temp[non_bone_count],
1976 bone_count,
1977 sizeof(MDeformWeight),
1979 dv->totweight -= num_to_drop;
1980 /* Do we want to clean/normalize here? */
1981 MEM_freeN(dv->dw);
1982 dv->dw = static_cast<MDeformWeight *>(
1983 MEM_reallocN(dw_temp, sizeof(MDeformWeight) * dv->totweight));
1984 remove_tot += num_to_drop;
1985 }
1986 else {
1987 MEM_freeN(dw_temp);
1988 }
1989 }
1990 }
1991 MEM_freeN(dvert_array);
1992 }
1993
1994 return remove_tot;
1995}
1996
1998 const bool *vgroup_validmap,
1999 const int vgroup_tot,
2000 const int /*subset_count*/,
2001 const float epsilon,
2002 const bool keep_single)
2003{
2004 MDeformVert **dvert_array = nullptr;
2005 int dvert_tot = 0;
2006 const bool use_vert_sel = vertex_group_use_vert_sel(ob);
2007 const bool use_mirror = (ob->type == OB_MESH) ?
2008 (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
2009 false;
2010
2011 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
2012
2013 if (dvert_array) {
2014 if (use_mirror && use_vert_sel) {
2015 /* correct behavior in this case isn't well defined
2016 * for now assume both sides are mirrored correctly,
2017 * so cleaning one side also cleans the other */
2018 vgroup_parray_mirror_assign(ob, dvert_array, dvert_tot);
2019 }
2020
2022 dvert_array, dvert_tot, vgroup_validmap, vgroup_tot, epsilon, keep_single);
2023
2024 MEM_freeN(dvert_array);
2025 }
2026}
2027
2029 const bool *vgroup_validmap,
2030 const int vgroup_tot,
2031 const int /*subset_count*/,
2032 const int steps)
2033{
2034 MDeformVert **dvert_array = nullptr;
2035 int dvert_tot = 0;
2036 const bool use_vert_sel = vertex_group_use_vert_sel(ob);
2037 const bool use_mirror = (ob->type == OB_MESH) ?
2038 (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
2039 false;
2040 vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
2041
2042 if (dvert_array) {
2043 const float steps_fl = steps;
2044 MDeformVert *dv;
2045
2046 if (use_mirror && use_vert_sel) {
2047 vgroup_parray_mirror_assign(ob, dvert_array, dvert_tot);
2048 }
2049
2050 for (int i = 0; i < dvert_tot; i++) {
2051 MDeformWeight *dw;
2052
2053 /* in case its not selected */
2054 if (!(dv = dvert_array[i])) {
2055 continue;
2056 }
2057
2058 int j;
2059 for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) {
2060 if ((dw->def_nr < vgroup_tot) && vgroup_validmap[dw->def_nr]) {
2061 dw->weight = floorf((dw->weight * steps_fl) + 0.5f) / steps_fl;
2062 CLAMP(dw->weight, 0.0f, 1.0f);
2063 }
2064 }
2065 }
2066
2067 MEM_freeN(dvert_array);
2068 }
2069}
2070
2071static void dvert_mirror_op(MDeformVert *dvert,
2072 MDeformVert *dvert_mirr,
2073 const char sel,
2074 const char sel_mirr,
2075 const int *flip_map,
2076 const int flip_map_len,
2077 const bool mirror_weights,
2078 const bool flip_vgroups,
2079 const bool all_vgroups,
2080 const int act_vgroup)
2081{
2082 BLI_assert(sel || sel_mirr);
2083
2084 if (sel_mirr && sel) {
2085 /* swap */
2086 if (mirror_weights) {
2087 if (all_vgroups) {
2088 std::swap(*dvert, *dvert_mirr);
2089 }
2090 else {
2091 MDeformWeight *dw = BKE_defvert_find_index(dvert, act_vgroup);
2092 MDeformWeight *dw_mirr = BKE_defvert_find_index(dvert_mirr, act_vgroup);
2093
2094 if (dw && dw_mirr) {
2095 std::swap(dw->weight, dw_mirr->weight);
2096 }
2097 else if (dw) {
2098 dw_mirr = BKE_defvert_ensure_index(dvert_mirr, act_vgroup);
2099 dw_mirr->weight = dw->weight;
2100 BKE_defvert_remove_group(dvert, dw);
2101 }
2102 else if (dw_mirr) {
2103 dw = BKE_defvert_ensure_index(dvert, act_vgroup);
2104 dw->weight = dw_mirr->weight;
2105 BKE_defvert_remove_group(dvert_mirr, dw_mirr);
2106 }
2107 }
2108 }
2109
2110 if (flip_vgroups) {
2111 BKE_defvert_flip(dvert, flip_map, flip_map_len);
2112 BKE_defvert_flip(dvert_mirr, flip_map, flip_map_len);
2113 }
2114 }
2115 else {
2116 /* dvert should always be the target, only swaps pointer */
2117 if (sel_mirr) {
2118 std::swap(dvert, dvert_mirr);
2119 }
2120
2121 if (mirror_weights) {
2122 if (all_vgroups) {
2123 BKE_defvert_copy(dvert, dvert_mirr);
2124 }
2125 else {
2126 BKE_defvert_copy_index(dvert, act_vgroup, dvert_mirr, act_vgroup);
2127 }
2128 }
2129
2130 /* flip map already modified for 'all_vgroups' */
2131 if (flip_vgroups) {
2132 BKE_defvert_flip(dvert, flip_map, flip_map_len);
2133 }
2134 }
2135}
2136
2138 const bool mirror_weights,
2139 const bool flip_vgroups,
2140 const bool all_vgroups,
2141 const bool use_topology,
2142 int *r_totmirr,
2143 int *r_totfail)
2144{
2145 /* TODO: vgroup locking. */
2146
2147 const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
2148 int totmirr = 0, totfail = 0;
2149
2150 *r_totmirr = *r_totfail = 0;
2151
2152 const ListBase *defbase = BKE_object_defgroup_list(ob);
2153
2154 if ((mirror_weights == false && flip_vgroups == false) ||
2155 (BLI_findlink(defbase, def_nr) == nullptr))
2156 {
2157 return;
2158 }
2159
2160 int *flip_map = nullptr;
2161 int flip_map_len;
2162 if (flip_vgroups) {
2163 flip_map = all_vgroups ? BKE_object_defgroup_flip_map(ob, false, &flip_map_len) :
2164 BKE_object_defgroup_flip_map_single(ob, false, def_nr, &flip_map_len);
2165
2166 BLI_assert(flip_map != nullptr);
2167
2168 if (flip_map == nullptr) {
2169 /* something went wrong!, possibly no groups */
2170 return;
2171 }
2172 }
2173 else {
2174 flip_map = nullptr;
2175 flip_map_len = 0;
2176 }
2177
2178 /* only the active group */
2179 if (ob->type == OB_MESH) {
2180 Mesh *mesh = static_cast<Mesh *>(ob->data);
2181
2182 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
2183 const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
2184 BMIter iter;
2185
2186 if (cd_dvert_offset == -1) {
2187 goto cleanup;
2188 }
2189
2190 EDBM_verts_mirror_cache_begin(em, 0, true, false, false, use_topology);
2191
2193
2194 /* Go through the list of edit-vertices and assign them. */
2195 BMVert *eve, *eve_mirr;
2196 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2197 if (!BM_elem_flag_test(eve, BM_ELEM_TAG)) {
2198 if ((eve_mirr = EDBM_verts_mirror_get(em, eve))) {
2199 if (eve_mirr != eve) {
2200 if (!BM_elem_flag_test(eve_mirr, BM_ELEM_TAG)) {
2201 const bool sel = BM_elem_flag_test(eve, BM_ELEM_SELECT);
2202 const bool sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT);
2203
2204 if ((sel || sel_mirr) && (eve != eve_mirr)) {
2206 static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)),
2207 static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset)),
2208 sel,
2209 sel_mirr,
2210 flip_map,
2211 flip_map_len,
2212 mirror_weights,
2213 flip_vgroups,
2214 all_vgroups,
2215 def_nr);
2216 totmirr++;
2217 }
2218
2219 /* don't use these again */
2222 }
2223 }
2224 }
2225 else {
2226 totfail++;
2227 }
2228 }
2229 }
2231 }
2232 else {
2233 /* object mode / weight paint */
2234 const bool use_sel = (mesh->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) !=
2235 0;
2236 if (mesh->deform_verts().is_empty()) {
2237 goto cleanup;
2238 }
2239
2240 BLI_bitmap *vert_tag = BLI_BITMAP_NEW(mesh->verts_num, __func__);
2241 MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write();
2242 const bke::AttributeAccessor attributes = mesh->attributes();
2243 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
2244 ".select_vert", bke::AttrDomain::Point, false);
2245
2246 for (int vidx = 0; vidx < mesh->verts_num; vidx++) {
2247 if (!BLI_BITMAP_TEST(vert_tag, vidx)) {
2248 int vidx_mirr;
2249 if ((vidx_mirr = mesh_get_x_mirror_vert(ob, nullptr, vidx, use_topology)) != -1) {
2250 if (vidx != vidx_mirr) {
2251 if (!BLI_BITMAP_TEST(vert_tag, vidx_mirr)) {
2252 const bool sel = use_sel ? select_vert[vidx] : true;
2253 const bool sel_mirr = use_sel ? select_vert[vidx_mirr] : true;
2254
2255 if (sel || sel_mirr) {
2256 dvert_mirror_op(&dverts[vidx],
2257 &dverts[vidx_mirr],
2258 sel,
2259 sel_mirr,
2260 flip_map,
2261 flip_map_len,
2262 mirror_weights,
2263 flip_vgroups,
2264 all_vgroups,
2265 def_nr);
2266 totmirr++;
2267 }
2268
2269 BLI_BITMAP_ENABLE(vert_tag, vidx);
2270 BLI_BITMAP_ENABLE(vert_tag, vidx_mirr);
2271 }
2272 }
2273 }
2274 else {
2275 totfail++;
2276 }
2277 }
2278 }
2279
2280 MEM_freeN(vert_tag);
2281 }
2282 }
2283 else if (ob->type == OB_LATTICE) {
2284 Lattice *lt = vgroup_edit_lattice(ob);
2285 /* half but found up odd value */
2286
2287 if (lt->pntsu == 1 || lt->dvert == nullptr) {
2288 goto cleanup;
2289 }
2290
2291 /* unlike editmesh we know that by only looping over the first half of
2292 * the 'u' indices it will cover all points except the middle which is
2293 * ok in this case */
2294 int pntsu_half = lt->pntsu / 2;
2295
2296 for (int w = 0; w < lt->pntsw; w++) {
2297 for (int v = 0; v < lt->pntsv; v++) {
2298 for (int u = 0; u < pntsu_half; u++) {
2299 int u_inv = (lt->pntsu - 1) - u;
2300 if (u != u_inv) {
2301 const int i1 = BKE_lattice_index_from_uvw(lt, u, v, w);
2302 const int i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w);
2303
2304 const BPoint *bp = &lt->def[i1];
2305 const BPoint *bp_mirr = &lt->def[i2];
2306
2307 const bool sel = bp->f1 & SELECT;
2308 const bool sel_mirr = bp_mirr->f1 & SELECT;
2309
2310 if (sel || sel_mirr) {
2311 dvert_mirror_op(&lt->dvert[i1],
2312 &lt->dvert[i2],
2313 sel,
2314 sel_mirr,
2315 flip_map,
2316 flip_map_len,
2317 mirror_weights,
2318 flip_vgroups,
2319 all_vgroups,
2320 def_nr);
2321 totmirr++;
2322 }
2323 }
2324 }
2325 }
2326 }
2327 }
2328
2329 /* disabled, confusing when you have an active pose bone */
2330#if 0
2331 /* flip active group index */
2332 if (flip_vgroups && flip_map[def_nr] >= 0) {
2333 ob->actdef = flip_map[def_nr] + 1;
2334 }
2335#endif
2336
2337cleanup:
2338 *r_totmirr = totmirr;
2339 *r_totfail = totfail;
2340
2341 if (flip_map) {
2342 MEM_freeN(flip_map);
2343 }
2344
2345#undef VGROUP_MIRR_OP
2346}
2347
2349{
2350 const ListBase *defbase = BKE_object_defgroup_list(ob);
2351 bDeformGroup *dg = static_cast<bDeformGroup *>(
2353 if (!dg) {
2354 return;
2355 }
2356
2358}
2359
2360/* only in editmode */
2361static void vgroup_assign_verts(Object *ob, Scene &scene, const float weight)
2362{
2363 const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
2364
2365 const ListBase *defbase = BKE_object_defgroup_list(ob);
2366 if (!BLI_findlink(defbase, def_nr)) {
2367 return;
2368 }
2369
2370 if (ob->type == OB_MESH) {
2371 Mesh *mesh = static_cast<Mesh *>(ob->data);
2372
2373 if (mesh->runtime->edit_mesh) {
2374 BMEditMesh *em = mesh->runtime->edit_mesh.get();
2375 int cd_dvert_offset;
2376
2377 BMIter iter;
2378 BMVert *eve;
2379
2382 }
2383
2384 cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
2385
2386 /* Go through the list of edit-vertices and assign them. */
2387 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
2389 MDeformVert *dv;
2390 MDeformWeight *dw;
2391 dv = static_cast<MDeformVert *>(
2392 BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)); /* can be nullptr */
2393 dw = BKE_defvert_ensure_index(dv, def_nr);
2394 if (dw) {
2395 dw->weight = weight;
2396 }
2397 }
2398 }
2399 }
2400 else {
2401 const bke::AttributeAccessor attributes = mesh->attributes();
2402 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
2403 ".select_vert", bke::AttrDomain::Point, false);
2404
2405 MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write();
2406
2407 for (int i = 0; i < mesh->verts_num; i++) {
2408 if (select_vert[i]) {
2409 MDeformWeight *dw;
2410 dw = BKE_defvert_ensure_index(&dverts[i], def_nr);
2411 if (dw) {
2412 dw->weight = weight;
2413 }
2414 }
2415 }
2416 }
2417 }
2418 else if (ob->type == OB_LATTICE) {
2419 Lattice *lt = vgroup_edit_lattice(ob);
2420 MDeformVert *dv;
2421 BPoint *bp;
2422 int a, tot;
2423
2424 if (lt->dvert == nullptr) {
2426 }
2427
2428 dv = lt->dvert;
2429
2430 tot = lt->pntsu * lt->pntsv * lt->pntsw;
2431 for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) {
2432 if (bp->f1 & SELECT) {
2433 MDeformWeight *dw;
2434
2435 dw = BKE_defvert_ensure_index(dv, def_nr);
2436 if (dw) {
2437 dw->weight = weight;
2438 }
2439 }
2440 }
2441 }
2442 else if (ob->type == OB_GREASE_PENCIL) {
2443 GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob->data);
2444 const bDeformGroup *defgroup = static_cast<const bDeformGroup *>(
2446
2447 {
2448 using namespace ed::greasepencil;
2449 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, *grease_pencil);
2450 for (MutableDrawingInfo info : drawings) {
2451 bke::greasepencil::assign_to_vertex_group(info.drawing, defgroup->name, weight);
2452 }
2453 }
2454 }
2455}
2456
2458
2459/* -------------------------------------------------------------------- */
2462
2464{
2466 CTX_wm_operator_poll_msg_set(C, "No active editable object");
2467 return false;
2468 }
2469
2470 if (!OB_TYPE_SUPPORT_VGROUP(ob->type)) {
2471 CTX_wm_operator_poll_msg_set(C, "Object type does not support vertex groups");
2472 return false;
2473 }
2474
2475 /* Data checks. */
2476 const ID *data = static_cast<const ID *>(ob->data);
2477 if (data == nullptr || !ID_IS_EDITABLE(data) || ID_IS_OVERRIDE_LIBRARY(data)) {
2478 CTX_wm_operator_poll_msg_set(C, "Object type \"%s\" does not have editable data");
2479 return false;
2480 }
2481
2482 return true;
2483}
2484
2486{
2487 Object *ob = context_object(C);
2489}
2490
2492{
2494 return false;
2495 }
2496
2497 const ListBase *defbase = BKE_object_defgroup_list(ob);
2498 if (BLI_listbase_is_empty(defbase)) {
2499 CTX_wm_operator_poll_msg_set(C, "Object has no vertex groups");
2500 return false;
2501 }
2502
2503 return true;
2504}
2505
2507{
2508 Object *ob = context_object(C);
2509 return vertex_group_poll_ex(C, ob);
2510}
2511
2513{
2514 Object *ob = context_object(C);
2515
2517 return false;
2518 }
2519
2521}
2522
2523/* editmode _or_ weight paint vertex sel */
2525 const bool needs_select,
2526 const short ob_type_flag)
2527{
2528 Object *ob = context_object(C);
2529
2531 return false;
2532 }
2533
2534 if (ob_type_flag && ((1 << ob->type) & ob_type_flag) == 0) {
2535 return false;
2536 }
2537
2539 return true;
2540 }
2541 if (ob->mode & OB_MODE_WEIGHT_PAINT) {
2542 if (needs_select) {
2544 return true;
2545 }
2546 CTX_wm_operator_poll_msg_set(C, "Vertex select needs to be enabled in weight paint mode");
2547 return false;
2548 }
2549 return true;
2550 }
2551 return false;
2552}
2553
2554#if 0
2555static bool vertex_group_vert_poll(bContext *C)
2556{
2557 return vertex_group_vert_poll_ex(C, false, 0);
2558}
2559#endif
2560
2562{
2563 return vertex_group_vert_poll_ex(C, false, (1 << OB_MESH));
2564}
2565
2567{
2568 return vertex_group_vert_poll_ex(C, true, 0);
2569}
2570
2571#if 0
2572static bool vertex_group_mesh_vert_select_poll(bContext *C)
2573{
2574 return vertex_group_vert_poll_ex(C, true, (1 << OB_MESH));
2575}
2576#endif
2577
2578/* editmode _or_ weight paint vertex sel and active group unlocked */
2580{
2581 Object *ob = context_object(C);
2582
2584 return false;
2585 }
2586
2588 return false;
2589 }
2590
2591 const int def_nr = BKE_object_defgroup_active_index_get(ob);
2592 if (def_nr != 0) {
2593 const ListBase *defbase = BKE_object_defgroup_list(ob);
2594 const bDeformGroup *dg = static_cast<const bDeformGroup *>(BLI_findlink(defbase, def_nr - 1));
2595 if (dg && (dg->flag & DG_LOCK_WEIGHT)) {
2596 CTX_wm_operator_poll_msg_set(C, "The active vertex group is locked");
2597 return false;
2598 }
2599 }
2600 return true;
2601}
2602
2604{
2605 Object *ob = context_object(C);
2606
2608 return false;
2609 }
2610
2611 /* only difference to #vertex_group_vert_select_poll */
2612 if (ob->type != OB_MESH) {
2613 return false;
2614 }
2615
2617}
2618
2620
2621/* -------------------------------------------------------------------- */
2624
2637
2639{
2640 /* identifiers */
2641 ot->name = "Add Vertex Group";
2642 ot->idname = "OBJECT_OT_vertex_group_add";
2643 ot->description = "Add a new vertex group to the active object";
2644
2645 /* API callbacks. */
2647 ot->exec = vertex_group_add_exec;
2648
2649 /* flags */
2650 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2651}
2652
2654
2655/* -------------------------------------------------------------------- */
2658
2660 Object &ob,
2661 bDeformGroup *dg,
2662 const bool use_selection,
2663 const bool all_drawings = false)
2664{
2665 using namespace ed::greasepencil;
2666 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob.data);
2667
2668 if (all_drawings) {
2669 /* When removing vgroup, iterate over all the drawing. */
2670 for (GreasePencilDrawingBase *base : grease_pencil.drawings()) {
2671 if (base->type != GP_DRAWING) {
2672 continue;
2673 }
2674 bke::greasepencil::Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(base)->wrap();
2675 bke::greasepencil::remove_from_vertex_group(drawing, dg->name, use_selection);
2676 }
2677 /* Remove vgroup from the list. */
2679 }
2680 else {
2681 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
2682 for (const MutableDrawingInfo &info : drawings) {
2683 bke::greasepencil::remove_from_vertex_group(info.drawing, dg->name, use_selection);
2684 }
2685 }
2686}
2687
2689 Object &ob,
2690 const bool use_selection,
2691 const bool all_drawings = false,
2692 const bool only_unlocked = false)
2693{
2694 const ListBase *defbase = BKE_object_defgroup_list(&ob);
2695
2696 bDeformGroup *dg = static_cast<bDeformGroup *>(defbase->first);
2697 while (dg) {
2698 bDeformGroup *next_group = dg->next;
2699 if (!only_unlocked || (dg->flag & DG_LOCK_WEIGHT) == 0) {
2700 grease_pencil_clear_from_vgroup(scene, ob, dg, use_selection, all_drawings);
2701 }
2702 dg = next_group;
2703 }
2704}
2705
2707{
2708 Object *ob = context_object(C);
2709 Scene &scene = *CTX_data_scene(C);
2710 const bool all_vgroup = RNA_boolean_get(op->ptr, "all");
2711 const bool only_unlocked = RNA_boolean_get(op->ptr, "all_unlocked");
2712
2713 if (ob->type == OB_GREASE_PENCIL) {
2714 if (all_vgroup || only_unlocked) {
2715 grease_pencil_clear_from_all_vgroup(scene, *ob, false, true, only_unlocked);
2716 }
2717 else {
2718 const ListBase *defbase = BKE_object_defgroup_list(ob);
2719 bDeformGroup *dg = static_cast<bDeformGroup *>(
2721
2722 if (!dg) {
2723 return OPERATOR_CANCELLED;
2724 }
2725 grease_pencil_clear_from_vgroup(scene, *ob, dg, false, true);
2726 }
2727 }
2728 else {
2729 if (all_vgroup || only_unlocked) {
2730 BKE_object_defgroup_remove_all_ex(ob, only_unlocked);
2731 }
2732 else {
2734 }
2735 }
2736
2741
2742 return OPERATOR_FINISHED;
2743}
2744
2746{
2747 /* identifiers */
2748 ot->name = "Remove Vertex Group";
2749 ot->idname = "OBJECT_OT_vertex_group_remove";
2750 ot->description = "Delete the active or all vertex groups from the active object";
2751
2752 /* API callbacks. */
2753 ot->poll = vertex_group_poll;
2755
2756 /* flags */
2757 /* redo operator will fail in this case because vertex groups aren't stored
2758 * in local edit mode stack and toggling "all" property will lead to
2759 * all groups deleted without way to restore them (see #29527, sergey) */
2760 ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
2761
2762 /* properties */
2763 PropertyRNA *prop = RNA_def_boolean(ot->srna, "all", false, "All", "Remove all vertex groups");
2765 prop = RNA_def_boolean(
2766 ot->srna, "all_unlocked", false, "All Unlocked", "Remove all unlocked vertex groups");
2768}
2769
2771
2772/* -------------------------------------------------------------------- */
2775
2777{
2779 Object *ob = context_object(C);
2780 Scene &scene = *CTX_data_scene(C);
2781
2782 vgroup_assign_verts(ob, scene, ts->vgroup_weight);
2783
2784 if (ts->auto_normalize) {
2785 if (ob->type == OB_GREASE_PENCIL) {
2786 const int current_frame = scene.r.cfra;
2787 vgroup_normalize_all_deform_if_active_is_deform(ob, true, op->reports, current_frame);
2788 }
2789 else {
2791 }
2792 }
2793
2796
2797 return OPERATOR_FINISHED;
2798}
2799
2801{
2802 /* identifiers */
2803 ot->name = "Assign to Vertex Group";
2804 ot->idname = "OBJECT_OT_vertex_group_assign";
2805 ot->description = "Assign the selected vertices to the active vertex group";
2806
2807 /* API callbacks. */
2810
2811 /* flags */
2812 /* redo operator will fail in this case because vertex group assignment
2813 * isn't stored in local edit mode stack and toggling "new" property will
2814 * lead to creating plenty of new vertex groups (see #29527, sergey) */
2815 ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
2816}
2817
2819
2820/* -------------------------------------------------------------------- */
2823
2824/* NOTE: just a wrapper around vertex_group_assign_exec(), except we add these to a new group */
2826{
2827 /* create new group... */
2828 Object *ob = context_object(C);
2830
2831 /* assign selection to new group */
2832 return vertex_group_assign_exec(C, op);
2833}
2834
2836{
2837 /* identifiers */
2838 ot->name = "Assign to New Group";
2839 ot->idname = "OBJECT_OT_vertex_group_assign_new";
2840 ot->description = "Assign the selected vertices to a new vertex group";
2841
2842 /* API callbacks. */
2845
2846 /* flags */
2847 /* redo operator will fail in this case because vertex group assignment
2848 * isn't stored in local edit mode stack and toggling "new" property will
2849 * lead to creating plenty of new vertex groups (see #29527, sergey) */
2850 ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
2851}
2852
2854
2855/* -------------------------------------------------------------------- */
2858
2860{
2861 const bool use_all_groups = RNA_boolean_get(op->ptr, "use_all_groups");
2862 const bool use_all_verts = RNA_boolean_get(op->ptr, "use_all_verts");
2863 Scene &scene = *CTX_data_scene(C);
2864
2865 Object *ob = context_object(C);
2866
2867 if (use_all_groups) {
2868 if (ob->type == OB_GREASE_PENCIL) {
2869 grease_pencil_clear_from_all_vgroup(scene, *ob, true);
2870 }
2871 else if (BKE_object_defgroup_clear_all(ob, true) == false) {
2872 return OPERATOR_CANCELLED;
2873 }
2874 }
2875 else {
2876 const ListBase *defbase = BKE_object_defgroup_list(ob);
2877 bDeformGroup *dg = static_cast<bDeformGroup *>(
2879 if (dg == nullptr) {
2880 return OPERATOR_CANCELLED;
2881 }
2882
2883 if (ob->type == OB_GREASE_PENCIL) {
2884 grease_pencil_clear_from_vgroup(scene, *ob, dg, !use_all_verts);
2885 }
2886 else if (BKE_object_defgroup_clear(ob, dg, !use_all_verts) == false) {
2887 return OPERATOR_CANCELLED;
2888 }
2889 }
2890
2892 if (ts->auto_normalize) {
2893 if (ob->type == OB_GREASE_PENCIL) {
2894 const int current_frame = scene.r.cfra;
2895 vgroup_normalize_all_deform_if_active_is_deform(ob, true, op->reports, current_frame);
2896 }
2897 else {
2899 }
2900 }
2901
2904
2905 return OPERATOR_FINISHED;
2906}
2907
2909{
2910 PropertyRNA *prop;
2911 /* identifiers */
2912 ot->name = "Remove from Vertex Group";
2913 ot->idname = "OBJECT_OT_vertex_group_remove_from";
2914 ot->description = "Remove the selected vertices from active or all vertex group(s)";
2915
2916 /* API callbacks. */
2919
2920 /* flags */
2921 /* redo operator will fail in this case because vertex groups assignment
2922 * isn't stored in local edit mode stack and toggling "all" property will lead to
2923 * removing vertices from all groups (see #29527, sergey) */
2924 ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
2925
2926 /* properties */
2927 prop = RNA_def_boolean(
2928 ot->srna, "use_all_groups", false, "All Groups", "Remove from all groups");
2930 prop = RNA_def_boolean(
2931 ot->srna, "use_all_verts", false, "All Vertices", "Clear the active group");
2933}
2934
2936
2937/* -------------------------------------------------------------------- */
2940
2942{
2943 const ToolSettings &tool_settings = *CTX_data_scene(C)->toolsettings;
2944 Object *ob = context_object(C);
2945 Scene &scene = *CTX_data_scene(C);
2946
2947 if (!ob || !ID_IS_EDITABLE(ob) || ID_IS_OVERRIDE_LIBRARY(ob)) {
2948 return OPERATOR_CANCELLED;
2949 }
2950
2951 vgroup_select_verts(tool_settings, ob, scene, 1);
2954
2955 return OPERATOR_FINISHED;
2956}
2957
2959{
2960 /* identifiers */
2961 ot->name = "Select Vertex Group";
2962 ot->idname = "OBJECT_OT_vertex_group_select";
2963 ot->description = "Select all the vertices assigned to the active vertex group";
2964
2965 /* API callbacks. */
2968
2969 /* flags */
2970 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2971}
2972
2974
2975/* -------------------------------------------------------------------- */
2978
2980{
2981 const ToolSettings &tool_settings = *CTX_data_scene(C)->toolsettings;
2982 Object *ob = context_object(C);
2983 Scene &scene = *CTX_data_scene(C);
2984
2985 vgroup_select_verts(tool_settings, ob, scene, 0);
2988
2989 return OPERATOR_FINISHED;
2990}
2991
2993{
2994 /* identifiers */
2995 ot->name = "Deselect Vertex Group";
2996 ot->idname = "OBJECT_OT_vertex_group_deselect";
2997 ot->description = "Deselect all selected vertices assigned to the active vertex group";
2998
2999 /* API callbacks. */
3002
3003 /* flags */
3004 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3005}
3006
3008
3009/* -------------------------------------------------------------------- */
3012
3025
3027{
3028 /* identifiers */
3029 ot->name = "Duplicate Vertex Group";
3030 ot->idname = "OBJECT_OT_vertex_group_copy";
3031 ot->description = "Make a copy of the active vertex group";
3032
3033 /* API callbacks. */
3034 ot->poll = vertex_group_poll;
3035 ot->exec = vertex_group_copy_exec;
3036
3037 /* flags */
3038 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3039}
3040
3042
3043/* -------------------------------------------------------------------- */
3046
3048{
3049 Object *ob = context_object(C);
3050
3051 float offset = RNA_float_get(op->ptr, "offset");
3052 float gain = RNA_float_get(op->ptr, "gain");
3053 eVGroupSelect subset_type = static_cast<eVGroupSelect>(
3054 RNA_enum_get(op->ptr, "group_select_mode"));
3055
3056 int subset_count, vgroup_tot;
3057
3058 const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3059 ob, subset_type, &vgroup_tot, &subset_count);
3060 vgroup_levels_subset(ob, vgroup_validmap, vgroup_tot, subset_count, offset, gain);
3061 MEM_freeN(vgroup_validmap);
3062
3066
3067 return OPERATOR_FINISHED;
3068}
3069
3071{
3072 /* identifiers */
3073 ot->name = "Vertex Group Levels";
3074 ot->idname = "OBJECT_OT_vertex_group_levels";
3075 ot->description =
3076 "Add some offset and multiply with some gain the weights of the active vertex group";
3077
3078 /* API callbacks. */
3079 ot->poll = vertex_group_poll;
3081
3082 /* flags */
3083 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3084
3087 ot->srna, "offset", 0.0f, -1.0, 1.0, "Offset", "Value to add to weights", -1.0f, 1.0f);
3089 ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply weights by", 0.0f, 10.0f);
3090}
3091
3093
3094/* -------------------------------------------------------------------- */
3097
3099{
3100 Object *ob = context_object(C);
3101 bool changed;
3102
3103 changed = vgroup_normalize(ob);
3104
3105 if (changed) {
3109
3110 return OPERATOR_FINISHED;
3111 }
3112 return OPERATOR_CANCELLED;
3113}
3114
3116{
3117 /* identifiers */
3118 ot->name = "Normalize Vertex Group";
3119 ot->idname = "OBJECT_OT_vertex_group_normalize";
3120 ot->description =
3121 "Normalize weights of the active vertex group, so that the highest ones are now 1.0";
3122
3123 /* API callbacks. */
3124 ot->poll = vertex_group_poll;
3126
3127 /* flags */
3128 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3129}
3130
3132
3133/* -------------------------------------------------------------------- */
3136
3137/*
3138 * For a given object, determine which target vertex group to normalize.
3139 */
3141{
3142 /* Default to All Groups. */
3143 eVGroupSelect target_group = WT_VGROUP_ALL;
3144
3145 /* If armature is present, and armature is actively deforming the object
3146 * (i.e armature modifier isn't disabled) use BONE DEFORM. */
3148
3149 int defgroup_tot = BKE_object_defgroup_count(ob);
3150 bool *defgroup_validmap = BKE_object_defgroup_validmap_get(ob, defgroup_tot);
3151
3152 for (int i = 0; i < defgroup_tot; i++) {
3153 if (defgroup_validmap[i] == true) {
3154 target_group = WT_VGROUP_BONE_DEFORM;
3155 break;
3156 }
3157 }
3158 MEM_freeN(defgroup_validmap);
3159 }
3160
3161 return target_group;
3162}
3163
3165{
3166 Object *ob = context_object(C);
3167
3169
3170 RNA_enum_set(op->ptr, "group_select_mode", target_group);
3171
3172 bool lock_active = RNA_boolean_get(op->ptr, "lock_active");
3173 eVGroupSelect subset_type = static_cast<eVGroupSelect>(
3174 RNA_enum_get(op->ptr, "group_select_mode"));
3175 bool changed;
3176 int subset_count, vgroup_tot;
3177 const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3178 ob, subset_type, &vgroup_tot, &subset_count);
3179
3180 if (subset_count == 0) {
3181 BKE_report(op->reports, RPT_ERROR, "No vertex groups to operate on");
3182 changed = false;
3183 }
3184 else {
3185 if (ob->type == OB_GREASE_PENCIL) {
3186 int current_frame = CTX_data_scene(C)->r.cfra;
3187 changed = vgroup_normalize_all(
3188 ob, vgroup_validmap, vgroup_tot, lock_active, op->reports, current_frame);
3189 }
3190 else {
3191 changed = vgroup_normalize_all(ob, vgroup_validmap, vgroup_tot, lock_active, op->reports);
3192 }
3193 }
3194
3195 MEM_freeN(vgroup_validmap);
3196
3197 if (changed) {
3201
3202 return OPERATOR_FINISHED;
3203 }
3204
3205 /* allow to adjust settings */
3206 return OPERATOR_FINISHED;
3207}
3208
3210{
3211 /* identifiers */
3212 ot->name = "Normalize All Vertex Groups";
3213 ot->idname = "OBJECT_OT_vertex_group_normalize_all";
3214 ot->description =
3215 "Normalize all weights of all vertex groups, "
3216 "so that for each vertex, the sum of all weights is 1.0";
3217
3218 /* API callbacks. */
3219 ot->poll = vertex_group_poll;
3221
3222 /* flags */
3223 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3224
3226 RNA_def_boolean(ot->srna,
3227 "lock_active",
3228 true,
3229 "Lock Active",
3230 "Keep the values of the active group while normalizing others");
3231}
3232
3234
3235/* -------------------------------------------------------------------- */
3238
3240{
3241 Object *ob = context_object(C);
3242
3243 int action = RNA_enum_get(op->ptr, "action");
3244 int mask = RNA_enum_get(op->ptr, "mask");
3245
3246 vgroup_lock_all(ob, action, mask);
3247
3249
3250 return OPERATOR_FINISHED;
3251}
3252
3254 wmOperatorType * /*ot*/,
3255 PointerRNA *ptr)
3256{
3257 int action = RNA_enum_get(ptr, "action");
3258 int mask = RNA_enum_get(ptr, "mask");
3259
3260 /* NOTE: constructing the following string literals can be done in a less verbose way,
3261 * however the resulting strings can't be usefully translated, (via `TIP_`). */
3262 switch (action) {
3263 case VGROUP_LOCK:
3264 switch (mask) {
3265 case VGROUP_MASK_ALL:
3266 return TIP_("Lock all vertex groups of the active object");
3268 return TIP_("Lock selected vertex groups of the active object");
3270 return TIP_("Lock unselected vertex groups of the active object");
3272 return TIP_("Lock selected and unlock unselected vertex groups of the active object");
3273 }
3274 break;
3275 case VGROUP_UNLOCK:
3276 switch (mask) {
3277 case VGROUP_MASK_ALL:
3278 return TIP_("Unlock all vertex groups of the active object");
3280 return TIP_("Unlock selected vertex groups of the active object");
3282 return TIP_("Unlock unselected vertex groups of the active object");
3284 return TIP_("Unlock selected and lock unselected vertex groups of the active object");
3285 }
3286 break;
3287 case VGROUP_TOGGLE:
3288 switch (mask) {
3289 case VGROUP_MASK_ALL:
3290 return TIP_("Toggle locks of all vertex groups of the active object");
3292 return TIP_("Toggle locks of selected vertex groups of the active object");
3294 return TIP_("Toggle locks of unselected vertex groups of the active object");
3296 return TIP_(
3297 "Toggle locks of all and invert unselected vertex groups of the active object");
3298 }
3299 break;
3300 case VGROUP_INVERT:
3301 switch (mask) {
3302 case VGROUP_MASK_ALL:
3303 return TIP_("Invert locks of all vertex groups of the active object");
3306 return TIP_("Invert locks of selected vertex groups of the active object");
3308 return TIP_("Invert locks of unselected vertex groups of the active object");
3309 }
3310 break;
3311 default:
3312 return {};
3313 }
3314 return {};
3315}
3316
3318{
3319 /* identifiers */
3320 ot->name = "Change the Lock On Vertex Groups";
3321 ot->idname = "OBJECT_OT_vertex_group_lock";
3322 ot->description = "Change the lock state of all or some vertex groups of active object";
3323
3324 /* API callbacks. */
3325 ot->poll = vertex_group_poll;
3326 ot->exec = vertex_group_lock_exec;
3327 ot->get_description = vertex_group_lock_get_description;
3328
3329 /* flags */
3330 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3331
3332 RNA_def_enum(ot->srna,
3333 "action",
3336 "Action",
3337 "Lock action to execute on vertex groups");
3338
3339 RNA_def_enum(ot->srna,
3340 "mask",
3343 "Mask",
3344 "Apply the action based on vertex group selection");
3345}
3346
3348
3349/* -------------------------------------------------------------------- */
3352
3354{
3355 Object *ob = context_object(C);
3356 bool auto_assign = RNA_boolean_get(op->ptr, "auto_assign");
3357 bool auto_remove = RNA_boolean_get(op->ptr, "auto_remove");
3358
3359 eVGroupSelect subset_type = static_cast<eVGroupSelect>(
3360 RNA_enum_get(op->ptr, "group_select_mode"));
3361
3362 int subset_count, vgroup_tot;
3363
3364 const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3365 ob, subset_type, &vgroup_tot, &subset_count);
3366 vgroup_invert_subset(ob, vgroup_validmap, vgroup_tot, subset_count, auto_assign, auto_remove);
3367 MEM_freeN(vgroup_validmap);
3368
3372
3373 return OPERATOR_FINISHED;
3374}
3375
3377{
3378 /* identifiers */
3379 ot->name = "Invert Vertex Group";
3380 ot->idname = "OBJECT_OT_vertex_group_invert";
3381 ot->description = "Invert active vertex group's weights";
3382
3383 /* API callbacks. */
3384 ot->poll = vertex_group_poll;
3386
3387 /* flags */
3388 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3389
3391 RNA_def_boolean(ot->srna,
3392 "auto_assign",
3393 true,
3394 "Add Weights",
3395 "Add vertices from groups that have zero weight before inverting");
3396 RNA_def_boolean(ot->srna,
3397 "auto_remove",
3398 true,
3399 "Remove Weights",
3400 "Remove vertices from groups that have zero weight after inverting");
3401}
3402
3404
3405/* -------------------------------------------------------------------- */
3408
3410{
3411 const float fac = RNA_float_get(op->ptr, "factor");
3412 const int repeat = RNA_int_get(op->ptr, "repeat");
3413 const eVGroupSelect subset_type = static_cast<eVGroupSelect>(
3414 RNA_enum_get(op->ptr, "group_select_mode"));
3415 const float fac_expand = RNA_float_get(op->ptr, "expand");
3416
3417 bool has_vgroup_multi = false;
3419 for (Object *ob : objects) {
3420 int subset_count, vgroup_tot;
3421
3422 bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3423 ob, subset_type, &vgroup_tot, &subset_count);
3424
3425 if (vgroup_tot) {
3426 const bool *locked_vgroups = BKE_object_defgroup_lock_flags_get(ob, vgroup_tot);
3427 if (locked_vgroups) {
3428 /* Remove locked groups from the vgroup valid map. */
3429 for (int i = 0; i < vgroup_tot; i++) {
3430 if (vgroup_validmap[i] && locked_vgroups[i]) {
3431 vgroup_validmap[i] = false;
3432 subset_count--;
3433 }
3434 }
3435 }
3436 MEM_SAFE_FREE(locked_vgroups);
3437
3438 has_vgroup_multi = true;
3439
3440 if (subset_count) {
3442 ob, vgroup_validmap, vgroup_tot, subset_count, fac, repeat, fac_expand);
3443
3447 }
3448 }
3449
3450 MEM_freeN(vgroup_validmap);
3451 }
3452
3453 /* NOTE: typically we would return canceled if no changes were made (`changed_multi`).
3454 * In this case it's important only to do this if none of the objects *could* be changed.
3455 * TODO: skip meshes without any selected vertices.
3456 *
3457 * The reason this is a special case is returning canceled prevents the `group_select_mode`
3458 * from being changed, where this setting could have been the reason no change was possible. */
3459 if (!has_vgroup_multi) {
3460 BKE_reportf(op->reports, RPT_WARNING, "No meshes with vertex groups found");
3461 return OPERATOR_CANCELLED;
3462 }
3463 return OPERATOR_FINISHED;
3464}
3465
3467{
3468 /* identifiers */
3469 ot->name = "Smooth Vertex Weights";
3470 ot->idname = "OBJECT_OT_vertex_group_smooth";
3471 ot->description = "Smooth weights for selected vertices";
3472
3473 /* API callbacks. */
3476
3477 /* flags */
3478 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3479
3481 RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0, "Factor", "", 0.0f, 1.0f);
3482 RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
3483
3484 RNA_def_float(ot->srna,
3485 "expand",
3486 0.0f,
3487 -1.0f,
3488 1.0,
3489 "Expand/Contract",
3490 "Expand/contract weights",
3491 -1.0f,
3492 1.0f);
3493}
3494
3496
3497/* -------------------------------------------------------------------- */
3500
3502{
3503 const float limit = RNA_float_get(op->ptr, "limit");
3504 const bool keep_single = RNA_boolean_get(op->ptr, "keep_single");
3505 const eVGroupSelect subset_type = static_cast<eVGroupSelect>(
3506 RNA_enum_get(op->ptr, "group_select_mode"));
3507
3509 for (Object *ob : objects) {
3510 int subset_count, vgroup_tot;
3511
3512 const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3513 ob, subset_type, &vgroup_tot, &subset_count);
3514
3515 vgroup_clean_subset(ob, vgroup_validmap, vgroup_tot, subset_count, limit, keep_single);
3516 MEM_freeN(vgroup_validmap);
3517
3521 }
3522
3523 return OPERATOR_FINISHED;
3524}
3525
3527{
3528 /* identifiers */
3529 ot->name = "Clean Vertex Group Weights";
3530 ot->idname = "OBJECT_OT_vertex_group_clean";
3531 ot->description = "Remove vertex group assignments which are not required";
3532
3533 /* API callbacks. */
3534 ot->poll = vertex_group_poll;
3536
3537 /* flags */
3538 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3539
3541 RNA_def_float(ot->srna,
3542 "limit",
3543 0.0f,
3544 0.0f,
3545 1.0,
3546 "Limit",
3547 "Remove vertices which weight is below or equal to this limit",
3548 0.0f,
3549 0.99f);
3550 RNA_def_boolean(ot->srna,
3551 "keep_single",
3552 false,
3553 "Keep Single",
3554 "Keep verts assigned to at least one group when cleaning");
3555}
3556
3558
3559/* -------------------------------------------------------------------- */
3562
3564{
3565 Object *ob = context_object(C);
3566
3567 const int steps = RNA_int_get(op->ptr, "steps");
3568 eVGroupSelect subset_type = static_cast<eVGroupSelect>(
3569 RNA_enum_get(op->ptr, "group_select_mode"));
3570
3571 int subset_count, vgroup_tot;
3572
3573 const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3574 ob, subset_type, &vgroup_tot, &subset_count);
3575 vgroup_quantize_subset(ob, vgroup_validmap, vgroup_tot, subset_count, steps);
3576 MEM_freeN(vgroup_validmap);
3577
3581
3582 return OPERATOR_FINISHED;
3583}
3584
3586{
3587 /* identifiers */
3588 ot->name = "Quantize Vertex Weights";
3589 ot->idname = "OBJECT_OT_vertex_group_quantize";
3590 ot->description = "Set weights to a fixed number of steps";
3591
3592 /* API callbacks. */
3593 ot->poll = vertex_group_poll;
3595
3596 /* flags */
3597 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3598
3600 RNA_def_int(ot->srna, "steps", 4, 1, 1000, "Steps", "Number of steps between 0 and 1", 1, 100);
3601}
3602
3604
3605/* -------------------------------------------------------------------- */
3608
3610{
3611 const int limit = RNA_int_get(op->ptr, "limit");
3612 const eVGroupSelect subset_type = static_cast<eVGroupSelect>(
3613 RNA_enum_get(op->ptr, "group_select_mode"));
3614 int remove_multi_count = 0;
3615
3617 for (Object *ob : objects) {
3618
3619 int subset_count, vgroup_tot;
3620 const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
3621 ob, subset_type, &vgroup_tot, &subset_count);
3622 const int remove_count = vgroup_limit_total_subset(
3623 ob, vgroup_validmap, vgroup_tot, subset_count, limit);
3624 MEM_freeN(vgroup_validmap);
3625
3626 if (remove_count != 0) {
3630 }
3631 remove_multi_count += remove_count;
3632 }
3633
3634 if (remove_multi_count) {
3635 BKE_reportf(op->reports,
3636 remove_multi_count ? RPT_INFO : RPT_WARNING,
3637 "%d vertex weights limited",
3638 remove_multi_count);
3639
3640 return OPERATOR_FINISHED;
3641 }
3642
3643 /* NOTE: would normally return canceled, except we want the redo
3644 * UI to show up for users to change */
3645 return OPERATOR_FINISHED;
3646}
3647
3649{
3650 /* identifiers */
3651 ot->name = "Limit Number of Weights per Vertex";
3652 ot->idname = "OBJECT_OT_vertex_group_limit_total";
3653 ot->description =
3654 "Limit deform weights associated with a vertex to a specified number by removing lowest "
3655 "weights";
3656
3657 /* API callbacks. */
3658 ot->poll = vertex_group_poll;
3660
3661 /* flags */
3662 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3663
3665 RNA_def_int(ot->srna, "limit", 4, 1, 32, "Limit", "Maximum number of deform weights", 1, 32);
3666}
3667
3669
3670/* -------------------------------------------------------------------- */
3673
3675{
3676 Object *ob = context_object(C);
3677 int totmirr = 0, totfail = 0;
3678
3679 vgroup_mirror(ob,
3680 RNA_boolean_get(op->ptr, "mirror_weights"),
3681 RNA_boolean_get(op->ptr, "flip_group_names"),
3682 RNA_boolean_get(op->ptr, "all_groups"),
3683 RNA_boolean_get(op->ptr, "use_topology"),
3684 &totmirr,
3685 &totfail);
3686
3687 ED_mesh_report_mirror(op, totmirr, totfail);
3688
3693
3694 return OPERATOR_FINISHED;
3695}
3696
3698{
3699 /* identifiers */
3700 ot->name = "Mirror Vertex Group";
3701 ot->idname = "OBJECT_OT_vertex_group_mirror";
3702 ot->description =
3703 "Mirror vertex group, flip weights and/or names, editing only selected vertices, "
3704 "flipping when both sides are selected otherwise copy from unselected";
3705
3706 /* API callbacks. */
3707 ot->poll = vertex_group_poll;
3709
3710 /* flags */
3711 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3712
3713 /* properties */
3714 RNA_def_boolean(ot->srna, "mirror_weights", true, "Mirror Weights", "Mirror weights");
3716 ot->srna, "flip_group_names", true, "Flip Group Names", "Flip vertex group names");
3717 RNA_def_boolean(ot->srna, "all_groups", false, "All Groups", "Mirror all vertex groups weights");
3719 ot->srna,
3720 "use_topology",
3721 false,
3722 "Topology Mirror",
3723 "Use topology based mirroring (for when both sides of mesh have matching, unique topology)");
3724}
3725
3727
3728/* -------------------------------------------------------------------- */
3731
3733{
3734 Object *obact = context_object(C);
3735 int changed_tot = 0;
3736 int fail = 0;
3737
3738 CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
3739 if (obact != ob && BKE_object_supports_vertex_groups(ob)) {
3740 if (vgroup_array_copy(ob, obact)) {
3744 changed_tot++;
3745 }
3746 else {
3747 fail++;
3748 }
3749 }
3750 }
3752
3753 if ((changed_tot == 0 && fail == 0) || fail) {
3754 BKE_reportf(op->reports,
3755 RPT_ERROR,
3756 "Copy vertex groups to selected: %d done, %d failed (object data must support "
3757 "vertex groups and have matching indices)",
3758 changed_tot,
3759 fail);
3760 }
3761
3762 return OPERATOR_FINISHED;
3763}
3764
3766{
3767 /* identifiers */
3768 ot->name = "Copy Vertex Group to Selected";
3769 ot->idname = "OBJECT_OT_vertex_group_copy_to_selected";
3770 ot->description = "Replace vertex groups of selected objects by vertex groups of active object";
3771
3772 /* API callbacks. */
3773 ot->poll = vertex_group_poll;
3775
3776 /* flags */
3777 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3778}
3779
3781
3782/* -------------------------------------------------------------------- */
3785
3787{
3788 Object *ob = context_object(C);
3789 int nr = RNA_enum_get(op->ptr, "group");
3790
3791 BLI_assert(nr + 1 >= 0);
3793
3796
3797 return OPERATOR_FINISHED;
3798}
3799
3801 PointerRNA * /*ptr*/,
3802 PropertyRNA * /*prop*/,
3803 bool *r_free)
3804{
3805 if (C == nullptr) {
3807 }
3808
3809 Object *ob = context_object(C);
3810 EnumPropertyItem tmp = {0, "", 0, "", ""};
3811 EnumPropertyItem *item = nullptr;
3812 bDeformGroup *def;
3813 int a, totitem = 0;
3814
3815 if (!ob) {
3817 }
3818
3819 const ListBase *defbase = BKE_object_defgroup_list(ob);
3820 for (a = 0, def = static_cast<bDeformGroup *>(defbase->first); def; def = def->next, a++) {
3821 tmp.value = a;
3822 tmp.icon = ICON_GROUP_VERTEX;
3823 tmp.identifier = def->name;
3824 tmp.name = def->name;
3825 RNA_enum_item_add(&item, &totitem, &tmp);
3826 }
3827
3828 RNA_enum_item_end(&item, &totitem);
3829 *r_free = true;
3830
3831 return item;
3832}
3833
3835{
3836 PropertyRNA *prop;
3837
3838 /* identifiers */
3839 ot->name = "Set Active Vertex Group";
3840 ot->idname = "OBJECT_OT_vertex_group_set_active";
3841 ot->description = "Set the active vertex group";
3842
3843 /* API callbacks. */
3844 ot->poll = vertex_group_poll;
3845 ot->exec = set_active_group_exec;
3846 ot->invoke = WM_menu_invoke;
3847
3848 /* flags */
3849 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3850
3851 /* properties */
3852 prop = RNA_def_enum(
3853 ot->srna, "group", rna_enum_dummy_NULL_items, 0, "Group", "Vertex group to set as active");
3856 ot->prop = prop;
3857}
3858
3860
3861/* -------------------------------------------------------------------- */
3864
3865/* creates the name_array parameter for vgroup_do_remap, call this before fiddling
3866 * with the order of vgroups then call vgroup_do_remap after */
3867static char *vgroup_init_remap(Object *ob)
3868{
3869 const ListBase *defbase = BKE_object_defgroup_list(ob);
3870 int defbase_tot = BLI_listbase_count(defbase);
3871 char *name_array = static_cast<char *>(
3872 MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * defbase_tot, "sort vgroups"));
3873 char *name;
3874
3875 name = name_array;
3876 LISTBASE_FOREACH (const bDeformGroup *, def, defbase) {
3877 BLI_strncpy(name, def->name, MAX_VGROUP_NAME);
3878 name += MAX_VGROUP_NAME;
3879 }
3880
3881 return name_array;
3882}
3883
3884static wmOperatorStatus vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
3885{
3886 MDeformVert *dvert = nullptr;
3887 const bDeformGroup *def;
3888 const ListBase *defbase = BKE_object_defgroup_list(ob);
3889 int defbase_tot = BLI_listbase_count(defbase);
3890
3891 /* Needs a dummy index at the start. */
3892 int *sort_map_update = MEM_malloc_arrayN<int>((defbase_tot + 1), __func__);
3893 int *sort_map = sort_map_update + 1;
3894
3895 const char *name;
3896 int i;
3897
3898 name = name_array;
3899 for (def = static_cast<const bDeformGroup *>(defbase->first), i = 0; def; def = def->next, i++) {
3900 sort_map[i] = BKE_defgroup_name_index(defbase, name);
3901 name += MAX_VGROUP_NAME;
3902
3903 BLI_assert(sort_map[i] != -1);
3904 }
3905
3906 if (ob->type == OB_GREASE_PENCIL) {
3907 /* For Grease Pencil objects we don't have to do anything, because all drawings in the object
3908 * store their own set of #vertex_group_names. So changing the vertex group order on object
3909 * level is just a UI matter, no remapping in drawings is needed. */
3910 }
3911 else if (ob->mode == OB_MODE_EDIT) {
3912 if (ob->type == OB_MESH) {
3914 const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
3915
3916 if (cd_dvert_offset != -1) {
3917 BMIter iter;
3918 BMVert *eve;
3919
3920 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
3921 dvert = static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
3922 if (dvert->totweight) {
3923 BKE_defvert_remap(dvert, sort_map, defbase_tot);
3924 }
3925 }
3926 }
3927 }
3928 else {
3929 BKE_report(op->reports, RPT_ERROR, "Editmode lattice is not supported yet");
3930 MEM_freeN(sort_map_update);
3931 return OPERATOR_CANCELLED;
3932 }
3933 }
3934 else {
3935 int dvert_tot = 0;
3936 BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dvert, &dvert_tot);
3937
3938 /* Create as necessary. */
3939 if (dvert) {
3940 while (dvert_tot--) {
3941 if (dvert->totweight) {
3942 BKE_defvert_remap(dvert, sort_map, defbase_tot);
3943 }
3944 dvert++;
3945 }
3946 }
3947 }
3948
3949 /* update users */
3950 for (i = 0; i < defbase_tot; i++) {
3951 sort_map[i]++;
3952 }
3953
3954 sort_map_update[0] = 0;
3955 BKE_object_defgroup_remap_update_users(ob, sort_map_update);
3956
3957 BLI_assert(sort_map_update[BKE_object_defgroup_active_index_get(ob)] >= 0);
3959 sort_map_update[BKE_object_defgroup_active_index_get(ob)]);
3960
3961 MEM_freeN(sort_map_update);
3962
3963 return OPERATOR_FINISHED;
3964}
3965
3966static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr)
3967{
3968 const bDeformGroup *def_a = static_cast<const bDeformGroup *>(def_a_ptr);
3969 const bDeformGroup *def_b = static_cast<const bDeformGroup *>(def_b_ptr);
3970
3971 return BLI_strcasecmp_natural(def_a->name, def_b->name);
3972}
3973
3978static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase)
3979{
3980 if (bonebase == nullptr) {
3982 if (armobj != nullptr) {
3983 bArmature *armature = static_cast<bArmature *>(armobj->data);
3984 bonebase = &armature->bonebase;
3985 }
3986 }
3988
3989 if (bonebase != nullptr) {
3990 LISTBASE_FOREACH_BACKWARD (Bone *, bone, bonebase) {
3992 vgroup_sort_bone_hierarchy(ob, &bone->childbase);
3993
3994 if (dg != nullptr) {
3995 BLI_remlink(defbase, dg);
3996 BLI_addhead(defbase, dg);
3997 }
3998 }
3999 }
4000}
4001
4002enum {
4005};
4006
4008{
4009 Object *ob = context_object(C);
4010 char *name_array;
4012 int sort_type = RNA_enum_get(op->ptr, "sort_type");
4013
4014 /* Init remapping. */
4015 name_array = vgroup_init_remap(ob);
4016
4018
4019 /* Sort vgroup names. */
4020 switch (sort_type) {
4021 case SORT_TYPE_NAME:
4023 break;
4025 vgroup_sort_bone_hierarchy(ob, nullptr);
4026 break;
4027 }
4028
4029 /* Remap vgroup data to map to correct names. */
4030 ret = vgroup_do_remap(ob, name_array, op);
4031
4032 if (ret != OPERATOR_CANCELLED) {
4035 }
4036
4037 if (name_array) {
4038 MEM_freeN(name_array);
4039 }
4040
4041 return ret;
4042}
4043
4045{
4046 static const EnumPropertyItem vgroup_sort_type[] = {
4047 {SORT_TYPE_NAME, "NAME", 0, "Name", ""},
4048 {SORT_TYPE_BONEHIERARCHY, "BONE_HIERARCHY", 0, "Bone Hierarchy", ""},
4049 {0, nullptr, 0, nullptr, nullptr},
4050 };
4051
4052 ot->name = "Sort Vertex Groups";
4053 ot->idname = "OBJECT_OT_vertex_group_sort";
4054 ot->description = "Sort vertex groups";
4055
4056 /* API callbacks. */
4057 ot->poll = vertex_group_poll;
4058 ot->exec = vertex_group_sort_exec;
4059
4060 /* flags */
4061 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4062
4063 RNA_def_enum(ot->srna, "sort_type", vgroup_sort_type, SORT_TYPE_NAME, "Sort Type", "Sort type");
4064}
4065
4067
4068/* -------------------------------------------------------------------- */
4071
4073{
4074 Object *ob = context_object(C);
4075 bDeformGroup *def;
4076 char *name_array;
4077 int dir = RNA_enum_get(op->ptr, "direction");
4079
4081
4082 def = static_cast<bDeformGroup *>(
4084 if (!def) {
4085 return OPERATOR_CANCELLED;
4086 }
4087
4088 name_array = vgroup_init_remap(ob);
4089
4090 if (BLI_listbase_link_move(defbase, def, dir)) {
4091 ret = vgroup_do_remap(ob, name_array, op);
4092
4093 if (ret != OPERATOR_CANCELLED) {
4096 }
4097 }
4098
4099 if (name_array) {
4100 MEM_freeN(name_array);
4101 }
4102
4103 return ret;
4104}
4105
4107{
4108 static const EnumPropertyItem vgroup_slot_move[] = {
4109 {-1, "UP", 0, "Up", ""},
4110 {1, "DOWN", 0, "Down", ""},
4111 {0, nullptr, 0, nullptr, nullptr},
4112 };
4113
4114 /* identifiers */
4115 ot->name = "Move Vertex Group";
4116 ot->idname = "OBJECT_OT_vertex_group_move";
4117 ot->description = "Move the active vertex group up/down in the list";
4118
4119 /* API callbacks. */
4120 ot->poll = vertex_group_poll;
4121 ot->exec = vgroup_move_exec;
4122
4123 /* flags */
4124 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4125
4126 RNA_def_enum(ot->srna,
4127 "direction",
4128 vgroup_slot_move,
4129 0,
4130 "Direction",
4131 "Direction to move the active vertex group towards");
4132}
4133
4135
4136/* -------------------------------------------------------------------- */
4139
4140static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
4141{
4142 MDeformVert *dvert_act;
4143
4144 Mesh *mesh = static_cast<Mesh *>(ob->data);
4145 int i;
4146
4147 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
4148 const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
4149 BMIter iter;
4150 BMVert *eve, *eve_act;
4151
4152 dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
4153 if (dvert_act == nullptr) {
4154 return;
4155 }
4156
4157 BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
4158 if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && (eve != eve_act)) {
4159 MDeformVert *dvert_dst = static_cast<MDeformVert *>(
4160 BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
4161
4162 BKE_defvert_copy_index(dvert_dst, def_nr, dvert_act, def_nr);
4163
4164 if (mesh->symmetry & ME_SYMMETRY_X) {
4165 mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
4166 }
4167 }
4168 }
4169
4170 if (mesh->symmetry & ME_SYMMETRY_X) {
4171 mesh_defvert_mirror_update_em(ob, eve_act, -1, -1, cd_dvert_offset);
4172 }
4173 }
4174 else {
4175 int v_act;
4176
4177 dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
4178 if (dvert_act == nullptr) {
4179 return;
4180 }
4181
4182 MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write();
4183 const bke::AttributeAccessor attributes = mesh->attributes();
4184 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
4185 ".select_vert", bke::AttrDomain::Point, false);
4186
4187 for (i = 0; i < mesh->verts_num; i++) {
4188 if (select_vert[i] && (&dverts[i] != dvert_act)) {
4189 BKE_defvert_copy_index(&dverts[i], def_nr, dvert_act, def_nr);
4190
4191 if (mesh->symmetry & ME_SYMMETRY_X) {
4193 }
4194 }
4195 }
4196
4197 if (mesh->symmetry & ME_SYMMETRY_X) {
4198 mesh_defvert_mirror_update_ob(ob, -1, v_act);
4199 }
4200 }
4201}
4202
4203static bool check_vertex_group_accessible(wmOperator *op, Object *ob, int def_nr)
4204{
4205 const ListBase *defbase = BKE_object_defgroup_list(ob);
4206 bDeformGroup *dg = static_cast<bDeformGroup *>(BLI_findlink(defbase, def_nr));
4207
4208 if (!dg) {
4209 BKE_report(op->reports, RPT_ERROR, "Invalid vertex group index");
4210 return false;
4211 }
4212
4213 if (dg->flag & DG_LOCK_WEIGHT) {
4214 BKE_report(op->reports, RPT_ERROR, "Vertex group is locked");
4215 return false;
4216 }
4217
4218 return true;
4219}
4220
4222{
4223 Object *ob = context_object(C);
4224 const int def_nr = RNA_int_get(op->ptr, "weight_group");
4225
4226 if (!check_vertex_group_accessible(op, ob, def_nr)) {
4227 return OPERATOR_CANCELLED;
4228 }
4229
4231
4234
4235 return OPERATOR_FINISHED;
4236}
4237
4239{
4240 PropertyRNA *prop;
4241
4242 ot->name = "Paste Weight to Selected";
4243 ot->idname = "OBJECT_OT_vertex_weight_paste";
4244 ot->description =
4245 "Copy this group's weight to other selected vertices (disabled if vertex group is locked)";
4246
4247 /* API callbacks. */
4250
4251 /* flags */
4252 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4253
4254 prop = RNA_def_int(ot->srna,
4255 "weight_group",
4256 -1,
4257 -1,
4258 INT_MAX,
4259 "Weight Index",
4260 "Index of source weight in active vertex group",
4261 -1,
4262 INT_MAX);
4264}
4265
4267
4268/* -------------------------------------------------------------------- */
4271
4273{
4274 Object *ob = context_object(C);
4275 const int def_nr = RNA_int_get(op->ptr, "weight_group");
4276
4277 if (!check_vertex_group_accessible(op, ob, def_nr)) {
4278 return OPERATOR_CANCELLED;
4279 }
4280
4281 vgroup_remove_weight(ob, def_nr);
4282
4285
4286 return OPERATOR_FINISHED;
4287}
4288
4290{
4291 PropertyRNA *prop;
4292
4293 ot->name = "Delete Weight";
4294 ot->idname = "OBJECT_OT_vertex_weight_delete";
4295 ot->description = "Delete this weight from the vertex (disabled if vertex group is locked)";
4296
4297 /* API callbacks. */
4300
4301 /* flags */
4302 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4303
4304 prop = RNA_def_int(ot->srna,
4305 "weight_group",
4306 -1,
4307 -1,
4308 INT_MAX,
4309 "Weight Index",
4310 "Index of source weight in active vertex group",
4311 -1,
4312 INT_MAX);
4314}
4315
4317
4318/* -------------------------------------------------------------------- */
4321
4323{
4324 Object *ob = context_object(C);
4325 const int wg_index = RNA_int_get(op->ptr, "weight_group");
4326
4327 if (wg_index != -1) {
4328 BKE_object_defgroup_active_index_set(ob, wg_index + 1);
4331 }
4332
4333 return OPERATOR_FINISHED;
4334}
4335
4337{
4338 PropertyRNA *prop;
4339
4340 ot->name = "Set Active Group";
4341 ot->idname = "OBJECT_OT_vertex_weight_set_active";
4342 ot->description = "Set as active vertex group";
4343
4344 /* API callbacks. */
4347
4348 /* flags */
4349 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4350
4351 prop = RNA_def_int(ot->srna,
4352 "weight_group",
4353 -1,
4354 -1,
4355 INT_MAX,
4356 "Weight Index",
4357 "Index of source weight in active vertex group",
4358 -1,
4359 INT_MAX);
4361}
4362
4364
4365/* -------------------------------------------------------------------- */
4368
4370 wmOperator * /*op*/)
4371{
4372 Object *ob = context_object(C);
4374 eVGroupSelect subset_type = static_cast<eVGroupSelect>(ts->vgroupsubset);
4375 bool changed;
4376
4377 changed = vgroup_normalize_active_vertex(ob, subset_type);
4378
4379 if (changed) {
4382
4383 return OPERATOR_FINISHED;
4384 }
4385 return OPERATOR_CANCELLED;
4386}
4387
4389{
4390
4391 ot->name = "Normalize Active";
4392 ot->idname = "OBJECT_OT_vertex_weight_normalize_active_vertex";
4393 ot->description = "Normalize active vertex's weights";
4394
4395 /* API callbacks. */
4398
4399 /* flags */
4400 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4401}
4402
4404
4405/* -------------------------------------------------------------------- */
4408
4410{
4411 Object *ob = context_object(C);
4413 eVGroupSelect subset_type = static_cast<eVGroupSelect>(ts->vgroupsubset);
4414
4415 vgroup_copy_active_to_sel(ob, subset_type);
4416
4419
4420 return OPERATOR_FINISHED;
4421}
4422
4424{
4425
4426 ot->name = "Copy Active";
4427 ot->idname = "OBJECT_OT_vertex_weight_copy";
4428 ot->description = "Copy weights from active to selected";
4429
4430 /* API callbacks. */
4433
4434 /* flags */
4435 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4436}
4437
4439
4440} // namespace blender::ed::object
#define CTX_DATA_BEGIN(C, Type, instance, member)
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
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
Low-level operations for curves.
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:148
void BKE_object_defgroup_active_index_set(Object *ob, int new_index)
Definition deform.cc:601
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:192
void BKE_defvert_normalize_lock_single(MDeformVert *dvert, const bool *vgroup_subset, int vgroup_num, uint def_nr_lock)
Definition deform.cc:296
int BKE_object_defgroup_active_index_get(const Object *ob)
Definition deform.cc:596
void BKE_defvert_flip(MDeformVert *dvert, const int *flip_map, int flip_map_num)
Definition deform.cc:405
bDeformGroup * BKE_defgroup_duplicate(const bDeformGroup *ingroup)
Definition deform.cc:80
bool BKE_object_supports_vertex_groups(const Object *ob)
Definition deform.cc:452
void BKE_defvert_add_index_notest(MDeformVert *dv, int defgroup, float weight)
Definition deform.cc:845
int BKE_object_defgroup_count(const Object *ob)
Definition deform.cc:591
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:110
void BKE_defvert_remap(MDeformVert *dvert, const int *map, int map_len)
Definition deform.cc:218
void BKE_defvert_normalize_subset(MDeformVert *dvert, const bool *vgroup_subset, int vgroup_num)
Definition deform.cc:230
int BKE_defgroup_name_index(const ListBase *defbase, blender::StringRef name)
Definition deform.cc:529
const ListBase * BKE_object_defgroup_list(const Object *ob)
Definition deform.cc:574
int BKE_object_defgroup_flip_index(const Object *ob, int index, bool use_default)
Definition deform.cc:703
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:741
int * BKE_object_defgroup_flip_map_single(const Object *ob, bool use_default, int defgroup, int *r_flip_map_num)
Definition deform.cc:668
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:585
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:763
bDeformGroup * BKE_object_defgroup_find_name(const Object *ob, blender::StringRef name)
Definition deform.cc:515
void BKE_defvert_copy_subset(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const bool *vgroup_subset, int vgroup_num)
Definition deform.cc:97
int * BKE_object_defgroup_flip_map_unlocked(const Object *ob, bool use_default, int *r_flip_map_num)
Definition deform.cc:661
void BKE_defvert_copy(MDeformVert *dvert_dst, const MDeformVert *dvert_src)
Definition deform.cc:125
void BKE_defvert_remove_group(MDeformVert *dvert, MDeformWeight *dw)
Definition deform.cc:869
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:350
int * BKE_object_defgroup_flip_map(const Object *ob, bool use_default, int *r_flip_map_num)
Definition deform.cc:656
int BKE_object_defgroup_name_index(const Object *ob, blender::StringRef name)
Definition deform.cc:580
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:61
Utility functions for vertex groups in grease pencil objects.
BPoint * BKE_lattice_active_point_get(Lattice *lt)
Definition lattice.cc:581
int BKE_lattice_index_from_uvw(const Lattice *lt, int u, int v, int w)
Definition lattice.cc:199
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:126
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition BLI_bitmap.h:37
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition BLI_bitmap.h:61
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition BLI_bitmap.h:78
unsigned int BLI_bitmap
Definition BLI_bitmap.h:13
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void BLI_addhead(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:91
void void void bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL()
Definition listbase.cc:436
void void BLI_listbase_sort(ListBase *listbase, int(*cmp)(const void *, const void *)) ATTR_NONNULL(1
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
void void void void void void BLI_duplicatelist(ListBase *dst, const ListBase *src) ATTR_NONNULL(1
MINLINE float max_ff(float a, float b)
MINLINE int signum_i(float a)
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
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:1009
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1026
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ ID_ME
@ ID_LT
@ ID_GP
@ 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
struct Object Object
#define MAX_VGROUP_NAME
#define OB_TYPE_SUPPORT_VGROUP(_type)
@ DG_LOCK_WEIGHT
eVGroupSelect
@ WT_VGROUP_BONE_SELECT
@ WT_VGROUP_ALL
@ WT_VGROUP_ACTIVE
@ WT_VGROUP_BONE_DEFORM
#define WT_VGROUP_MASK_ALL
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
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:787
int mesh_get_x_mirror_vert(Object *ob, Mesh *mesh_eval, int index, bool use_topology)
Definition meshtools.cc:911
void EDBM_deselect_flush(BMEditMesh *em)
int ED_mesh_mirror_get_vert(Object *ob, int index)
Definition meshtools.cc:981
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:972
#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.
@ PROP_ENUM_NO_TRANSLATE
Definition RNA_types.hh:406
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
@ PROP_HIDDEN
Definition RNA_types.hh:324
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:390
#define ND_DRAW
Definition WM_types.hh:458
#define ND_DATA
Definition WM_types.hh:506
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_VERTEX_GROUP
Definition WM_types.hh:507
ReportList * reports
Definition WM_types.hh:1025
#define ND_SELECT
Definition WM_types.hh:505
#define NC_OBJECT
Definition WM_types.hh:376
@ 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
BMesh const char void * data
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:509
constexpr bool is_empty() const
Definition BLI_span.hh:260
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
bke::CurvesGeometry & strokes_for_write()
#define SELECT
#define floorf(x)
#define fabsf(x)
#define select(A, B, C)
#define MEM_SAFE_FREE(v)
#define ID_IS_EDITABLE(_id)
#define MEM_reallocN(vmemh, len)
#define ID_IS_OVERRIDE_LIBRARY(_id)
#define GS(a)
blender::bke::AttrDomain ED_grease_pencil_edit_selection_domain_get(const ToolSettings *tool_settings)
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
bool remove_from_vertex_group(Drawing &drawing, StringRef name, bool use_selection)
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)
bke::GSpanAttributeWriter ensure_selection_attribute(bke::CurvesGeometry &curves, bke::AttrDomain selection_domain, eCustomDataType create_type, StringRef attribute_name)
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)
static wmOperatorStatus vertex_group_limit_total_exec(bContext *C, wmOperator *op)
static wmOperatorStatus vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
void OBJECT_OT_vertex_group_normalize(wmOperatorType *ot)
static wmOperatorStatus vertex_weight_copy_exec(bContext *C, wmOperator *)
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)
void OBJECT_OT_vertex_weight_set_active(wmOperatorType *ot)
static wmOperatorStatus vertex_weight_normalize_active_vertex_exec(bContext *C, wmOperator *)
static void vgroup_quantize_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int, const int steps)
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 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)
static wmOperatorStatus vertex_group_levels_exec(bContext *C, wmOperator *op)
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 wmOperatorStatus vertex_group_assign_exec(bContext *C, wmOperator *op)
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 wmOperatorStatus vertex_weight_paste_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem * rna_vertex_group_with_single_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free)
static wmOperatorStatus vertex_weight_set_active_exec(bContext *C, wmOperator *op)
void OBJECT_OT_vertex_weight_normalize_active_vertex(wmOperatorType *ot)
static void mesh_defvert_mirror_update_internal(Object *ob, MDeformVert *dvert_dst, MDeformVert *dvert_src, const int def_nr)
static void vgroup_normalize_all_deform_if_active_is_deform(Object *ob, const bool lock_active, ReportList *reports, std::optional< int > current_frame={})
void OBJECT_OT_vertex_group_assign(wmOperatorType *ot)
bool vgroup_sync_from_pose(Object *ob)
void OBJECT_OT_vertex_group_limit_total(wmOperatorType *ot)
static wmOperatorStatus vertex_group_copy_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 wmOperatorStatus vertex_group_clean_exec(bContext *C, wmOperator *op)
bool vgroup_parray_alloc(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, bool use_vert_sel, std::optional< int > current_frame={})
static const EnumPropertyItem vgroup_lock_mask[]
void OBJECT_OT_vertex_group_copy_to_selected(wmOperatorType *ot)
static bool vertex_group_supported_poll(bContext *C)
static void mesh_defvert_mirror_update_em(Object *ob, BMVert *eve, int def_nr, int vidx, const int cd_dvert_offset)
void OBJECT_OT_vertex_weight_copy(wmOperatorType *ot)
static void vgroup_grease_pencil_select_verts(const Scene &scene, const ToolSettings &tool_settings, const bDeformGroup *def_group, const bool select, Object &object)
void vgroup_parray_mirror_assign(Object *ob, MDeformVert **dvert_array, int dvert_tot)
static bool UNUSED_FUNCTION vertex_group_poll_edit(bContext *C)
static wmOperatorStatus vertex_group_invert_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 wmOperatorStatus vertex_group_lock_exec(bContext *C, wmOperator *op)
static wmOperatorStatus vertex_group_assign_new_exec(bContext *C, wmOperator *op)
Object * context_object(const bContext *C)
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 wmOperatorStatus vertex_group_add_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 wmOperatorStatus set_active_group_exec(bContext *C, wmOperator *op)
static char * vgroup_init_remap(Object *ob)
static wmOperatorStatus vertex_group_select_exec(bContext *C, wmOperator *)
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 vgroup_normalize_all(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const bool lock_active, ReportList *reports, std::optional< int > current_frame={})
static bool vertex_group_poll_ex(bContext *C, Object *ob)
static wmOperatorStatus vertex_group_remove_from_exec(bContext *C, wmOperator *op)
static void vgroup_delete_active(Object *ob)
void OBJECT_OT_vertex_group_invert(wmOperatorType *ot)
void OBJECT_OT_vertex_group_move(wmOperatorType *ot)
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 wmOperatorStatus vertex_group_mirror_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 wmOperatorStatus vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op)
static void mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx)
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)
static wmOperatorStatus vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
void OBJECT_OT_vertex_group_assign_new(wmOperatorType *ot)
static wmOperatorStatus vertex_group_deselect_exec(bContext *C, wmOperator *)
static void vgroup_operator_subset_select_props(wmOperatorType *ot, bool use_active)
void OBJECT_OT_vertex_weight_delete(wmOperatorType *ot)
static wmOperatorStatus vertex_weight_delete_exec(bContext *C, wmOperator *op)
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)
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 wmOperatorStatus vertex_group_smooth_exec(bContext *C, wmOperator *op)
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 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 wmOperatorStatus vgroup_move_exec(bContext *C, wmOperator *op)
static wmOperatorStatus vertex_group_quantize_exec(bContext *C, wmOperator *op)
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 wmOperatorStatus vertex_group_sort_exec(bContext *C, wmOperator *op)
static bool check_vertex_group_accessible(wmOperator *op, Object *ob, int def_nr)
void OBJECT_OT_vertex_group_add(wmOperatorType *ot)
static void vgroup_assign_verts(Object *ob, Scene &scene, const float weight)
static wmOperatorStatus vertex_group_normalize_exec(bContext *C, wmOperator *)
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 wmOperatorStatus vertex_group_remove_exec(bContext *C, wmOperator *op)
static bool * vgroup_selected_get(Object *ob)
void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
VecBase< int32_t, 2 > int2
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)
static void def_group(BlenderRNA *, StructRNA *srna)
const EnumPropertyItem rna_enum_dummy_NULL_items[]
Definition rna_rna.cc:26
static const int steps
#define FLT_MAX
Definition stdcycles.h:14
float co[3]
CustomData vdata
uint8_t f1
char name[64]
struct Lattice * latt
const char * identifier
Definition RNA_types.hh:623
const char * name
Definition RNA_types.hh:627
Definition DNA_ID.h:404
char name[66]
Definition DNA_ID.h:415
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 RenderData r
struct bDeformGroup * next
struct ReportList * reports
struct PointerRNA * ptr
i
Definition text_draw.cc:230
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4226
wmOperatorType * ot
Definition wm_files.cc:4225
wmOperatorStatus WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)