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