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