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