Blender V5.0
deform.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 <cctype>
10#include <cstddef>
11#include <cstdlib>
12#include <cstring>
13
14#include "MEM_guardedalloc.h"
15
18#include "DNA_lattice_types.h"
19#include "DNA_mesh_types.h"
20#include "DNA_meshdata_types.h"
21#include "DNA_modifier_enums.h"
22#include "DNA_object_types.h"
23
24#include "BLI_listbase.h"
25#include "BLI_math_vector.h"
26#include "BLI_span.hh"
27#include "BLI_string_utf8.h"
28#include "BLI_string_utils.hh"
29#include "BLI_utildefines.h"
30
31#include "BLT_translation.hh"
32
33#include "BKE_customdata.hh"
34#include "BKE_deform.hh" /* own include */
35#include "BKE_grease_pencil.hh"
37#include "BKE_mesh.hh"
38#include "BKE_object.hh"
39#include "BKE_object_deform.h"
40
41#include "BLO_read_write.hh"
42
44
45using blender::Span;
47
49{
50 bDeformGroup *defgroup;
51
53
54 defgroup = MEM_callocN<bDeformGroup>(__func__);
55
56 name.copy_utf8_truncated(defgroup->name);
57
59
60 BLI_addtail(defbase, defgroup);
62
63 if (ob->type == OB_GREASE_PENCIL) {
65 *static_cast<GreasePencil *>(ob->data));
66 }
67
69
70 return defgroup;
71}
72
73void BKE_defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
74{
75 BLI_listbase_clear(outbase);
76 LISTBASE_FOREACH (const bDeformGroup *, defgroup, inbase) {
77 bDeformGroup *defgroupn = BKE_defgroup_duplicate(defgroup);
78 BLI_addtail(outbase, defgroupn);
79 }
80}
81
83{
84 if (!ingroup) {
85 BLI_assert(0);
86 return nullptr;
87 }
88
89 bDeformGroup *outgroup = MEM_callocN<bDeformGroup>(__func__);
90
91 /* For now, just copy everything over. */
92 memcpy(outgroup, ingroup, sizeof(bDeformGroup));
93
94 outgroup->next = outgroup->prev = nullptr;
95
96 return outgroup;
97}
98
100 const MDeformVert *dvert_src,
101 const bool *vgroup_subset,
102 const int vgroup_num)
103{
104 int defgroup;
105 for (defgroup = 0; defgroup < vgroup_num; defgroup++) {
106 if (vgroup_subset[defgroup]) {
107 BKE_defvert_copy_index(dvert_dst, defgroup, dvert_src, defgroup);
108 }
109 }
110}
111
113 const MDeformVert *dvert_src,
114 const bool *vgroup_subset,
115 const int vgroup_num,
116 const int *flip_map,
117 const int flip_map_num)
118{
119 int defgroup;
120 for (defgroup = 0; defgroup < vgroup_num && defgroup < flip_map_num; defgroup++) {
121 if (vgroup_subset[defgroup] && (dvert_dst != dvert_src || flip_map[defgroup] != defgroup)) {
122 BKE_defvert_copy_index(dvert_dst, flip_map[defgroup], dvert_src, defgroup);
123 }
124 }
125}
126
127void BKE_defvert_copy(MDeformVert *dvert_dst, const MDeformVert *dvert_src)
128{
129 if (dvert_dst->totweight == dvert_src->totweight) {
130 if (dvert_src->totweight) {
131 memcpy(dvert_dst->dw, dvert_src->dw, dvert_src->totweight * sizeof(MDeformWeight));
132 }
133 }
134 else {
135 if (dvert_dst->dw) {
136 MEM_freeN(dvert_dst->dw);
137 }
138
139 if (dvert_src->totweight) {
140 dvert_dst->dw = static_cast<MDeformWeight *>(MEM_dupallocN(dvert_src->dw));
141 }
142 else {
143 dvert_dst->dw = nullptr;
144 }
145
146 dvert_dst->totweight = dvert_src->totweight;
147 }
148}
149
151 const int defgroup_dst,
152 const MDeformVert *dvert_src,
153 const int defgroup_src)
154{
155 MDeformWeight *dw_dst;
156
157 const MDeformWeight *dw_src = BKE_defvert_find_index(dvert_src, defgroup_src);
158
159 if (dw_src) {
160 /* Source is valid, ensure destination is created. */
161 dw_dst = BKE_defvert_ensure_index(dvert_dst, defgroup_dst);
162 dw_dst->weight = dw_src->weight;
163 }
164 else {
165 /* Source was nullptr, assign zero (could also remove). */
166 dw_dst = BKE_defvert_find_index(dvert_dst, defgroup_dst);
167
168 if (dw_dst) {
169 dw_dst->weight = 0.0f;
170 }
171 }
172}
173
174void BKE_defvert_sync(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const bool use_ensure)
175{
176 if (dvert_src->totweight && dvert_dst->totweight) {
177 MDeformWeight *dw_src = dvert_src->dw;
178 for (int i = 0; i < dvert_src->totweight; i++, dw_src++) {
179 MDeformWeight *dw_dst;
180 if (use_ensure) {
181 dw_dst = BKE_defvert_ensure_index(dvert_dst, dw_src->def_nr);
182 }
183 else {
184 dw_dst = BKE_defvert_find_index(dvert_dst, dw_src->def_nr);
185 }
186
187 if (dw_dst) {
188 dw_dst->weight = dw_src->weight;
189 }
190 }
191 }
192}
193
195 const MDeformVert *dvert_src,
196 const int *flip_map,
197 const int flip_map_num,
198 const bool use_ensure)
199{
200 if (dvert_src->totweight && dvert_dst->totweight) {
201 MDeformWeight *dw_src = dvert_src->dw;
202 for (int i = 0; i < dvert_src->totweight; i++, dw_src++) {
203 if (dw_src->def_nr < flip_map_num) {
204 MDeformWeight *dw_dst;
205 if (use_ensure) {
206 dw_dst = BKE_defvert_ensure_index(dvert_dst, flip_map[dw_src->def_nr]);
207 }
208 else {
209 dw_dst = BKE_defvert_find_index(dvert_dst, flip_map[dw_src->def_nr]);
210 }
211
212 if (dw_dst) {
213 dw_dst->weight = dw_src->weight;
214 }
215 }
216 }
217 }
218}
219
220void BKE_defvert_remap(MDeformVert *dvert, const int *map, const int map_len)
221{
222 MDeformWeight *dw = dvert->dw;
223 for (int i = dvert->totweight; i != 0; i--, dw++) {
224 if (dw->def_nr < map_len) {
225 BLI_assert(map[dw->def_nr] >= 0);
226
227 dw->def_nr = map[dw->def_nr];
228 }
229 }
230}
231
233{
234 BKE_defvert_normalize_ex(dvert, subset_flags, {}, {});
235}
236
238{
239 BKE_defvert_normalize_ex(dvert, {}, {}, {});
240}
241
243 blender::Span<bool> subset_flags,
244 blender::Span<bool> lock_flags)
245{
246 BKE_defvert_normalize_ex(dvert, subset_flags, lock_flags, {});
247}
248
250 blender::Span<bool> subset_flags,
251 blender::Span<bool> lock_flags,
252 blender::Span<bool> soft_lock_flags)
253{
254 const bool use_subset = !subset_flags.is_empty();
255 const bool use_locks = !lock_flags.is_empty();
256 const bool use_soft_locks = !soft_lock_flags.is_empty();
257
258 /* Note: confusingly, `totweight` isn't the total weight on the vertex, it's
259 * the number of vertex groups assigned to the vertex. It's a DNA field, so
260 * I'm leaving it named as-is for now despite it being confusing. */
261 if (dvert.totweight == 0) {
262 /* No vertex groups assigned: do nothing. */
263 return;
264 }
265
266 if (dvert.totweight == 1) {
267 /* Only one vertex group is assigned to the vertex.
268 *
269 * TODO: this special case for single-group vertices should be completely
270 * unnecessary. The code further below works just as well for one assigned
271 * group as for twenty. However, the old version of this function was *not*
272 * consistent in its behavior between single-group and multi-group vertices:
273 * single-group vertices would set the group weight to 1.0 even if the
274 * initial weight was zero, whereas multi-group vertices with all weights
275 * set to zero would be left as-is.
276 *
277 * I (Nathan Vegdahl) decided to leave this special case here just in case
278 * any other code depends on this odd behavior. But we should revisit this
279 * at some point to check if that's actually the case, and simply remove
280 * this special case if nothing is depending on it. */
281
282 MDeformWeight *dw = dvert.dw;
283
284 if (use_subset && !subset_flags[dw->def_nr]) {
285 return;
286 }
287
288 const bool is_unlocked = lock_flags.is_empty() || !lock_flags[dw->def_nr];
289 if (is_unlocked) {
290 dw->weight = 1.0f;
291 }
292 return;
293 }
294
296 dvert.totweight);
297
298 /* Collect weights. */
299 float total_locked_weight = 0.0f;
300 float total_soft_locked_weight = 0.0f;
301 float total_regular_weight = 0.0f; /* Neither locked nor soft locked. */
302 int soft_locked_group_count = 0;
303 for (MDeformWeight &dw : vertex_weights) {
304 if (use_subset && !subset_flags[dw.def_nr]) {
305 /* Not part of the subset being normalized. */
306 continue;
307 }
308
309 if (use_locks && lock_flags[dw.def_nr]) {
310 /* Locked. */
311 total_locked_weight += dw.weight;
312 }
313 else if (use_soft_locks && soft_lock_flags[dw.def_nr]) {
314 total_soft_locked_weight += dw.weight;
315 soft_locked_group_count++;
316 }
317 else {
318 total_regular_weight += dw.weight;
319 }
320 }
321
322 const float available_weight = max_ff(0.0f, 1.0f - total_locked_weight);
323
324 /* Special case: all non-hard-locked vertex groups have zero weight.
325 *
326 * Note: conceptually this if condition is checking for `== 0.0`, because
327 * negative weights shouldn't be possible. We're just being paranoid with
328 * the `<=`. */
329 if (total_regular_weight <= 0.0f && total_soft_locked_weight <= 0.0f) {
330 /* There isn't any "right" thing to do here.
331 *
332 * What we choose to do is: if there are any soft-locked groups on the
333 * vertex, distribute the needed weight equally among them. If there are no
334 * soft-locked groups on the vertex, we do nothing. The rationale behind
335 * this is that:
336 *
337 * 1. Zero-weight groups should typically be treated the same as unassigned
338 * groups.
339 * 2. But soft-locked groups can be treated specially: since their intended
340 * use case is indicating vertex groups that have just now had their
341 * weights set, we know they were intentionally set. Therefore even when
342 * zero-weight we can consider them assigned.
343 *
344 * There isn't any deep truth behind this approach, but after discussion
345 * with a few people I (Nathan Vegdahl) think in practice this is likely to
346 * be the least surprising behavior to users (out of several bad options).
347 * In particular, when the user modifies weights with auto-normalize
348 * enabled, they expect Blender to ensure normalized weights whenever
349 * possible (see issue #141024), and this approach achieves that.
350 *
351 * However, this approach is very much worth revisiting if it ends up
352 * causing other problems. */
353
354 if (soft_locked_group_count == 0) {
355 return;
356 }
357
358 const float weight = available_weight / soft_locked_group_count;
359 for (MDeformWeight &dw : vertex_weights) {
360 if (!subset_flags.is_empty() && !subset_flags[dw.def_nr]) {
361 /* Not part of the subset being normalized. */
362 continue;
363 }
364
365 if (!lock_flags.is_empty() && lock_flags[dw.def_nr]) {
366 /* Locked. */
367 continue;
368 }
369
370 if (use_soft_locks && soft_lock_flags[dw.def_nr]) {
371 dw.weight = weight;
372 }
373 }
374
375 return;
376 }
377
378 /* Compute scale factors for soft-locked and regular group weights. */
379 float soft_locked_scale;
380 float regular_scale;
381 const bool must_adjust_soft_locked = total_soft_locked_weight >= available_weight ||
382 total_regular_weight <= 0.0f;
383 if (must_adjust_soft_locked) {
384 soft_locked_scale = available_weight / total_soft_locked_weight;
385 regular_scale = 0.0f;
386 }
387 else {
388 soft_locked_scale = 1.0f;
389 regular_scale = (available_weight - total_soft_locked_weight) / total_regular_weight;
390 }
391
392 /* Normalize the weights via scaling by the appropriate factors. */
393 for (MDeformWeight &dw : vertex_weights) {
394 if (use_subset && !subset_flags[dw.def_nr]) {
395 /* Not part of the subset being normalized. */
396 continue;
397 }
398
399 if (use_locks && lock_flags[dw.def_nr]) {
400 /* Locked. */
401 continue;
402 }
403
404 if (use_soft_locks && soft_lock_flags[dw.def_nr]) {
405 dw.weight *= soft_locked_scale;
406 }
407 else {
408 dw.weight *= regular_scale;
409 }
410
411 /* In case of division errors with very low weights. */
412 CLAMP(dw.weight, 0.0f, 1.0f);
413 }
414}
415
416void BKE_defvert_flip(MDeformVert *dvert, const int *flip_map, const int flip_map_num)
417{
418 MDeformWeight *dw;
419 int i;
420
421 for (dw = dvert->dw, i = 0; i < dvert->totweight; dw++, i++) {
422 if (dw->def_nr < flip_map_num) {
423 if (flip_map[dw->def_nr] >= 0) {
424 dw->def_nr = flip_map[dw->def_nr];
425 }
426 }
427 }
428}
429
430void BKE_defvert_flip_merged(MDeformVert *dvert, const int *flip_map, const int flip_map_num)
431{
432 MDeformWeight *dw, *dw_cpy;
433 float weight;
434 int i, totweight = dvert->totweight;
435
436 /* copy weights */
437 for (dw = dvert->dw, i = 0; i < totweight; dw++, i++) {
438 if (dw->def_nr < flip_map_num) {
439 if (flip_map[dw->def_nr] >= 0) {
440 /* error checkers complain of this but we'll never get nullptr return */
441 dw_cpy = BKE_defvert_ensure_index(dvert, flip_map[dw->def_nr]);
442 dw = &dvert->dw[i]; /* in case array got realloced */
443
444 /* distribute weights: if only one of the vertex groups was
445 * assigned this will halve the weights, otherwise it gets
446 * evened out. this keeps it proportional to other groups */
447 weight = 0.5f * (dw_cpy->weight + dw->weight);
448 dw_cpy->weight = weight;
449 dw->weight = weight;
450 }
451 }
452 }
453}
454
456{
457 if (id == nullptr) {
458 return false;
459 }
460 return ELEM(GS(id->name), ID_ME, ID_LT, ID_GD_LEGACY, ID_GP);
461}
462
464{
465 const ID *id = static_cast<const ID *>(ob->data);
466
468}
469
471{
472 switch (GS(id->name)) {
473 case ID_ME: {
474 const Mesh *mesh = (const Mesh *)id;
475 return &mesh->vertex_group_names;
476 }
477 case ID_LT: {
478 const Lattice *lt = (const Lattice *)id;
479 return &lt->vertex_group_names;
480 }
481 case ID_GD_LEGACY: {
482 const bGPdata *gpd = (const bGPdata *)id;
483 return &gpd->vertex_group_names;
484 }
485 case ID_GP: {
486 const GreasePencil *grease_pencil = (const GreasePencil *)id;
487 return &grease_pencil->vertex_group_names;
488 }
489 default: {
491 }
492 }
493 return nullptr;
494}
495
496static const int *object_defgroup_active_index_get_p(const Object *ob)
497{
499 switch (ob->type) {
500 case OB_MESH: {
501 const Mesh *mesh = (const Mesh *)ob->data;
502 return &mesh->vertex_group_active_index;
503 }
504 case OB_LATTICE: {
505 const Lattice *lattice = (const Lattice *)ob->data;
506 return &lattice->vertex_group_active_index;
507 }
508 case OB_GPENCIL_LEGACY: {
509 const bGPdata *gpd = (const bGPdata *)ob->data;
510 return &gpd->vertex_group_active_index;
511 }
512 case OB_GREASE_PENCIL: {
513 const GreasePencil *grease_pencil = (const GreasePencil *)ob->data;
514 return &grease_pencil->vertex_group_active_index;
515 }
516 }
517 return nullptr;
518}
519
521{
522 /* Cast away const just for the accessor. */
524}
525
527{
528 if (name.is_empty()) {
529 return nullptr;
530 }
531 const ListBase *defbase = BKE_object_defgroup_list(ob);
532 LISTBASE_FOREACH (bDeformGroup *, group, defbase) {
533 if (name == group->name) {
534 return group;
535 }
536 }
537 return nullptr;
538}
539
541{
542 int index;
543 if (!BKE_defgroup_listbase_name_find(defbase, name, &index, nullptr)) {
544 return -1;
545 }
546 return index;
547}
548
553
555 const StringRef name,
556 int *r_index,
557 bDeformGroup **r_group)
558{
559 if (name.is_empty()) {
560 return false;
561 }
562 int index;
563 LISTBASE_FOREACH_INDEX (bDeformGroup *, group, defbase, index) {
564 if (name == group->name) {
565 if (r_index != nullptr) {
566 *r_index = index;
567 }
568 if (r_group != nullptr) {
569 *r_group = group;
570 }
571 return true;
572 }
573 }
574 return false;
575}
576
578 const StringRef name,
579 int *r_index,
580 bDeformGroup **r_group)
581{
583}
584
590
592{
593 return BKE_id_defgroup_name_index((ID *)ob->data, name);
594}
595
601
606
611
612void BKE_object_defgroup_active_index_set(Object *ob, const int new_index)
613{
614 /* Cast away const just for the accessor. */
615 int *index = (int *)object_defgroup_active_index_get_p(ob);
616 *index = new_index;
617}
618
620 const bool use_default,
621 const bool use_only_unlocked,
622 int *r_flip_map_num)
623{
624 const ListBase *defbase = BKE_object_defgroup_list(ob);
625 const int defbase_num = BLI_listbase_count(defbase);
626 *r_flip_map_num = defbase_num;
627
628 if (defbase_num == 0) {
629 return nullptr;
630 }
631
632 bDeformGroup *dg;
633 char name_flip[sizeof(dg->name)];
634 int i, flip_num;
635 int *map = MEM_malloc_arrayN<int>(size_t(defbase_num), __func__);
636
637 for (i = 0; i < defbase_num; i++) {
638 map[i] = -1;
639 }
640
641 for (dg = static_cast<bDeformGroup *>(defbase->first), i = 0; dg; dg = dg->next, i++) {
642 if (map[i] == -1) { /* may be calculated previously */
643
644 /* in case no valid value is found, use this */
645 if (use_default) {
646 map[i] = i;
647 }
648
649 if (use_only_unlocked && (dg->flag & DG_LOCK_WEIGHT)) {
650 continue;
651 }
652
653 BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
654
655 if (!STREQ(name_flip, dg->name)) {
656 flip_num = BKE_object_defgroup_name_index(ob, name_flip);
657 if (flip_num != -1) {
658 map[i] = flip_num;
659 map[flip_num] = i; /* save an extra lookup */
660 }
661 }
662 }
663 }
664 return map;
665}
666
667int *BKE_object_defgroup_flip_map(const Object *ob, const bool use_default, int *r_flip_map_num)
668{
669 return object_defgroup_unlocked_flip_map_ex(ob, use_default, false, r_flip_map_num);
670}
671
673 const bool use_default,
674 int *r_flip_map_num)
675{
676 return object_defgroup_unlocked_flip_map_ex(ob, use_default, true, r_flip_map_num);
677}
678
680 const bool use_default,
681 const int defgroup,
682 int *r_flip_map_num)
683{
684 const ListBase *defbase = BKE_object_defgroup_list(ob);
685 const int defbase_num = BLI_listbase_count(defbase);
686 *r_flip_map_num = defbase_num;
687
688 if (defbase_num == 0) {
689 return nullptr;
690 }
691
692 char name_flip[sizeof(bDeformGroup::name)];
693 int i, flip_num, *map = MEM_malloc_arrayN<int>(size_t(defbase_num), __func__);
694
695 for (i = 0; i < defbase_num; i++) {
696 map[i] = use_default ? i : -1;
697 }
698
699 bDeformGroup *dg = static_cast<bDeformGroup *>(BLI_findlink(defbase, defgroup));
700
701 BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
702 if (!STREQ(name_flip, dg->name)) {
703 flip_num = BKE_object_defgroup_name_index(ob, name_flip);
704
705 if (flip_num != -1) {
706 map[defgroup] = flip_num;
707 map[flip_num] = defgroup;
708 }
709 }
710
711 return map;
712}
713
714int BKE_object_defgroup_flip_index(const Object *ob, int index, const bool use_default)
715{
716 const ListBase *defbase = BKE_object_defgroup_list(ob);
717 bDeformGroup *dg = static_cast<bDeformGroup *>(BLI_findlink(defbase, index));
718 int flip_index = -1;
719
720 if (dg) {
721 char name_flip[sizeof(dg->name)];
722 BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
723
724 if (!STREQ(name_flip, dg->name)) {
725 flip_index = BKE_object_defgroup_name_index(ob, name_flip);
726 }
727 }
728
729 return (flip_index == -1 && use_default) ? index : flip_index;
730}
731
736
738{
739 const ListBase *defbase = BKE_object_defgroup_list(ob);
740
741 LISTBASE_FOREACH (bDeformGroup *, curdef, defbase) {
742 if (dg != curdef) {
743 if (curdef->name == name) {
744 return true;
745 }
746 }
747 }
748
749 return false;
750}
751
753{
755 [&](const blender::StringRef name) { return defgroup_find_name_dupe(name, dg, ob); },
756 DATA_("Group"),
757 '.',
758 dg->name,
759 sizeof(dg->name));
760}
761
762void BKE_object_defgroup_set_name(bDeformGroup *dg, Object *ob, const char *new_name)
763{
764 std::string old_name = dg->name;
765 STRNCPY_UTF8(dg->name, new_name);
767
768 if (ob->type == OB_GREASE_PENCIL) {
769 /* Update vgroup names stored in CurvesGeometry */
770 BKE_grease_pencil_vgroup_name_update(ob, old_name.c_str(), dg->name);
771 }
772}
773
774float BKE_defvert_find_weight(const MDeformVert *dvert, const int defgroup)
775{
776 MDeformWeight *dw = BKE_defvert_find_index(dvert, defgroup);
777 return dw ? dw->weight : 0.0f;
778}
779
781 const int index,
782 const int defgroup,
783 const bool invert)
784{
785 /* Invalid defgroup index means the vgroup selected is invalid,
786 * does not exist, in that case it is OK to return 1.0
787 * (i.e. maximum weight, as if no vgroup was selected).
788 * But in case of valid defgroup and nullptr dvert data pointer, it means that vgroup **is**
789 * valid, and just totally empty, so we shall return '0.0' (or '1.0' if inverted) value then! */
790 if (defgroup == -1) {
791 return 1.0f;
792 }
793 if (dvert == nullptr) {
794 return invert ? 1.0 : 0.0f;
795 }
796
797 float weight = BKE_defvert_find_weight(dvert + index, defgroup);
798
799 if (invert) {
800 weight = 1.0f - weight;
801 }
802
803 return weight;
804}
805
806MDeformWeight *BKE_defvert_find_index(const MDeformVert *dvert, const int defgroup)
807{
808 if (dvert && defgroup >= 0) {
809 MDeformWeight *dw = dvert->dw;
810 uint i;
811
812 for (i = dvert->totweight; i != 0; i--, dw++) {
813 if (dw->def_nr == defgroup) {
814 return dw;
815 }
816 }
817 }
818 else {
819 BLI_assert(0);
820 }
821
822 return nullptr;
823}
824
826{
827 MDeformWeight *dw_new;
828
829 /* do this check always, this function is used to check for it */
830 if (!dvert || defgroup < 0) {
831 BLI_assert(0);
832 return nullptr;
833 }
834
835 dw_new = BKE_defvert_find_index(dvert, defgroup);
836 if (dw_new) {
837 return dw_new;
838 }
839
840 dw_new = MEM_malloc_arrayN<MDeformWeight>(size_t(dvert->totweight + 1), __func__);
841 if (dvert->dw) {
842 memcpy(dw_new, dvert->dw, sizeof(MDeformWeight) * dvert->totweight);
843 MEM_freeN(dvert->dw);
844 }
845 dvert->dw = dw_new;
846 dw_new += dvert->totweight;
847 dw_new->weight = 0.0f;
848 dw_new->def_nr = defgroup;
849 /* Group index */
850
851 dvert->totweight++;
852
853 return dw_new;
854}
855
856void BKE_defvert_add_index_notest(MDeformVert *dvert, const int defgroup, const float weight)
857{
858 /* TODO: merge with #BKE_defvert_ensure_index! */
859
860 MDeformWeight *dw_new;
861
862 /* do this check always, this function is used to check for it */
863 if (!dvert || defgroup < 0) {
864 BLI_assert(0);
865 return;
866 }
867
868 dw_new = MEM_calloc_arrayN<MDeformWeight>(size_t(dvert->totweight + 1), __func__);
869 if (dvert->dw) {
870 memcpy(dw_new, dvert->dw, sizeof(MDeformWeight) * dvert->totweight);
871 MEM_freeN(dvert->dw);
872 }
873 dvert->dw = dw_new;
874 dw_new += dvert->totweight;
875 dw_new->weight = weight;
876 dw_new->def_nr = defgroup;
877 dvert->totweight++;
878}
879
881{
882 if (UNLIKELY(!dvert || !dw)) {
883 return;
884 }
885 /* Ensure `dw` is part of `dvert` (security check). */
886 if (UNLIKELY(uintptr_t(dw - dvert->dw) >= uintptr_t(dvert->totweight))) {
887 /* Assert as an invalid `dw` (while supported) isn't likely to do what the caller expected. */
889 return;
890 }
891
892 const int i = dw - dvert->dw;
893 dvert->totweight--;
894 /* If there are still other deform weights attached to this vert then remove
895 * this deform weight, and reshuffle the others. */
896 if (dvert->totweight) {
897 BLI_assert(dvert->dw != nullptr);
898
899 if (i != dvert->totweight) {
900 dvert->dw[i] = dvert->dw[dvert->totweight];
901 }
902
903 dvert->dw = static_cast<MDeformWeight *>(
904 MEM_reallocN(dvert->dw, sizeof(MDeformWeight) * dvert->totweight));
905 }
906 else {
907 /* If there are no other deform weights left then just remove this one. */
908 MEM_freeN(dvert->dw);
909 dvert->dw = nullptr;
910 }
911}
912
914{
915 MEM_SAFE_FREE(dvert->dw);
916
917 dvert->totweight = 0;
918}
919
920int BKE_defvert_find_shared(const MDeformVert *dvert_a, const MDeformVert *dvert_b)
921{
922 if (dvert_a->totweight && dvert_b->totweight) {
923 MDeformWeight *dw = dvert_a->dw;
924 uint i;
925
926 for (i = dvert_a->totweight; i != 0; i--, dw++) {
927 if (dw->weight > 0.0f && BKE_defvert_find_weight(dvert_b, dw->def_nr) > 0.0f) {
928 return dw->def_nr;
929 }
930 }
931 }
932
933 return -1;
934}
935
936bool BKE_defvert_is_weight_zero(const MDeformVert *dvert, const int defgroup_tot)
937{
938 MDeformWeight *dw = dvert->dw;
939 for (int i = dvert->totweight; i != 0; i--, dw++) {
940 if (dw->weight != 0.0f) {
941 /* check the group is in-range, happens on rare situations */
942 if (LIKELY(dw->def_nr < defgroup_tot)) {
943 return false;
944 }
945 }
946 }
947 return true;
948}
949
951 int defbase_num,
952 const bool *defbase_sel)
953{
954 float total = 0.0f;
955 const MDeformWeight *dw = dv->dw;
956
957 if (defbase_sel == nullptr) {
958 return total;
959 }
960
961 for (int i = dv->totweight; i != 0; i--, dw++) {
962 if (dw->def_nr < defbase_num) {
963 if (defbase_sel[dw->def_nr]) {
964 total += dw->weight;
965 }
966 }
967 }
968
969 return total;
970}
971
973 const int defbase_num,
974 const bool *defbase_sel,
975 const int defbase_sel_num,
976 const bool is_normalized)
977{
978 float total = BKE_defvert_total_selected_weight(dv, defbase_num, defbase_sel);
979
980 /* in multipaint, get the average if auto normalize is inactive
981 * get the sum if it is active */
982 if (!is_normalized) {
983 total /= defbase_sel_num;
984 }
985
986 return total;
987}
988
990 float locked_weight,
991 float unlocked_weight)
992{
993 /* First try normalizing unlocked weights. */
994 if (unlocked_weight > 0.0f) {
995 return weight / unlocked_weight;
996 }
997
998 /* If no unlocked weight exists, take locked into account. */
999 if (locked_weight <= 0.0f) {
1000 return weight;
1001 }
1002
1003 /* handle division by zero */
1004 if (locked_weight >= 1.0f - VERTEX_WEIGHT_LOCK_EPSILON) {
1005 if (weight != 0.0f) {
1006 return 1.0f;
1007 }
1008
1009 /* resolve 0/0 to 0 */
1010 return 0.0f;
1011 }
1012
1013 /* non-degenerate division */
1014 return weight / (1.0f - locked_weight);
1015}
1016
1017float BKE_defvert_lock_relative_weight(const float weight,
1018 const MDeformVert *dv,
1019 const int defbase_num,
1020 const bool *defbase_locked,
1021 const bool *defbase_unlocked)
1022{
1023 float unlocked = BKE_defvert_total_selected_weight(dv, defbase_num, defbase_unlocked);
1024
1025 if (unlocked > 0.0f) {
1026 return weight / unlocked;
1027 }
1028
1029 float locked = BKE_defvert_total_selected_weight(dv, defbase_num, defbase_locked);
1030
1031 return BKE_defvert_calc_lock_relative_weight(weight, locked, unlocked);
1032}
1033
1034/* -------------------------------------------------------------------- */
1037
1038void BKE_defvert_array_copy(MDeformVert *dst, const MDeformVert *src, int totvert)
1039{
1040 /* Assumes dst is already set up */
1041
1042 if (!src || !dst) {
1043 return;
1044 }
1045
1046 memcpy(dst, src, totvert * sizeof(MDeformVert));
1047
1048 for (int i = 0; i < totvert; i++) {
1049 if (src[i].dw) {
1050 dst[i].dw = MEM_malloc_arrayN<MDeformWeight>(size_t(src[i].totweight), __func__);
1051 memcpy(dst[i].dw, src[i].dw, sizeof(MDeformWeight) * src[i].totweight);
1052 }
1053 }
1054}
1055
1057{
1058 /* Instead of freeing the verts directly,
1059 * call this function to delete any special
1060 * vert data */
1061
1062 if (!dvert) {
1063 return;
1064 }
1065
1066 /* Free any special data from the verts */
1067 for (int i = 0; i < totvert; i++) {
1068 if (dvert[i].dw) {
1069 MEM_freeN(dvert[i].dw);
1070 }
1071 }
1072}
1073
1074void BKE_defvert_array_free(MDeformVert *dvert, int totvert)
1075{
1076 /* Instead of freeing the verts directly,
1077 * call this function to delete any special
1078 * vert data */
1079 if (!dvert) {
1080 return;
1081 }
1082
1083 /* Free any special data from the verts */
1084 BKE_defvert_array_free_elems(dvert, totvert);
1085
1086 MEM_freeN(dvert);
1087}
1088
1090 const int defgroup,
1091 const int verts_num,
1092 const bool invert_vgroup,
1093 float *r_weights)
1094{
1095 if (dvert && defgroup != -1) {
1096 int i = verts_num;
1097
1098 while (i--) {
1099 const float w = BKE_defvert_find_weight(&dvert[i], defgroup);
1100 r_weights[i] = invert_vgroup ? (1.0f - w) : w;
1101 }
1102 }
1103 else {
1104 copy_vn_fl(r_weights, verts_num, invert_vgroup ? 1.0f : 0.0f);
1105 }
1106}
1107
1109 const int defgroup,
1110 const int verts_num,
1112 const bool invert_vgroup,
1113 float *r_weights)
1114{
1115 if (UNLIKELY(!dvert || defgroup == -1)) {
1116 copy_vn_fl(r_weights, edges.size(), 0.0f);
1117 return;
1118 }
1119
1120 int i = edges.size();
1121 float *tmp_weights = MEM_malloc_arrayN<float>(size_t(verts_num), __func__);
1122
1124 dvert, defgroup, verts_num, invert_vgroup, tmp_weights);
1125
1126 while (i--) {
1127 const blender::int2 &edge = edges[i];
1128
1129 r_weights[i] = (tmp_weights[edge[0]] + tmp_weights[edge[1]]) * 0.5f;
1130 }
1131
1132 MEM_freeN(tmp_weights);
1133}
1134
1136 const int defgroup,
1137 const int verts_num,
1138 const Span<int> corner_verts,
1139 const bool invert_vgroup,
1140 float *r_weights)
1141{
1142 if (UNLIKELY(!dvert || defgroup == -1)) {
1143 copy_vn_fl(r_weights, corner_verts.size(), 0.0f);
1144 return;
1145 }
1146
1147 int i = corner_verts.size();
1148 float *tmp_weights = MEM_malloc_arrayN<float>(size_t(verts_num), __func__);
1149
1151 dvert, defgroup, verts_num, invert_vgroup, tmp_weights);
1152
1153 while (i--) {
1154 r_weights[i] = tmp_weights[corner_verts[i]];
1155 }
1156
1157 MEM_freeN(tmp_weights);
1158}
1159
1161 const int defgroup,
1162 const int verts_num,
1163 const Span<int> corner_verts,
1165 const bool invert_vgroup,
1166 float *r_weights)
1167{
1168 if (UNLIKELY(!dvert || defgroup == -1)) {
1169 copy_vn_fl(r_weights, faces.size(), 0.0f);
1170 return;
1171 }
1172
1173 int i = faces.size();
1174 float *tmp_weights = MEM_malloc_arrayN<float>(size_t(verts_num), __func__);
1175
1177 dvert, defgroup, verts_num, invert_vgroup, tmp_weights);
1178
1179 while (i--) {
1180 const blender::IndexRange face = faces[i];
1181 const int *corner_vert = &corner_verts[face.start()];
1182 int j = face.size();
1183 float w = 0.0f;
1184
1185 for (; j--; corner_vert++) {
1186 w += tmp_weights[*corner_vert];
1187 }
1188 r_weights[i] = w / float(face.size());
1189 }
1190
1191 MEM_freeN(tmp_weights);
1192}
1193
1195
1196/* -------------------------------------------------------------------- */
1199
1201 void *dest,
1202 const void **sources,
1203 const float *weights,
1204 const int count,
1205 const float mix_factor)
1206{
1207 MDeformVert **data_src = (MDeformVert **)sources;
1208 MDeformVert *data_dst = (MDeformVert *)dest;
1209 const int idx_src = laymap->data_src_n;
1210 const int idx_dst = laymap->data_dst_n;
1211
1212 const int mix_mode = laymap->mix_mode;
1213
1214 int i, j;
1215
1216 MDeformWeight *dw_dst = BKE_defvert_find_index(data_dst, idx_dst);
1217 float weight_src = 0.0f, weight_dst = 0.0f;
1218
1219 bool has_dw_sources = false;
1220 if (sources) {
1221 for (i = count; i--;) {
1222 for (j = data_src[i]->totweight; j--;) {
1223 const MDeformWeight *dw_src = &data_src[i]->dw[j];
1224 if (dw_src->def_nr == idx_src) {
1225 weight_src += dw_src->weight * weights[i];
1226 has_dw_sources = true;
1227 break;
1228 }
1229 }
1230 }
1231 }
1232
1233 if (dw_dst) {
1234 weight_dst = dw_dst->weight;
1235 }
1236 else if (mix_mode == CDT_MIX_REPLACE_ABOVE_THRESHOLD) {
1237 return; /* Do not affect destination. */
1238 }
1239
1240 weight_src = data_transfer_interp_float_do(mix_mode, weight_dst, weight_src, mix_factor);
1241
1242 CLAMP(weight_src, 0.0f, 1.0f);
1243
1244 /* Do not create a destination MDeformWeight data if we had no sources at all. */
1245 if (!has_dw_sources) {
1246 BLI_assert(weight_src == 0.0f);
1247 if (dw_dst) {
1248 dw_dst->weight = weight_src;
1249 }
1250 }
1251 else if (!dw_dst) {
1252 BKE_defvert_add_index_notest(data_dst, idx_dst, weight_src);
1253 }
1254 else {
1255 dw_dst->weight = weight_src;
1256 }
1257}
1258
1260 const int mix_mode,
1261 const float mix_factor,
1262 const float *mix_weights,
1263 const bool use_create,
1264 const bool use_delete,
1265 Object *ob_dst,
1266 const Mesh &mesh_src,
1267 Mesh &mesh_dst,
1268 const bool /*use_dupref_dst*/,
1269 const int tolayers,
1270 const bool *use_layers_src,
1271 const int num_layers_src)
1272{
1273 int idx_src;
1274 int idx_dst;
1275 const ListBase *src_list = &mesh_src.vertex_group_names;
1276 ListBase *dst_defbase = &mesh_dst.vertex_group_names;
1277
1278 const int tot_dst = BLI_listbase_count(dst_defbase);
1279
1280 const size_t elem_size = sizeof(MDeformVert);
1281
1282 switch (tolayers) {
1284 idx_dst = tot_dst;
1285
1286 /* Find last source actually used! */
1287 idx_src = num_layers_src;
1288 while (idx_src-- && !use_layers_src[idx_src]) {
1289 /* pass */
1290 }
1291 idx_src++;
1292
1293 if (idx_dst < idx_src) {
1294 if (use_create) {
1295 /* Create as much vgroups as necessary! */
1296 for (; idx_dst < idx_src; idx_dst++) {
1298 }
1299 }
1300 else {
1301 /* Otherwise, just try to map what we can with existing dst vgroups. */
1302 idx_src = idx_dst;
1303 }
1304 }
1305 else if (use_delete && idx_dst > idx_src) {
1306 while (idx_dst-- > idx_src) {
1307 BKE_object_defgroup_remove(ob_dst, static_cast<bDeformGroup *>(dst_defbase->last));
1308 }
1309 }
1310 if (r_map) {
1311 while (idx_src--) {
1312 if (!use_layers_src[idx_src]) {
1313 continue;
1314 }
1317 mix_mode,
1318 mix_factor,
1319 mix_weights,
1320 mesh_src.deform_verts().data(),
1321 mesh_dst.deform_verts_for_write().data(),
1322 idx_src,
1323 idx_src,
1324 elem_size,
1325 0,
1326 0,
1327 0,
1329 nullptr);
1330 }
1331 }
1332 break;
1333 case DT_LAYERS_NAME_DST: {
1334 bDeformGroup *dg_src, *dg_dst;
1335
1336 if (use_delete) {
1337 /* Remove all unused dst vgroups first, simpler in this case. */
1338 for (dg_dst = static_cast<bDeformGroup *>(dst_defbase->first); dg_dst;) {
1339 bDeformGroup *dg_dst_next = dg_dst->next;
1340
1341 if (BKE_id_defgroup_name_index(&mesh_src.id, dg_dst->name) == -1) {
1342 BKE_object_defgroup_remove(ob_dst, dg_dst);
1343 }
1344 dg_dst = dg_dst_next;
1345 }
1346 }
1347
1348 for (idx_src = 0, dg_src = static_cast<bDeformGroup *>(src_list->first);
1349 idx_src < num_layers_src;
1350 idx_src++, dg_src = dg_src->next)
1351 {
1352 if (!use_layers_src[idx_src]) {
1353 continue;
1354 }
1355
1356 idx_dst = BKE_object_defgroup_name_index(ob_dst, dg_src->name);
1357 if (idx_dst == -1) {
1358 if (use_create) {
1359 BKE_object_defgroup_add_name(ob_dst, dg_src->name);
1360 idx_dst = BKE_object_defgroup_active_index_get(ob_dst) - 1;
1361 }
1362 else {
1363 /* If we are not allowed to create missing dst vgroups, just skip matching src one. */
1364 continue;
1365 }
1366 }
1367 if (r_map) {
1370 mix_mode,
1371 mix_factor,
1372 mix_weights,
1373 mesh_src.deform_verts().data(),
1374 mesh_dst.deform_verts_for_write().data(),
1375 idx_src,
1376 idx_dst,
1377 elem_size,
1378 0,
1379 0,
1380 0,
1382 nullptr);
1383 }
1384 }
1385 break;
1386 }
1387 default:
1388 return false;
1389 }
1390
1391 return true;
1392}
1393
1395 const int mix_mode,
1396 const float mix_factor,
1397 const float *mix_weights,
1398 const bool use_create,
1399 const bool use_delete,
1400 Object *ob_src,
1401 Object *ob_dst,
1402 const Mesh &mesh_src,
1403 Mesh &mesh_dst,
1404 const bool use_dupref_dst,
1405 const int fromlayers,
1406 const int tolayers)
1407{
1408 int idx_src, idx_dst;
1409
1410 const size_t elem_size = sizeof(MDeformVert);
1411
1412 /* NOTE:
1413 * We may have to handle data layout itself while having nullptr data itself,
1414 * and even have to support nullptr data_src in transfer data code
1415 * (we always create a data_dst, though).
1416 */
1417
1418 const ListBase *src_defbase = BKE_object_defgroup_list(ob_src);
1419 if (BLI_listbase_is_empty(src_defbase)) {
1420 if (use_delete) {
1422 }
1423 return true;
1424 }
1425
1426 if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) {
1427 /* NOTE: use_delete has not much meaning in this case, ignored. */
1428
1429 if (fromlayers >= 0) {
1430 idx_src = fromlayers;
1431 if (idx_src >= BLI_listbase_count(src_defbase)) {
1432 /* This can happen when vgroups are removed from source object...
1433 * Remapping would be really tricky here, we'd need to go over all objects in
1434 * Main every time we delete a vgroup... for now, simpler and safer to abort. */
1435 return false;
1436 }
1437 }
1438 else if ((idx_src = BKE_object_defgroup_active_index_get(ob_src) - 1) == -1) {
1439 return false;
1440 }
1441
1442 if (tolayers >= 0) {
1443 /* NOTE: in this case we assume layer exists! */
1444 idx_dst = tolayers;
1445 const ListBase *dst_defbase = BKE_object_defgroup_list(ob_dst);
1446 BLI_assert(idx_dst < BLI_listbase_count(dst_defbase));
1447 UNUSED_VARS_NDEBUG(dst_defbase);
1448 }
1449 else if (tolayers == DT_LAYERS_ACTIVE_DST) {
1450 idx_dst = BKE_object_defgroup_active_index_get(ob_dst) - 1;
1451 if (idx_dst == -1) {
1452 bDeformGroup *dg_src;
1453 if (!use_create) {
1454 return true;
1455 }
1456 dg_src = static_cast<bDeformGroup *>(BLI_findlink(src_defbase, idx_src));
1457 BKE_object_defgroup_add_name(ob_dst, dg_src->name);
1458 idx_dst = BKE_object_defgroup_active_index_get(ob_dst) - 1;
1459 }
1460 }
1461 else if (tolayers == DT_LAYERS_INDEX_DST) {
1462 int num = BLI_listbase_count(src_defbase);
1463 idx_dst = idx_src;
1464 if (num <= idx_dst) {
1465 if (!use_create) {
1466 return true;
1467 }
1468 /* Create as much vgroups as necessary! */
1469 for (; num <= idx_dst; num++) {
1471 }
1472 }
1473 }
1474 else if (tolayers == DT_LAYERS_NAME_DST) {
1475 bDeformGroup *dg_src = static_cast<bDeformGroup *>(BLI_findlink(src_defbase, idx_src));
1476 idx_dst = BKE_object_defgroup_name_index(ob_dst, dg_src->name);
1477 if (idx_dst == -1) {
1478 if (!use_create) {
1479 return true;
1480 }
1481 BKE_object_defgroup_add_name(ob_dst, dg_src->name);
1482 idx_dst = BKE_object_defgroup_active_index_get(ob_dst) - 1;
1483 }
1484 }
1485 else {
1486 return false;
1487 }
1488
1489 if (r_map) {
1492 mix_mode,
1493 mix_factor,
1494 mix_weights,
1495 mesh_src.deform_verts().data(),
1496 mesh_dst.deform_verts_for_write().data(),
1497 idx_src,
1498 idx_dst,
1499 elem_size,
1500 0,
1501 0,
1502 0,
1504 nullptr);
1505 }
1506 }
1507 else {
1508 int num_src, num_sel_unused;
1509 bool *use_layers_src = nullptr;
1510 bool ret = false;
1511
1512 switch (fromlayers) {
1513 case DT_LAYERS_ALL_SRC:
1515 ob_src, WT_VGROUP_ALL, &num_src, &num_sel_unused);
1516 break;
1519 ob_src, WT_VGROUP_BONE_SELECT, &num_src, &num_sel_unused);
1520 break;
1523 ob_src, WT_VGROUP_BONE_DEFORM, &num_src, &num_sel_unused);
1524 break;
1525 }
1526
1527 if (use_layers_src) {
1529 mix_mode,
1530 mix_factor,
1531 mix_weights,
1532 use_create,
1533 use_delete,
1534 ob_dst,
1535 mesh_src,
1536 mesh_dst,
1537 use_dupref_dst,
1538 tolayers,
1539 use_layers_src,
1540 num_src);
1541 }
1542
1543 MEM_SAFE_FREE(use_layers_src);
1544 return ret;
1545 }
1546
1547 return true;
1548}
1549
1551
1552/* -------------------------------------------------------------------- */
1555
1556void BKE_defvert_weight_to_rgb(float r_rgb[3], const float weight)
1557{
1558 const float blend = ((weight / 2.0f) + 0.5f);
1559
1560 if (weight <= 0.25f) { /* blue->cyan */
1561 r_rgb[0] = 0.0f;
1562 r_rgb[1] = blend * weight * 4.0f;
1563 r_rgb[2] = blend;
1564 }
1565 else if (weight <= 0.50f) { /* cyan->green */
1566 r_rgb[0] = 0.0f;
1567 r_rgb[1] = blend;
1568 r_rgb[2] = blend * (1.0f - ((weight - 0.25f) * 4.0f));
1569 }
1570 else if (weight <= 0.75f) { /* green->yellow */
1571 r_rgb[0] = blend * ((weight - 0.50f) * 4.0f);
1572 r_rgb[1] = blend;
1573 r_rgb[2] = 0.0f;
1574 }
1575 else if (weight <= 1.0f) { /* yellow->red */
1576 r_rgb[0] = blend;
1577 r_rgb[1] = blend * (1.0f - ((weight - 0.75f) * 4.0f));
1578 r_rgb[2] = 0.0f;
1579 }
1580 else {
1581 /* exceptional value, unclamped or nan,
1582 * avoid uninitialized memory use */
1583 r_rgb[0] = 1.0f;
1584 r_rgb[1] = 0.0f;
1585 r_rgb[2] = 1.0f;
1586 }
1587}
1588
1590
1591/* -------------------------------------------------------------------- */
1594
1595void BKE_defbase_blend_write(BlendWriter *writer, const ListBase *defbase)
1596{
1597 LISTBASE_FOREACH (bDeformGroup *, defgroup, defbase) {
1598 BLO_write_struct(writer, bDeformGroup, defgroup);
1599 }
1600}
1601
1602void BKE_defvert_blend_write(BlendWriter *writer, int count, const MDeformVert *dvlist)
1603{
1604 if (dvlist == nullptr) {
1605 return;
1606 }
1607
1608 /* Write the dvert list */
1609 BLO_write_struct_array(writer, MDeformVert, count, dvlist);
1610
1611 /* Write deformation data for each dvert */
1612 for (int i = 0; i < count; i++) {
1613 if (dvlist[i].dw) {
1614 BLO_write_struct_array(writer, MDeformWeight, dvlist[i].totweight, dvlist[i].dw);
1615 }
1616 }
1617}
1618
1620{
1621 if (mdverts == nullptr) {
1622 return;
1623 }
1624
1625 for (int i = count; i > 0; i--, mdverts++) {
1626 /* Convert to vertex group allocation system. */
1627 MDeformWeight *dw = mdverts->dw;
1628 BLO_read_struct_array(reader, MDeformWeight, mdverts->totweight, &dw);
1629 if (dw) {
1630 void *dw_tmp = MEM_malloc_arrayN<MDeformWeight>(size_t(mdverts->totweight), __func__);
1631 const size_t dw_len = sizeof(MDeformWeight) * mdverts->totweight;
1632 memcpy(dw_tmp, dw, dw_len);
1633 mdverts->dw = static_cast<MDeformWeight *>(dw_tmp);
1634 MEM_freeN(dw);
1635 }
1636 else {
1637 mdverts->dw = nullptr;
1638 mdverts->totweight = 0;
1639 }
1640 }
1641}
1642
1644
1645/* -------------------------------------------------------------------- */
1648
1649namespace blender::bke {
1650
1652 private:
1653 MDeformVert *dverts_;
1654 const int dvert_index_;
1655
1656 public:
1658 : VMutableArrayImpl<float>(dverts.size()), dverts_(dverts.data()), dvert_index_(dvert_index)
1659 {
1660 }
1661
1663 : VMutableArrayImpl<float>(dverts.size()),
1664 dverts_(const_cast<MDeformVert *>(dverts.data())),
1665 dvert_index_(dvert_index)
1666 {
1667 }
1668
1669 float get(const int64_t index) const override
1670 {
1671 if (dverts_ == nullptr) {
1672 return 0.0f;
1673 }
1674 if (const MDeformWeight *weight = this->find_weight_at_index(index)) {
1675 return weight->weight;
1676 }
1677 return 0.0f;
1678 }
1679
1680 void set(const int64_t index, const float value) override
1681 {
1682 MDeformVert &dvert = dverts_[index];
1683 if (value == 0.0f) {
1684 if (MDeformWeight *weight = this->find_weight_at_index(index)) {
1685 weight->weight = 0.0f;
1686 }
1687 }
1688 else {
1689 MDeformWeight *weight = BKE_defvert_ensure_index(&dvert, dvert_index_);
1690 weight->weight = value;
1691 }
1692 }
1693
1694 void set_all(Span<float> src) override
1695 {
1696 threading::parallel_for(src.index_range(), 4096, [&](const IndexRange range) {
1697 for (const int64_t i : range) {
1698 this->set(i, src[i]);
1699 }
1700 });
1701 }
1702
1704 float *dst,
1705 const bool /*dst_is_uninitialized*/) const override
1706 {
1707 if (dverts_ == nullptr) {
1708 mask.foreach_index([&](const int i) { dst[i] = 0.0f; });
1709 }
1710 threading::parallel_for(mask.index_range(), 4096, [&](const IndexRange range) {
1711 mask.slice(range).foreach_index_optimized<int64_t>([&](const int64_t index) {
1712 if (const MDeformWeight *weight = this->find_weight_at_index(index)) {
1713 dst[index] = weight->weight;
1714 }
1715 else {
1716 dst[index] = 0.0f;
1717 }
1718 });
1719 });
1720 }
1721
1722 private:
1723 MDeformWeight *find_weight_at_index(const int64_t index)
1724 {
1725 for (MDeformWeight &weight : MutableSpan(dverts_[index].dw, dverts_[index].totweight)) {
1726 if (weight.def_nr == dvert_index_) {
1727 return &weight;
1728 }
1729 }
1730 return nullptr;
1731 }
1732 const MDeformWeight *find_weight_at_index(const int64_t index) const
1733 {
1734 for (const MDeformWeight &weight : Span(dverts_[index].dw, dverts_[index].totweight)) {
1735 if (weight.def_nr == dvert_index_) {
1736 return &weight;
1737 }
1738 }
1739 return nullptr;
1740 }
1741};
1742
1744{
1745 return VArray<float>::from<VArrayImpl_For_VertexWeights>(dverts, defgroup_index);
1746}
1748 const int defgroup_index)
1749{
1750 return VMutableArray<float>::from<VArrayImpl_For_VertexWeights>(dverts, defgroup_index);
1751}
1752
1753void remove_defgroup_index(MutableSpan<MDeformVert> dverts, const int defgroup_index)
1754{
1755 threading::parallel_for(dverts.index_range(), 1024, [&](IndexRange range) {
1756 for (MDeformVert &dvert : dverts.slice(range)) {
1757 MDeformWeight *weight = BKE_defvert_find_index(&dvert, defgroup_index);
1758 BKE_defvert_remove_group(&dvert, weight);
1759 for (MDeformWeight &weight : MutableSpan(dvert.dw, dvert.totweight)) {
1760 if (weight.def_nr > defgroup_index) {
1761 weight.def_nr--;
1762 }
1763 }
1764 }
1765 });
1766}
1767
1769 const Span<int> indices,
1771{
1772 threading::parallel_for(indices.index_range(), 512, [&](const IndexRange range) {
1773 for (const int dst_i : range) {
1774 const int src_i = indices[dst_i];
1775 dst[dst_i].dw = static_cast<MDeformWeight *>(MEM_dupallocN(src[src_i].dw));
1776 dst[dst_i].totweight = src[src_i].totweight;
1777 dst[dst_i].flag = src[src_i].flag;
1778 }
1779 });
1780}
1782 const IndexMask &indices,
1784{
1785 indices.foreach_index(GrainSize(512), [&](const int64_t src_i, const int64_t dst_i) {
1786 dst[dst_i].dw = static_cast<MDeformWeight *>(MEM_dupallocN(src[src_i].dw));
1787 dst[dst_i].totweight = src[src_i].totweight;
1788 dst[dst_i].flag = src[src_i].flag;
1789 });
1790}
1791
1792} // namespace blender::bke
1793
CustomData interface, see also DNA_customdata_types.h.
support for deformation groups and hooks.
MDeformWeight * BKE_defvert_ensure_index(MDeformVert *dv, int defgroup)
Definition deform.cc:825
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:774
#define VERTEX_WEIGHT_LOCK_EPSILON
Low-level operations for grease pencil.
void BKE_grease_pencil_vgroup_name_update(Object *ob, const char *old_name, const char *new_name)
Utility functions for vertex groups in grease pencil objects.
General operations, lookup, etc. for blender objects.
void BKE_object_batch_cache_dirty_tag(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)
void BKE_object_defgroup_remove(struct Object *ob, struct bDeformGroup *defgroup)
struct bDeformGroup * BKE_object_defgroup_add(struct Object *ob)
struct bDeformGroup * BKE_object_defgroup_add_name(struct Object *ob, const char *name)
void BKE_object_defgroup_remove_all(struct Object *ob)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define final(a, b, c)
Definition BLI_hash.h:19
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 void BLI_listbase_clear(ListBase *lb)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
MINLINE float max_ff(float a, float b)
void copy_vn_fl(float *array_tar, int size, float val)
ATTR_WARN_UNUSED_RESULT const size_t num
#define STRNCPY_UTF8(dst, src)
size_t BLI_string_flip_side_name(char *name_dst, const char *name_src, bool strip_number, size_t name_dst_maxncpy) ATTR_NONNULL(1
size_t void BLI_uniquename_cb(blender::FunctionRef< bool(blender::StringRefNull)> unique_check, const char *defname, char delim, char *name, size_t name_maxncpy) ATTR_NONNULL(2
unsigned int uint
#define CLAMP(a, b, c)
#define UNUSED_VARS_NDEBUG(...)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
#define LIKELY(x)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define DATA_(msgid)
@ ID_GD_LEGACY
@ ID_ME
@ ID_LT
@ ID_GP
@ DT_LAYERS_VGROUP_SRC_BONE_SELECT
@ DT_LAYERS_VGROUP_SRC_BONE_DEFORM
@ DT_LAYERS_ALL_SRC
@ DT_LAYERS_ACTIVE_SRC
@ DT_LAYERS_ACTIVE_DST
@ DT_LAYERS_INDEX_DST
@ DT_LAYERS_NAME_DST
@ CDT_MIX_REPLACE_ABOVE_THRESHOLD
Object is a sort of wrapper for general info.
@ DG_LOCK_WEIGHT
@ OB_LATTICE
@ OB_GREASE_PENCIL
@ OB_MESH
@ OB_GPENCIL_LEGACY
#define OB_TYPE_SUPPORT_VGROUP(_type)
@ WT_VGROUP_BONE_SELECT
@ WT_VGROUP_ALL
@ WT_VGROUP_BONE_DEFORM
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
BMesh const char void * data
long long int int64_t
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
static VArray from(Args &&...args)
constexpr int64_t size() const
constexpr int64_t start() const
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
static VMutableArray from(Args &&...args)
void set_all(Span< float > src) override
Definition deform.cc:1694
float get(const int64_t index) const override
Definition deform.cc:1669
void set(const int64_t index, const float value) override
Definition deform.cc:1680
VArrayImpl_For_VertexWeights(MutableSpan< MDeformVert > dverts, const int dvert_index)
Definition deform.cc:1657
VArrayImpl_For_VertexWeights(Span< MDeformVert > dverts, const int dvert_index)
Definition deform.cc:1662
void materialize(const IndexMask &mask, float *dst, const bool) const override
Definition deform.cc:1703
nullptr float
void data_transfer_layersmapping_add_item(ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights, const void *data_src, void *data_dst, const int data_src_n, const int data_dst_n, const size_t elem_size, const size_t data_size, const size_t data_offset, const uint64_t data_flag, cd_datatransfer_interp interp, void *interp_data)
float data_transfer_interp_float_do(const int mix_mode, const float val_dst, const float val_src, const float mix_factor)
@ CD_FAKE_MDEFORMVERT
void BKE_defvert_extract_vgroup_to_faceweights(const MDeformVert *dvert, const int defgroup, const int verts_num, const Span< int > corner_verts, const blender::OffsetIndices< int > faces, const bool invert_vgroup, float *r_weights)
Definition deform.cc:1160
int BKE_object_defgroup_name_index(const Object *ob, const StringRef name)
Definition deform.cc:591
void BKE_defvert_blend_write(BlendWriter *writer, int count, const MDeformVert *dvlist)
Definition deform.cc:1602
void BKE_defbase_blend_write(BlendWriter *writer, const ListBase *defbase)
Definition deform.cc:1595
ListBase * BKE_id_defgroup_list_get_mutable(ID *id)
Definition deform.cc:520
void BKE_defvert_array_free(MDeformVert *dvert, int totvert)
Definition deform.cc:1074
static const int * object_defgroup_active_index_get_p(const Object *ob)
Definition deform.cc:496
void BKE_defvert_array_copy(MDeformVert *dst, const MDeformVert *src, int totvert)
Definition deform.cc:1038
bool BKE_defgroup_listbase_name_find(const ListBase *defbase, const StringRef name, int *r_index, bDeformGroup **r_group)
Definition deform.cc:554
bool BKE_id_supports_vertex_groups(const ID *id)
Definition deform.cc:455
int BKE_object_defgroup_active_index_get(const Object *ob)
Definition deform.cc:607
bDeformGroup * BKE_object_defgroup_find_name(const Object *ob, const StringRef name)
Definition deform.cc:526
void BKE_defvert_flip_merged(MDeformVert *dvert, const int *flip_map, const int flip_map_num)
Definition deform.cc:430
static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map, const int mix_mode, const float mix_factor, const float *mix_weights, const bool use_create, const bool use_delete, Object *ob_dst, const Mesh &mesh_src, Mesh &mesh_dst, const bool, const int tolayers, const bool *use_layers_src, const int num_layers_src)
Definition deform.cc:1259
void BKE_defvert_copy_index(MDeformVert *dvert_dst, const int defgroup_dst, const MDeformVert *dvert_src, const int defgroup_src)
Definition deform.cc:150
float BKE_defvert_lock_relative_weight(const float weight, const MDeformVert *dv, const int defbase_num, const bool *defbase_locked, const bool *defbase_unlocked)
Definition deform.cc:1017
void BKE_defvert_copy_subset(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const bool *vgroup_subset, const int vgroup_num)
Definition deform.cc:99
void BKE_defvert_extract_vgroup_to_loopweights(const MDeformVert *dvert, const int defgroup, const int verts_num, const Span< int > corner_verts, const bool invert_vgroup, float *r_weights)
Definition deform.cc:1135
int BKE_defgroup_name_index(const ListBase *defbase, const StringRef name)
Definition deform.cc:540
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_weight_to_rgb(float r_rgb[3], const float weight)
Definition deform.cc:1556
void BKE_defvert_normalize_ex(MDeformVert &dvert, blender::Span< bool > subset_flags, blender::Span< bool > lock_flags, blender::Span< bool > soft_lock_flags)
Definition deform.cc:249
float BKE_defvert_array_find_weight_safe(const MDeformVert *dvert, const int index, const int defgroup, const bool invert)
Definition deform.cc:780
int BKE_object_defgroup_count(const Object *ob)
Definition deform.cc:602
int * BKE_object_defgroup_flip_map_single(const Object *ob, const bool use_default, const int defgroup, int *r_flip_map_num)
Definition deform.cc:679
bool BKE_id_defgroup_name_find(const ID *id, const StringRef name, int *r_index, bDeformGroup **r_group)
Definition deform.cc:577
bool BKE_defvert_is_weight_zero(const MDeformVert *dvert, const int defgroup_tot)
Definition deform.cc:936
void BKE_object_defgroup_active_index_set(Object *ob, const int new_index)
Definition deform.cc:612
const ListBase * BKE_object_defgroup_list(const Object *ob)
Definition deform.cc:585
static bool defgroup_find_name_dupe(const StringRef name, bDeformGroup *dg, Object *ob)
Definition deform.cc:737
int BKE_object_defgroup_flip_index(const Object *ob, int index, const bool use_default)
Definition deform.cc:714
float BKE_defvert_calc_lock_relative_weight(float weight, float locked_weight, float unlocked_weight)
Definition deform.cc:989
void BKE_defvert_normalize(MDeformVert &dvert)
Definition deform.cc:237
int BKE_id_defgroup_name_index(const ID *id, const StringRef name)
Definition deform.cc:549
float BKE_defvert_find_weight(const MDeformVert *dvert, const int defgroup)
Definition deform.cc:774
void BKE_defvert_sync(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const bool use_ensure)
Definition deform.cc:174
static void vgroups_datatransfer_interp(const CustomDataTransferLayerMap *laymap, void *dest, const void **sources, const float *weights, const int count, const float mix_factor)
Definition deform.cc:1200
void BKE_defvert_mirror_subset(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const bool *vgroup_subset, const int vgroup_num, const int *flip_map, const int flip_map_num)
Definition deform.cc:112
int BKE_defvert_find_shared(const MDeformVert *dvert_a, const MDeformVert *dvert_b)
Definition deform.cc:920
void BKE_object_defgroup_unique_name(bDeformGroup *dg, Object *ob)
Definition deform.cc:752
void BKE_defvert_array_free_elems(MDeformVert *dvert, int totvert)
Definition deform.cc:1056
float BKE_defvert_total_selected_weight(const MDeformVert *dv, int defbase_num, const bool *defbase_sel)
Definition deform.cc:950
bool data_transfer_layersmapping_vgroups(ListBase *r_map, const int mix_mode, const float mix_factor, const float *mix_weights, const bool use_create, const bool use_delete, Object *ob_src, Object *ob_dst, const Mesh &mesh_src, Mesh &mesh_dst, const bool use_dupref_dst, const int fromlayers, const int tolayers)
Definition deform.cc:1394
bDeformGroup * BKE_object_defgroup_new(Object *ob, const StringRef name)
Definition deform.cc:48
void BKE_defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
Definition deform.cc:73
float BKE_defvert_multipaint_collective_weight(const MDeformVert *dv, const int defbase_num, const bool *defbase_sel, const int defbase_sel_num, const bool is_normalized)
Definition deform.cc:972
void BKE_defvert_extract_vgroup_to_vertweights(const MDeformVert *dvert, const int defgroup, const int verts_num, const bool invert_vgroup, float *r_weights)
Definition deform.cc:1089
void BKE_defvert_clear(MDeformVert *dvert)
Definition deform.cc:913
ListBase * BKE_object_defgroup_list_mutable(Object *ob)
Definition deform.cc:596
void BKE_defvert_flip(MDeformVert *dvert, const int *flip_map, const int flip_map_num)
Definition deform.cc:416
void BKE_defvert_add_index_notest(MDeformVert *dvert, const int defgroup, const float weight)
Definition deform.cc:856
void BKE_defvert_blend_read(BlendDataReader *reader, int count, MDeformVert *mdverts)
Definition deform.cc:1619
static int * object_defgroup_unlocked_flip_map_ex(const Object *ob, const bool use_default, const bool use_only_unlocked, int *r_flip_map_num)
Definition deform.cc:619
void BKE_defvert_copy(MDeformVert *dvert_dst, const MDeformVert *dvert_src)
Definition deform.cc:127
void BKE_defvert_sync_mapped(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const int *flip_map, const int flip_map_num, const bool use_ensure)
Definition deform.cc:194
int * BKE_object_defgroup_flip_map(const Object *ob, const bool use_default, int *r_flip_map_num)
Definition deform.cc:667
MDeformWeight * BKE_defvert_ensure_index(MDeformVert *dvert, const int defgroup)
Definition deform.cc:825
void BKE_defvert_remove_group(MDeformVert *dvert, MDeformWeight *dw)
Definition deform.cc:880
void BKE_defvert_remap(MDeformVert *dvert, const int *map, const int map_len)
Definition deform.cc:220
void BKE_defvert_normalize_lock_map(MDeformVert &dvert, blender::Span< bool > subset_flags, blender::Span< bool > lock_flags)
Definition deform.cc:242
MDeformWeight * BKE_defvert_find_index(const MDeformVert *dvert, const int defgroup)
Definition deform.cc:806
const ListBase * BKE_id_defgroup_list_get(const ID *id)
Definition deform.cc:470
void BKE_defvert_normalize_subset(MDeformVert &dvert, blender::Span< bool > subset_flags)
Definition deform.cc:232
int * BKE_object_defgroup_flip_map_unlocked(const Object *ob, const bool use_default, int *r_flip_map_num)
Definition deform.cc:672
void BKE_object_defgroup_set_name(bDeformGroup *dg, Object *ob, const char *new_name)
Definition deform.cc:762
void BKE_defvert_extract_vgroup_to_edgeweights(const MDeformVert *dvert, const int defgroup, const int verts_num, blender::Span< blender::int2 > edges, const bool invert_vgroup, float *r_weights)
Definition deform.cc:1108
#define GS(x)
static ushort indices[]
int count
CCL_NAMESPACE_BEGIN ccl_device float invert(const float color, const float factor)
Definition invert.h:11
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
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)
static char faces[256]
void validate_drawing_vertex_groups(GreasePencil &grease_pencil)
void remove_defgroup_index(MutableSpan< MDeformVert > dverts, int defgroup_index)
Definition deform.cc:1753
void gather_deform_verts(Span< MDeformVert > src, Span< int > indices, MutableSpan< MDeformVert > dst)
Definition deform.cc:1768
VMutableArray< float > varray_for_mutable_deform_verts(MutableSpan< MDeformVert > dverts, int defgroup_index)
Definition deform.cc:1747
VArray< float > varray_for_deform_verts(Span< MDeformVert > dverts, int defgroup_index)
Definition deform.cc:1743
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
const char * name
return ret
bDeformGroup * dg
Definition deform.cc:734
Definition DNA_ID.h:414
char name[258]
Definition DNA_ID.h:432
ListBase vertex_group_names
int vertex_group_active_index
void * last
void * first
struct MDeformWeight * dw
unsigned int def_nr
ListBase vertex_group_names
int vertex_group_active_index
struct bDeformGroup * next
struct bDeformGroup * prev
ListBase vertex_group_names
i
Definition text_draw.cc:230
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)