Blender V5.0
customdata.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2006 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11
12#include <algorithm>
13
14#include "MEM_guardedalloc.h"
15
16/* Since we have versioning code here (CustomData_verify_versions()). */
17#define DNA_DEPRECATED_ALLOW
18
19#include "DNA_ID.h"
21#include "DNA_meshdata_types.h"
22#include "DNA_modifier_enums.h"
23#include "DNA_userdef_types.h"
24#include "DNA_vec_types.h"
25
26#include "BLI_bit_vector.hh"
27#include "BLI_bitmap.h"
28#include "BLI_index_range.hh"
31#include "BLI_math_vector.hh"
32#include "BLI_memory_counter.hh"
33#include "BLI_mempool.h"
34#include "BLI_path_utils.hh"
35#include "BLI_resource_scope.hh"
36#include "BLI_set.hh"
37#include "BLI_span.hh"
38#include "BLI_string.h"
39#include "BLI_string_ref.hh"
40#include "BLI_string_utf8.h"
41#include "BLI_string_utils.hh"
42#include "BLI_utildefines.h"
43
44#ifndef NDEBUG
45# include "BLI_dynstr.h"
46#endif
47
48#include "BLT_translation.hh"
49
52#include "BKE_attribute_math.hh"
54#include "BKE_ccg.hh"
55#include "BKE_customdata.hh"
56#include "BKE_customdata_file.h"
57#include "BKE_deform.hh"
58#include "BKE_library.hh"
59#include "BKE_main.hh"
60#include "BKE_mesh_remap.hh"
61#include "BKE_multires.hh"
62
63#include "BLO_read_write.hh"
64
65#include "bmesh.hh"
66
67#include "CLG_log.h"
68
69/* only for customdata_data_transfer_interp_normal_normals */
71
72using blender::Array;
74using blender::float2;
78using blender::Set;
79using blender::Span;
81using blender::Vector;
82
83/* number of layers to add when growing a CustomData object */
84#define CUSTOMDATA_GROW 5
85
86/* ensure typemap size is ok */
87BLI_STATIC_ASSERT(BOUNDED_ARRAY_TYPE_SIZE<decltype(CustomData::typemap)>() == CD_NUMTYPES,
88 "size mismatch");
89
90static CLG_LogRef LOG = {"geom.customdata"};
91
92/* -------------------------------------------------------------------- */
95
97 const CustomData_MeshMasks *mask_src)
98{
99 mask_dst->vmask |= mask_src->vmask;
100 mask_dst->emask |= mask_src->emask;
101 mask_dst->fmask |= mask_src->fmask;
102 mask_dst->pmask |= mask_src->pmask;
103 mask_dst->lmask |= mask_src->lmask;
104}
105
107 const CustomData_MeshMasks *mask_required)
108{
109 return (((mask_required->vmask & mask_ref->vmask) == mask_required->vmask) &&
110 ((mask_required->emask & mask_ref->emask) == mask_required->emask) &&
111 ((mask_required->fmask & mask_ref->fmask) == mask_required->fmask) &&
112 ((mask_required->pmask & mask_ref->pmask) == mask_required->pmask) &&
113 ((mask_required->lmask & mask_ref->lmask) == mask_required->lmask));
114}
115
117
118/* -------------------------------------------------------------------- */
121
123 int size; /* the memory size of one element of this layer's data */
125
127 const char *structname;
130
137 const char *defaultname;
138
145
152
165
167 void (*swap)(void *data, const int *corner_indices);
168
178 void (*construct)(void *data, int count);
179
182
184 bool (*equal)(const void *data1, const void *data2);
185 void (*multiply)(void *data, float fac);
186 void (*initminmax)(void *min, void *max);
187 void (*add)(void *data1, const void *data2);
188 void (*dominmax)(const void *data1, void *min, void *max);
189 void (*copyvalue)(const void *source, void *dest, int mixmode, const float mixfactor);
190
192 bool (*read)(CDataFile *cdf, void *data, int count);
193
195 bool (*write)(CDataFile *cdf, const void *data, int count);
196
198 size_t (*filesize)(CDataFile *cdf, const void *data, int count);
199
204 int (*layers_max)();
205};
206
208
209/* -------------------------------------------------------------------- */
212
213static void layerCopy_mdeformvert(const void *source, void *dest, const int count)
214{
215 int i, size = sizeof(MDeformVert);
216
217 memcpy(dest, source, count * size);
218
219 for (i = 0; i < count; i++) {
220 MDeformVert *dvert = static_cast<MDeformVert *>(POINTER_OFFSET(dest, i * size));
221
222 if (dvert->totweight) {
223 MDeformWeight *dw = MEM_malloc_arrayN<MDeformWeight>(size_t(dvert->totweight), __func__);
224
225 memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw));
226 dvert->dw = dw;
227 }
228 else {
229 dvert->dw = nullptr;
230 }
231 }
232}
233
234static void layerFree_mdeformvert(void *data, const int count)
235{
236 for (MDeformVert &dvert : MutableSpan(static_cast<MDeformVert *>(data), count)) {
237 if (dvert.dw) {
238 MEM_freeN(dvert.dw);
239 dvert.dw = nullptr;
240 dvert.totweight = 0;
241 }
242 }
243}
244
245static void layerInterp_mdeformvert(const void **sources,
246 const float *weights,
247 const int count,
248 void *dest)
249{
250 /* A single linked list of #MDeformWeight's.
251 * use this to avoid double allocations (which #LinkNode would do). */
252 struct MDeformWeight_Link {
253 MDeformWeight_Link *next;
254 MDeformWeight dw;
255 };
256
257 MDeformVert *dvert = static_cast<MDeformVert *>(dest);
258 MDeformWeight_Link *dest_dwlink = nullptr;
259 MDeformWeight_Link *node;
260
261 /* build a list of unique def_nrs for dest */
262 int totweight = 0;
263 for (int i = 0; i < count; i++) {
264 const MDeformVert *source = static_cast<const MDeformVert *>(sources[i]);
265 float interp_weight = weights[i];
266
267 for (int j = 0; j < source->totweight; j++) {
268 MDeformWeight *dw = &source->dw[j];
269 float weight = dw->weight * interp_weight;
270
271 if (weight == 0.0f) {
272 continue;
273 }
274
275 for (node = dest_dwlink; node; node = node->next) {
276 MDeformWeight *tmp_dw = &node->dw;
277
278 if (tmp_dw->def_nr == dw->def_nr) {
279 tmp_dw->weight += weight;
280 break;
281 }
282 }
283
284 /* if this def_nr is not in the list, add it */
285 if (!node) {
286 MDeformWeight_Link *tmp_dwlink = static_cast<MDeformWeight_Link *>(
287 alloca(sizeof(*tmp_dwlink)));
288 tmp_dwlink->dw.def_nr = dw->def_nr;
289 tmp_dwlink->dw.weight = weight;
290
291 /* Inline linked-list. */
292 tmp_dwlink->next = dest_dwlink;
293 dest_dwlink = tmp_dwlink;
294
295 totweight++;
296 }
297 }
298 }
299
300 /* Delay writing to the destination in case dest is in sources. */
301
302 /* now we know how many unique deform weights there are, so realloc */
303 if (dvert->dw && (dvert->totweight == totweight)) {
304 /* pass (fast-path if we don't need to realloc). */
305 }
306 else {
307 if (dvert->dw) {
308 MEM_freeN(dvert->dw);
309 }
310
311 if (totweight) {
312 dvert->dw = MEM_malloc_arrayN<MDeformWeight>(size_t(totweight), __func__);
313 }
314 }
315
316 if (totweight) {
317 dvert->totweight = totweight;
318 int i = 0;
319 for (node = dest_dwlink; node; node = node->next, i++) {
320 node->dw.weight = std::min(node->dw.weight, 1.0f);
321 dvert->dw[i] = node->dw;
322 }
323 }
324 else {
325 *dvert = MDeformVert{};
326 }
327}
328
329static void layerConstruct_mdeformvert(void *data, const int count)
330{
331 std::fill_n(static_cast<MDeformVert *>(data), count, MDeformVert{});
332}
333
335
336/* -------------------------------------------------------------------- */
339
340static void layerInterp_normal(const void **sources,
341 const float *weights,
342 const int count,
343 void *dest)
344{
345 /* NOTE: This is linear interpolation, which is not optimal for vectors.
346 * Unfortunately, spherical interpolation of more than two values is hairy,
347 * so for now it will do... */
348 float no[3] = {0.0f};
349
350 for (const int i : IndexRange(count)) {
351 madd_v3_v3fl(no, (const float *)sources[i], weights[i]);
352 }
353
354 /* Weighted sum of normalized vectors will **not** be normalized, even if weights are. */
355 normalize_v3_v3((float *)dest, no);
356}
357
358static void layerCopyValue_normal(const void *source,
359 void *dest,
360 const int mixmode,
361 const float mixfactor)
362{
363 const float *no_src = (const float *)source;
364 float *no_dst = (float *)dest;
365 float no_tmp[3];
366
367 if (ELEM(mixmode,
371 {
372 /* Above/below threshold modes are not supported here, fallback to nomix (just in case). */
373 copy_v3_v3(no_dst, no_src);
374 }
375 else { /* Modes that support 'real' mix factor. */
376 /* Since we normalize in the end, MIX and ADD are the same op here. */
377 if (ELEM(mixmode, CDT_MIX_MIX, CDT_MIX_ADD)) {
378 add_v3_v3v3(no_tmp, no_dst, no_src);
379 normalize_v3(no_tmp);
380 }
381 else if (mixmode == CDT_MIX_SUB) {
382 sub_v3_v3v3(no_tmp, no_dst, no_src);
383 normalize_v3(no_tmp);
384 }
385 else if (mixmode == CDT_MIX_MUL) {
386 mul_v3_v3v3(no_tmp, no_dst, no_src);
387 normalize_v3(no_tmp);
388 }
389 else {
390 copy_v3_v3(no_tmp, no_src);
391 }
392 interp_v3_v3v3_slerp_safe(no_dst, no_dst, no_tmp, mixfactor);
393 }
394}
395
397
398/* -------------------------------------------------------------------- */
401
402static void layerCopy_tface(const void *source, void *dest, const int count)
403{
404 const MTFace *source_tf = (const MTFace *)source;
405 MTFace *dest_tf = (MTFace *)dest;
406 for (int i = 0; i < count; i++) {
407 dest_tf[i] = source_tf[i];
408 }
409}
410
411static void layerInterp_tface(const void **sources,
412 const float *weights,
413 const int count,
414 void *dest)
415{
416 MTFace *tf = static_cast<MTFace *>(dest);
417 float uv[4][2] = {{0.0f}};
418
419 for (int i = 0; i < count; i++) {
420 const float interp_weight = weights[i];
421 const MTFace *src = static_cast<const MTFace *>(sources[i]);
422
423 for (int j = 0; j < 4; j++) {
424 madd_v2_v2fl(uv[j], src->uv[j], interp_weight);
425 }
426 }
427
428 /* Delay writing to the destination in case dest is in sources. */
429 *tf = *(MTFace *)(*sources);
430 memcpy(tf->uv, uv, sizeof(tf->uv));
431}
432
433static void layerSwap_tface(void *data, const int *corner_indices)
434{
435 MTFace *tf = static_cast<MTFace *>(data);
436 float uv[4][2];
437
438 for (int j = 0; j < 4; j++) {
439 const int source_index = corner_indices[j];
440 copy_v2_v2(uv[j], tf->uv[source_index]);
441 }
442
443 memcpy(tf->uv, uv, sizeof(tf->uv));
444}
445
446static void layerDefault_tface(void *data, const int count)
447{
448 static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
449 MTFace *tf = (MTFace *)data;
450
451 for (int i = 0; i < count; i++) {
452 tf[i] = default_tf;
453 }
454}
455
457{
458 return MAX_MTFACE;
459}
460
462
463/* -------------------------------------------------------------------- */
466
467static void layerCopy_propFloat(const void *source, void *dest, const int count)
468{
469 memcpy(dest, source, sizeof(MFloatProperty) * count);
470}
471
472static void layerInterp_propFloat(const void **sources,
473 const float *weights,
474 const int count,
475 void *dest)
476{
477 float result = 0.0f;
478 for (int i = 0; i < count; i++) {
479 const float interp_weight = weights[i];
480 const float src = *(const float *)sources[i];
481 result += src * interp_weight;
482 }
483 *(float *)dest = result;
484}
485
486static bool layerValidate_propFloat(void *data, const uint totitems, const bool do_fixes)
487{
488 MFloatProperty *fp = static_cast<MFloatProperty *>(data);
489 bool has_errors = false;
490
491 for (int i = 0; i < totitems; i++, fp++) {
492 if (!isfinite(fp->f)) {
493 if (do_fixes) {
494 fp->f = 0.0f;
495 }
496 has_errors = true;
497 }
498 }
499
500 return has_errors;
501}
502
504
505/* -------------------------------------------------------------------- */
508
509static void layerInterp_propInt(const void **sources,
510 const float *weights,
511 const int count,
512 void *dest)
513{
514 float result = 0.0f;
515 for (const int i : IndexRange(count)) {
516 const float weight = weights[i];
517 const float src = *static_cast<const int *>(sources[i]);
518 result += src * weight;
519 }
520 const int rounded_result = int(round(result));
521 *static_cast<int *>(dest) = rounded_result;
522}
523
525
526/* -------------------------------------------------------------------- */
529
530static void layerCopy_propString(const void *source, void *dest, const int count)
531{
532 memcpy(dest, source, sizeof(MStringProperty) * count);
533}
534
536
537/* -------------------------------------------------------------------- */
540
541static void layerCopy_origspace_face(const void *source, void *dest, const int count)
542{
543 const OrigSpaceFace *source_tf = (const OrigSpaceFace *)source;
544 OrigSpaceFace *dest_tf = (OrigSpaceFace *)dest;
545
546 for (int i = 0; i < count; i++) {
547 dest_tf[i] = source_tf[i];
548 }
549}
550
551static void layerInterp_origspace_face(const void **sources,
552 const float *weights,
553 const int count,
554 void *dest)
555{
556 OrigSpaceFace *osf = static_cast<OrigSpaceFace *>(dest);
557 float uv[4][2] = {{0.0f}};
558
559 for (int i = 0; i < count; i++) {
560 const float interp_weight = weights[i];
561 const OrigSpaceFace *src = static_cast<const OrigSpaceFace *>(sources[i]);
562
563 for (int j = 0; j < 4; j++) {
564 madd_v2_v2fl(uv[j], src->uv[j], interp_weight);
565 }
566 }
567
568 /* Delay writing to the destination in case dest is in sources. */
569 memcpy(osf->uv, uv, sizeof(osf->uv));
570}
571
572static void layerSwap_origspace_face(void *data, const int *corner_indices)
573{
574 OrigSpaceFace *osf = static_cast<OrigSpaceFace *>(data);
575 float uv[4][2];
576
577 for (int j = 0; j < 4; j++) {
578 copy_v2_v2(uv[j], osf->uv[corner_indices[j]]);
579 }
580 memcpy(osf->uv, uv, sizeof(osf->uv));
581}
582
583static void layerDefault_origspace_face(void *data, const int count)
584{
585 static OrigSpaceFace default_osf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
587
588 for (int i = 0; i < count; i++) {
589 osf[i] = default_osf;
590 }
591}
592
594
595/* -------------------------------------------------------------------- */
598
599static void layerSwap_mdisps(void *data, const int *ci)
600{
601 MDisps *s = static_cast<MDisps *>(data);
602
603 if (s->disps) {
604 int nverts = (ci[1] == 3) ? 4 : 3; /* silly way to know vertex count of face */
605 int corners = multires_mdisp_corners(s);
606 int cornersize = s->totdisp / corners;
607
608 if (corners != nverts) {
609 /* happens when face changed vertex count in edit mode
610 * if it happened, just forgot displacement */
611
612 MEM_freeN(s->disps);
613 s->totdisp = (s->totdisp / corners) * nverts;
614 s->disps = MEM_calloc_arrayN<float[3]>(s->totdisp, "mdisp swap");
615 return;
616 }
617
618 float (*d)[3] = MEM_calloc_arrayN<float[3]>(s->totdisp, "mdisps swap");
619
620 for (int S = 0; S < corners; S++) {
621 memcpy(d + cornersize * S, s->disps + cornersize * ci[S], sizeof(float[3]) * cornersize);
622 }
623
624 MEM_freeN(s->disps);
625 s->disps = d;
626 }
627}
628
629static void layerCopy_mdisps(const void *source, void *dest, const int count)
630{
631 const MDisps *s = static_cast<const MDisps *>(source);
632 MDisps *d = static_cast<MDisps *>(dest);
633
634 for (int i = 0; i < count; i++) {
635 if (s[i].disps) {
636 d[i].disps = static_cast<float (*)[3]>(MEM_dupallocN(s[i].disps));
637 d[i].hidden = static_cast<uint *>(MEM_dupallocN(s[i].hidden));
638 }
639 else {
640 d[i].disps = nullptr;
641 d[i].hidden = nullptr;
642 }
643
644 /* still copy even if not in memory, displacement can be external */
645 d[i].totdisp = s[i].totdisp;
646 d[i].level = s[i].level;
647 }
648}
649
650static void layerFree_mdisps(void *data, const int count)
651{
652 for (MDisps &d : MutableSpan(static_cast<MDisps *>(data), count)) {
653 MEM_SAFE_FREE(d.disps);
654 MEM_SAFE_FREE(d.hidden);
655 d.totdisp = 0;
656 d.level = 0;
657 }
658}
659
660static void layerConstruct_mdisps(void *data, const int count)
661{
662 std::fill_n(static_cast<MDisps *>(data), count, MDisps{});
663}
664
665static bool layerRead_mdisps(CDataFile *cdf, void *data, const int count)
666{
667 MDisps *d = static_cast<MDisps *>(data);
668
669 for (int i = 0; i < count; i++) {
670 if (!d[i].disps) {
671 d[i].disps = MEM_calloc_arrayN<float[3]>(d[i].totdisp, "mdisps read");
672 }
673
674 if (!cdf_read_data(cdf, sizeof(float[3]) * d[i].totdisp, d[i].disps)) {
675 CLOG_ERROR(&LOG, "failed to read multires displacement %d/%d %d", i, count, d[i].totdisp);
676 return false;
677 }
678 }
679
680 return true;
681}
682
683static bool layerWrite_mdisps(CDataFile *cdf, const void *data, const int count)
684{
685 const MDisps *d = static_cast<const MDisps *>(data);
686
687 for (int i = 0; i < count; i++) {
688 if (!cdf_write_data(cdf, sizeof(float[3]) * d[i].totdisp, d[i].disps)) {
689 CLOG_ERROR(&LOG, "failed to write multires displacement %d/%d %d", i, count, d[i].totdisp);
690 return false;
691 }
692 }
693
694 return true;
695}
696
697static size_t layerFilesize_mdisps(CDataFile * /*cdf*/, const void *data, const int count)
698{
699 const MDisps *d = static_cast<const MDisps *>(data);
700 size_t size = 0;
701
702 for (int i = 0; i < count; i++) {
703 size += sizeof(float[3]) * d[i].totdisp;
704 }
705
706 return size;
707}
708
710
711/* -------------------------------------------------------------------- */
714
715/* copy just zeros in this case */
716static void layerCopy_bmesh_elem_py_ptr(const void * /*source*/, void *dest, const int count)
717{
718 const int size = sizeof(void *);
719
720 for (int i = 0; i < count; i++) {
721 void **ptr = (void **)POINTER_OFFSET(dest, i * size);
722 *ptr = nullptr;
723 }
724}
725
726#ifndef WITH_PYTHON
728{
729 /* dummy */
730}
731#endif
732
733static void layerFree_bmesh_elem_py_ptr(void *data, const int count)
734{
735 for (int i = 0; i < count; i++) {
736 void **ptr = (void **)POINTER_OFFSET(data, i * sizeof(void *));
737 if (*ptr) {
739 }
740 }
741}
742
744
745/* -------------------------------------------------------------------- */
748
749static void layerCopy_grid_paint_mask(const void *source, void *dest, const int count)
750{
751 const GridPaintMask *s = static_cast<const GridPaintMask *>(source);
752 GridPaintMask *d = static_cast<GridPaintMask *>(dest);
753
754 for (int i = 0; i < count; i++) {
755 if (s[i].data) {
756 d[i].data = static_cast<float *>(MEM_dupallocN(s[i].data));
757 d[i].level = s[i].level;
758 }
759 else {
760 d[i].data = nullptr;
761 d[i].level = 0;
762 }
763 }
764}
765
766static void layerFree_grid_paint_mask(void *data, const int count)
767{
768 for (GridPaintMask &gpm : MutableSpan(static_cast<GridPaintMask *>(data), count)) {
769 MEM_SAFE_FREE(gpm.data);
770 gpm.level = 0;
771 }
772}
773
774static void layerConstruct_grid_paint_mask(void *data, const int count)
775{
776 std::fill_n(static_cast<GridPaintMask *>(data), count, GridPaintMask{});
777}
778
780
781/* -------------------------------------------------------------------- */
784
785static void layerCopyValue_mloopcol(const void *source,
786 void *dest,
787 const int mixmode,
788 const float mixfactor)
789{
790 const MLoopCol *m1 = static_cast<const MLoopCol *>(source);
791 MLoopCol *m2 = static_cast<MLoopCol *>(dest);
792 uchar tmp_col[4];
793
794 if (ELEM(mixmode,
798 {
799 /* Modes that do a full copy or nothing. */
801 /* TODO: Check for a real valid way to get 'factor' value of our dest color? */
802 const float f = (float(m2->r) + float(m2->g) + float(m2->b)) / 3.0f;
803 if (mixmode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && f < mixfactor) {
804 return; /* Do Nothing! */
805 }
806 if (mixmode == CDT_MIX_REPLACE_BELOW_THRESHOLD && f > mixfactor) {
807 return; /* Do Nothing! */
808 }
809 }
810 m2->r = m1->r;
811 m2->g = m1->g;
812 m2->b = m1->b;
813 m2->a = m1->a;
814 }
815 else { /* Modes that support 'real' mix factor. */
816 uchar src[4] = {m1->r, m1->g, m1->b, m1->a};
817 uchar dst[4] = {m2->r, m2->g, m2->b, m2->a};
818
819 if (mixmode == CDT_MIX_MIX) {
820 blend_color_mix_byte(tmp_col, dst, src);
821 }
822 else if (mixmode == CDT_MIX_ADD) {
823 blend_color_add_byte(tmp_col, dst, src);
824 }
825 else if (mixmode == CDT_MIX_SUB) {
826 blend_color_sub_byte(tmp_col, dst, src);
827 }
828 else if (mixmode == CDT_MIX_MUL) {
829 blend_color_mul_byte(tmp_col, dst, src);
830 }
831 else {
832 memcpy(tmp_col, src, sizeof(tmp_col));
833 }
834
835 blend_color_interpolate_byte(dst, dst, tmp_col, mixfactor);
836
837 m2->r = char(dst[0]);
838 m2->g = char(dst[1]);
839 m2->b = char(dst[2]);
840 m2->a = char(dst[3]);
841 }
842}
843
844static bool layerEqual_mloopcol(const void *data1, const void *data2)
845{
846 const MLoopCol *m1 = static_cast<const MLoopCol *>(data1);
847 const MLoopCol *m2 = static_cast<const MLoopCol *>(data2);
848 float r, g, b, a;
849
850 r = m1->r - m2->r;
851 g = m1->g - m2->g;
852 b = m1->b - m2->b;
853 a = m1->a - m2->a;
854
855 return r * r + g * g + b * b + a * a < 0.001f;
856}
857
858static void layerMultiply_mloopcol(void *data, const float fac)
859{
860 MLoopCol *m = static_cast<MLoopCol *>(data);
861
862 m->r = float(m->r) * fac;
863 m->g = float(m->g) * fac;
864 m->b = float(m->b) * fac;
865 m->a = float(m->a) * fac;
866}
867
868static void layerAdd_mloopcol(void *data1, const void *data2)
869{
870 MLoopCol *m = static_cast<MLoopCol *>(data1);
871 const MLoopCol *m2 = static_cast<const MLoopCol *>(data2);
872
873 m->r += m2->r;
874 m->g += m2->g;
875 m->b += m2->b;
876 m->a += m2->a;
877}
878
879static void layerDoMinMax_mloopcol(const void *data, void *vmin, void *vmax)
880{
881 const MLoopCol *m = static_cast<const MLoopCol *>(data);
882 MLoopCol *min = static_cast<MLoopCol *>(vmin);
883 MLoopCol *max = static_cast<MLoopCol *>(vmax);
884
885 min->r = std::min(m->r, min->r);
886 min->g = std::min(m->g, min->g);
887 min->b = std::min(m->b, min->b);
888 min->a = std::min(m->a, min->a);
889 max->r = std::max(m->r, max->r);
890 max->g = std::max(m->g, max->g);
891 max->b = std::max(m->b, max->b);
892 max->a = std::max(m->a, max->a);
893}
894
895static void layerInitMinMax_mloopcol(void *vmin, void *vmax)
896{
897 MLoopCol *min = static_cast<MLoopCol *>(vmin);
898 MLoopCol *max = static_cast<MLoopCol *>(vmax);
899
900 min->r = 255;
901 min->g = 255;
902 min->b = 255;
903 min->a = 255;
904
905 max->r = 0;
906 max->g = 0;
907 max->b = 0;
908 max->a = 0;
909}
910
911static void layerDefault_mloopcol(void *data, const int count)
912{
913 MLoopCol default_mloopcol = {255, 255, 255, 255};
914 MLoopCol *mlcol = (MLoopCol *)data;
915 for (int i = 0; i < count; i++) {
916 mlcol[i] = default_mloopcol;
917 }
918}
919
920static void layerInterp_mloopcol(const void **sources, const float *weights, int count, void *dest)
921{
922 MLoopCol *mc = static_cast<MLoopCol *>(dest);
923 struct {
924 float a;
925 float r;
926 float g;
927 float b;
928 } col = {0};
929
930 for (int i = 0; i < count; i++) {
931 const float interp_weight = weights[i];
932 const MLoopCol *src = static_cast<const MLoopCol *>(sources[i]);
933 col.r += src->r * interp_weight;
934 col.g += src->g * interp_weight;
935 col.b += src->b * interp_weight;
936 col.a += src->a * interp_weight;
937 }
938
939 /* Subdivide smooth or fractal can cause problems without clamping
940 * although weights should also not cause this situation */
941
942 /* Also delay writing to the destination in case dest is in sources. */
947}
948
950
951/* -------------------------------------------------------------------- */
954
955/* origspace is almost exact copy of #MLoopUV, keep in sync. */
956static void layerCopyValue_mloop_origspace(const void *source,
957 void *dest,
958 const int /*mixmode*/,
959 const float /*mixfactor*/)
960{
961 const OrigSpaceLoop *luv1 = static_cast<const OrigSpaceLoop *>(source);
962 OrigSpaceLoop *luv2 = static_cast<OrigSpaceLoop *>(dest);
963
964 copy_v2_v2(luv2->uv, luv1->uv);
965}
966
967static bool layerEqual_mloop_origspace(const void *data1, const void *data2)
968{
969 const OrigSpaceLoop *luv1 = static_cast<const OrigSpaceLoop *>(data1);
970 const OrigSpaceLoop *luv2 = static_cast<const OrigSpaceLoop *>(data2);
971
972 return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f;
973}
974
975static void layerMultiply_mloop_origspace(void *data, const float fac)
976{
977 OrigSpaceLoop *luv = static_cast<OrigSpaceLoop *>(data);
978
979 mul_v2_fl(luv->uv, fac);
980}
981
982static void layerInitMinMax_mloop_origspace(void *vmin, void *vmax)
983{
984 OrigSpaceLoop *min = static_cast<OrigSpaceLoop *>(vmin);
985 OrigSpaceLoop *max = static_cast<OrigSpaceLoop *>(vmax);
986
987 INIT_MINMAX2(min->uv, max->uv);
988}
989
990static void layerDoMinMax_mloop_origspace(const void *data, void *vmin, void *vmax)
991{
992 const OrigSpaceLoop *luv = static_cast<const OrigSpaceLoop *>(data);
993 OrigSpaceLoop *min = static_cast<OrigSpaceLoop *>(vmin);
994 OrigSpaceLoop *max = static_cast<OrigSpaceLoop *>(vmax);
995
996 minmax_v2v2_v2(min->uv, max->uv, luv->uv);
997}
998
999static void layerAdd_mloop_origspace(void *data1, const void *data2)
1000{
1001 OrigSpaceLoop *l1 = static_cast<OrigSpaceLoop *>(data1);
1002 const OrigSpaceLoop *l2 = static_cast<const OrigSpaceLoop *>(data2);
1003
1004 add_v2_v2(l1->uv, l2->uv);
1005}
1006
1007static void layerInterp_mloop_origspace(const void **sources,
1008 const float *weights,
1009 int count,
1010 void *dest)
1011{
1012 float uv[2];
1013 zero_v2(uv);
1014
1015 for (int i = 0; i < count; i++) {
1016 const float interp_weight = weights[i];
1017 const OrigSpaceLoop *src = static_cast<const OrigSpaceLoop *>(sources[i]);
1018 madd_v2_v2fl(uv, src->uv, interp_weight);
1019 }
1020
1021 /* Delay writing to the destination in case dest is in sources. */
1022 copy_v2_v2(((OrigSpaceLoop *)dest)->uv, uv);
1023}
1024/* --- end copy */
1025
1026static void layerInterp_mcol(const void **sources,
1027 const float *weights,
1028 const int count,
1029 void *dest)
1030{
1031 MCol *mc = static_cast<MCol *>(dest);
1032 struct {
1033 float a;
1034 float r;
1035 float g;
1036 float b;
1037 } col[4] = {{0.0f}};
1038
1039 for (int i = 0; i < count; i++) {
1040 const float interp_weight = weights[i];
1041
1042 for (int j = 0; j < 4; j++) {
1043 const MCol *src = static_cast<const MCol *>(sources[i]);
1044 col[j].a += src[j].a * interp_weight;
1045 col[j].r += src[j].r * interp_weight;
1046 col[j].g += src[j].g * interp_weight;
1047 col[j].b += src[j].b * interp_weight;
1048 }
1049 }
1050
1051 /* Delay writing to the destination in case dest is in sources. */
1052 for (int j = 0; j < 4; j++) {
1053
1054 /* Subdivide smooth or fractal can cause problems without clamping
1055 * although weights should also not cause this situation */
1056 mc[j].a = round_fl_to_uchar_clamp(col[j].a);
1057 mc[j].r = round_fl_to_uchar_clamp(col[j].r);
1058 mc[j].g = round_fl_to_uchar_clamp(col[j].g);
1059 mc[j].b = round_fl_to_uchar_clamp(col[j].b);
1060 }
1061}
1062
1063static void layerSwap_mcol(void *data, const int *corner_indices)
1064{
1065 MCol *mcol = static_cast<MCol *>(data);
1066 MCol col[4];
1067
1068 for (int j = 0; j < 4; j++) {
1069 col[j] = mcol[corner_indices[j]];
1070 }
1071
1072 memcpy(mcol, col, sizeof(col));
1073}
1074
1075static void layerDefault_mcol(void *data, const int count)
1076{
1077 static MCol default_mcol = {255, 255, 255, 255};
1078 MCol *mcol = (MCol *)data;
1079
1080 for (int i = 0; i < 4 * count; i++) {
1081 mcol[i] = default_mcol;
1082 }
1083}
1084
1085static void layerDefault_origindex(void *data, const int count)
1086{
1088}
1089
1090static void layerInterp_shapekey(const void **sources, const float *weights, int count, void *dest)
1091{
1092 float **in = (float **)sources;
1093
1094 if (count <= 0) {
1095 return;
1096 }
1097
1098 float co[3];
1099 zero_v3(co);
1100
1101 for (int i = 0; i < count; i++) {
1102 const float interp_weight = weights[i];
1103 madd_v3_v3fl(co, in[i], interp_weight);
1104 }
1105
1106 /* Delay writing to the destination in case dest is in sources. */
1107 copy_v3_v3((float *)dest, co);
1108}
1109
1111
1112/* -------------------------------------------------------------------- */
1115
1116static void layerDefault_mvert_skin(void *data, const int count)
1117{
1118 MVertSkin *vs = static_cast<MVertSkin *>(data);
1119
1120 for (int i = 0; i < count; i++) {
1121 copy_v3_fl(vs[i].radius, 0.25f);
1122 vs[i].flag = 0;
1123 }
1124}
1125
1126static void layerCopy_mvert_skin(const void *source, void *dest, const int count)
1127{
1128 memcpy(dest, source, sizeof(MVertSkin) * count);
1129}
1130
1131static void layerInterp_mvert_skin(const void **sources,
1132 const float *weights,
1133 int count,
1134 void *dest)
1135{
1136 float radius[3];
1137 zero_v3(radius);
1138
1139 for (int i = 0; i < count; i++) {
1140 const float interp_weight = weights[i];
1141 const MVertSkin *vs_src = static_cast<const MVertSkin *>(sources[i]);
1142
1143 madd_v3_v3fl(radius, vs_src->radius, interp_weight);
1144 }
1145
1146 /* Delay writing to the destination in case dest is in sources. */
1147 MVertSkin *vs_dst = static_cast<MVertSkin *>(dest);
1148 copy_v3_v3(vs_dst->radius, radius);
1149 vs_dst->flag &= ~MVERT_SKIN_ROOT;
1150}
1151
1153
1154/* -------------------------------------------------------------------- */
1157
1158static void layerSwap_flnor(void *data, const int *corner_indices)
1159{
1160 short (*flnors)[4][3] = static_cast<short (*)[4][3]>(data);
1161 short nors[4][3];
1162 int i = 4;
1163
1164 while (i--) {
1165 copy_v3_v3_short(nors[i], (*flnors)[corner_indices[i]]);
1166 }
1167
1168 memcpy(flnors, nors, sizeof(nors));
1169}
1170
1172
1173/* -------------------------------------------------------------------- */
1176
1177static void layerCopyValue_propcol(const void *source,
1178 void *dest,
1179 const int mixmode,
1180 const float mixfactor)
1181{
1182 const MPropCol *m1 = static_cast<const MPropCol *>(source);
1183 MPropCol *m2 = static_cast<MPropCol *>(dest);
1184 float tmp_col[4];
1185
1186 if (ELEM(mixmode,
1190 {
1191 /* Modes that do a full copy or nothing. */
1193 /* TODO: Check for a real valid way to get 'factor' value of our dest color? */
1194 const float f = (m2->color[0] + m2->color[1] + m2->color[2]) / 3.0f;
1195 if (mixmode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && f < mixfactor) {
1196 return; /* Do Nothing! */
1197 }
1198 if (mixmode == CDT_MIX_REPLACE_BELOW_THRESHOLD && f > mixfactor) {
1199 return; /* Do Nothing! */
1200 }
1201 }
1202 copy_v4_v4(m2->color, m1->color);
1203 }
1204 else { /* Modes that support 'real' mix factor. */
1205 if (mixmode == CDT_MIX_MIX) {
1206 blend_color_mix_float(tmp_col, m2->color, m1->color);
1207 }
1208 else if (mixmode == CDT_MIX_ADD) {
1209 blend_color_add_float(tmp_col, m2->color, m1->color);
1210 }
1211 else if (mixmode == CDT_MIX_SUB) {
1212 blend_color_sub_float(tmp_col, m2->color, m1->color);
1213 }
1214 else if (mixmode == CDT_MIX_MUL) {
1215 blend_color_mul_float(tmp_col, m2->color, m1->color);
1216 }
1217 else {
1218 memcpy(tmp_col, m1->color, sizeof(tmp_col));
1219 }
1220 blend_color_interpolate_float(m2->color, m2->color, tmp_col, mixfactor);
1221 }
1222}
1223
1224static bool layerEqual_propcol(const void *data1, const void *data2)
1225{
1226 const MPropCol *m1 = static_cast<const MPropCol *>(data1);
1227 const MPropCol *m2 = static_cast<const MPropCol *>(data2);
1228 float tot = 0;
1229
1230 for (int i = 0; i < 4; i++) {
1231 float c = (m1->color[i] - m2->color[i]);
1232 tot += c * c;
1233 }
1234
1235 return tot < 0.001f;
1236}
1237
1238static void layerMultiply_propcol(void *data, const float fac)
1239{
1240 MPropCol *m = static_cast<MPropCol *>(data);
1241 mul_v4_fl(m->color, fac);
1242}
1243
1244static void layerAdd_propcol(void *data1, const void *data2)
1245{
1246 MPropCol *m = static_cast<MPropCol *>(data1);
1247 const MPropCol *m2 = static_cast<const MPropCol *>(data2);
1248 add_v4_v4(m->color, m2->color);
1249}
1250
1251static void layerDoMinMax_propcol(const void *data, void *vmin, void *vmax)
1252{
1253 const MPropCol *m = static_cast<const MPropCol *>(data);
1254 MPropCol *min = static_cast<MPropCol *>(vmin);
1255 MPropCol *max = static_cast<MPropCol *>(vmax);
1256 minmax_v4v4_v4(min->color, max->color, m->color);
1257}
1258
1259static void layerInitMinMax_propcol(void *vmin, void *vmax)
1260{
1261 MPropCol *min = static_cast<MPropCol *>(vmin);
1262 MPropCol *max = static_cast<MPropCol *>(vmax);
1263
1264 copy_v4_fl(min->color, FLT_MAX);
1265 copy_v4_fl(max->color, FLT_MIN);
1266}
1267
1268static void layerDefault_propcol(void *data, const int count)
1269{
1270 /* Default to white, full alpha. */
1271 MPropCol default_propcol = {{1.0f, 1.0f, 1.0f, 1.0f}};
1272 MPropCol *pcol = (MPropCol *)data;
1273 for (int i = 0; i < count; i++) {
1274 copy_v4_v4(pcol[i].color, default_propcol.color);
1275 }
1276}
1277
1278static void layerInterp_propcol(const void **sources, const float *weights, int count, void *dest)
1279{
1280 MPropCol *mc = static_cast<MPropCol *>(dest);
1281 float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
1282 for (int i = 0; i < count; i++) {
1283 const float interp_weight = weights[i];
1284 const MPropCol *src = static_cast<const MPropCol *>(sources[i]);
1285 madd_v4_v4fl(col, src->color, interp_weight);
1286 }
1287 copy_v4_v4(mc->color, col);
1288}
1289
1291
1292/* -------------------------------------------------------------------- */
1295
1296static void layerInterp_propfloat3(const void **sources,
1297 const float *weights,
1298 int count,
1299 void *dest)
1300{
1301 vec3f result = {0.0f, 0.0f, 0.0f};
1302 for (int i = 0; i < count; i++) {
1303 const float interp_weight = weights[i];
1304 const vec3f *src = static_cast<const vec3f *>(sources[i]);
1305 madd_v3_v3fl(&result.x, &src->x, interp_weight);
1306 }
1307 copy_v3_v3((float *)dest, &result.x);
1308}
1309
1310static void layerMultiply_propfloat3(void *data, const float fac)
1311{
1312 vec3f *vec = static_cast<vec3f *>(data);
1313 vec->x *= fac;
1314 vec->y *= fac;
1315 vec->z *= fac;
1316}
1317
1318static void layerAdd_propfloat3(void *data1, const void *data2)
1319{
1320 vec3f *vec1 = static_cast<vec3f *>(data1);
1321 const vec3f *vec2 = static_cast<const vec3f *>(data2);
1322 vec1->x += vec2->x;
1323 vec1->y += vec2->y;
1324 vec1->z += vec2->z;
1325}
1326
1327static bool layerValidate_propfloat3(void *data, const uint totitems, const bool do_fixes)
1328{
1329 float *values = static_cast<float *>(data);
1330 bool has_errors = false;
1331 for (int i = 0; i < totitems * 3; i++) {
1332 if (!isfinite(values[i])) {
1333 if (do_fixes) {
1334 values[i] = 0.0f;
1335 }
1336 has_errors = true;
1337 }
1338 }
1339 return has_errors;
1340}
1341
1343
1344/* -------------------------------------------------------------------- */
1347
1348static void layerInterp_propfloat2(const void **sources,
1349 const float *weights,
1350 int count,
1351 void *dest)
1352{
1353 vec2f result = {0.0f, 0.0f};
1354 for (int i = 0; i < count; i++) {
1355 const float interp_weight = weights[i];
1356 const vec2f *src = static_cast<const vec2f *>(sources[i]);
1357 madd_v2_v2fl(&result.x, &src->x, interp_weight);
1358 }
1359 copy_v2_v2((float *)dest, &result.x);
1360}
1361
1362static void layerMultiply_propfloat2(void *data, const float fac)
1363{
1364 vec2f *vec = static_cast<vec2f *>(data);
1365 vec->x *= fac;
1366 vec->y *= fac;
1367}
1368
1369static void layerAdd_propfloat2(void *data1, const void *data2)
1370{
1371 vec2f *vec1 = static_cast<vec2f *>(data1);
1372 const vec2f *vec2 = static_cast<const vec2f *>(data2);
1373 vec1->x += vec2->x;
1374 vec1->y += vec2->y;
1375}
1376
1377static bool layerValidate_propfloat2(void *data, const uint totitems, const bool do_fixes)
1378{
1379 float *values = static_cast<float *>(data);
1380 bool has_errors = false;
1381 for (int i = 0; i < totitems * 2; i++) {
1382 if (!isfinite(values[i])) {
1383 if (do_fixes) {
1384 values[i] = 0.0f;
1385 }
1386 has_errors = true;
1387 }
1388 }
1389 return has_errors;
1390}
1391
1392static bool layerEqual_propfloat2(const void *data1, const void *data2)
1393{
1394 const float2 &a = *static_cast<const float2 *>(data1);
1395 const float2 &b = *static_cast<const float2 *>(data2);
1396 return blender::math::distance_squared(a, b) < 0.00001f;
1397}
1398
1399static void layerInitMinMax_propfloat2(void *vmin, void *vmax)
1400{
1401 float2 &min = *static_cast<float2 *>(vmin);
1402 float2 &max = *static_cast<float2 *>(vmax);
1404}
1405
1406static void layerDoMinMax_propfloat2(const void *data, void *vmin, void *vmax)
1407{
1408 const float2 &value = *static_cast<const float2 *>(data);
1409 float2 &a = *static_cast<float2 *>(vmin);
1410 float2 &b = *static_cast<float2 *>(vmax);
1411 blender::math::min_max(value, a, b);
1412}
1413
1414static void layerCopyValue_propfloat2(const void *source,
1415 void *dest,
1416 const int mixmode,
1417 const float mixfactor)
1418{
1419 const float2 &a = *static_cast<const float2 *>(source);
1420 float2 &b = *static_cast<float2 *>(dest);
1421
1422 /* We only support a limited subset of advanced mixing here-
1423 * namely the mixfactor interpolation. */
1424 if (mixmode == CDT_MIX_NOMIX) {
1425 b = a;
1426 }
1427 else {
1428 b = blender::math::interpolate(b, a, mixfactor);
1429 }
1430}
1431
1433
1434/* -------------------------------------------------------------------- */
1437
1438static void layerInterp_propbool(const void **sources, const float *weights, int count, void *dest)
1439{
1440 bool result = false;
1441 for (int i = 0; i < count; i++) {
1442 const float interp_weight = weights[i];
1443 const bool src = *(const bool *)sources[i];
1444 result |= src && (interp_weight > 0.0f);
1445 }
1446 *(bool *)dest = result;
1447}
1448
1450
1451/* -------------------------------------------------------------------- */
1454
1455static void layerDefault_propquaternion(void *data, const int count)
1456{
1457 using namespace blender;
1459}
1460
1461static void layerInterp_propquaternion(const void **sources,
1462 const float *weights,
1463 int count,
1464 void *dest)
1465{
1467 Quaternion result;
1469 Quaternion::identity());
1470
1471 for (int i = 0; i < count; i++) {
1472 const float interp_weight = weights[i];
1473 const Quaternion *src = static_cast<const Quaternion *>(sources[i]);
1474 mixer.mix_in(0, *src, interp_weight);
1475 }
1476 mixer.finalize();
1477 *static_cast<Quaternion *>(dest) = result;
1478}
1479
1480/* -------------------------------------------------------------------- */
1483
1484static void layerDefault_propfloat4x4(void *data, const int count)
1485{
1486 using namespace blender;
1488}
1489
1491
1492/* -------------------------------------------------------------------- */
1495
1497 /* 0: CD_MVERT */ /* DEPRECATED */
1498 {sizeof(MVert),
1499 alignof(MVert),
1500 "MVert",
1501 1,
1502 nullptr,
1503 nullptr,
1504 nullptr,
1505 nullptr,
1506 nullptr,
1507 nullptr},
1508 /* 1: CD_MSTICKY */ /* DEPRECATED */
1509 {sizeof(float[2]),
1510 alignof(float2),
1511 "",
1512 1,
1513 nullptr,
1514 nullptr,
1515 nullptr,
1516 nullptr,
1517 nullptr,
1518 nullptr},
1519 /* 2: CD_MDEFORMVERT */
1520 {sizeof(MDeformVert),
1521 alignof(MDeformVert),
1522 "MDeformVert",
1523 1,
1524 nullptr,
1528 nullptr,
1529 nullptr,
1531 /* 3: CD_MEDGE */ /* DEPRECATED */
1532 {sizeof(MEdge),
1533 alignof(MEdge),
1534 "MEdge",
1535 1,
1536 nullptr,
1537 nullptr,
1538 nullptr,
1539 nullptr,
1540 nullptr,
1541 nullptr},
1542 /* 4: CD_MFACE */
1543 {sizeof(MFace),
1544 alignof(MFace),
1545 "MFace",
1546 1,
1547 nullptr,
1548 nullptr,
1549 nullptr,
1550 nullptr,
1551 nullptr,
1552 nullptr},
1553 /* 5: CD_MTFACE */
1554 {sizeof(MTFace),
1555 alignof(MTFace),
1556 "MTFace",
1557 1,
1558 N_("UVMap"),
1560 nullptr,
1563 nullptr,
1565 nullptr,
1566 nullptr,
1567 nullptr,
1568 nullptr,
1569 nullptr,
1570 nullptr,
1571 nullptr,
1572 nullptr,
1573 nullptr,
1574 nullptr,
1576 /* 6: CD_MCOL */
1577 /* 4 MCol structs per face */
1578 {sizeof(MCol[4]),
1579 alignof(MCol[4]),
1580 "MCol",
1581 4,
1582 N_("Col"),
1583 nullptr,
1584 nullptr,
1588 /* 7: CD_ORIGINDEX */
1589 {sizeof(int),
1590 alignof(int),
1591 "",
1592 0,
1593 nullptr,
1594 nullptr,
1595 nullptr,
1596 nullptr,
1597 nullptr,
1599 /* 8: CD_NORMAL */
1600 /* 3 floats per normal vector */
1601 {sizeof(float[3]),
1602 alignof(blender::float3),
1603 "vec3f",
1604 1,
1605 nullptr,
1606 nullptr,
1607 nullptr,
1609 nullptr,
1610 nullptr,
1611 nullptr,
1612 nullptr,
1613 nullptr,
1614 nullptr,
1615 nullptr,
1616 nullptr,
1617 nullptr,
1619 /* 9: CD_FACEMAP */ /* DEPRECATED */
1620 {sizeof(int), alignof(int), ""},
1621 /* 10: CD_PROP_FLOAT */
1622 {sizeof(MFloatProperty),
1623 alignof(float),
1624 "MFloatProperty",
1625 1,
1626 N_("Float"),
1628 nullptr,
1630 nullptr,
1631 nullptr,
1632 nullptr,
1634 /* 11: CD_PROP_INT32 */
1635 {sizeof(MIntProperty),
1636 alignof(int),
1637 "MIntProperty",
1638 1,
1639 N_("Int"),
1640 nullptr,
1641 nullptr,
1643 nullptr},
1644 /* 12: CD_PROP_STRING */
1645 {sizeof(MStringProperty),
1646 alignof(MStringProperty),
1647 "MStringProperty",
1648 1,
1649 N_("String"),
1651 nullptr,
1652 nullptr,
1653 nullptr},
1654 /* 13: CD_ORIGSPACE */
1655 {sizeof(OrigSpaceFace),
1656 alignof(OrigSpaceFace),
1657 "OrigSpaceFace",
1658 1,
1659 N_("UVMap"),
1661 nullptr,
1665 /* 14: CD_ORCO */
1666 {sizeof(float[3]),
1667 alignof(blender::float3),
1668 "",
1669 0,
1670 nullptr,
1671 nullptr,
1672 nullptr,
1673 nullptr,
1674 nullptr,
1675 nullptr},
1676 /* 15: CD_MTEXPOLY */ /* DEPRECATED */
1677 /* NOTE: when we expose the UV Map / TexFace split to the user,
1678 * change this back to face Texture. */
1679 {sizeof(int), alignof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
1680 /* 16: CD_MLOOPUV */ /* DEPRECATED */
1681 {sizeof(MLoopUV), alignof(MLoopUV), "MLoopUV", 1, N_("UVMap")},
1682 /* 17: CD_PROP_BYTE_COLOR */
1683 {sizeof(MLoopCol),
1684 alignof(MLoopCol),
1685 "MLoopCol",
1686 1,
1687 N_("Col"),
1688 nullptr,
1689 nullptr,
1691 nullptr,
1693 nullptr,
1694 nullptr,
1701 nullptr,
1702 nullptr,
1703 nullptr,
1704 nullptr},
1705 /* 18: CD_TANGENT */ /* DEPRECATED */
1706 {sizeof(float[4]), alignof(float[4]), "", 0, N_("Tangent")},
1707 /* 19: CD_MDISPS */
1708 {sizeof(MDisps),
1709 alignof(MDisps),
1710 "MDisps",
1711 1,
1712 nullptr,
1715 nullptr,
1717 nullptr,
1719 nullptr,
1720 nullptr,
1721 nullptr,
1722 nullptr,
1723 nullptr,
1724 nullptr,
1725 nullptr,
1729 /* 20: CD_PREVIEW_MCOL */
1730 {sizeof(blender::float4x4),
1731 alignof(blender::float4x4),
1732 "mat4x4f",
1733 1,
1734 N_("4 by 4 Float Matrix"),
1735 nullptr,
1736 nullptr,
1737 nullptr,
1738 nullptr,
1740 /* 21: CD_ID_MCOL */ /* DEPRECATED */
1741 {sizeof(MCol[4]),
1742 alignof(MCol[4]),
1743 "",
1744 0,
1745 nullptr,
1746 nullptr,
1747 nullptr,
1748 nullptr,
1749 nullptr,
1750 nullptr},
1751 /* 22: CD_PROP_INT16_2D */
1752 {sizeof(blender::short2),
1753 alignof(blender::short2),
1754 "vec2s",
1755 1,
1756 N_("2D 16-Bit Integer"),
1757 nullptr,
1758 nullptr,
1759 nullptr,
1760 nullptr,
1761 nullptr},
1762 /* 23: CD_CLOTH_ORCO */
1763 {sizeof(float[3]),
1764 alignof(float[3]),
1765 "",
1766 0,
1767 nullptr,
1768 nullptr,
1769 nullptr,
1770 nullptr,
1771 nullptr,
1772 nullptr},
1773 /* 24: CD_RECAST */
1774 {sizeof(MRecast),
1775 alignof(MRecast),
1776 "MRecast",
1777 1,
1778 N_("Recast"),
1779 nullptr,
1780 nullptr,
1781 nullptr,
1782 nullptr},
1783 /* 25: CD_MPOLY */ /* DEPRECATED */
1784 {sizeof(MPoly),
1785 alignof(MPoly),
1786 "MPoly",
1787 1,
1788 N_("NGon Face"),
1789 nullptr,
1790 nullptr,
1791 nullptr,
1792 nullptr,
1793 nullptr},
1794 /* 26: CD_MLOOP */ /* DEPRECATED */
1795 {sizeof(MLoop),
1796 alignof(MLoop),
1797 "MLoop",
1798 1,
1799 N_("NGon Face-Vertex"),
1800 nullptr,
1801 nullptr,
1802 nullptr,
1803 nullptr,
1804 nullptr},
1805 /* 27: CD_SHAPE_KEYINDEX */
1806 {sizeof(int), alignof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
1807 /* 28: CD_SHAPEKEY */
1808 {sizeof(float[3]),
1809 alignof(float[3]),
1810 "",
1811 0,
1812 N_("ShapeKey"),
1813 nullptr,
1814 nullptr,
1816 /* 29: CD_BWEIGHT */ /* DEPRECATED */
1817 {sizeof(MFloatProperty), alignof(MFloatProperty), "MFloatProperty", 1},
1818 /* 30: CD_CREASE */ /* DEPRECATED */
1819 {sizeof(float), alignof(float), ""},
1820 /* 31: CD_ORIGSPACE_MLOOP */
1821 {sizeof(OrigSpaceLoop),
1822 alignof(OrigSpaceLoop),
1823 "OrigSpaceLoop",
1824 1,
1825 N_("OS Loop"),
1826 nullptr,
1827 nullptr,
1829 nullptr,
1830 nullptr,
1831 nullptr,
1832 nullptr,
1839 /* 32: CD_PREVIEW_MLOOPCOL */ /* DEPRECATED */ /* UNUSED */
1840 {},
1841 /* 33: CD_BM_ELEM_PYPTR */
1842 {sizeof(void *),
1843 alignof(void *),
1844 "",
1845 1,
1846 nullptr,
1849 nullptr,
1850 nullptr,
1851 nullptr},
1852 /* 34: CD_PAINT_MASK */ /* DEPRECATED */
1853 {sizeof(float), alignof(float), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
1854 /* 35: CD_GRID_PAINT_MASK */
1855 {sizeof(GridPaintMask),
1856 alignof(GridPaintMask),
1857 "GridPaintMask",
1858 1,
1859 nullptr,
1862 nullptr,
1863 nullptr,
1864 nullptr,
1866 /* 36: CD_MVERT_SKIN */
1867 {sizeof(MVertSkin),
1868 alignof(MVertSkin),
1869 "MVertSkin",
1870 1,
1871 nullptr,
1873 nullptr,
1875 nullptr,
1877 /* 37: CD_FREESTYLE_EDGE */ /* DEPRECATED */
1878 {sizeof(FreestyleEdge), alignof(FreestyleEdge), "FreestyleEdge", 1},
1879 /* 38: CD_FREESTYLE_FACE */ /* DEPRECATED */
1880 {sizeof(FreestyleFace), alignof(FreestyleFace), "FreestyleFace", 1},
1881 /* 39: CD_MLOOPTANGENT */
1882 {sizeof(float[4]),
1883 alignof(float[4]),
1884 "",
1885 0,
1886 nullptr,
1887 nullptr,
1888 nullptr,
1889 nullptr,
1890 nullptr,
1891 nullptr},
1892 /* 40: CD_TESSLOOPNORMAL */
1893 {sizeof(short[4][3]),
1894 alignof(short[4][3]),
1895 "",
1896 0,
1897 nullptr,
1898 nullptr,
1899 nullptr,
1900 nullptr,
1902 nullptr},
1903 /* 41: CD_CUSTOMLOOPNORMAL */ /* DEPRECATED */
1904 {sizeof(short[2]), alignof(short[2]), "vec2s", 1},
1905 /* 42: CD_SCULPT_FACE_SETS */ /* DEPRECATED */
1906 {sizeof(int), alignof(int), ""},
1907 /* 43: CD_LOCATION */
1908 {sizeof(float[3]),
1909 alignof(float[3]),
1910 "vec3f",
1911 1,
1912 nullptr,
1913 nullptr,
1914 nullptr,
1915 nullptr,
1916 nullptr,
1917 nullptr},
1918 /* 44: CD_RADIUS */
1919 {sizeof(float),
1920 alignof(float),
1921 "MFloatProperty",
1922 1,
1923 nullptr,
1924 nullptr,
1925 nullptr,
1926 nullptr,
1927 nullptr,
1928 nullptr},
1929 /* 45: CD_PROP_INT8 */
1930 {sizeof(int8_t),
1931 alignof(int8_t),
1932 "MInt8Property",
1933 1,
1934 N_("Int8"),
1935 nullptr,
1936 nullptr,
1937 nullptr,
1938 nullptr,
1939 nullptr},
1940 /* 46: CD_PROP_INT32_2D */
1941 {sizeof(blender::int2),
1942 alignof(blender::int2),
1943 "vec2i",
1944 1,
1945 N_("Int 2D"),
1946 nullptr,
1947 nullptr,
1948 nullptr,
1949 nullptr,
1950 nullptr},
1951 /* 47: CD_PROP_COLOR */
1952 {sizeof(MPropCol),
1953 alignof(MPropCol),
1954 "MPropCol",
1955 1,
1956 N_("Color"),
1957 nullptr,
1958 nullptr,
1960 nullptr,
1962 nullptr,
1963 nullptr,
1970 nullptr,
1971 nullptr,
1972 nullptr,
1973 nullptr},
1974 /* 48: CD_PROP_FLOAT3 */
1975 {sizeof(float[3]),
1976 alignof(blender::float3),
1977 "vec3f",
1978 1,
1979 N_("Float3"),
1980 nullptr,
1981 nullptr,
1983 nullptr,
1984 nullptr,
1985 nullptr,
1987 nullptr,
1989 nullptr,
1991 /* 49: CD_PROP_FLOAT2 */
1992 {sizeof(float[2]),
1993 alignof(float2),
1994 "vec2f",
1995 1,
1996 N_("Float2"),
1997 nullptr,
1998 nullptr,
2000 nullptr,
2001 nullptr,
2002 nullptr,
2010 /* 50: CD_PROP_BOOL */
2011 {sizeof(bool),
2012 alignof(bool),
2013 "bool",
2014 1,
2015 N_("Boolean"),
2016 nullptr,
2017 nullptr,
2019 nullptr,
2020 nullptr,
2021 nullptr,
2022 nullptr,
2023 nullptr,
2024 nullptr,
2025 nullptr},
2026 /* 51: CD_HAIRLENGTH */ /* DEPRECATED */ /* UNUSED */
2027 {sizeof(float),
2028 alignof(float),
2029 "float",
2030 1,
2031 nullptr,
2032 nullptr,
2033 nullptr,
2034 nullptr,
2035 nullptr,
2036 nullptr},
2037 /* 52: CD_PROP_QUATERNION */
2038 {sizeof(float[4]),
2039 alignof(blender::float4),
2040 "vec4f",
2041 1,
2042 N_("Quaternion"),
2043 nullptr,
2044 nullptr,
2046 nullptr,
2048};
2049
2050static_assert(sizeof(mat4x4f) == sizeof(blender::float4x4));
2051
2052static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
2053 /* 0-4 */ "CDMVert",
2054 "CDMSticky",
2055 "CDMDeformVert",
2056 "CDMEdge",
2057 "CDMFace",
2058 /* 5-9 */ "CDMTFace",
2059 "CDMCol",
2060 "CDOrigIndex",
2061 "CDNormal",
2062 "CDFaceMap",
2063 /* 10-14 */ "CDMFloatProperty",
2064 "CDMIntProperty",
2065 "CDMStringProperty",
2066 "CDOrigSpace",
2067 "CDOrco",
2068 /* 15-19 */ "CDMTexPoly",
2069 "CDMLoopUV",
2070 "CDMloopCol",
2071 "CDTangent",
2072 "CDMDisps",
2073 /* 20-24 */ "CDPreviewMCol",
2074 "CDIDMCol",
2075 "CDTextureMCol",
2076 "CDClothOrco",
2077 "CDMRecast",
2078
2079 /* BMESH ONLY */
2080 /* 25-29 */ "CDMPoly",
2081 "CDMLoop",
2082 "CDShapeKeyIndex",
2083 "CDShapeKey",
2084 "CDBevelWeight",
2085 /* 30-34 */ "CDSubSurfCrease",
2086 "CDOrigSpaceLoop",
2087 "CDPreviewLoopCol",
2088 "CDBMElemPyPtr",
2089 "CDPaintMask",
2090 /* 35-36 */ "CDGridPaintMask",
2091 "CDMVertSkin",
2092 /* 37-38 */ "CDFreestyleEdge",
2093 "CDFreestyleFace",
2094 /* 39-42 */ "CDMLoopTangent",
2095 "CDTessLoopNormal",
2096 "CDCustomLoopNormal",
2097 "CDSculptFaceGroups",
2098 /* 43-46 */ "CDHairPoint",
2099 "CDPropInt8",
2100 "CDHairMapping",
2101 "CDPoint",
2102 "CDPropCol",
2103 "CDPropFloat3",
2104 "CDPropFloat2",
2105 "CDPropBoolean",
2106 "CDHairLength",
2107 "CDPropQuaternion",
2108};
2109
2111 /*vmask*/ CD_MASK_PROP_FLOAT3,
2112 /*emask*/ CD_MASK_PROP_INT32_2D,
2113 /*fmask*/ 0,
2114 /*pmask*/ 0,
2115 /*lmask*/ CD_MASK_PROP_INT32,
2116};
2120 /*fmask*/ 0,
2121 /*pmask*/ CD_MASK_ORIGINDEX,
2122 /*lmask*/ CD_MASK_PROP_INT32,
2123};
2126 /*emask*/
2128 /*fmask*/ 0,
2129 /*pmask*/
2131 /*lmask*/
2133};
2137 /*emask*/
2140 /*pmask*/
2142 /*lmask*/
2143 (CD_MASK_ORIGSPACE_MLOOP | CD_MASK_PROP_ALL), /* XXX: MISSING #CD_MASK_MLOOPTANGENT ? */
2144};
2170
2172{
2173 if (type < 0 || type >= CD_NUMTYPES) {
2174 return nullptr;
2175 }
2176
2177 return &LAYERTYPEINFO[type];
2178}
2179
2180static const char *layerType_getName(const eCustomDataType type)
2181{
2182 if (type < 0 || type >= CD_NUMTYPES) {
2183 return nullptr;
2184 }
2185
2186 return LAYERTYPENAMES[type];
2187}
2188
2190{
2191 printf("verts mask=0x%" PRIx64 ":\n", mask->vmask);
2192 for (int i = 0; i < CD_NUMTYPES; i++) {
2193 if (mask->vmask & CD_TYPE_AS_MASK(eCustomDataType(i))) {
2195 }
2196 }
2197
2198 printf("edges mask=0x%" PRIx64 ":\n", mask->emask);
2199 for (int i = 0; i < CD_NUMTYPES; i++) {
2200 if (mask->emask & CD_TYPE_AS_MASK(eCustomDataType(i))) {
2202 }
2203 }
2204
2205 printf("faces mask=0x%" PRIx64 ":\n", mask->fmask);
2206 for (int i = 0; i < CD_NUMTYPES; i++) {
2207 if (mask->fmask & CD_TYPE_AS_MASK(eCustomDataType(i))) {
2209 }
2210 }
2211
2212 printf("loops mask=0x%" PRIx64 ":\n", mask->lmask);
2213 for (int i = 0; i < CD_NUMTYPES; i++) {
2214 if (mask->lmask & CD_TYPE_AS_MASK(eCustomDataType(i))) {
2216 }
2217 }
2218
2219 printf("polys mask=0x%" PRIx64 ":\n", mask->pmask);
2220 for (int i = 0; i < CD_NUMTYPES; i++) {
2221 if (mask->pmask & CD_TYPE_AS_MASK(eCustomDataType(i))) {
2223 }
2224 }
2225}
2226
2228
2229/* -------------------------------------------------------------------- */
2232
2234
2237 eCustomDataType type,
2238 std::optional<eCDAllocType> alloctype,
2239 void *layer_data_to_assign,
2240 const ImplicitSharingInfo *sharing_info_to_assign,
2241 int totelem,
2242 const StringRef name);
2243
2245{
2246 int lasttype = -1;
2247
2248 for (int i = 0; i < CD_NUMTYPES; i++) {
2249 data->typemap[i] = -1;
2250 }
2251
2252 for (int i = 0; i < data->totlayer; i++) {
2253 const eCustomDataType type = eCustomDataType(data->layers[i].type);
2254 if (type != lasttype) {
2255 data->typemap[type] = i;
2256 lasttype = type;
2257 }
2258 }
2259}
2260
2261/* currently only used in BLI_assert */
2262#ifndef NDEBUG
2264{
2265 CustomData data_copy = *data;
2266 CustomData_update_typemap(&data_copy);
2267 return (memcmp(data->typemap, data_copy.typemap, sizeof(data->typemap)) == 0);
2268}
2269#endif
2270
2271static void *copy_layer_data(const eCustomDataType type, const void *data, const int totelem)
2272{
2273 const LayerTypeInfo &type_info = *layerType_getInfo(type);
2274 const int64_t size_in_bytes = int64_t(totelem) * type_info.size;
2275 void *new_data = MEM_mallocN_aligned(size_in_bytes, type_info.alignment, __func__);
2276 if (type_info.copy) {
2277 type_info.copy(data, new_data, totelem);
2278 }
2279 else {
2280 memcpy(new_data, data, size_in_bytes);
2281 }
2282 return new_data;
2283}
2284
2285static void free_layer_data(const eCustomDataType type, const void *data, const int totelem)
2286{
2287 const LayerTypeInfo &type_info = *layerType_getInfo(type);
2288 if (type_info.free) {
2289 type_info.free(const_cast<void *>(data), totelem);
2290 }
2291 MEM_freeN(const_cast<void *>(data));
2292}
2293
2294static bool customdata_merge_internal(const CustomData *source,
2295 CustomData *dest,
2296 const eCustomDataMask mask,
2297 const std::optional<eCDAllocType> alloctype,
2298 const int totelem)
2299{
2300 bool changed = false;
2301
2302 int last_type = -1;
2303 int last_active = 0;
2304 int last_render = 0;
2305 int last_clone = 0;
2306 int last_mask = 0;
2307 int current_type_layer_count = 0;
2308 int max_current_type_layer_count = -1;
2309
2310 for (int i = 0; i < source->totlayer; i++) {
2311 const CustomDataLayer &src_layer = source->layers[i];
2312 const eCustomDataType type = eCustomDataType(src_layer.type);
2313 const int src_layer_flag = src_layer.flag;
2314
2315 if (type != last_type) {
2316 /* Don't exceed layer count on destination. */
2317 const int layernum_dst = CustomData_number_of_layers(dest, type);
2318 current_type_layer_count = layernum_dst;
2319 max_current_type_layer_count = CustomData_layertype_layers_max(type);
2320 last_active = src_layer.active;
2321 last_render = src_layer.active_rnd;
2322 last_clone = src_layer.active_clone;
2323 last_mask = src_layer.active_mask;
2324 last_type = type;
2325 }
2326 else {
2327 current_type_layer_count++;
2328 }
2329
2330 if (src_layer_flag & CD_FLAG_NOCOPY) {
2331 /* Don't merge this layer because it's not supposed to leave the source data. */
2332 continue;
2333 }
2334 if (!(mask & CD_TYPE_AS_MASK(type))) {
2335 /* Don't merge this layer because it does not match the type mask. */
2336 continue;
2337 }
2338 if ((max_current_type_layer_count != -1) &&
2339 (current_type_layer_count >= max_current_type_layer_count))
2340 {
2341 /* Don't merge this layer because the maximum amount of layers of this type is reached. */
2342 continue;
2343 }
2344 if (CustomData_get_named_layer_index(dest, type, src_layer.name) != -1) {
2345 /* Don't merge this layer because it exists in the destination already. */
2346 continue;
2347 }
2348
2349 void *layer_data_to_assign = nullptr;
2350 const ImplicitSharingInfo *sharing_info_to_assign = nullptr;
2351 if (!alloctype.has_value()) {
2352 if (src_layer.data != nullptr) {
2353 if (src_layer.sharing_info == nullptr) {
2354 /* Can't share the layer, duplicate it instead. */
2355 layer_data_to_assign = copy_layer_data(type, src_layer.data, totelem);
2356 }
2357 else {
2358 /* Share the layer. */
2359 layer_data_to_assign = src_layer.data;
2360 sharing_info_to_assign = src_layer.sharing_info;
2361 }
2362 }
2363 }
2364
2366 type,
2367 alloctype,
2368 layer_data_to_assign,
2369 sharing_info_to_assign,
2370 totelem,
2371 src_layer.name);
2372
2373 new_layer->uid = src_layer.uid;
2374 new_layer->flag |= src_layer_flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY);
2375 new_layer->active = last_active;
2376 new_layer->active_rnd = last_render;
2377 new_layer->active_clone = last_clone;
2378 new_layer->active_mask = last_mask;
2379 changed = true;
2380 }
2381
2383 return changed;
2384}
2385
2386bool CustomData_merge(const CustomData *source,
2387 CustomData *dest,
2388 eCustomDataMask mask,
2389 int totelem)
2390{
2391 return customdata_merge_internal(source, dest, mask, std::nullopt, totelem);
2392}
2393
2395 CustomData *dest,
2396 const eCustomDataMask mask,
2397 const eCDAllocType alloctype,
2398 const int totelem)
2399{
2400 return customdata_merge_internal(source, dest, mask, alloctype, totelem);
2401}
2402
2404 const eCustomDataMask mask)
2405{
2406 Vector<CustomDataLayer> dst_layers;
2407 for (const CustomDataLayer &layer : Span<CustomDataLayer>{src->layers, src->totlayer}) {
2408 if (BM_attribute_stored_in_bmesh_builtin(layer.name)) {
2409 continue;
2410 }
2411 if (!(mask & CD_TYPE_AS_MASK(eCustomDataType(layer.type)))) {
2412 continue;
2413 }
2414 dst_layers.append(layer);
2415 }
2416
2417 CustomData dst = *src;
2418 dst.layers = MEM_calloc_arrayN<CustomDataLayer>(dst_layers.size(), __func__);
2419 dst.maxlayer = dst.totlayer = dst_layers.size();
2420 memcpy(dst.layers, dst_layers.data(), dst_layers.as_span().size_in_bytes());
2421
2423
2424 return dst;
2425}
2426
2432 private:
2433 const void *data_;
2434 int totelem_;
2435 const eCustomDataType type_;
2436
2437 public:
2438 CustomDataLayerImplicitSharing(const void *data, const int totelem, const eCustomDataType type)
2439 : ImplicitSharingInfo(), data_(data), totelem_(totelem), type_(type)
2440 {
2441 }
2442
2443 private:
2444 void delete_self_with_data() override
2445 {
2446 if (data_ != nullptr) {
2447 free_layer_data(type_, data_, totelem_);
2448 }
2449 MEM_delete(this);
2450 }
2451
2452 void delete_data_only() override
2453 {
2454 free_layer_data(type_, data_, totelem_);
2455 data_ = nullptr;
2456 totelem_ = 0;
2457 }
2458};
2459
2462 const void *data,
2463 const int totelem)
2464{
2465 return MEM_new<CustomDataLayerImplicitSharing>(__func__, data, totelem, type);
2466}
2467
2471static void ensure_layer_data_is_mutable(CustomDataLayer &layer, const int totelem)
2472{
2473 if (layer.data == nullptr) {
2474 return;
2475 }
2476 BLI_assert(layer.sharing_info != nullptr);
2477 if (layer.sharing_info->is_mutable()) {
2478 layer.sharing_info->tag_ensured_mutable();
2479 }
2480 else {
2481 const eCustomDataType type = eCustomDataType(layer.type);
2482 const void *old_data = layer.data;
2483 /* Copy the layer before removing the user because otherwise the data might be freed while
2484 * we're still copying from it here. */
2485 layer.data = copy_layer_data(type, old_data, totelem);
2486 layer.sharing_info->remove_user_and_delete_if_last();
2487 layer.sharing_info = make_implicit_sharing_info_for_layer(type, layer.data, totelem);
2488 }
2489}
2490
2491[[maybe_unused]] static bool layer_is_mutable(CustomDataLayer &layer)
2492{
2493 if (!layer.data) {
2494 return true;
2495 }
2496 return layer.sharing_info->is_mutable();
2497}
2498
2500{
2501 ensure_layer_data_is_mutable(*layer, totelem);
2502}
2503
2505{
2506 for (const int i : IndexRange(data->totlayer)) {
2507 ensure_layer_data_is_mutable(data->layers[i], totelem);
2508 }
2509}
2510
2512 const int old_size,
2513 const int new_size,
2514 const eCDAllocType alloctype)
2515{
2516 BLI_assert(new_size >= 0);
2517 for (int i = 0; i < data->totlayer; i++) {
2518 CustomDataLayer *layer = &data->layers[i];
2519 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer->type));
2520 const int64_t old_size_in_bytes = int64_t(old_size) * typeInfo->size;
2521 const int64_t new_size_in_bytes = int64_t(new_size) * typeInfo->size;
2522
2523 void *new_layer_data = (new_size > 0) ? MEM_mallocN_aligned(
2524 new_size_in_bytes, typeInfo->alignment, __func__) :
2525 nullptr;
2526 if (old_size_in_bytes > 0) {
2527 if (new_layer_data != nullptr) {
2528 /* Copy data to new array. */
2529 if (typeInfo->copy) {
2530 typeInfo->copy(layer->data, new_layer_data, std::min(old_size, new_size));
2531 }
2532 else {
2533 BLI_assert(layer->data != nullptr);
2534 memcpy(new_layer_data, layer->data, std::min(old_size_in_bytes, new_size_in_bytes));
2535 }
2536 }
2537 BLI_assert(layer->sharing_info != nullptr);
2538 layer->sharing_info->remove_user_and_delete_if_last();
2539 layer->sharing_info = nullptr;
2540 }
2541 /* Take ownership of new array. */
2542 layer->data = new_layer_data;
2543 if (layer->data) {
2545 eCustomDataType(layer->type), layer->data, new_size);
2546 }
2547
2548 if (new_size > old_size) {
2549 const int new_elements_num = new_size - old_size;
2550 void *new_elements_begin = POINTER_OFFSET(layer->data, old_size_in_bytes);
2551 switch (alloctype) {
2552 case CD_CONSTRUCT: {
2553 /* Initialize new values for non-trivial types. */
2554 if (typeInfo->construct) {
2555 typeInfo->construct(new_elements_begin, new_elements_num);
2556 }
2557 break;
2558 }
2559 case CD_SET_DEFAULT: {
2560 if (typeInfo->set_default_value) {
2561 typeInfo->set_default_value(new_elements_begin, new_elements_num);
2562 }
2563 else {
2564 memset(new_elements_begin, 0, typeInfo->size * new_elements_num);
2565 }
2566 break;
2567 }
2568 }
2569 }
2570 }
2571}
2572
2574 CustomData *dest,
2575 eCustomDataMask mask,
2576 int totelem)
2577{
2578 CustomData_reset(dest);
2579
2580 if (source->external) {
2581 dest->external = static_cast<CustomDataExternal *>(MEM_dupallocN(source->external));
2582 }
2583
2584 CustomData_merge(source, dest, mask, totelem);
2585}
2586
2588 CustomData *dest,
2589 eCustomDataMask mask,
2590 eCDAllocType alloctype,
2591 int totelem)
2592{
2593 CustomData_reset(dest);
2594
2595 if (source->external) {
2596 dest->external = static_cast<CustomDataExternal *>(MEM_dupallocN(source->external));
2597 }
2598
2599 CustomData_merge_layout(source, dest, mask, alloctype, totelem);
2600}
2601
2603{
2604 if (!layer->sharing_info) {
2605 BLI_assert(!layer->data);
2606 return;
2607 }
2608 layer->sharing_info->remove_user_and_delete_if_last();
2609 layer->sharing_info = nullptr;
2610}
2611
2613{
2614 if (data->external) {
2615 MEM_freeN(data->external);
2616 data->external = nullptr;
2617 }
2618}
2619
2621{
2622 *data = CustomData{};
2623 copy_vn_i(data->typemap, CD_NUMTYPES, -1);
2624}
2625
2627{
2628 for (int i = 0; i < data->totlayer; i++) {
2630 }
2631
2632 if (data->layers) {
2633 MEM_freeN(data->layers);
2634 }
2635
2638}
2639
2641{
2642 const LayerTypeInfo *typeInfo;
2643 int offset = 0;
2644
2645 for (int i = 0; i < data->totlayer; i++) {
2646 typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type));
2647
2648 data->layers[i].offset = offset;
2649 offset += typeInfo->size;
2650 }
2651
2652 data->totsize = offset;
2654}
2655
2656/* to use when we're in the middle of modifying layers */
2658 const eCustomDataType type)
2659{
2660 for (int i = 0; i < data->totlayer; i++) {
2661 if (data->layers[i].type == type) {
2662 return i;
2663 }
2664 }
2665
2666 return -1;
2667}
2668
2669/* -------------------------------------------------------------------- */
2670/* index values to access the layers (offset from the layer start) */
2671
2673{
2675 return data->typemap[type];
2676}
2677
2679{
2680 BLI_assert(n >= 0);
2681 int i = CustomData_get_layer_index(data, type);
2682
2683 if (i != -1) {
2684 /* If the value of n goes past the block of layers of the correct type, return -1. */
2685 i = (i + n < data->totlayer && data->layers[i + n].type == type) ? (i + n) : (-1);
2686 }
2687
2688 return i;
2689}
2690
2692 const eCustomDataType type,
2693 const StringRef name)
2694{
2695 for (int i = 0; i < data->totlayer; i++) {
2696 if (data->layers[i].type == type) {
2697 if (data->layers[i].name == name) {
2698 return i;
2699 }
2700 }
2701 }
2702
2703 return -1;
2704}
2705
2707{
2708 for (int i = 0; i < data->totlayer; i++) {
2709 if (data->layers[i].name == name) {
2710 return i;
2711 }
2712 }
2713
2714 return -1;
2715}
2716
2718{
2719 const int layer_index = data->typemap[type];
2721 return (layer_index != -1) ? layer_index + data->layers[layer_index].active : -1;
2722}
2723
2725{
2726 const int layer_index = data->typemap[type];
2728 return (layer_index != -1) ? layer_index + data->layers[layer_index].active_rnd : -1;
2729}
2730
2732{
2733 const int layer_index = data->typemap[type];
2735 return (layer_index != -1) ? layer_index + data->layers[layer_index].active_clone : -1;
2736}
2737
2739{
2740 const int layer_index = data->typemap[type];
2742 return (layer_index != -1) ? layer_index + data->layers[layer_index].active_mask : -1;
2743}
2744
2745/* -------------------------------------------------------------------- */
2746/* index values per layer type */
2747
2749 const eCustomDataType type,
2750 const StringRef name)
2751{
2752 const int named_index = CustomData_get_named_layer_index(data, type, name);
2753 const int layer_index = data->typemap[type];
2755 return (named_index != -1) ? named_index - layer_index : -1;
2756}
2757
2759{
2760 const int layer_index = data->typemap[type];
2762 return (layer_index != -1) ? data->layers[layer_index].active : -1;
2763}
2764
2766{
2767 const int layer_index = data->typemap[type];
2769 return (layer_index != -1) ? data->layers[layer_index].active_rnd : -1;
2770}
2771
2773{
2774 const int layer_index = data->typemap[type];
2776 return (layer_index != -1) ? data->layers[layer_index].active_clone : -1;
2777}
2778
2780{
2781 const int layer_index = data->typemap[type];
2783 return (layer_index != -1) ? data->layers[layer_index].active_mask : -1;
2784}
2785
2787{
2788 /* Get the layer index of the active layer of this type. */
2789 const int layer_index = CustomData_get_active_layer_index(data, type);
2790 return layer_index < 0 ? nullptr : data->layers[layer_index].name;
2791}
2792
2794{
2795 const int layer_index = CustomData_get_render_layer_index(data, type);
2796 return layer_index < 0 ? nullptr : data->layers[layer_index].name;
2797}
2798
2800{
2801#ifndef NDEBUG
2802 const int layer_num = CustomData_number_of_layers(data, type);
2803#endif
2804 for (int i = 0; i < data->totlayer; i++) {
2805 if (data->layers[i].type == type) {
2806 BLI_assert(uint(n) < uint(layer_num));
2807 data->layers[i].active = n;
2808 }
2809 }
2810}
2811
2813{
2814#ifndef NDEBUG
2815 const int layer_num = CustomData_number_of_layers(data, type);
2816#endif
2817 for (int i = 0; i < data->totlayer; i++) {
2818 if (data->layers[i].type == type) {
2819 BLI_assert(uint(n) < uint(layer_num));
2820 data->layers[i].active_rnd = n;
2821 }
2822 }
2823}
2824
2826{
2827#ifndef NDEBUG
2828 const int layer_num = CustomData_number_of_layers(data, type);
2829#endif
2830 for (int i = 0; i < data->totlayer; i++) {
2831 if (data->layers[i].type == type) {
2832 BLI_assert(uint(n) < uint(layer_num));
2833 data->layers[i].active_clone = n;
2834 }
2835 }
2836}
2837
2839{
2840#ifndef NDEBUG
2841 const int layer_num = CustomData_number_of_layers(data, type);
2842#endif
2843 for (int i = 0; i < data->totlayer; i++) {
2844 if (data->layers[i].type == type) {
2845 BLI_assert(uint(n) < uint(layer_num));
2846 data->layers[i].active_mask = n;
2847 }
2848 }
2849}
2850
2852{
2853#ifndef NDEBUG
2854 const int layer_num = CustomData_number_of_layers(data, type);
2855#endif
2856 const int layer_index = n - data->typemap[type];
2858
2859 for (int i = 0; i < data->totlayer; i++) {
2860 if (data->layers[i].type == type) {
2861 BLI_assert(uint(layer_index) < uint(layer_num));
2862 data->layers[i].active = layer_index;
2863 }
2864 }
2865}
2866
2868{
2869#ifndef NDEBUG
2870 const int layer_num = CustomData_number_of_layers(data, type);
2871#endif
2872 const int layer_index = n - data->typemap[type];
2874
2875 for (int i = 0; i < data->totlayer; i++) {
2876 if (data->layers[i].type == type) {
2877 BLI_assert(uint(layer_index) < uint(layer_num));
2878 data->layers[i].active_rnd = layer_index;
2879 }
2880 }
2881}
2882
2884{
2885#ifndef NDEBUG
2886 const int layer_num = CustomData_number_of_layers(data, type);
2887#endif
2888 const int layer_index = n - data->typemap[type];
2890
2891 for (int i = 0; i < data->totlayer; i++) {
2892 if (data->layers[i].type == type) {
2893 BLI_assert(uint(layer_index) < uint(layer_num));
2894 data->layers[i].active_clone = layer_index;
2895 }
2896 }
2897}
2898
2900{
2901 for (int i = 0; i < data->totlayer; i++) {
2902 if (data->layers[i].type == type) {
2903 data->layers[i].flag |= flag;
2904 }
2905 }
2906}
2907
2909{
2910 const int layer_index = CustomData_get_layer_index_n(data, type, n);
2911
2912 BLI_assert(layer_index >= 0);
2913
2914 return blender::bke::attribute_name_is_anonymous(data->layers[layer_index].name);
2915}
2916
2917static void customData_resize(CustomData *data, const int grow_amount)
2918{
2919 data->layers = static_cast<CustomDataLayer *>(
2920 MEM_reallocN(data->layers, (data->maxlayer + grow_amount) * sizeof(CustomDataLayer)));
2921 data->maxlayer += grow_amount;
2922}
2923
2926 const eCustomDataType type,
2927 const std::optional<eCDAllocType> alloctype,
2928 void *layer_data_to_assign,
2929 const ImplicitSharingInfo *sharing_info_to_assign,
2930 const int totelem,
2932{
2933 const LayerTypeInfo &type_info = *layerType_getInfo(type);
2934 int flag = 0;
2935
2936 /* Some layer types only support a single layer. */
2937 if (!type_info.defaultname && CustomData_has_layer(data, type)) {
2938 /* This function doesn't support dealing with existing layer data for these layer types when
2939 * the layer already exists. */
2940 BLI_assert(layer_data_to_assign == nullptr);
2941 return &data->layers[CustomData_get_layer_index(data, type)];
2942 }
2943
2944 int index = data->totlayer;
2945 if (index >= data->maxlayer) {
2947 }
2948
2949 data->totlayer++;
2950
2951 /* Keep layers ordered by type. */
2952 for (; index > 0 && data->layers[index - 1].type > type; index--) {
2953 data->layers[index] = data->layers[index - 1];
2954 }
2955
2956 CustomDataLayer &new_layer = data->layers[index];
2957
2958 /* Clear remaining data on the layer. The original data on the layer has been moved to another
2959 * index. Without this, it can happen that information from the previous layer at that index
2960 * leaks into the new layer. */
2961 new_layer = CustomDataLayer{};
2962
2963 const int64_t size_in_bytes = int64_t(totelem) * type_info.size;
2964 const char *alloc_name = layerType_getName(type);
2965
2966 if (alloctype.has_value()) {
2967 switch (*alloctype) {
2968 case CD_SET_DEFAULT: {
2969 if (totelem > 0) {
2970 new_layer.data = MEM_mallocN_aligned(size_in_bytes, type_info.alignment, alloc_name);
2971 if (type_info.set_default_value) {
2972 type_info.set_default_value(new_layer.data, totelem);
2973 }
2974 else {
2975 /* Alternatively, #MEM_calloc_arrayN is faster, but has no aligned version. */
2976 memset(new_layer.data, 0, size_in_bytes);
2977 }
2978 }
2979 break;
2980 }
2981 case CD_CONSTRUCT: {
2982 if (totelem > 0) {
2983 new_layer.data = MEM_mallocN_aligned(size_in_bytes, type_info.alignment, alloc_name);
2984 if (type_info.construct) {
2985 type_info.construct(new_layer.data, totelem);
2986 }
2987 }
2988 break;
2989 }
2990 }
2991 }
2992 else {
2993 if (totelem == 0 && sharing_info_to_assign == nullptr) {
2994 MEM_SAFE_FREE(layer_data_to_assign);
2995 }
2996 else {
2997 new_layer.data = layer_data_to_assign;
2998 new_layer.sharing_info = sharing_info_to_assign;
2999 if (new_layer.sharing_info) {
3000 new_layer.sharing_info->add_user();
3001 }
3002 }
3003 }
3004
3005 if (new_layer.data != nullptr && new_layer.sharing_info == nullptr) {
3006 /* Make layer data shareable. */
3007 new_layer.sharing_info = make_implicit_sharing_info_for_layer(type, new_layer.data, totelem);
3008 }
3009
3010 new_layer.type = type;
3011 new_layer.flag = flag;
3012
3013 /* Set default name if none exists. Note we only call DATA_() once
3014 * we know there is a default name, to avoid overhead of locale lookups
3015 * in the depsgraph. */
3016 if (name.is_empty() && type_info.defaultname) {
3017 name = DATA_(type_info.defaultname);
3018 }
3019
3020 if (!name.is_empty()) {
3021 name.copy_utf8_truncated(new_layer.name);
3023 }
3024 else {
3025 new_layer.name[0] = '\0';
3026 }
3027
3028 if (index > 0 && data->layers[index - 1].type == type) {
3029 new_layer.active = data->layers[index - 1].active;
3030 new_layer.active_rnd = data->layers[index - 1].active_rnd;
3031 new_layer.active_clone = data->layers[index - 1].active_clone;
3032 new_layer.active_mask = data->layers[index - 1].active_mask;
3033 }
3034 else {
3035 new_layer.active = 0;
3036 new_layer.active_rnd = 0;
3037 new_layer.active_clone = 0;
3038 new_layer.active_mask = 0;
3039 }
3040
3042
3043 return &data->layers[index];
3044}
3045
3047 const eCustomDataType type,
3048 eCDAllocType alloctype,
3049 const int totelem)
3050{
3051 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
3052
3054 data, type, alloctype, nullptr, nullptr, totelem, typeInfo->defaultname);
3056
3057 if (layer) {
3058 return layer->data;
3059 }
3060
3061 return nullptr;
3062}
3063
3065 const eCustomDataType type,
3066 void *layer_data,
3067 const int totelem,
3068 const ImplicitSharingInfo *sharing_info)
3069{
3070 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
3071
3073 data, type, std::nullopt, layer_data, sharing_info, totelem, typeInfo->defaultname);
3075
3076 if (layer) {
3077 return layer->data;
3078 }
3079
3080 return nullptr;
3081}
3082
3084 const eCustomDataType type,
3085 const eCDAllocType alloctype,
3086 const int totelem,
3087 const StringRef name)
3088{
3090 data, type, alloctype, nullptr, nullptr, totelem, name);
3092
3093 if (layer) {
3094 return layer->data;
3095 }
3096 return nullptr;
3097}
3098
3100 eCustomDataType type,
3101 void *layer_data,
3102 int totelem,
3103 const StringRef name,
3104 const ImplicitSharingInfo *sharing_info)
3105{
3107 data, type, std::nullopt, layer_data, sharing_info, totelem, name);
3109
3110 if (layer) {
3111 return layer->data;
3112 }
3113 return nullptr;
3114}
3115
3116bool CustomData_free_layer(CustomData *data, const eCustomDataType type, const int index)
3117{
3118 const int index_first = CustomData_get_layer_index(data, type);
3119 const int n = index - index_first;
3120
3121 BLI_assert(index >= index_first);
3122 if ((index_first == -1) || (n < 0)) {
3123 return false;
3124 }
3125 BLI_assert(data->layers[index].type == type);
3126
3127 customData_free_layer__internal(&data->layers[index]);
3128
3129 for (int i = index + 1; i < data->totlayer; i++) {
3130 data->layers[i - 1] = data->layers[i];
3131 }
3132
3133 data->totlayer--;
3134
3135 /* if layer was last of type in array, set new active layer */
3137
3138 if (i != -1) {
3139 /* don't decrement zero index */
3140 const int index_nonzero = n ? n : 1;
3141 CustomDataLayer *layer;
3142
3143 for (layer = &data->layers[i]; i < data->totlayer && layer->type == type; i++, layer++) {
3144 if (layer->active >= index_nonzero) {
3145 layer->active--;
3146 }
3147 if (layer->active_rnd >= index_nonzero) {
3148 layer->active_rnd--;
3149 }
3150 if (layer->active_clone >= index_nonzero) {
3151 layer->active_clone--;
3152 }
3153 if (layer->active_mask >= index_nonzero) {
3154 layer->active_mask--;
3155 }
3156 }
3157 }
3158
3159 if (data->totlayer <= data->maxlayer - CUSTOMDATA_GROW) {
3161 }
3162
3164
3165 return true;
3166}
3167
3169{
3170 for (const int i : IndexRange(data->totlayer)) {
3171 const CustomDataLayer &layer = data->layers[i];
3172 if (StringRef(layer.name) == name) {
3174 return true;
3175 }
3176 }
3177 return false;
3178}
3179
3181{
3182 const int index = CustomData_get_active_layer_index(data, type);
3183 if (index == -1) {
3184 return false;
3185 }
3186 return CustomData_free_layer(data, type, index);
3187}
3188
3190{
3191 const int index = CustomData_get_layer_index(data, type);
3192 while (CustomData_free_layer(data, type, index)) {
3193 /* pass */
3194 }
3195}
3196
3198 const eCustomDataType type,
3199 const StringRef name)
3200{
3201 return CustomData_get_named_layer_index(data, type, name) != -1;
3202}
3203
3205{
3206 return (CustomData_get_layer_index(data, type) != -1);
3207}
3208
3210{
3211 int number = 0;
3212
3213 for (int i = 0; i < data->totlayer; i++) {
3214 if (data->layers[i].type == type) {
3215 number++;
3216 }
3217 }
3218
3219 return number;
3220}
3221
3223{
3224 int number = 0;
3225
3226 for (int i = 0; i < data->totlayer; i++) {
3227 if (data->layers[i].type == type &&
3229 {
3230 number++;
3231 }
3232 }
3233
3234 return number;
3235}
3236
3238{
3239 int number = 0;
3240
3241 for (int i = 0; i < data->totlayer; i++) {
3242 if (mask & CD_TYPE_AS_MASK(eCustomDataType(data->layers[i].type))) {
3243 number++;
3244 }
3245 }
3246
3247 return number;
3248}
3249
3250void CustomData_set_only_copy(const CustomData *data, const eCustomDataMask mask)
3251{
3252 for (int i = 0; i < data->totlayer; i++) {
3253 if (!(mask & CD_TYPE_AS_MASK(eCustomDataType(data->layers[i].type)))) {
3254 data->layers[i].flag |= CD_FLAG_NOCOPY;
3255 }
3256 }
3257}
3258
3260 const void *src_data,
3261 void *dst_data,
3262 const int count)
3263{
3264 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
3265
3266 if (typeInfo->copy) {
3267 typeInfo->copy(src_data, dst_data, count);
3268 }
3269 else {
3270 memcpy(dst_data, src_data, size_t(count) * typeInfo->size);
3271 }
3272}
3273
3275 CustomData *dest,
3276 const int src_layer_index,
3277 const int dst_layer_index,
3278 const int src_index,
3279 const int dst_index,
3280 const int count)
3281{
3282 const LayerTypeInfo *typeInfo;
3283
3284 BLI_assert(layer_is_mutable(dest->layers[dst_layer_index]));
3285
3286 const void *src_data = source->layers[src_layer_index].data;
3287 void *dst_data = dest->layers[dst_layer_index].data;
3288
3289 typeInfo = layerType_getInfo(eCustomDataType(source->layers[src_layer_index].type));
3290
3291 const size_t src_offset = size_t(src_index) * typeInfo->size;
3292 const size_t dst_offset = size_t(dst_index) * typeInfo->size;
3293
3294 if (!count || !src_data || !dst_data) {
3295 if (count && !(src_data == nullptr && dst_data == nullptr)) {
3296 CLOG_WARN(&LOG,
3297 "null data for %s type (%p --> %p), skipping",
3298 layerType_getName(eCustomDataType(source->layers[src_layer_index].type)),
3299 (void *)src_data,
3300 (void *)dst_data);
3301 }
3302 return;
3303 }
3304
3305 if (typeInfo->copy) {
3306 typeInfo->copy(
3307 POINTER_OFFSET(src_data, src_offset), POINTER_OFFSET(dst_data, dst_offset), count);
3308 }
3309 else {
3310 memcpy(POINTER_OFFSET(dst_data, dst_offset),
3311 POINTER_OFFSET(src_data, src_offset),
3312 size_t(count) * typeInfo->size);
3313 }
3314}
3315
3317 CustomData *dest,
3318 const int source_index,
3319 const int dest_index,
3320 const int count)
3321{
3322 /* copies a layer at a time */
3323 int dest_i = 0;
3324 for (int src_i = 0; src_i < source->totlayer; src_i++) {
3325
3326 /* find the first dest layer with type >= the source type
3327 * (this should work because layers are ordered by type)
3328 */
3329 while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
3330 dest_i++;
3331 }
3332
3333 /* if there are no more dest layers, we're done */
3334 if (dest_i >= dest->totlayer) {
3335 return;
3336 }
3337
3338 /* if we found a matching layer, copy the data */
3339 if (dest->layers[dest_i].type == source->layers[src_i].type) {
3340 CustomData_copy_data_layer(source, dest, src_i, dest_i, source_index, dest_index, count);
3341
3342 /* if there are multiple source & dest layers of the same type,
3343 * we don't want to copy all source layers to the same dest, so
3344 * increment dest_i
3345 */
3346 dest_i++;
3347 }
3348 }
3349}
3350
3352 CustomData *destination,
3353 const eCustomDataType type,
3354 int source_index,
3355 int destination_index,
3356 int count)
3357{
3358 const int source_layer_index = CustomData_get_layer_index(source, type);
3359 if (source_layer_index == -1) {
3360 return;
3361 }
3362 const int destinaiton_layer_index = CustomData_get_layer_index(destination, type);
3363 if (destinaiton_layer_index == -1) {
3364 return;
3365 }
3367 destination,
3368 source_layer_index,
3369 destinaiton_layer_index,
3370 source_index,
3371 destination_index,
3372 count);
3373}
3374
3375void CustomData_free_elem(CustomData *data, const int index, const int count)
3376{
3377 for (int i = 0; i < data->totlayer; i++) {
3378 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type));
3379
3380 if (typeInfo->free) {
3381 size_t offset = size_t(index) * typeInfo->size;
3382 BLI_assert(layer_is_mutable(data->layers[i]));
3383
3384 typeInfo->free(POINTER_OFFSET(data->layers[i].data, offset), count);
3385 }
3386 }
3387}
3388
3389#define SOURCE_BUF_SIZE 100
3390
3392 CustomData *dest,
3393 const int *src_indices,
3394 const float *weights,
3395 int count,
3396 int dest_index)
3397{
3398 if (count <= 0) {
3399 return;
3400 }
3401
3402 const void *source_buf[SOURCE_BUF_SIZE];
3403 const void **sources = source_buf;
3404
3405 /* Slow fallback in case we're interpolating a ridiculous number of elements. */
3406 if (count > SOURCE_BUF_SIZE) {
3407 sources = MEM_malloc_arrayN<const void *>(size_t(count), __func__);
3408 }
3409
3410 /* If no weights are given, generate default ones to produce an average result. */
3411 float default_weights_buf[SOURCE_BUF_SIZE];
3412 float *default_weights = nullptr;
3413 if (weights == nullptr) {
3414 default_weights = (count > SOURCE_BUF_SIZE) ?
3415 MEM_malloc_arrayN<float>(size_t(count), __func__) :
3416 default_weights_buf;
3417 copy_vn_fl(default_weights, count, 1.0f / count);
3418 weights = default_weights;
3419 }
3420
3421 /* interpolates a layer at a time */
3422 int dest_i = 0;
3423 for (int src_i = 0; src_i < source->totlayer; src_i++) {
3424 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(source->layers[src_i].type));
3425 if (!typeInfo->interp) {
3426 continue;
3427 }
3428
3429 /* find the first dest layer with type >= the source type
3430 * (this should work because layers are ordered by type)
3431 */
3432 while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
3433 dest_i++;
3434 }
3435
3436 /* if there are no more dest layers, we're done */
3437 if (dest_i >= dest->totlayer) {
3438 break;
3439 }
3440
3441 /* if we found a matching layer, copy the data */
3442 if (dest->layers[dest_i].type == source->layers[src_i].type) {
3443 void *src_data = source->layers[src_i].data;
3444
3445 for (int j = 0; j < count; j++) {
3446 sources[j] = POINTER_OFFSET(src_data, size_t(src_indices[j]) * typeInfo->size);
3447 }
3448
3449 typeInfo->interp(
3450 sources,
3451 weights,
3452 count,
3453 POINTER_OFFSET(dest->layers[dest_i].data, size_t(dest_index) * typeInfo->size));
3454
3455 /* if there are multiple source & dest layers of the same type,
3456 * we don't want to copy all source layers to the same dest, so
3457 * increment dest_i
3458 */
3459 dest_i++;
3460 }
3461 }
3462
3463 if (count > SOURCE_BUF_SIZE) {
3464 MEM_freeN(sources);
3465 }
3466 if (!ELEM(default_weights, nullptr, default_weights_buf)) {
3467 MEM_freeN(default_weights);
3468 }
3469}
3470
3471void CustomData_swap_corners(CustomData *data, const int index, const int *corner_indices)
3472{
3473 for (int i = 0; i < data->totlayer; i++) {
3474 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type));
3475
3476 if (typeInfo->swap) {
3477 const size_t offset = size_t(index) * typeInfo->size;
3478
3479 typeInfo->swap(POINTER_OFFSET(data->layers[i].data, offset), corner_indices);
3480 }
3481 }
3482}
3483
3485 const int index,
3486 const eCustomDataType type,
3487 int totelem)
3488{
3489 BLI_assert(index >= 0);
3490 void *layer_data = CustomData_get_layer_for_write(data, type, totelem);
3491 if (!layer_data) {
3492 return nullptr;
3493 }
3494 return POINTER_OFFSET(layer_data, size_t(index) * layerType_getInfo(type)->size);
3495}
3496
3498 CustomData *data, const eCustomDataType type, const int index, const int n, int totelem)
3499{
3500 BLI_assert(index >= 0);
3501 void *layer_data = CustomData_get_layer_n_for_write(data, type, n, totelem);
3502 if (!layer_data) {
3503 return nullptr;
3504 }
3505
3506 return POINTER_OFFSET(layer_data, size_t(index) * layerType_getInfo(type)->size);
3507}
3508
3510{
3511 int layer_index = CustomData_get_active_layer_index(data, type);
3512 if (layer_index == -1) {
3513 return nullptr;
3514 }
3515
3516 return data->layers[layer_index].data;
3517}
3518
3520 const eCustomDataType type,
3521 const int totelem)
3522{
3523 const int layer_index = CustomData_get_active_layer_index(data, type);
3524 if (layer_index == -1) {
3525 return nullptr;
3526 }
3527 CustomDataLayer &layer = data->layers[layer_index];
3528 ensure_layer_data_is_mutable(layer, totelem);
3529 return layer.data;
3530}
3531
3532const void *CustomData_get_layer_n(const CustomData *data, const eCustomDataType type, const int n)
3533{
3534 int layer_index = CustomData_get_layer_index_n(data, type, n);
3535 if (layer_index == -1) {
3536 return nullptr;
3537 }
3538 return data->layers[layer_index].data;
3539}
3540
3542 const eCustomDataType type,
3543 const int n,
3544 const int totelem)
3545{
3546 const int layer_index = CustomData_get_layer_index_n(data, type, n);
3547 if (layer_index == -1) {
3548 return nullptr;
3549 }
3550 CustomDataLayer &layer = data->layers[layer_index];
3551 ensure_layer_data_is_mutable(layer, totelem);
3552 return layer.data;
3553}
3554
3556 const eCustomDataType type,
3557 const StringRef name)
3558{
3559 int layer_index = CustomData_get_named_layer_index(data, type, name);
3560 if (layer_index == -1) {
3561 return nullptr;
3562 }
3563 return data->layers[layer_index].data;
3564}
3565
3567 const eCustomDataType type,
3568 const StringRef name,
3569 const int totelem)
3570{
3571 const int layer_index = CustomData_get_named_layer_index(data, type, name);
3572 if (layer_index == -1) {
3573 return nullptr;
3574 }
3575 CustomDataLayer &layer = data->layers[layer_index];
3576 ensure_layer_data_is_mutable(layer, totelem);
3577 return layer.data;
3578}
3579
3581{
3582 int layer_index = CustomData_get_active_layer_index(data, type);
3583 if (layer_index == -1) {
3584 return -1;
3585 }
3586 return data->layers[layer_index].offset;
3587}
3588
3589int CustomData_get_n_offset(const CustomData *data, const eCustomDataType type, const int n)
3590{
3591 int layer_index = CustomData_get_layer_index_n(data, type, n);
3592 if (layer_index == -1) {
3593 return -1;
3594 }
3595
3596 return data->layers[layer_index].offset;
3597}
3598
3600 const eCustomDataType type,
3601 const StringRef name)
3602{
3603 int layer_index = CustomData_get_named_layer_index(data, type, name);
3604 if (layer_index == -1) {
3605 return -1;
3606 }
3607
3608 return data->layers[layer_index].offset;
3609}
3610
3612 const eCustomDataType type,
3613 const int n,
3614 const StringRef name)
3615{
3616 const int layer_index = CustomData_get_layer_index_n(data, type, n);
3617 if (layer_index == -1) {
3618 return false;
3619 }
3620
3621 name.copy_utf8_truncated(data->layers[layer_index].name);
3622
3623 return true;
3624}
3625
3627 const eCustomDataType type,
3628 const int n)
3629{
3630 const int layer_index = CustomData_get_layer_index_n(data, type, n);
3631
3632 return (layer_index == -1) ? nullptr : data->layers[layer_index].name;
3633}
3634
3635/* BMesh functions */
3636
3637void CustomData_bmesh_init_pool(CustomData *data, const int totelem, const char htype)
3638{
3639 int chunksize;
3640
3641 /* Dispose old pools before calling here to avoid leaks */
3642 BLI_assert(data->pool == nullptr);
3643
3644 switch (htype) {
3645 case BM_VERT:
3646 chunksize = bm_mesh_chunksize_default.totvert;
3647 break;
3648 case BM_EDGE:
3649 chunksize = bm_mesh_chunksize_default.totedge;
3650 break;
3651 case BM_LOOP:
3652 chunksize = bm_mesh_chunksize_default.totloop;
3653 break;
3654 case BM_FACE:
3655 chunksize = bm_mesh_chunksize_default.totface;
3656 break;
3657 default:
3659 chunksize = 512;
3660 break;
3661 }
3662
3663 /* If there are no layers, no pool is needed just yet */
3664 if (data->totlayer) {
3665 data->pool = BLI_mempool_create(data->totsize, totelem, chunksize, BLI_MEMPOOL_NOP);
3666 }
3667}
3668
3670 CustomData *dest,
3671 eCustomDataMask mask,
3672 eCDAllocType alloctype,
3673 BMesh *bm,
3674 const char htype)
3675{
3676
3677 if (CustomData_number_of_layers_typemask(source, mask) == 0) {
3678 return false;
3679 }
3680
3681 /* copy old layer description so that old data can be copied into
3682 * the new allocation */
3683 CustomData destold = *dest;
3684 if (destold.layers) {
3685 destold.layers = static_cast<CustomDataLayer *>(MEM_dupallocN(destold.layers));
3686 }
3687
3688 if (CustomData_merge_layout(source, dest, mask, alloctype, 0) == false) {
3689 if (destold.layers) {
3690 MEM_freeN(destold.layers);
3691 }
3692 return false;
3693 }
3694
3695 const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc(destold, *dest);
3696
3697 int iter_type;
3698 int totelem;
3699 switch (htype) {
3700 case BM_VERT:
3701 iter_type = BM_VERTS_OF_MESH;
3702 totelem = bm->totvert;
3703 break;
3704 case BM_EDGE:
3705 iter_type = BM_EDGES_OF_MESH;
3706 totelem = bm->totedge;
3707 break;
3708 case BM_LOOP:
3709 iter_type = BM_LOOPS_OF_FACE;
3710 totelem = bm->totloop;
3711 break;
3712 case BM_FACE:
3713 iter_type = BM_FACES_OF_MESH;
3714 totelem = bm->totface;
3715 break;
3716 default: /* should never happen */
3717 BLI_assert_msg(0, "invalid type given");
3718 iter_type = BM_VERTS_OF_MESH;
3719 totelem = bm->totvert;
3720 break;
3721 }
3722
3723 dest->pool = nullptr;
3724 CustomData_bmesh_init_pool(dest, totelem, htype);
3725
3726 if (iter_type != BM_LOOPS_OF_FACE) {
3727 BMHeader *h;
3728 BMIter iter;
3729 /* Ensure all current elements follow new customdata layout. */
3730 BM_ITER_MESH (h, &iter, bm, iter_type) {
3731 void *tmp = nullptr;
3732 CustomData_bmesh_copy_block(*dest, map, h->data, &tmp);
3733 CustomData_bmesh_free_block(&destold, &h->data);
3734 h->data = tmp;
3735 }
3736 }
3737 else {
3738 BMFace *f;
3739 BMLoop *l;
3740 BMIter iter;
3741 BMIter liter;
3742
3743 /* Ensure all current elements follow new customdata layout. */
3744 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
3745 BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
3746 void *tmp = nullptr;
3747 CustomData_bmesh_copy_block(*dest, map, l->head.data, &tmp);
3748 CustomData_bmesh_free_block(&destold, &l->head.data);
3749 l->head.data = tmp;
3750 }
3751 }
3752 }
3753
3754 if (destold.pool) {
3755 BLI_mempool_destroy(destold.pool);
3756 }
3757 if (destold.layers) {
3758 MEM_freeN(destold.layers);
3759 }
3760 return true;
3761}
3762
3764{
3765 if (*block == nullptr) {
3766 return;
3767 }
3768
3769 for (int i = 0; i < data->totlayer; i++) {
3770 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type));
3771
3772 if (typeInfo->free) {
3773 int offset = data->layers[i].offset;
3774 typeInfo->free(POINTER_OFFSET(*block, offset), 1);
3775 }
3776 }
3777
3778 if (data->totsize) {
3779 BLI_mempool_free(data->pool, *block);
3780 }
3781
3782 *block = nullptr;
3783}
3784
3786{
3787 if (block == nullptr) {
3788 return;
3789 }
3790 for (int i = 0; i < data->totlayer; i++) {
3791 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type));
3792 if (typeInfo->free) {
3793 const size_t offset = data->layers[i].offset;
3794 typeInfo->free(POINTER_OFFSET(block, offset), 1);
3795 }
3796 }
3797 if (data->totsize) {
3798 memset(block, 0, data->totsize);
3799 }
3800}
3801
3803{
3804 if (*block) {
3806 }
3807
3808 if (data->totsize > 0) {
3809 *block = BLI_mempool_alloc(data->pool);
3810 }
3811 else {
3812 *block = nullptr;
3813 }
3814}
3815
3817{
3818 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
3819 if (typeInfo->set_default_value) {
3820 typeInfo->set_default_value(elem, 1);
3821 }
3822 else {
3823 memset(elem, 0, typeInfo->size);
3824 }
3825}
3826
3827static void CustomData_bmesh_set_default_n(CustomData *data, void **block, const int n)
3828{
3829 const int offset = data->layers[n].offset;
3831 POINTER_OFFSET(*block, offset));
3832}
3833
3835{
3836 if (*block == nullptr) {
3838 }
3839
3840 for (int i = 0; i < data->totlayer; i++) {
3842 }
3843}
3844
3846 const CustomData &dst,
3847 const eCustomDataMask mask_exclude)
3848{
3850 for (const CustomDataLayer &layer_dst : Span(dst.layers, dst.totlayer)) {
3851 const int dst_offset = layer_dst.offset;
3852 const eCustomDataType dst_type = eCustomDataType(layer_dst.type);
3853 const LayerTypeInfo &type_info = *layerType_getInfo(dst_type);
3854
3855 const int src_offset = CustomData_get_offset_named(&src, dst_type, layer_dst.name);
3856 if (src_offset == -1 || CD_TYPE_AS_MASK(dst_type) & mask_exclude) {
3857 if (type_info.set_default_value) {
3858 map.defaults.append({type_info.set_default_value, dst_offset});
3859 }
3860 else {
3861 map.trivial_defaults.append({type_info.size, dst_offset});
3862 }
3863 }
3864 else {
3865 if (type_info.copy) {
3866 map.copies.append({type_info.copy, src_offset, dst_offset});
3867 }
3868 else {
3869 /* NOTE: A way to improve performance of copies (by reducing the number of `memcpy`
3870 * calls) would be combining contiguous chunks in the source and result format. */
3871 map.trivial_copies.append({type_info.size, src_offset, dst_offset});
3872 }
3873 }
3874
3875 if (type_info.free) {
3876 map.free.append({type_info.free, dst_offset});
3877 }
3878 }
3879 return map;
3880}
3881
3883 const BMCustomDataCopyMap &copy_map,
3884 const void *src_block,
3885 void **dst_block)
3886{
3887 if (*dst_block) {
3888 for (const BMCustomDataCopyMap::Free &info : copy_map.free) {
3889 info.fn(POINTER_OFFSET(*dst_block, info.dst_offset), 1);
3890 }
3891 }
3892 else {
3893 if (dst_data.totsize == 0) {
3894 return;
3895 }
3896 *dst_block = BLI_mempool_alloc(dst_data.pool);
3897 }
3898
3899 for (const BMCustomDataCopyMap::TrivialCopy &info : copy_map.trivial_copies) {
3900 memcpy(POINTER_OFFSET(*dst_block, info.dst_offset),
3901 POINTER_OFFSET(src_block, info.src_offset),
3902 info.size);
3903 }
3904 for (const BMCustomDataCopyMap::Copy &info : copy_map.copies) {
3905 info.fn(POINTER_OFFSET(src_block, info.src_offset),
3906 POINTER_OFFSET(*dst_block, info.dst_offset),
3907 1);
3908 }
3909 for (const BMCustomDataCopyMap::TrivialDefault &info : copy_map.trivial_defaults) {
3910 memset(POINTER_OFFSET(*dst_block, info.dst_offset), 0, info.size);
3911 }
3912 for (const BMCustomDataCopyMap::Default &info : copy_map.defaults) {
3913 info.fn(POINTER_OFFSET(*dst_block, info.dst_offset), 1);
3914 }
3915}
3916
3917void CustomData_bmesh_copy_block(CustomData &data, void *src_block, void **dst_block)
3918{
3919 if (*dst_block) {
3920 for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
3921 const LayerTypeInfo &info = *layerType_getInfo(eCustomDataType(layer.type));
3922 if (info.free) {
3923 info.free(POINTER_OFFSET(*dst_block, layer.offset), 1);
3924 }
3925 }
3926 }
3927 else {
3928 if (data.totsize == 0) {
3929 return;
3930 }
3931 *dst_block = BLI_mempool_alloc(data.pool);
3932 }
3933
3934 for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
3935 const int offset = layer.offset;
3936 const LayerTypeInfo &info = *layerType_getInfo(eCustomDataType(layer.type));
3937 if (info.copy) {
3938 info.copy(POINTER_OFFSET(src_block, offset), POINTER_OFFSET(*dst_block, offset), 1);
3939 }
3940 else {
3941 memcpy(POINTER_OFFSET(*dst_block, offset), POINTER_OFFSET(src_block, offset), info.size);
3942 }
3943 }
3944}
3945
3946void *CustomData_bmesh_get(const CustomData *data, void *block, const eCustomDataType type)
3947{
3948 int layer_index = CustomData_get_active_layer_index(data, type);
3949 if (layer_index == -1) {
3950 return nullptr;
3951 }
3952
3953 return POINTER_OFFSET(block, data->layers[layer_index].offset);
3954}
3955
3957 void *block,
3958 const eCustomDataType type,
3959 const int n)
3960{
3961 int layer_index = CustomData_get_layer_index(data, type);
3962 if (layer_index == -1) {
3963 return nullptr;
3964 }
3965
3966 return POINTER_OFFSET(block, data->layers[layer_index + n].offset);
3967}
3968
3969void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, const int n)
3970{
3971 if (n < 0 || n >= data->totlayer) {
3972 return nullptr;
3973 }
3974
3975 return POINTER_OFFSET(block, data->layers[n].offset);
3976}
3977
3978bool CustomData_layer_has_math(const CustomData *data, const int layer_n)
3979{
3980 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[layer_n].type));
3981
3982 if (typeInfo->equal && typeInfo->add && typeInfo->multiply && typeInfo->initminmax &&
3983 typeInfo->dominmax)
3984 {
3985 return true;
3986 }
3987
3988 return false;
3989}
3990
3991bool CustomData_layer_has_interp(const CustomData *data, const int layer_n)
3992{
3993 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[layer_n].type));
3994
3995 if (typeInfo->interp) {
3996 return true;
3997 }
3998
3999 return false;
4000}
4001
4003{
4004 /* interpolates a layer at a time */
4005 for (int i = 0; i < data->totlayer; i++) {
4007 return true;
4008 }
4009 }
4010
4011 return false;
4012}
4013
4015{
4016 for (int i = 0; i < data->totlayer; i++) {
4017 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type));
4018 if (typeInfo->free) {
4019 return true;
4020 }
4021 }
4022 return false;
4023}
4024
4026{
4027 /* interpolates a layer at a time */
4028 for (int i = 0; i < data->totlayer; i++) {
4030 return true;
4031 }
4032 }
4033
4034 return false;
4035}
4036
4037void CustomData_data_copy_value(const eCustomDataType type, const void *source, void *dest)
4038{
4039 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
4040
4041 if (!dest) {
4042 return;
4043 }
4044
4045 if (typeInfo->copy) {
4046 typeInfo->copy(source, dest, 1);
4047 }
4048 else {
4049 memcpy(dest, source, typeInfo->size);
4050 }
4051}
4052
4054 const void *source,
4055 void *dest,
4056 const int mixmode,
4057 const float mixfactor)
4058{
4059 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
4060
4061 if (!dest) {
4062 return;
4063 }
4064
4065 if (typeInfo->copyvalue) {
4066 typeInfo->copyvalue(source, dest, mixmode, mixfactor);
4067 }
4068 else {
4069 /* Mere copy if no advanced interpolation is supported. */
4070 memcpy(dest, source, typeInfo->size);
4071 }
4072}
4073
4074bool CustomData_data_equals(const eCustomDataType type, const void *data1, const void *data2)
4075{
4076 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
4077
4078 if (typeInfo->equal) {
4079 return typeInfo->equal(data1, data2);
4080 }
4081
4082 return !memcmp(data1, data2, typeInfo->size);
4083}
4084
4086{
4087 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
4088
4089 if (typeInfo->initminmax) {
4090 typeInfo->initminmax(min, max);
4091 }
4092}
4093
4094void CustomData_data_dominmax(const eCustomDataType type, const void *data, void *min, void *max)
4095{
4096 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
4097
4098 if (typeInfo->dominmax) {
4099 typeInfo->dominmax(data, min, max);
4100 }
4101}
4102
4103void CustomData_data_multiply(const eCustomDataType type, void *data, const float fac)
4104{
4105 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
4106
4107 if (typeInfo->multiply) {
4108 typeInfo->multiply(data, fac);
4109 }
4110}
4111
4112void CustomData_data_add(const eCustomDataType type, void *data1, const void *data2)
4113{
4114 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
4115
4116 if (typeInfo->add) {
4117 typeInfo->add(data1, data2);
4118 }
4119}
4120
4122 CustomData *data, void *block, const eCustomDataType type, const int n, const void *source)
4123{
4124 void *dest = CustomData_bmesh_get_n(data, block, type, n);
4125 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
4126
4127 if (!dest) {
4128 return;
4129 }
4130
4131 if (typeInfo->copy) {
4132 typeInfo->copy(source, dest, 1);
4133 }
4134 else {
4135 memcpy(dest, source, typeInfo->size);
4136 }
4137}
4138
4140 const void **src_blocks_ofs,
4141 const float *weights,
4142 int count,
4143 void *dst_block_ofs,
4144 int n)
4145{
4146 BLI_assert(weights != nullptr);
4147 BLI_assert(count > 0);
4148
4149 CustomDataLayer *layer = &data->layers[n];
4150 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer->type));
4151
4152 typeInfo->interp(src_blocks_ofs, weights, count, dst_block_ofs);
4153}
4154
4156 CustomData *data, const void **src_blocks, const float *weights, int count, void *dst_block)
4157{
4158 if (count <= 0) {
4159 return;
4160 }
4161
4162 void *source_buf[SOURCE_BUF_SIZE];
4163 const void **sources = (const void **)source_buf;
4164
4165 /* Slow fallback in case we're interpolating a ridiculous number of elements. */
4166 if (count > SOURCE_BUF_SIZE) {
4167 sources = MEM_malloc_arrayN<const void *>(size_t(count), __func__);
4168 }
4169
4170 /* If no weights are given, generate default ones to produce an average result. */
4171 float default_weights_buf[SOURCE_BUF_SIZE];
4172 float *default_weights = nullptr;
4173 if (weights == nullptr) {
4174 default_weights = (count > SOURCE_BUF_SIZE) ?
4175 MEM_malloc_arrayN<float>(size_t(count), __func__) :
4176 default_weights_buf;
4177 copy_vn_fl(default_weights, count, 1.0f / count);
4178 weights = default_weights;
4179 }
4180
4181 /* interpolates a layer at a time */
4182 for (int i = 0; i < data->totlayer; i++) {
4183 CustomDataLayer *layer = &data->layers[i];
4184 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer->type));
4185 if (typeInfo->interp) {
4186 for (int j = 0; j < count; j++) {
4187 sources[j] = POINTER_OFFSET(src_blocks[j], layer->offset);
4188 }
4190 data, sources, weights, count, POINTER_OFFSET(dst_block, layer->offset), i);
4191 }
4192 }
4193
4194 if (count > SOURCE_BUF_SIZE) {
4195 MEM_freeN(sources);
4196 }
4197 if (!ELEM(default_weights, nullptr, default_weights_buf)) {
4198 MEM_freeN(default_weights);
4199 }
4200}
4201
4203{
4204 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
4205
4206 return typeInfo->size;
4207}
4208
4210{
4211 return layerType_getName(type);
4212}
4213
4215{
4216 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
4217 return typeInfo->defaultname == nullptr;
4218}
4219
4221{
4222 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
4223
4224 return (typeInfo->free != nullptr);
4225}
4226
4228{
4229 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
4230
4231 /* Same test as for singleton above. */
4232 if (typeInfo->defaultname == nullptr) {
4233 return 1;
4234 }
4235 if (typeInfo->layers_max == nullptr) {
4236 return -1;
4237 }
4238
4239 return typeInfo->layers_max();
4240}
4241
4243 const StringRef name,
4244 const eCustomDataType type,
4245 const int index)
4246{
4247 /* see if there is a duplicate */
4248 for (int i = 0; i < data->totlayer; i++) {
4249 if (i != index) {
4250 CustomDataLayer *layer = &data->layers[i];
4251
4252 if (CD_TYPE_AS_MASK(type) & CD_MASK_PROP_ALL) {
4254 layer->name == name)
4255 {
4256 return true;
4257 }
4258 }
4259 else {
4260 if (i != index && layer->type == type && layer->name == name) {
4261 return true;
4262 }
4263 }
4264 }
4265 }
4266
4267 return false;
4268}
4269
4271{
4272 if (name.startswith(".")) {
4274 }
4275 for (const blender::StringRef prefix : {UV_PINNED_NAME "."}) {
4276 if (name.startswith(prefix)) {
4278 }
4279 }
4281}
4282
4284{
4285 CustomDataLayer *nlayer = &data->layers[index];
4286 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(nlayer->type));
4287
4288 if (!typeInfo->defaultname) {
4289 return;
4290 }
4291
4292 const int name_maxncpy = CustomData_name_maxncpy_calc(nlayer->name);
4293
4294 /* Set default name if none specified. Note we only call DATA_() when
4295 * needed to avoid overhead of locale lookups in the depsgraph. */
4296 if (nlayer->name[0] == '\0') {
4297 STRNCPY_UTF8(nlayer->name, DATA_(typeInfo->defaultname));
4298 }
4299
4300 const char *defname = ""; /* Dummy argument, never used as `name` is never zero length. */
4302 [&](const StringRef name) {
4303 return cd_layer_find_dupe(data, name, eCustomDataType(nlayer->type), index);
4304 },
4305 defname,
4306 '.',
4307 nlayer->name,
4308 name_maxncpy);
4309}
4310
4312 const eCustomDataType type,
4313 const StringRef name,
4314 char *outname)
4315{
4316 int index = -1;
4317
4318 /* if a layer name was given, try to find that layer */
4319 if (!name.is_empty()) {
4321 }
4322
4323 if (index == -1) {
4324 /* either no layer was specified, or the layer we want has been
4325 * deleted, so assign the active layer to name
4326 */
4328 BLI_strncpy_utf8(outname, data->layers[index].name, MAX_CUSTOMDATA_LAYER_NAME);
4329 }
4330 else {
4331 name.copy_utf8_truncated(outname, MAX_CUSTOMDATA_LAYER_NAME);
4332 }
4333}
4334
4336{
4337 const LayerTypeInfo *typeInfo;
4338 CustomDataLayer *layer = &data->layers[index];
4339 bool keeplayer = true;
4340
4341 if (layer->type >= CD_NUMTYPES) {
4342 keeplayer = false; /* unknown layer type from future version */
4343 }
4344 else {
4345 typeInfo = layerType_getInfo(eCustomDataType(layer->type));
4346
4347 if (!typeInfo->defaultname && (index > 0) && data->layers[index - 1].type == layer->type) {
4348 keeplayer = false; /* multiple layers of which we only support one */
4349 }
4350 /* This is a preemptive fix for cases that should not happen
4351 * (layers that should not be written in .blend files),
4352 * but can happen due to bugs (see e.g. #62318).
4353 * Also for forward compatibility, in future,
4354 * we may put into `.blend` file some currently un-written data types,
4355 * this should cover that case as well.
4356 * Better to be safe here, and fix issue on the fly rather than crash... */
4357 /* 0 structnum is used in writing code to tag layer types that should not be written. */
4358 else if (typeInfo->structnum == 0 &&
4359 /* XXX Not sure why those three are exception, maybe that should be fixed? */
4360 !ELEM(layer->type,
4361 CD_PAINT_MASK,
4362 CD_FACEMAP,
4363 CD_MTEXPOLY,
4364 CD_SCULPT_FACE_SETS,
4365 CD_CREASE))
4366 {
4367 keeplayer = false;
4368 CLOG_WARN(&LOG, ".blend file read: removing a data layer that should not have been written");
4369 }
4370 }
4371
4372 if (!keeplayer) {
4373 for (int i = index + 1; i < data->totlayer; i++) {
4374 data->layers[i - 1] = data->layers[i];
4375 }
4376 data->totlayer--;
4377 }
4378
4379 return keeplayer;
4380}
4381
4383{
4384 BLI_assert(layer);
4385 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer->type));
4386 BLI_assert(typeInfo);
4387
4388 if (layer->data || count == 0) {
4389 return false;
4390 }
4391
4392 switch (layer->type) {
4393 /* When more instances of corrupt files are found, add them here. */
4394 case CD_PROP_BOOL: /* See #84935. */
4395 case CD_MLOOPUV: /* See #90620. */
4396 case CD_PROP_FLOAT2: /* See #90620. */
4397 layer->data = MEM_calloc_arrayN(
4398 count, typeInfo->size, layerType_getName(eCustomDataType(layer->type)));
4399 BLI_assert(layer->data);
4400 if (typeInfo->set_default_value) {
4401 typeInfo->set_default_value(layer->data, count);
4402 }
4403 return true;
4404 break;
4405
4406 case CD_MTEXPOLY:
4407 /* TODO: Investigate multiple test failures on cycles, e.g. cycles_shadow_catcher_cpu. */
4408 break;
4409
4410 default:
4411 /* Log an error so we can collect instances of bad files. */
4412 CLOG_WARN(&LOG, "CustomDataLayer->data is null for type %d.", layer->type);
4413 break;
4414 }
4415 return false;
4416}
4417
4418bool CustomData_layer_validate(CustomDataLayer *layer, const uint totitems, const bool do_fixes)
4419{
4420 BLI_assert(layer);
4421 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer->type));
4422 BLI_assert(typeInfo);
4423
4424 if (do_fixes) {
4425 CustomData_layer_ensure_data_exists(layer, totitems);
4426 }
4427
4428 BLI_assert((totitems == 0) || layer->data);
4429
4430 if (typeInfo->validate != nullptr) {
4431 return typeInfo->validate(layer->data, totitems, do_fixes);
4432 }
4433
4434 return false;
4435}
4436
4438
4439/* -------------------------------------------------------------------- */
4442
4443static void customdata_external_filename(char filepath[FILE_MAX],
4444 ID *id,
4446{
4447 BLI_strncpy(filepath, external->filepath, FILE_MAX);
4449}
4450
4451void CustomData_external_reload(CustomData *data, ID * /*id*/, eCustomDataMask mask, int totelem)
4452{
4453 for (int i = 0; i < data->totlayer; i++) {
4454 CustomDataLayer *layer = &data->layers[i];
4455 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer->type));
4456
4457 if (!(mask & CD_TYPE_AS_MASK(eCustomDataType(layer->type)))) {
4458 /* pass */
4459 }
4460 else if ((layer->flag & CD_FLAG_EXTERNAL) && (layer->flag & CD_FLAG_IN_MEMORY)) {
4461 if (typeInfo->free) {
4462 typeInfo->free(layer->data, totelem);
4463 }
4464 layer->flag &= ~CD_FLAG_IN_MEMORY;
4465 }
4466 }
4467}
4468
4469void CustomData_external_read(CustomData *data, ID *id, eCustomDataMask mask, const int totelem)
4470{
4471 CustomDataExternal *external = data->external;
4472 CustomDataLayer *layer;
4473 char filepath[FILE_MAX];
4474 int update = 0;
4475
4476 if (!external) {
4477 return;
4478 }
4479
4480 for (int i = 0; i < data->totlayer; i++) {
4481 layer = &data->layers[i];
4482 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer->type));
4483
4484 if (!(mask & CD_TYPE_AS_MASK(eCustomDataType(layer->type)))) {
4485 /* pass */
4486 }
4487 else if (layer->flag & CD_FLAG_IN_MEMORY) {
4488 /* pass */
4489 }
4490 else if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->read) {
4491 update = 1;
4492 }
4493 }
4494
4495 if (!update) {
4496 return;
4497 }
4498
4500
4502 if (!cdf_read_open(cdf, filepath)) {
4503 cdf_free(cdf);
4504 CLOG_ERROR(&LOG,
4505 "Failed to read %s layer from %s.",
4507 filepath);
4508 return;
4509 }
4510
4511 for (int i = 0; i < data->totlayer; i++) {
4512 layer = &data->layers[i];
4513 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer->type));
4514
4515 if (!(mask & CD_TYPE_AS_MASK(eCustomDataType(layer->type)))) {
4516 /* pass */
4517 }
4518 else if (layer->flag & CD_FLAG_IN_MEMORY) {
4519 /* pass */
4520 }
4521 else if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->read) {
4522 const CDataFileLayer *blay = cdf_layer_find(cdf, layer->type, layer->name);
4523
4524 if (blay) {
4525 if (cdf_read_layer(cdf, blay)) {
4526 if (typeInfo->read(cdf, layer->data, totelem)) {
4527 /* pass */
4528 }
4529 else {
4530 break;
4531 }
4532 layer->flag |= CD_FLAG_IN_MEMORY;
4533 }
4534 else {
4535 break;
4536 }
4537 }
4538 }
4539 }
4540
4541 cdf_read_close(cdf);
4542 cdf_free(cdf);
4543}
4544
4546 CustomData *data, ID *id, eCustomDataMask mask, const int totelem, const int free)
4547{
4548 CustomDataExternal *external = data->external;
4549 int update = 0;
4550 char filepath[FILE_MAX];
4551
4552 if (!external) {
4553 return;
4554 }
4555
4556 /* test if there is anything to write */
4557 for (int i = 0; i < data->totlayer; i++) {
4558 CustomDataLayer *layer = &data->layers[i];
4559 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer->type));
4560
4561 if (!(mask & CD_TYPE_AS_MASK(eCustomDataType(layer->type)))) {
4562 /* pass */
4563 }
4564 else if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) {
4565 update = 1;
4566 }
4567 }
4568
4569 if (!update) {
4570 return;
4571 }
4572
4573 /* make sure data is read before we try to write */
4574 CustomData_external_read(data, id, mask, totelem);
4576
4578
4579 for (int i = 0; i < data->totlayer; i++) {
4580 CustomDataLayer *layer = &data->layers[i];
4581 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer->type));
4582
4583 if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->filesize) {
4584 if (layer->flag & CD_FLAG_IN_MEMORY) {
4586 cdf, layer->type, layer->name, typeInfo->filesize(cdf, layer->data, totelem));
4587 }
4588 else {
4589 cdf_free(cdf);
4590 return; /* read failed for a layer! */
4591 }
4592 }
4593 }
4594
4595 if (!cdf_write_open(cdf, filepath)) {
4596 CLOG_ERROR(&LOG, "Failed to open %s for writing.", filepath);
4597 cdf_free(cdf);
4598 return;
4599 }
4600
4601 int i;
4602 for (i = 0; i < data->totlayer; i++) {
4603 CustomDataLayer *layer = &data->layers[i];
4604 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer->type));
4605
4606 if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) {
4607 CDataFileLayer *blay = cdf_layer_find(cdf, layer->type, layer->name);
4608
4609 if (cdf_write_layer(cdf, blay)) {
4610 if (typeInfo->write(cdf, layer->data, totelem)) {
4611 /* pass */
4612 }
4613 else {
4614 break;
4615 }
4616 }
4617 else {
4618 break;
4619 }
4620 }
4621 }
4622
4623 if (i != data->totlayer) {
4624 CLOG_ERROR(&LOG, "Failed to write data to %s.", filepath);
4625 cdf_write_close(cdf);
4626 cdf_free(cdf);
4627 return;
4628 }
4629
4630 for (i = 0; i < data->totlayer; i++) {
4631 CustomDataLayer *layer = &data->layers[i];
4632 const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer->type));
4633
4634 if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) {
4635 if (free) {
4636 if (typeInfo->free) {
4637 typeInfo->free(layer->data, totelem);
4638 }
4639 layer->flag &= ~CD_FLAG_IN_MEMORY;
4640 }
4641 }
4642 }
4643
4644 cdf_write_close(cdf);
4645 cdf_free(cdf);
4646}
4647
4649 ID * /*id*/,
4650 const eCustomDataType type,
4651 const int /*totelem*/,
4652 const char *filepath)
4653{
4654 CustomDataExternal *external = data->external;
4655
4656 int layer_index = CustomData_get_active_layer_index(data, type);
4657 if (layer_index == -1) {
4658 return;
4659 }
4660
4661 CustomDataLayer *layer = &data->layers[layer_index];
4662
4663 if (layer->flag & CD_FLAG_EXTERNAL) {
4664 return;
4665 }
4666
4667 if (!external) {
4669 data->external = external;
4670 }
4671 STRNCPY(external->filepath, filepath);
4672
4674}
4675
4677 ID *id,
4678 const eCustomDataType type,
4679 const int totelem)
4680{
4681 CustomDataExternal *external = data->external;
4682
4683 int layer_index = CustomData_get_active_layer_index(data, type);
4684 if (layer_index == -1) {
4685 return;
4686 }
4687
4688 CustomDataLayer *layer = &data->layers[layer_index];
4689
4690 if (!external) {
4691 return;
4692 }
4693
4694 if (layer->flag & CD_FLAG_EXTERNAL) {
4695 if (!(layer->flag & CD_FLAG_IN_MEMORY)) {
4697 }
4698
4699 layer->flag &= ~CD_FLAG_EXTERNAL;
4700 }
4701}
4702
4704{
4705 int layer_index = CustomData_get_active_layer_index(data, type);
4706 if (layer_index == -1) {
4707 return false;
4708 }
4709
4710 CustomDataLayer *layer = &data->layers[layer_index];
4711 return (layer->flag & CD_FLAG_EXTERNAL) != 0;
4712}
4713
4715
4716/* -------------------------------------------------------------------- */
4719
4720static void copy_bit_flag(void *dst, const void *src, const size_t data_size, const uint64_t flag)
4721{
4722#define COPY_BIT_FLAG(_type, _dst, _src, _f) \
4723 { \
4724 const _type _val = *((_type *)(_src)) & (_type)(_f); \
4725 *((_type *)(_dst)) &= ~(_type)(_f); \
4726 *((_type *)(_dst)) |= _val; \
4727 } \
4728 (void)0
4729
4730 switch (data_size) {
4731 case 1:
4732 COPY_BIT_FLAG(uint8_t, dst, src, flag);
4733 break;
4734 case 2:
4735 COPY_BIT_FLAG(uint16_t, dst, src, flag);
4736 break;
4737 case 4:
4738 COPY_BIT_FLAG(uint32_t, dst, src, flag);
4739 break;
4740 case 8:
4741 COPY_BIT_FLAG(uint64_t, dst, src, flag);
4742 break;
4743 default:
4744 // CLOG_ERROR(&LOG, "Unknown flags-container size (%zu)", datasize);
4745 break;
4746 }
4747
4748#undef COPY_BIT_FLAG
4749}
4750
4751static bool check_bit_flag(const void *data, const size_t data_size, const uint64_t flag)
4752{
4753 switch (data_size) {
4754 case 1:
4755 return ((*((uint8_t *)data) & uint8_t(flag)) != 0);
4756 case 2:
4757 return ((*((uint16_t *)data) & uint16_t(flag)) != 0);
4758 case 4:
4759 return ((*((uint32_t *)data) & uint32_t(flag)) != 0);
4760 case 8:
4761 return ((*((uint64_t *)data) & uint64_t(flag)) != 0);
4762 default:
4763 // CLOG_ERROR(&LOG, "Unknown flags-container size (%zu)", datasize);
4764 return false;
4765 }
4766}
4767
4769 void *data_dst,
4770 const void **sources,
4771 const float *weights,
4772 const int count,
4773 const float mix_factor)
4774{
4775 BLI_assert(weights != nullptr);
4776 BLI_assert(count > 0);
4777
4778 /* Fake interpolation, we actually copy highest weighted source to dest.
4779 * Note we also handle bitflags here,
4780 * in which case we rather choose to transfer value of elements totaling
4781 * more than 0.5 of weight. */
4782 int best_src_idx = 0;
4783
4784 const int data_type = laymap->data_type;
4785 const int mix_mode = laymap->mix_mode;
4786
4787 size_t data_size;
4788 const uint64_t data_flag = laymap->data_flag;
4789
4790 cd_interp interp_cd = nullptr;
4791 cd_copy copy_cd = nullptr;
4792
4793 if (!sources) {
4794 /* Not supported here, abort. */
4795 return;
4796 }
4797
4798 if (int(data_type) & CD_FAKE) {
4799 data_size = laymap->data_size;
4800 }
4801 else {
4802 const LayerTypeInfo *type_info = layerType_getInfo(eCustomDataType(data_type));
4803
4804 data_size = size_t(type_info->size);
4805 interp_cd = type_info->interp;
4806 copy_cd = type_info->copy;
4807 }
4808
4809 void *tmp_dst = MEM_mallocN(data_size, __func__);
4810
4811 if (count > 1 && !interp_cd) {
4812 if (data_flag) {
4813 /* Boolean case, we can 'interpolate' in two groups,
4814 * and choose value from highest weighted group. */
4815 float tot_weight_true = 0.0f;
4816 int item_true_idx = -1, item_false_idx = -1;
4817
4818 for (int i = 0; i < count; i++) {
4819 if (check_bit_flag(sources[i], data_size, data_flag)) {
4820 tot_weight_true += weights[i];
4821 item_true_idx = i;
4822 }
4823 else {
4824 item_false_idx = i;
4825 }
4826 }
4827 best_src_idx = (tot_weight_true >= 0.5f) ? item_true_idx : item_false_idx;
4828 }
4829 else {
4830 /* We just choose highest weighted source. */
4831 float max_weight = 0.0f;
4832
4833 for (int i = 0; i < count; i++) {
4834 if (weights[i] > max_weight) {
4835 max_weight = weights[i];
4836 best_src_idx = i;
4837 }
4838 }
4839 }
4840 }
4841
4842 BLI_assert(best_src_idx >= 0);
4843
4844 if (interp_cd) {
4845 interp_cd(sources, weights, count, tmp_dst);
4846 }
4847 else if (data_flag) {
4848 copy_bit_flag(tmp_dst, sources[best_src_idx], data_size, data_flag);
4849 }
4850 /* No interpolation, just copy highest weight source element's data. */
4851 else if (copy_cd) {
4852 copy_cd(sources[best_src_idx], tmp_dst, 1);
4853 }
4854 else {
4855 memcpy(tmp_dst, sources[best_src_idx], data_size);
4856 }
4857
4858 if (data_flag) {
4859 /* Bool flags, only copy if dest data is set (resp. unset) -
4860 * only 'advanced' modes we can support here! */
4861 if (mix_factor >= 0.5f && ((mix_mode == CDT_MIX_TRANSFER) ||
4862 (mix_mode == CDT_MIX_REPLACE_ABOVE_THRESHOLD &&
4863 check_bit_flag(data_dst, data_size, data_flag)) ||
4864 (mix_mode == CDT_MIX_REPLACE_BELOW_THRESHOLD &&
4865 !check_bit_flag(data_dst, data_size, data_flag))))
4866 {
4867 copy_bit_flag(data_dst, tmp_dst, data_size, data_flag);
4868 }
4869 }
4870 else if (!(int(data_type) & CD_FAKE)) {
4871 CustomData_data_mix_value(eCustomDataType(data_type), tmp_dst, data_dst, mix_mode, mix_factor);
4872 }
4873 /* Else we can do nothing by default, needs custom interp func!
4874 * Note this is here only for sake of consistency, not expected to be used much actually? */
4875 else {
4876 if (mix_factor >= 0.5f) {
4877 memcpy(data_dst, tmp_dst, data_size);
4878 }
4879 }
4880
4881 MEM_freeN(tmp_dst);
4882}
4883
4885 void *data_dst,
4886 const void **sources,
4887 const float *weights,
4888 const int count,
4889 const float mix_factor)
4890{
4891 BLI_assert(weights != nullptr);
4892 BLI_assert(count > 0);
4893
4894 const eCustomDataType data_type = eCustomDataType(laymap->data_type);
4895 BLI_assert(data_type == CD_NORMAL);
4896 const int mix_mode = laymap->mix_mode;
4897
4898 SpaceTransform *space_transform = static_cast<SpaceTransform *>(laymap->interp_data);
4899
4900 const LayerTypeInfo *type_info = layerType_getInfo(data_type);
4901 cd_interp interp_cd = type_info->interp;
4902
4903 float tmp_dst[3];
4904
4905 if (!sources) {
4906 /* Not supported here, abort. */
4907 return;
4908 }
4909
4910 interp_cd(sources, weights, count, tmp_dst);
4911 if (space_transform) {
4912 /* tmp_dst is in source space so far, bring it back in destination space. */
4913 BLI_space_transform_invert_normal(space_transform, tmp_dst);
4914 }
4915
4916 CustomData_data_mix_value(data_type, tmp_dst, data_dst, mix_mode, mix_factor);
4917}
4918
4920 const CustomDataTransferLayerMap *laymap)
4921{
4922 MeshPairRemapItem *mapit = me_remap->items;
4923 const int totelem = me_remap->items_num;
4924
4925 const int data_type = laymap->data_type;
4926 const void *data_src = laymap->data_src;
4927 void *data_dst = laymap->data_dst;
4928
4929 size_t data_step;
4930 size_t data_size;
4931 size_t data_offset;
4932
4934
4935 size_t tmp_buff_size = 32;
4936 const void **tmp_data_src = nullptr;
4937
4938 /* NOTE: null data_src may happen and be valid (see vgroups...). */
4939 if (!data_dst) {
4940 return;
4941 }
4942
4943 if (data_src) {
4944 tmp_data_src = MEM_malloc_arrayN<const void *>(tmp_buff_size, __func__);
4945 }
4946
4947 if (int(data_type) & CD_FAKE) {
4948 data_step = laymap->elem_size;
4949 data_size = laymap->data_size;
4950 data_offset = laymap->data_offset;
4951 }
4952 else {
4953 const LayerTypeInfo *type_info = layerType_getInfo(eCustomDataType(data_type));
4954
4955 /* NOTE: we can use 'fake' CDLayers for crease :/. */
4956 data_size = size_t(type_info->size);
4957 data_step = laymap->elem_size ? laymap->elem_size : data_size;
4958 data_offset = laymap->data_offset;
4959 }
4960
4962
4963 for (int i = 0; i < totelem; i++, data_dst = POINTER_OFFSET(data_dst, data_step), mapit++) {
4964 const int sources_num = mapit->sources_num;
4965 const float mix_factor = laymap->mix_factor *
4966 (laymap->mix_weights ? laymap->mix_weights[i] : 1.0f);
4967
4968 if (!sources_num) {
4969 /* No sources for this element, skip it. */
4970 continue;
4971 }
4972
4973 if (tmp_data_src) {
4974 if (UNLIKELY(sources_num > tmp_buff_size)) {
4975 tmp_buff_size = size_t(sources_num);
4976 tmp_data_src = (const void **)MEM_reallocN((void *)tmp_data_src,
4977 sizeof(*tmp_data_src) * tmp_buff_size);
4978 }
4979
4980 for (int j = 0; j < sources_num; j++) {
4981 const size_t src_idx = size_t(mapit->indices_src[j]);
4982 tmp_data_src[j] = POINTER_OFFSET(data_src, (data_step * src_idx) + data_offset);
4983 }
4984 }
4985
4986 interp(laymap,
4987 POINTER_OFFSET(data_dst, data_offset),
4988 tmp_data_src,
4989 mapit->weights_src,
4990 sources_num,
4991 mix_factor);
4992 }
4993
4994 MEM_SAFE_FREE(tmp_data_src);
4995}
4996
4998
4999/* -------------------------------------------------------------------- */
5002
5004 const char **r_struct_name,
5005 int *r_struct_num)
5006{
5007 const LayerTypeInfo *typeInfo = layerType_getInfo(type);
5008
5009 *r_struct_name = typeInfo->structname;
5010 *r_struct_num = typeInfo->structnum;
5011}
5012
5014 const blender::bke::AttrDomain domain,
5015 const int domain_size,
5016 Vector<CustomDataLayer, 16> &layers_to_write,
5018{
5019 using namespace blender::bke;
5020 for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
5021 if (layer.flag & CD_FLAG_NOCOPY) {
5022 continue;
5023 }
5024 const StringRef name = layer.name;
5026 continue;
5027 }
5028
5029 /* We always write the data in the new #AttributeStorage format, even though it's not yet used
5030 * at runtime. This block should be removed when the new format is used at runtime. */
5031 const eCustomDataType data_type = eCustomDataType(layer.type);
5032 if (const std::optional<AttrType> type = custom_data_type_to_attr_type(data_type)) {
5033 ::Attribute attribute_dna{};
5034 attribute_dna.name = layer.name;
5035 attribute_dna.data_type = int16_t(*type);
5036 attribute_dna.domain = int8_t(domain);
5037 attribute_dna.storage_type = int8_t(AttrStorageType::Array);
5038
5039 /* Do not increase the user count; #::AttributeArray does not act as an owner of the
5040 * attribute data, since it's only used temporarily for writing files. Changing the user
5041 * count would be okay too, but it's unnecessary because none of this data should be
5042 * modified while it's being written anyway. */
5043 auto &array_dna = write_data.scope.construct<::AttributeArray>();
5044 array_dna.data = layer.data;
5045 array_dna.sharing_info = layer.sharing_info;
5046 array_dna.size = domain_size;
5047 attribute_dna.data = &array_dna;
5048
5049 write_data.attributes.append(attribute_dna);
5050 continue;
5051 }
5052
5053 layers_to_write.append(layer);
5054 }
5055 data.totlayer = layers_to_write.size();
5056 data.maxlayer = data.totlayer;
5057 std::fill_n(data.typemap, CD_NUMTYPES, 0);
5058 data.totsize = 0;
5059 if (layers_to_write.is_empty()) {
5060 data.layers = nullptr;
5061 }
5062
5063 /* NOTE: `data->layers` may be null, this happens when adding
5064 * a legacy #MPoly struct to a mesh with no other face attributes.
5065 * This leaves us with no unique ID for DNA to identify the old
5066 * data with when loading the file. */
5067 if (!data.layers && layers_to_write.size() > 0) {
5068 /* We just need an address that's unique. */
5069 data.layers = reinterpret_cast<CustomDataLayer *>(&data.layers);
5070 }
5071}
5072
5073static void write_mdisps(BlendWriter *writer,
5074 const int count,
5075 const MDisps *mdlist,
5076 const int external)
5077{
5078 if (mdlist) {
5079 BLO_write_struct_array(writer, MDisps, count, mdlist);
5080 for (int i = 0; i < count; i++) {
5081 const MDisps *md = &mdlist[i];
5082 if (md->disps) {
5083 if (!external) {
5084 BLO_write_float3_array(writer, md->totdisp, &md->disps[0][0]);
5085 }
5086 }
5087
5088 if (md->hidden) {
5089 BLO_write_int8_array(writer,
5090 BLI_BITMAP_SIZE(md->totdisp) * sizeof(BLI_bitmap),
5091 reinterpret_cast<const int8_t *>(md->hidden));
5092 }
5093 }
5094 }
5095}
5096
5098 int count,
5099 const GridPaintMask *grid_paint_mask)
5100{
5101 if (grid_paint_mask) {
5102 BLO_write_struct_array(writer, GridPaintMask, count, grid_paint_mask);
5103 for (int i = 0; i < count; i++) {
5104 const GridPaintMask *gpm = &grid_paint_mask[i];
5105 if (gpm->data) {
5106 const uint32_t gridsize = uint32_t(CCG_grid_size(gpm->level));
5107 BLO_write_float_array(writer, gridsize * gridsize, gpm->data);
5108 }
5109 }
5110 }
5111}
5112
5114 const CustomDataLayer &layer,
5115 const int count)
5116{
5117 switch (layer.type) {
5118 case CD_MDEFORMVERT:
5119 BKE_defvert_blend_write(writer, count, static_cast<const MDeformVert *>(layer.data));
5120 break;
5121 case CD_MDISPS:
5123 writer, count, static_cast<const MDisps *>(layer.data), layer.flag & CD_FLAG_EXTERNAL);
5124 break;
5125 case CD_PAINT_MASK:
5126 BLO_write_float_array(writer, count, static_cast<const float *>(layer.data));
5127 break;
5128 case CD_GRID_PAINT_MASK:
5129 write_grid_paint_mask(writer, count, static_cast<const GridPaintMask *>(layer.data));
5130 break;
5131 case CD_PROP_BOOL:
5132 BLI_STATIC_ASSERT(sizeof(bool) == sizeof(uint8_t),
5133 "bool type is expected to have the same size as uint8_t")
5134 BLO_write_uint8_array(writer, count, static_cast<const uint8_t *>(layer.data));
5135 break;
5136 default: {
5137 const char *structname;
5138 int structnum;
5139 get_type_file_write_info(eCustomDataType(layer.type), &structname, &structnum);
5140 if (structnum > 0) {
5141 int datasize = structnum * count;
5142 BLO_write_struct_array_by_name(writer, structname, datasize, layer.data);
5143 }
5144 else if (!BLO_write_is_undo(writer)) { /* Do not warn on undo. */
5145 printf("%s error: layer '%s':%d - can't be written to file\n",
5146 __func__,
5147 structname,
5148 layer.type);
5149 }
5150 }
5151 }
5152}
5153
5156 Span<CustomDataLayer> layers_to_write,
5157 int count,
5158 eCustomDataMask cddata_mask,
5159 ID *id)
5160{
5161 /* write external customdata (not for undo) */
5162 if (data->external && !BLO_write_is_undo(writer)) {
5163 CustomData_external_write(data, id, cddata_mask, count, 0);
5164 }
5165
5166 for (const CustomDataLayer &layer : layers_to_write) {
5167 const size_t size_in_bytes = CustomData_sizeof(eCustomDataType(layer.type)) * count;
5168 BLO_write_shared(writer, layer.data, size_in_bytes, layer.sharing_info, [&]() {
5169 blend_write_layer_data(writer, layer, count);
5170 });
5171 }
5172
5174 writer, CustomDataLayer, data->totlayer, data->layers, layers_to_write.data());
5175
5176 if (data->external) {
5177 BLO_write_struct(writer, CustomDataExternal, data->external);
5178 }
5179}
5180
5182 const int count,
5183 MDisps *mdisps,
5184 const int external)
5185{
5186 if (mdisps) {
5187 for (int i = 0; i < count; i++) {
5188 MDisps &md = mdisps[i];
5189
5190 BLO_read_float3_array(reader, md.totdisp, reinterpret_cast<float **>(&md.disps));
5191 BLO_read_int8_array(reader,
5192 BLI_BITMAP_SIZE(md.totdisp) * sizeof(BLI_bitmap),
5193 reinterpret_cast<int8_t **>(&md.hidden));
5194
5195 if (md.totdisp && !md.level) {
5196 /* this calculation is only correct for loop mdisps;
5197 * if loading pre-BMesh face mdisps this will be
5198 * overwritten with the correct value in
5199 * #bm_corners_to_loops() */
5200 float gridsize = sqrtf(md.totdisp);
5201 md.level = int(logf(gridsize - 1.0f) / float(M_LN2)) + 1;
5202 }
5203
5204 if (!external && !md.disps) {
5205 md.totdisp = 0;
5206 }
5207 }
5208 }
5209}
5210
5212 int count,
5213 GridPaintMask *grid_paint_mask)
5214{
5215 if (grid_paint_mask) {
5216 for (int i = 0; i < count; i++) {
5217 GridPaintMask *gpm = &grid_paint_mask[i];
5218 if (gpm->data) {
5219 const int gridsize = CCG_grid_size(gpm->level);
5220 BLO_read_float_array(reader, gridsize * gridsize, &gpm->data);
5221 }
5222 }
5223 }
5224}
5225
5226static void blend_read_layer_data(BlendDataReader *reader, CustomDataLayer &layer, const int count)
5227{
5228 switch (layer.type) {
5229 case CD_MDEFORMVERT:
5230 BLO_read_struct_array(reader, MDeformVert, count, &layer.data);
5231 BKE_defvert_blend_read(reader, count, static_cast<MDeformVert *>(layer.data));
5232 break;
5233 case CD_MDISPS:
5234 BLO_read_struct_array(reader, MDisps, count, &layer.data);
5236 reader, count, static_cast<MDisps *>(layer.data), layer.flag & CD_FLAG_EXTERNAL);
5237 break;
5238 case CD_PAINT_MASK:
5239 BLO_read_float_array(reader, count, reinterpret_cast<float **>(&layer.data));
5240 break;
5241 case CD_GRID_PAINT_MASK:
5243 blend_read_paint_mask(reader, count, static_cast<GridPaintMask *>(layer.data));
5244 break;
5245 case CD_PROP_BOOL:
5246 BLI_STATIC_ASSERT(sizeof(bool) == sizeof(uint8_t),
5247 "bool type is expected to have the same size as uint8_t")
5248 BLO_read_uint8_array(reader, count, reinterpret_cast<uint8_t **>(&layer.data));
5249 break;
5250 default: {
5251 const char *structname;
5252 int structnum;
5253 get_type_file_write_info(eCustomDataType(layer.type), &structname, &structnum);
5254 if (structnum > 0) {
5255 const int data_num = structnum * count;
5256 layer.data = BLO_read_struct_by_name_array(reader, structname, data_num, layer.data);
5257 }
5258 else {
5259 /* Can happen with deprecated types of customdata. */
5260 const size_t elem_size = CustomData_sizeof(eCustomDataType(layer.type));
5261 BLO_read_struct_array(reader, char, elem_size *count, &layer.data);
5262 }
5263 }
5264 }
5265
5267 /* Under normal operations, this shouldn't happen, but...
5268 * For a CD_PROP_BOOL example, see #84935.
5269 * For a CD_MLOOPUV example, see #90620. */
5270 CLOG_WARN(&LOG,
5271 "Allocated custom data layer that was not saved correctly for layer.type = %d.",
5272 layer.type);
5273 }
5274}
5275
5277{
5278 BLO_read_struct_array(reader, CustomDataLayer, data->totlayer, &data->layers);
5279
5280 /* Annoying workaround for bug #31079 loading legacy files with
5281 * no polygons _but_ have stale custom-data. */
5282 if (UNLIKELY(count == 0 && data->layers == nullptr && data->totlayer != 0)) {
5284 return;
5285 }
5286 /* There was a short time (Blender 500 sub 33) where the custom data struct was saved in an
5287 * invalid state (see @11d2f48882). This check is unfortunate, but avoids crashing when trying to
5288 * load the invalid data (see e.g. #143720). */
5289 if (UNLIKELY(data->layers == nullptr && data->totlayer != 0)) {
5291 return;
5292 }
5293
5294 BLO_read_struct(reader, CustomDataExternal, &data->external);
5295
5296 int i = 0;
5297 while (i < data->totlayer) {
5298 CustomDataLayer *layer = &data->layers[i];
5299
5300 if (layer->flag & CD_FLAG_EXTERNAL) {
5301 layer->flag &= ~CD_FLAG_IN_MEMORY;
5302 }
5303 layer->sharing_info = nullptr;
5304
5307 reader, &layer->data, [&]() -> const ImplicitSharingInfo * {
5308 blend_read_layer_data(reader, *layer, count);
5309 if (layer->data == nullptr) {
5310 return nullptr;
5311 }
5313 eCustomDataType(layer->type), layer->data, count);
5314 });
5315 i++;
5316 }
5317 }
5318
5319 /* Ensure allocated size is set to the size of the read array. While this should always be the
5320 * case (see #CustomData_blend_write_prepare), there can be some corruption in rare cases (e.g.
5321 * files saved between ff3d535bc2a63092 and 945f32e66d6ada2a). */
5322 data->maxlayer = data->totlayer;
5323
5325}
5326
5328
5329/* -------------------------------------------------------------------- */
5332
5333#ifndef NDEBUG
5334
5335void CustomData_debug_info_from_layers(const CustomData *data, const char *indent, DynStr *dynstr)
5336{
5337 for (eCustomDataType type = eCustomDataType(0); type < CD_NUMTYPES;
5338 type = eCustomDataType(type + 1))
5339 {
5340 if (CustomData_has_layer(data, type)) {
5341 /* NOTE: doesn't account for multiple layers. */
5342 const char *name = CustomData_layertype_name(type);
5343 const int size = CustomData_sizeof(type);
5344 const void *pt = CustomData_get_layer(data, type);
5345 const int pt_size = pt ? int(MEM_allocN_len(pt) / size) : 0;
5346 const char *structname;
5347 int structnum;
5348 get_type_file_write_info(type, &structname, &structnum);
5350 dynstr,
5351 "%sdict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
5352 indent,
5353 name,
5354 structname,
5355 type,
5356 pt,
5357 size,
5358 pt_size);
5359 }
5360 }
5361}
5362
5363#endif /* !NDEBUG */
5364
5366
5367namespace blender::bke {
5368
5369/* -------------------------------------------------------------------- */
5372
5373std::optional<VolumeGridType> custom_data_type_to_volume_grid_type(const eCustomDataType type)
5374{
5375 switch (type) {
5376 case CD_PROP_FLOAT:
5377 return VOLUME_GRID_FLOAT;
5378 case CD_PROP_FLOAT3:
5380 case CD_PROP_INT32:
5381 return VOLUME_GRID_INT;
5382 case CD_PROP_BOOL:
5383 return VOLUME_GRID_BOOLEAN;
5384 default:
5385 return std::nullopt;
5386 }
5387}
5388
5389std::optional<eCustomDataType> volume_grid_type_to_custom_data_type(const VolumeGridType type)
5390{
5391 switch (type) {
5392 case VOLUME_GRID_FLOAT:
5393 return CD_PROP_FLOAT;
5395 return CD_PROP_FLOAT3;
5396 case VOLUME_GRID_INT:
5397 return CD_PROP_INT32;
5399 return CD_PROP_BOOL;
5400 default:
5401 return std::nullopt;
5402 }
5403}
5404
5406
5407} // namespace blender::bke
5408
5410{
5411 return LAYERTYPEINFO[layer->type].size;
5412}
5413
5415 const int totelem,
5416 blender::MemoryCounter &memory)
5417{
5418 for (const CustomDataLayer &layer : Span{data.layers, data.totlayer}) {
5419 memory.add_shared(layer.sharing_info, [&](blender::MemoryCounter &shared_memory) {
5420 /* Not quite correct for all types, but this is only a rough approximation anyway. */
5421 const int64_t elem_size = CustomData_get_elem_size(&layer);
5422 shared_memory.add(totelem * elem_size);
5423 });
5424 }
5425}
int CCG_grid_size(const int level)
Definition BKE_ccg.hh:104
CustomData interface, see also DNA_customdata_types.h.
const CustomData_MeshMasks CD_MASK_EVERYTHING
void(*)(const void **sources, const float *weights, int count, void *dest) cd_interp
const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX
eCDAllocType
@ CD_SET_DEFAULT
@ CD_CONSTRUCT
eCustomDataMask CD_TYPE_AS_MASK(eCustomDataType type)
void(*)(void *data, int count) cd_set_default_value
void(*)(const CustomDataTransferLayerMap *laymap, void *dest, const void **sources, const float *weights, int count, float mix_factor) cd_datatransfer_interp
const CustomData_MeshMasks CD_MASK_BAREMESH
void(*)(void *data, int count) cd_free
const CustomData_MeshMasks CD_MASK_BMESH
#define ORIGINDEX_NONE
void(*)(const void *source, void *dest, int count) cd_copy
bool(*)(void *item, uint totitems, bool do_fixes) cd_validate
#define UV_PINNED_NAME
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
const CustomData_MeshMasks CD_MASK_DERIVEDMESH
const CustomData_MeshMasks CD_MASK_MESH
CDataFile * cdf_create(int type)
bool cdf_read_layer(CDataFile *cdf, const CDataFileLayer *blay)
bool cdf_write_open(CDataFile *cdf, const char *filepath)
bool cdf_read_data(CDataFile *cdf, unsigned int size, void *data)
bool cdf_write_data(CDataFile *cdf, unsigned int size, const void *data)
#define CDF_TYPE_MESH
CDataFileLayer * cdf_layer_find(CDataFile *cdf, int type, const char *name)
void cdf_read_close(CDataFile *cdf)
CDataFileLayer * cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t datasize)
void cdf_write_close(CDataFile *cdf)
void cdf_free(CDataFile *cdf)
bool cdf_write_layer(CDataFile *cdf, CDataFileLayer *blay)
bool cdf_read_open(CDataFile *cdf, const char *filepath)
support for deformation groups and hooks.
void BKE_defvert_blend_write(BlendWriter *writer, int count, const MDeformVert *dvlist)
Definition deform.cc:1602
void BKE_defvert_blend_read(BlendDataReader *reader, int count, MDeformVert *mdverts)
Definition deform.cc:1619
int multires_mdisp_corners(const MDisps *s)
Definition multires.cc:693
VolumeGridType
@ VOLUME_GRID_VECTOR_FLOAT
@ VOLUME_GRID_BOOLEAN
@ VOLUME_GRID_INT
@ VOLUME_GRID_FLOAT
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_STATIC_ASSERT(a, msg)
Definition BLI_assert.h:83
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define BLI_BITMAP_SIZE(_num)
Definition BLI_bitmap.h:32
unsigned int BLI_bitmap
Definition BLI_bitmap.h:13
A dynamically sized string ADT.
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format,...) ATTR_PRINTF_FORMAT(2
void BLI_kdtree_nd_ free(KDTree *tree)
MINLINE unsigned char round_fl_to_uchar_clamp(float a)
MINLINE void blend_color_add_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_sub_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_mul_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_mul_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_sub_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_add_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_mix_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4], float ft)
MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], const float src2[4], float t)
#define M_LN2
void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float no[3])
MINLINE void mul_v4_fl(float r[4], float f)
MINLINE void add_v4_v4(float r[4], const float a[4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v2_v2fl(float r[2], const float a[2], float f)
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
void copy_vn_fl(float *array_tar, int size, float val)
void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], float t)
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3_short(short r[3], const short a[3])
void minmax_v4v4_v4(float min[4], float max[4], const float vec[4])
MINLINE void mul_v3_v3v3(float r[3], const float v1[3], const float v2[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
void copy_vn_i(int *array_tar, int size, int val)
MINLINE void zero_v2(float r[2])
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void madd_v4_v4fl(float r[4], const float a[4], float f)
MINLINE void zero_v3(float r[3])
MINLINE void copy_v4_fl(float r[4], float f)
MINLINE float normalize_v3(float n[3])
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
@ BLI_MEMPOOL_NOP
void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
#define FILE_MAX
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define STRNCPY_UTF8(dst, src)
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 char uchar
unsigned int uint
#define INIT_MINMAX2(min, max)
#define UNLIKELY(x)
#define ELEM(...)
#define POINTER_OFFSET(v, ofs)
void BLO_write_float_array(BlendWriter *writer, int64_t num, const float *data_ptr)
void BLO_read_uint8_array(BlendDataReader *reader, int64_t array_size, uint8_t **ptr_p)
Definition readfile.cc:5776
void BLO_read_float3_array(BlendDataReader *reader, int64_t array_size, float **ptr_p)
Definition readfile.cc:5816
#define BLO_write_struct_array_at_address(writer, struct_name, array_size, address, data_ptr)
void BLO_write_struct_array_by_name(BlendWriter *writer, const char *struct_name, int64_t array_size, const void *data_ptr)
void BLO_read_float_array(BlendDataReader *reader, int64_t array_size, float **ptr_p)
Definition readfile.cc:5809
void BLO_write_uint8_array(BlendWriter *writer, int64_t num, const uint8_t *data_ptr)
#define BLO_write_struct(writer, struct_name, data_ptr)
void * BLO_read_struct_by_name_array(BlendDataReader *reader, const char *struct_name, int64_t items_num, const void *old_address)
Definition readfile.cc:5719
void BLO_write_float3_array(BlendWriter *writer, int64_t num, const float *data_ptr)
void BLO_write_int8_array(BlendWriter *writer, int64_t num, const int8_t *data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
void BLO_read_int8_array(BlendDataReader *reader, int64_t array_size, int8_t **ptr_p)
Definition readfile.cc:5782
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define BLO_read_struct(reader, struct_name, ptr_p)
bool BLO_write_is_undo(BlendWriter *writer)
void BLO_write_shared(BlendWriter *writer, const void *data, size_t approximate_size_in_bytes, const blender::ImplicitSharingInfo *sharing_info, blender::FunctionRef< void()> write_fn)
const blender::ImplicitSharingInfo * BLO_read_shared(BlendDataReader *reader, T **data_ptr, blender::FunctionRef< const blender::ImplicitSharingInfo *()> read_fn)
#define DATA_(msgid)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:188
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:189
ID and Library types, which are fundamental for SDNA.
#define ID_BLEND_PATH_FROM_GLOBAL(_id)
Definition DNA_ID.h:688
#define CD_MASK_BM_ELEM_PYPTR
#define MAX_CUSTOMDATA_LAYER_NAME
#define CD_MASK_NORMAL
#define CD_MASK_PROP_FLOAT3
#define CD_MASK_ORIGINDEX
#define CD_MASK_MCOL
#define CD_MASK_ORCO
#define CD_MASK_MDEFORMVERT
#define CD_MASK_TESSLOOPNORMAL
#define CD_MASK_MVERT_SKIN
#define CD_MASK_PROP_ALL
#define CD_MASK_PROP_INT32_2D
#define CD_MASK_SHAPE_KEYINDEX
#define CD_MASK_MTFACE
#define CD_MASK_ORIGSPACE_MLOOP
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_MDEFORMVERT
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
@ CD_GRID_PAINT_MASK
#define CD_MASK_CLOTH_ORCO
#define CD_MASK_PROP_INT32
#define CD_MASK_GRID_PAINT_MASK
@ CD_FLAG_NOCOPY
@ CD_FLAG_IN_MEMORY
@ CD_FLAG_EXTERNAL
#define CD_MASK_SHAPEKEY
#define CD_MASK_MFACE
#define MAX_MTFACE
#define CD_MASK_MDISPS
#define CD_MASK_ORIGSPACE
#define CD_MASK_MLOOPTANGENT
#define MAX_CUSTOMDATA_LAYER_NAME_NO_PREFIX
@ MVERT_SKIN_ROOT
@ CDT_MIX_SUB
@ CDT_MIX_REPLACE_BELOW_THRESHOLD
@ CDT_MIX_REPLACE_ABOVE_THRESHOLD
@ CDT_MIX_ADD
@ CDT_MIX_MUL
@ CDT_MIX_TRANSFER
@ CDT_MIX_MIX
@ CDT_MIX_NOMIX
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
@ BM_LOOP
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_FACE
BMesh const char void * data
BMesh * bm
const BMAllocTemplate bm_mesh_chunksize_default
Definition bmesh_mesh.cc:31
bool BM_attribute_stored_in_bmesh_builtin(const StringRef name)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
ATTR_WARN_UNUSED_RESULT const BMLoop * l
long long int int64_t
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
CustomDataLayerImplicitSharing(const void *data, const int totelem, const eCustomDataType type)
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
T & construct(Args &&...args)
constexpr const T * data() const
Definition BLI_span.hh:215
int64_t size() const
void append(const T &value)
bool is_empty() const
Span< T > as_span() const
void add_shared(const ImplicitSharingInfo *sharing_info, const FunctionRef< void(MemoryCounter &shared_memory)> count_fn)
nullptr float
void CustomData_debug_info_from_layers(const CustomData *data, const char *indent, DynStr *dynstr)
static int layerMaxNum_tface()
void * CustomData_get_layer_named_for_write(CustomData *data, const eCustomDataType type, const StringRef name, const int totelem)
bool CustomData_verify_versions(CustomData *data, const int index)
static void layerFree_mdisps(void *data, const int count)
void * CustomData_get_for_write(CustomData *data, const int index, const eCustomDataType type, int totelem)
static void layerCopy_propString(const void *source, void *dest, const int count)
static void layerInterp_origspace_face(const void **sources, const float *weights, const int count, void *dest)
static void layerDoMinMax_propcol(const void *data, void *vmin, void *vmax)
static void customData_free_layer__internal(CustomDataLayer *layer)
static void layerMultiply_propfloat2(void *data, const float fac)
void CustomData_data_mix_value(const eCustomDataType type, const void *source, void *dest, const int mixmode, const float mixfactor)
static void layerInitMinMax_mloop_origspace(void *vmin, void *vmax)
int CustomData_get_active_layer(const CustomData *data, const eCustomDataType type)
int CustomData_get_layer_index_n(const CustomData *data, const eCustomDataType type, const int n)
void * CustomData_get_n_for_write(CustomData *data, const eCustomDataType type, const int index, const int n, int totelem)
static const LayerTypeInfo * layerType_getInfo(const eCustomDataType type)
static size_t layerFilesize_mdisps(CDataFile *, const void *data, const int count)
static void layerSwap_flnor(void *data, const int *corner_indices)
static void layerInitMinMax_propfloat2(void *vmin, void *vmax)
static void blend_write_layer_data(BlendWriter *writer, const CustomDataLayer &layer, const int count)
static void layerInterp_mloop_origspace(const void **sources, const float *weights, int count, void *dest)
static void layerCopyValue_mloop_origspace(const void *source, void *dest, const int, const float)
bool CustomData_free_layer_named(CustomData *data, const StringRef name)
void CustomData_bmesh_interp_n(CustomData *data, const void **src_blocks_ofs, const float *weights, int count, void *dst_block_ofs, int n)
void CustomData_set_layer_flag(CustomData *data, const eCustomDataType type, const int flag)
int CustomData_layertype_layers_max(const eCustomDataType type)
static void layerInitMinMax_mloopcol(void *vmin, void *vmax)
static bool layerRead_mdisps(CDataFile *cdf, void *data, const int count)
void CustomData_set_layer_active_index(CustomData *data, const eCustomDataType type, const int n)
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES]
int CustomData_get_offset_named(const CustomData *data, const eCustomDataType type, const StringRef name)
void CustomData_validate_layer_name(const CustomData *data, const eCustomDataType type, const StringRef name, char *outname)
void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLayerMap *laymap, void *data_dst, const void **sources, const float *weights, const int count, const float mix_factor)
static void blend_read_mdisps(BlendDataReader *reader, const int count, MDisps *mdisps, const int external)
static bool check_bit_flag(const void *data, const size_t data_size, const uint64_t flag)
bool CustomData_layer_is_anonymous(const CustomData *data, eCustomDataType type, int n)
static void layerConstruct_mdeformvert(void *data, const int count)
void CustomData_blend_write(BlendWriter *writer, CustomData *data, Span< CustomDataLayer > layers_to_write, int count, eCustomDataMask cddata_mask, ID *id)
static bool layerEqual_mloop_origspace(const void *data1, const void *data2)
static void layerCopy_propFloat(const void *source, void *dest, const int count)
static void layerMultiply_mloopcol(void *data, const float fac)
static void layerDefault_mloopcol(void *data, const int count)
int CustomData_get_stencil_layer(const CustomData *data, const eCustomDataType type)
int CustomData_get_render_layer_index(const CustomData *data, const eCustomDataType type)
const char * CustomData_layertype_name(const eCustomDataType type)
void CustomData_free_layers(CustomData *data, const eCustomDataType type)
void CustomData_set_layer_stencil(CustomData *data, const eCustomDataType type, const int n)
void CustomData_bmesh_free_block(CustomData *data, void **block)
static bool CustomData_layer_ensure_data_exists(CustomDataLayer *layer, size_t count)
void CustomData_data_add(const eCustomDataType type, void *data1, const void *data2)
static void layerCopy_grid_paint_mask(const void *source, void *dest, const int count)
static void customdata_data_transfer_interp_generic(const CustomDataTransferLayerMap *laymap, void *data_dst, const void **sources, const float *weights, const int count, const float mix_factor)
void * CustomData_get_layer_for_write(CustomData *data, const eCustomDataType type, const int totelem)
bool CustomData_layertype_is_dynamic(const eCustomDataType type)
static void layerDefault_propquaternion(void *data, const int count)
const void * CustomData_get_layer_n(const CustomData *data, const eCustomDataType type, const int n)
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst, const CustomData_MeshMasks *mask_src)
Definition customdata.cc:96
void CustomData_set_layer_render_index(CustomData *data, const eCustomDataType type, const int n)
int CustomData_get_named_layer_index_notype(const CustomData *data, const StringRef name)
static void layerInterp_propfloat3(const void **sources, const float *weights, int count, void *dest)
static void layerCopy_origspace_face(const void *source, void *dest, const int count)
static bool layerEqual_propfloat2(const void *data1, const void *data2)
void CustomData_copy_layer_type_data(const CustomData *source, CustomData *destination, const eCustomDataType type, int source_index, int destination_index, int count)
static void layerMultiply_mloop_origspace(void *data, const float fac)
static void write_mdisps(BlendWriter *writer, const int count, const MDisps *mdlist, const int external)
static void CustomData_bmesh_set_default_n(CustomData *data, void **block, const int n)
void customData_mask_layers__print(const CustomData_MeshMasks *mask)
void CustomData_blend_read(BlendDataReader *reader, CustomData *data, const int count)
void CustomData_reset(CustomData *data)
static void layerMultiply_propcol(void *data, const float fac)
static void layerFree_grid_paint_mask(void *data, const int count)
static void layerCopy_bmesh_elem_py_ptr(const void *, void *dest, const int count)
static void * copy_layer_data(const eCustomDataType type, const void *data, const int totelem)
#define SOURCE_BUF_SIZE
static void write_grid_paint_mask(BlendWriter *writer, int count, const GridPaintMask *grid_paint_mask)
static void layerDefault_origspace_face(void *data, const int count)
static void layerMultiply_propfloat3(void *data, const float fac)
int CustomData_get_layer_index(const CustomData *data, const eCustomDataType type)
static void layerDoMinMax_mloop_origspace(const void *data, void *vmin, void *vmax)
static void layerSwap_tface(void *data, const int *corner_indices)
bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref, const CustomData_MeshMasks *mask_required)
bool CustomData_free_layer(CustomData *data, const eCustomDataType type, const int index)
void CustomData_copy_elements(const eCustomDataType type, const void *src_data, void *dst_data, const int count)
int CustomData_get_render_layer(const CustomData *data, const eCustomDataType type)
int CustomData_get_clone_layer_index(const CustomData *data, const eCustomDataType type)
static const ImplicitSharingInfo * make_implicit_sharing_info_for_layer(const eCustomDataType type, const void *data, const int totelem)
void CustomData_copy_data(const CustomData *source, CustomData *dest, const int source_index, const int dest_index, const int count)
bool CustomData_has_interp(const CustomData *data)
bool CustomData_layer_validate(CustomDataLayer *layer, const uint totitems, const bool do_fixes)
const void * CustomData_add_layer_with_data(CustomData *data, const eCustomDataType type, void *layer_data, const int totelem, const ImplicitSharingInfo *sharing_info)
int CustomData_get_active_layer_index(const CustomData *data, const eCustomDataType type)
static void customData_update_offsets(CustomData *data)
const char * CustomData_get_render_layer_name(const CustomData *data, const eCustomDataType type)
static void layerAdd_mloopcol(void *data1, const void *data2)
static void copy_bit_flag(void *dst, const void *src, const size_t data_size, const uint64_t flag)
static void layerCopy_mdeformvert(const void *source, void *dest, const int count)
static CustomDataLayer * customData_add_layer__internal(CustomData *data, eCustomDataType type, std::optional< eCDAllocType > alloctype, void *layer_data_to_assign, const ImplicitSharingInfo *sharing_info_to_assign, int totelem, const StringRef name)
void CustomData_data_initminmax(const eCustomDataType type, void *min, void *max)
static void layerAdd_mloop_origspace(void *data1, const void *data2)
void CustomData_set_layer_render(CustomData *data, const eCustomDataType type, const int n)
void CustomData_free(CustomData *data)
static void layerInterp_propcol(const void **sources, const float *weights, int count, void *dest)
static void layerSwap_origspace_face(void *data, const int *corner_indices)
static void layerCopy_mvert_skin(const void *source, void *dest, const int count)
int CustomData_name_maxncpy_calc(const blender::StringRef name)
void * CustomData_bmesh_get(const CustomData *data, void *block, const eCustomDataType type)
static void layerInterp_normal(const void **sources, const float *weights, const int count, void *dest)
void CustomData_data_copy_value(const eCustomDataType type, const void *source, void *dest)
void CustomData_init_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, int totelem)
const void * CustomData_add_layer_named_with_data(CustomData *data, eCustomDataType type, void *layer_data, int totelem, const StringRef name, const ImplicitSharingInfo *sharing_info)
static bool layerEqual_propcol(const void *data1, const void *data2)
static void layerInitMinMax_propcol(void *vmin, void *vmax)
const void * CustomData_get_layer_named(const CustomData *data, const eCustomDataType type, const StringRef name)
bool CustomData_has_layer(const CustomData *data, const eCustomDataType type)
bool CustomData_merge_layout(const CustomData *source, CustomData *dest, const eCustomDataMask mask, const eCDAllocType alloctype, const int totelem)
static void layerInterp_tface(const void **sources, const float *weights, const int count, void *dest)
static void get_type_file_write_info(const eCustomDataType type, const char **r_struct_name, int *r_struct_num)
bool CustomData_merge(const CustomData *source, CustomData *dest, eCustomDataMask mask, int totelem)
int CustomData_number_of_layers_typemask(const CustomData *data, const eCustomDataMask mask)
static void layerAdd_propfloat3(void *data1, const void *data2)
bool CustomData_data_equals(const eCustomDataType type, const void *data1, const void *data2)
static bool layerValidate_propfloat3(void *data, const uint totitems, const bool do_fixes)
void CustomData_external_reload(CustomData *data, ID *, eCustomDataMask mask, int totelem)
CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData *src, const eCustomDataMask mask)
static void layerDefault_tface(void *data, const int count)
void CustomData_set_layer_clone(CustomData *data, const eCustomDataType type, const int n)
void CustomData_free_elem(CustomData *data, const int index, const int count)
static void layerDefault_propcol(void *data, const int count)
static void blend_read_paint_mask(BlendDataReader *reader, int count, GridPaintMask *grid_paint_mask)
void CustomData_data_set_default_value(const eCustomDataType type, void *elem)
static bool layer_is_mutable(CustomDataLayer &layer)
static void layerCopy_tface(const void *source, void *dest, const int count)
static bool layerWrite_mdisps(CDataFile *cdf, const void *data, const int count)
void CustomData_update_typemap(CustomData *data)
void CustomData_bmesh_copy_block(CustomData &dst_data, const BMCustomDataCopyMap &copy_map, const void *src_block, void **dst_block)
void CustomData_bmesh_set_default(CustomData *data, void **block)
static void layerAdd_propcol(void *data1, const void *data2)
void CustomData_data_dominmax(const eCustomDataType type, const void *data, void *min, void *max)
void CustomData_bmesh_init_pool(CustomData *data, const int totelem, const char htype)
static void layerInterp_shapekey(const void **sources, const float *weights, int count, void *dest)
void CustomData_realloc(CustomData *data, const int old_size, const int new_size, const eCDAllocType alloctype)
void bpy_bm_generic_invalidate(struct BPy_BMGeneric *)
void CustomData_set_layer_clone_index(CustomData *data, const eCustomDataType type, const int n)
static void CustomData_external_free(CustomData *data)
static void layerAdd_propfloat2(void *data1, const void *data2)
const char * CustomData_get_active_layer_name(const CustomData *data, const eCustomDataType type)
static void layerInterp_propquaternion(const void **sources, const float *weights, int count, void *dest)
static bool customdata_typemap_is_valid(const CustomData *data)
static void layerDefault_mcol(void *data, const int count)
bool CustomData_layertype_is_singleton(const eCustomDataType type)
static void layerInterp_mdeformvert(const void **sources, const float *weights, const int count, void *dest)
bool CustomData_layer_has_interp(const CustomData *data, const int layer_n)
static void layerFree_mdeformvert(void *data, const int count)
void CustomData_interp(const CustomData *source, CustomData *dest, const int *src_indices, const float *weights, int count, int dest_index)
static bool layerEqual_mloopcol(const void *data1, const void *data2)
void CustomData_init_layout_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, int totelem)
void CustomData_data_transfer(const MeshPairRemap *me_remap, const CustomDataTransferLayerMap *laymap)
static void free_layer_data(const eCustomDataType type, const void *data, const int totelem)
static void layerInterp_mvert_skin(const void **sources, const float *weights, int count, void *dest)
static void layerDefault_origindex(void *data, const int count)
static void layerDefault_mvert_skin(void *data, const int count)
void * CustomData_add_layer(CustomData *data, const eCustomDataType type, eCDAllocType alloctype, const int totelem)
int CustomData_get_stencil_layer_index(const CustomData *data, const eCustomDataType type)
static void layerInterp_mloopcol(const void **sources, const float *weights, int count, void *dest)
int CustomData_get_named_layer(const CustomData *data, const eCustomDataType type, const StringRef name)
static void ensure_layer_data_is_mutable(CustomDataLayer &layer, const int totelem)
void CustomData_external_add(CustomData *data, ID *, const eCustomDataType type, const int, const char *filepath)
void CustomData_external_remove(CustomData *data, ID *id, const eCustomDataType type, const int totelem)
static void customdata_external_filename(char filepath[FILE_MAX], ID *id, CustomDataExternal *external)
bool CustomData_bmesh_has_free(const CustomData *data)
static void layerDefault_propfloat4x4(void *data, const int count)
static bool customdata_merge_internal(const CustomData *source, CustomData *dest, const eCustomDataMask mask, const std::optional< eCDAllocType > alloctype, const int totelem)
void CustomData_external_read(CustomData *data, ID *id, eCustomDataMask mask, const int totelem)
static void layerInterp_propFloat(const void **sources, const float *weights, const int count, void *dest)
static void layerFree_bmesh_elem_py_ptr(void *data, const int count)
int CustomData_number_of_anonymous_layers(const CustomData *data, const eCustomDataType type)
void CustomData_swap_corners(CustomData *data, const int index, const int *corner_indices)
static void layerCopyValue_propfloat2(const void *source, void *dest, const int mixmode, const float mixfactor)
size_t CustomData_get_elem_size(const CustomDataLayer *layer)
void CustomData_count_memory(const CustomData &data, const int totelem, blender::MemoryCounter &memory)
int CustomData_number_of_layers(const CustomData *data, const eCustomDataType type)
bool CustomData_has_layer_named(const CustomData *data, const eCustomDataType type, const StringRef name)
static void layerCopyValue_propcol(const void *source, void *dest, const int mixmode, const float mixfactor)
BMCustomDataCopyMap CustomData_bmesh_copy_map_calc(const CustomData &src, const CustomData &dst, const eCustomDataMask mask_exclude)
const void * CustomData_get_layer(const CustomData *data, const eCustomDataType type)
static void blend_read_layer_data(BlendDataReader *reader, CustomDataLayer &layer, const int count)
static int CustomData_get_layer_index__notypemap(const CustomData *data, const eCustomDataType type)
void CustomData_set_layer_unique_name(CustomData *data, const int index)
void CustomData_ensure_layers_are_mutable(CustomData *data, int totelem)
static void layerSwap_mcol(void *data, const int *corner_indices)
static void customData_resize(CustomData *data, const int grow_amount)
static bool layerValidate_propFloat(void *data, const uint totitems, const bool do_fixes)
static void layerInterp_propbool(const void **sources, const float *weights, int count, void *dest)
int CustomData_sizeof(const eCustomDataType type)
static void layerCopyValue_normal(const void *source, void *dest, const int mixmode, const float mixfactor)
bool CustomData_external_test(CustomData *data, const eCustomDataType type)
static void layerInterp_propInt(const void **sources, const float *weights, const int count, void *dest)
void CustomData_bmesh_set_n(CustomData *data, void *block, const eCustomDataType type, const int n, const void *source)
bool CustomData_bmesh_merge_layout(const CustomData *source, CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, BMesh *bm, const char htype)
static void layerInterp_mcol(const void **sources, const float *weights, const int count, void *dest)
bool CustomData_set_layer_name(CustomData *data, const eCustomDataType type, const int n, const StringRef name)
void CustomData_blend_write_prepare(CustomData &data, const blender::bke::AttrDomain domain, const int domain_size, Vector< CustomDataLayer, 16 > &layers_to_write, blender::bke::AttributeStorage::BlendWriteData &write_data)
int CustomData_get_clone_layer(const CustomData *data, const eCustomDataType type)
void CustomData_ensure_data_is_mutable(CustomDataLayer *layer, const int totelem)
static void layerDoMinMax_mloopcol(const void *data, void *vmin, void *vmax)
bool CustomData_free_layer_active(CustomData *data, const eCustomDataType type)
const char * CustomData_get_layer_name(const CustomData *data, const eCustomDataType type, const int n)
int CustomData_get_named_layer_index(const CustomData *data, const eCustomDataType type, const StringRef name)
static void layerConstruct_mdisps(void *data, const int count)
static const char * LAYERTYPENAMES[CD_NUMTYPES]
static void layerCopy_mdisps(const void *source, void *dest, const int count)
int CustomData_get_offset(const CustomData *data, const eCustomDataType type)
void * CustomData_bmesh_get_n(const CustomData *data, void *block, const eCustomDataType type, const int n)
bool CustomData_layer_has_math(const CustomData *data, const int layer_n)
static void layerDoMinMax_propfloat2(const void *data, void *vmin, void *vmax)
bool CustomData_has_math(const CustomData *data)
void CustomData_bmesh_alloc_block(CustomData *data, void **block)
static void layerInterp_propfloat2(const void **sources, const float *weights, int count, void *dest)
static bool cd_layer_find_dupe(CustomData *data, const StringRef name, const eCustomDataType type, const int index)
void CustomData_data_multiply(const eCustomDataType type, void *data, const float fac)
void CustomData_set_only_copy(const CustomData *data, const eCustomDataMask mask)
static const char * layerType_getName(const eCustomDataType type)
void * CustomData_bmesh_get_layer_n(const CustomData *data, void *block, const int n)
#define CUSTOMDATA_GROW
Definition customdata.cc:84
static bool layerValidate_propfloat2(void *data, const uint totitems, const bool do_fixes)
void CustomData_bmesh_free_block_data(CustomData *data, void *block)
#define COPY_BIT_FLAG(_type, _dst, _src, _f)
void CustomData_bmesh_interp(CustomData *data, const void **src_blocks, const float *weights, int count, void *dst_block)
void CustomData_external_write(CustomData *data, ID *id, eCustomDataMask mask, const int totelem, const int free)
void * CustomData_get_layer_n_for_write(CustomData *data, const eCustomDataType type, const int n, const int totelem)
static void layerCopyValue_mloopcol(const void *source, void *dest, const int mixmode, const float mixfactor)
static void layerSwap_mdisps(void *data, const int *ci)
void CustomData_set_layer_active(CustomData *data, const eCustomDataType type, const int n)
static void layerConstruct_grid_paint_mask(void *data, const int count)
void * CustomData_add_layer_named(CustomData *data, const eCustomDataType type, const eCDAllocType alloctype, const int totelem, const StringRef name)
void CustomData_copy_data_layer(const CustomData *source, CustomData *dest, const int src_layer_index, const int dst_layer_index, const int src_index, const int dst_index, const int count)
int CustomData_get_n_offset(const CustomData *data, const eCustomDataType type, const int n)
#define logf(x)
uint col
#define in
#define external
#define printf(...)
#define round
MatBase< 4, 4 > float4x4
int count
#define PRIx64
Definition inttypes.h:133
#define LOG(level)
Definition log.h:97
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
Definition mallocn.cc:138
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
size_t(* MEM_allocN_len)(const void *vmemh)
Definition mallocn.cc:36
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float interp(const float a, const float b, const float t)
Definition math_base.h:502
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static ulong * next
typename DefaultMixerStruct< T >::type DefaultMixer
bool attribute_name_is_anonymous(const StringRef name)
std::optional< AttrType > custom_data_type_to_attr_type(eCustomDataType data_type)
std::optional< VolumeGridType > custom_data_type_to_volume_grid_type(eCustomDataType type)
std::optional< eCustomDataType > volume_grid_type_to_custom_data_type(VolumeGridType type)
QuaternionBase< float > Quaternion
T interpolate(const T &a, const T &b, const FactorT &t)
void min_max(const T &value, T &min, T &max)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< float, 3 > float3
blender::VecBase< int16_t, 2 > short2
static void update(bNodeTree *ntree)
const char * name
#define sqrtf
#define min(a, b)
Definition sort.cc:36
#define FLT_MAX
Definition stdcycles.h:14
const char * name
blender::Vector< Free > free
blender::Vector< TrivialCopy > trivial_copies
blender::Vector< TrivialDefault > trivial_defaults
blender::Vector< Default > defaults
blender::Vector< Copy > copies
void * data
const ImplicitSharingInfoHandle * sharing_info
cd_datatransfer_interp interp
struct BLI_mempool * pool
CustomDataLayer * layers
CustomDataExternal * external
Definition DNA_ID.h:414
bool(* write)(CDataFile *cdf, const void *data, int count)
void(* dominmax)(const void *data1, void *min, void *max)
const char * defaultname
cd_interp interp
void(* copyvalue)(const void *source, void *dest, int mixmode, const float mixfactor)
void(* add)(void *data1, const void *data2)
cd_set_default_value set_default_value
size_t(* filesize)(CDataFile *cdf, const void *data, int count)
const char * structname
int(* layers_max)()
bool(* read)(CDataFile *cdf, void *data, int count)
void(* initminmax)(void *min, void *max)
cd_validate validate
void(* swap)(void *data, const int *corner_indices)
bool(* equal)(const void *data1, const void *data2)
void(* construct)(void *data, int count)
void(* multiply)(void *data, float fac)
unsigned char r
unsigned char a
unsigned char g
unsigned char b
struct MDeformWeight * dw
unsigned int def_nr
float(* disps)[3]
unsigned int * hidden
unsigned char a
unsigned char b
unsigned char r
unsigned char g
float uv[4][2]
MeshPairRemapItem * items
float x
float y
float x
float z
float y
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4238
uint8_t flag
Definition wm_window.cc:145