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
11
12#include <algorithm>
13
14#include "MEM_guardedalloc.h"
15
16/* Since we have versioning code here (CustomData_verify_versions()). */
17#define DNA_DEPRECATED_ALLOW
18
19#include "DNA_ID.h"
21#include "DNA_meshdata_types.h"
22#include "DNA_modifier_enums.h"
23
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/* -------------------------------------------------------------------- */
93
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
115
116/* -------------------------------------------------------------------- */
119
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
208
209/* -------------------------------------------------------------------- */
212
213static void layerCopy_mdeformvert(const void *source, void *dest, const int count)
214{
215 int i, size = sizeof(MDeformVert);
216
217 memcpy(dest, source, count * size);
218
219 for (i = 0; i < count; i++) {
220 MDeformVert *dvert = static_cast<MDeformVert *>(POINTER_OFFSET(dest, i * size));
221
222 if (dvert->totweight) {
223 MDeformWeight *dw = MEM_malloc_arrayN<MDeformWeight>(size_t(dvert->totweight), __func__);
224
225 memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw));
226 dvert->dw = dw;
227 }
228 else {
229 dvert->dw = nullptr;
230 }
231 }
232}
233
234static void layerFree_mdeformvert(void *data, const int count)
235{
236 for (MDeformVert &dvert : MutableSpan(static_cast<MDeformVert *>(data), count)) {
237 if (dvert.dw) {
238 MEM_freeN(dvert.dw);
239 dvert.dw = nullptr;
240 dvert.totweight = 0;
241 }
242 }
243}
244
245static void layerInterp_mdeformvert(const void **sources,
246 const float *weights,
247 const 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
336
337/* -------------------------------------------------------------------- */
340
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
399
400/* -------------------------------------------------------------------- */
403
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
473
474/* -------------------------------------------------------------------- */
477
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
516
517/* -------------------------------------------------------------------- */
520
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
538
539/* -------------------------------------------------------------------- */
542
543static void layerCopy_propString(const void *source, void *dest, const int count)
544{
545 memcpy(dest, source, sizeof(MStringProperty) * count);
546}
547
549
550/* -------------------------------------------------------------------- */
553
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
616
617/* -------------------------------------------------------------------- */
620
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
732
733/* -------------------------------------------------------------------- */
736
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
766
767/* -------------------------------------------------------------------- */
770
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
802
803/* -------------------------------------------------------------------- */
806
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
976
977/* -------------------------------------------------------------------- */
980
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
1156
1157/* -------------------------------------------------------------------- */
1160
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
1199
1200/* -------------------------------------------------------------------- */
1203
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
1218
1219/* -------------------------------------------------------------------- */
1222
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
1341
1342/* -------------------------------------------------------------------- */
1345
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
1394
1395/* -------------------------------------------------------------------- */
1398
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);
1463 blender::math::min_max(value, a, b);
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
1485
1486/* -------------------------------------------------------------------- */
1489
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
1506
1507/* -------------------------------------------------------------------- */
1510
1511static void layerDefault_propquaternion(void *data, const int count)
1512{
1513 using namespace blender;
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/* -------------------------------------------------------------------- */
1540
1541static void layerDefault_propfloat4x4(void *data, const int count)
1542{
1543 using namespace blender;
1545}
1546
1548
1549/* -------------------------------------------------------------------- */
1552
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
2312
2313/* -------------------------------------------------------------------- */
2316
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,
3015 StringRef name)
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:
3751 chunksize = bm_mesh_chunksize_default.totvert;
3752 break;
3753 case BM_EDGE:
3754 chunksize = bm_mesh_chunksize_default.totedge;
3755 break;
3756 case BM_LOOP:
3757 chunksize = bm_mesh_chunksize_default.totloop;
3758 break;
3759 case BM_FACE:
3760 chunksize = bm_mesh_chunksize_default.totface;
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);
3853 CustomData_bmesh_free_block(&destold, &l->head.data);
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 }
4014 for (const BMCustomDataCopyMap::TrivialDefault &info : copy_map.trivial_defaults) {
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()) {
4430 index = CustomData_get_named_layer_index(data, type, name);
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 {
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
4548
4549/* -------------------------------------------------------------------- */
4552
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
4825
4826/* -------------------------------------------------------------------- */
4829
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
5108
5109/* -------------------------------------------------------------------- */
5112
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
5436
5437/* -------------------------------------------------------------------- */
5440
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
5474
5475namespace blender::bke {
5476
5477/* -------------------------------------------------------------------- */
5480
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
5514
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
const CustomData_MeshMasks CD_MASK_EVERYTHING
const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX
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
const CustomData_MeshMasks CD_MASK_BAREMESH
void(*)(void *data, int count) cd_free
const CustomData_MeshMasks CD_MASK_BMESH
#define ORIGINDEX_NONE
void(*)(const void *source, void *dest, int count) cd_copy
bool(*)(void *item, uint totitems, bool do_fixes) cd_validate
#define UV_PINNED_NAME
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
const CustomData_MeshMasks CD_MASK_DERIVEDMESH
#define CD_TYPE_AS_MASK(_type)
#define UV_EDGESEL_NAME
const CustomData_MeshMasks CD_MASK_MESH
CDataFile * cdf_create(int type)
bool cdf_read_layer(CDataFile *cdf, const CDataFileLayer *blay)
bool cdf_write_open(CDataFile *cdf, const char *filepath)
bool cdf_read_data(CDataFile *cdf, unsigned int size, void *data)
bool cdf_write_data(CDataFile *cdf, unsigned int size, const void *data)
#define CDF_TYPE_MESH
CDataFileLayer * cdf_layer_find(CDataFile *cdf, int type, const char *name)
void cdf_read_close(CDataFile *cdf)
CDataFileLayer * cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t datasize)
void cdf_write_close(CDataFile *cdf)
void cdf_free(CDataFile *cdf)
bool cdf_write_layer(CDataFile *cdf, CDataFileLayer *blay)
bool cdf_read_open(CDataFile *cdf, const char *filepath)
support for deformation groups and hooks.
void BKE_defvert_blend_write(BlendWriter *writer, int count, const MDeformVert *dvlist)
Definition deform.cc: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
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.
@ CD_FLAG_NOCOPY
@ CD_FLAG_IN_MEMORY
@ CD_FLAG_EXTERNAL
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_MDEFORMVERT
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
@ CD_GRID_PAINT_MASK
@ MVERT_SKIN_ROOT
@ CDT_MIX_SUB
@ CDT_MIX_REPLACE_BELOW_THRESHOLD
@ CDT_MIX_REPLACE_ABOVE_THRESHOLD
@ CDT_MIX_ADD
@ CDT_MIX_MUL
@ CDT_MIX_TRANSFER
@ CDT_MIX_MIX
@ CDT_MIX_NOMIX
Read Guarded memory(de)allocation.
#define U
@ BM_LOOP
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_FACE
BMesh const char void * data
BMesh * bm
const BMAllocTemplate bm_mesh_chunksize_default
Definition bmesh_mesh.cc:31
bool BM_attribute_stored_in_bmesh_builtin(const StringRef name)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
ATTR_WARN_UNUSED_RESULT const BMLoop * l
long long int int64_t
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
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
constexpr bool is_empty() const
constexpr bool startswith(StringRef prefix) const
void copy_utf8_truncated(char *dst, int64_t dst_size) const
Definition string_ref.cc:28
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)
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)
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)
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)
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)
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)
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)
#define logf(x)
#define sqrtf(x)
uint col
#define round
MatBase< 4, 4 > float4x4
#define in
#define external
#define printf(...)
#define CD_MASK_BM_ELEM_PYPTR
#define MAX_CUSTOMDATA_LAYER_NAME
#define CD_MASK_NORMAL
#define CD_MASK_PROP_FLOAT3
#define CD_MASK_ORIGINDEX
#define CD_MASK_MCOL
#define CD_MASK_ORCO
#define CD_MASK_MDEFORMVERT
#define CD_MASK_TESSLOOPNORMAL
#define CD_MASK_MVERT_SKIN
#define MEM_SAFE_FREE(v)
#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 ID_BLEND_PATH_FROM_GLOBAL(_id)
#define CD_MASK_MTFACE
#define CD_MASK_ORIGSPACE_MLOOP
#define CD_MASK_CLOTH_ORCO
#define CD_MASK_PROP_INT32
#define CD_MASK_GRID_PAINT_MASK
#define MEM_reallocN(vmemh, len)
#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
int count
#define PRIx64
Definition inttypes.h:133
#define LOG(severity)
Definition log.h:32
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
Definition mallocn.cc:138
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
size_t(* MEM_allocN_len)(const void *vmemh)
Definition mallocn.cc:36
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float interp(const float a, const float b, const float t)
Definition math_base.h:502
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static ulong * next
typename DefaultMixerStruct< T >::type DefaultMixer
bool attribute_name_is_anonymous(const StringRef name)
std::optional< AttrType > custom_data_type_to_attr_type(eCustomDataType data_type)
std::optional< VolumeGridType > custom_data_type_to_volume_grid_type(eCustomDataType type)
std::optional< eCustomDataType > volume_grid_type_to_custom_data_type(VolumeGridType type)
QuaternionBase< float > Quaternion
T interpolate(const T &a, const T &b, const FactorT &t)
void min_max(const T &value, T &min, T &max)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< float, 3 > float3
blender::VecBase< int16_t, 2 > short2
static void update(bNodeTree *ntree)
#define min(a, b)
Definition sort.cc:36
#define FLT_MAX
Definition stdcycles.h:14
const char * name
blender::Vector< Free > free
blender::Vector< TrivialCopy > trivial_copies
blender::Vector< TrivialDefault > trivial_defaults
blender::Vector< Default > defaults
blender::Vector< Copy > copies
void * data
const ImplicitSharingInfoHandle * sharing_info
cd_datatransfer_interp interp
struct BLI_mempool * pool
CustomDataLayer * layers
CustomDataExternal * external
Definition DNA_ID.h: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
float x
float y
float x
float z
float y
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4226
uint8_t flag
Definition wm_window.cc:139