diff options
Diffstat (limited to 'source/blender/blenkernel/intern/customdata.c')
-rw-r--r-- | source/blender/blenkernel/intern/customdata.c | 768 |
1 files changed, 585 insertions, 183 deletions
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 7684c5a3a42..999f411cece 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -48,6 +48,7 @@ #include "BLI_string.h" #include "BLI_path_util.h" #include "BLI_math.h" +#include "BLI_math_color_blend.h" #include "BLI_mempool.h" #include "BLF_translation.h" @@ -56,6 +57,8 @@ #include "BKE_customdata_file.h" #include "BKE_global.h" #include "BKE_main.h" +#include "BKE_mesh_mapping.h" +#include "BKE_mesh_remap.h" #include "BKE_multires.h" #include "bmesh.h" @@ -92,7 +95,7 @@ typedef struct LayerTypeInfo { * (deep copy if appropriate) * if NULL, memcpy is used */ - void (*copy)(const void *source, void *dest, int count); + cd_copy copy; /** * a function to free any dynamically allocated components of this @@ -117,8 +120,7 @@ typedef struct LayerTypeInfo { * applying changes while reading from sources. * See bug [#32395] - Campbell. */ - void (*interp)(void **sources, const float *weights, const float *sub_weights, - int count, void *dest); + cd_interp interp; /** a function to swap the data in corners of the element */ void (*swap)(void *data, const int *corner_indices); @@ -134,7 +136,7 @@ typedef struct LayerTypeInfo { void (*initminmax)(void *min, void *max); void (*add)(void *data1, const void *data2); void (*dominmax)(const void *data1, void *min, void *max); - void (*copyvalue)(const void *source, void *dest); + void (*copyvalue)(const void *source, void *dest, const int mixmode, const float mixfactor); /** a function to read data from a cdf file */ int (*read)(CDataFile *cdf, void *data, int count); @@ -157,7 +159,7 @@ static void layerCopy_mdeformvert(const void *source, void *dest, memcpy(dest, source, count * size); for (i = 0; i < count; ++i) { - MDeformVert *dvert = (MDeformVert *)((char *)dest + i * size); + MDeformVert *dvert = POINTER_OFFSET(dest, i * size); if (dvert->totweight) { MDeformWeight *dw = MEM_mallocN(dvert->totweight * sizeof(*dw), @@ -176,7 +178,7 @@ static void layerFree_mdeformvert(void *data, int count, int size) int i; for (i = 0; i < count; ++i) { - MDeformVert *dvert = (MDeformVert *)((char *)data + i * size); + MDeformVert *dvert = POINTER_OFFSET(data, i * size); if (dvert->dw) { MEM_freeN(dvert->dw); @@ -193,7 +195,7 @@ static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest, int i, size = sizeof(void *); for (i = 0; i < count; ++i) { - void **ptr = (void **)((char *)dest + i * size); + void **ptr = POINTER_OFFSET(dest, i * size); *ptr = NULL; } } @@ -210,15 +212,16 @@ static void layerFree_bmesh_elem_py_ptr(void *data, int count, int size) int i; for (i = 0; i < count; ++i) { - void **ptr = (void *)((char *)data + i * size); + void **ptr = POINTER_OFFSET(data, i * size); if (*ptr) { bpy_bm_generic_invalidate(*ptr); } } } -static void layerInterp_mdeformvert(void **sources, const float *weights, - const float *UNUSED(sub_weights), int count, void *dest) +static void layerInterp_mdeformvert( + const void **sources, const float *weights, + const float *UNUSED(sub_weights), int count, void *dest) { /* a single linked list of MDeformWeight's * use this to avoid double allocs (which LinkNode would do) */ @@ -237,7 +240,7 @@ static void layerInterp_mdeformvert(void **sources, const float *weights, /* build a list of unique def_nrs for dest */ totweight = 0; for (i = 0; i < count; ++i) { - MDeformVert *source = sources[i]; + const MDeformVert *source = sources[i]; float interp_weight = weights ? weights[i] : 1.0f; for (j = 0; j < source->totweight; ++j) { @@ -298,6 +301,50 @@ static void layerInterp_mdeformvert(void **sources, const float *weights, } } +static void layerInterp_normal( + const void **sources, const float *weights, + const float *UNUSED(sub_weights), int count, void *dest) +{ + float no[3] = {0.0f}; + + while (count--) { + madd_v3_v3fl(no, (const float *)sources[count], weights[count]); + } + + copy_v3_v3((float *)dest, no); +} + +static void layerCopyValue_normal(const void *source, void *dest, const int mixmode, const float mixfactor) +{ + const float *no_src = source; + float *no_dst = dest; + float no_tmp[3]; + + if (ELEM(mixmode, CDT_MIX_NOMIX, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) { + /* Above/below threshold modes are not supported here, fallback to nomix (just in case). */ + copy_v3_v3(no_dst, no_src); + } + else { /* Modes that support 'real' mix factor. */ + /* Since we normalize in the end, MIX and ADD are the same op here. */ + if (ELEM(mixmode, CDT_MIX_MIX, CDT_MIX_ADD)) { + add_v3_v3v3(no_tmp, no_dst, no_src); + normalize_v3(no_tmp); + } + else if (mixmode == CDT_MIX_SUB) { + sub_v3_v3v3(no_tmp, no_dst, no_src); + normalize_v3(no_tmp); + } + else if (mixmode == CDT_MIX_MUL) { + mul_v3_v3v3(no_tmp, no_dst, no_src); + normalize_v3(no_tmp); + } + else { + copy_v3_v3(no_tmp, no_src); + } + interp_v3_v3v3_slerp_safe(no_dst, no_dst, no_tmp, mixfactor); + } +} + static void layerCopy_tface(const void *source, void *dest, int count) { const MTFace *source_tf = (const MTFace *)source; @@ -308,8 +355,9 @@ static void layerCopy_tface(const void *source, void *dest, int count) dest_tf[i] = source_tf[i]; } -static void layerInterp_tface(void **sources, const float *weights, - const float *sub_weights, int count, void *dest) +static void layerInterp_tface( + const void **sources, const float *weights, + const float *sub_weights, int count, void *dest) { MTFace *tf = dest; int i, j, k; @@ -321,7 +369,7 @@ static void layerInterp_tface(void **sources, const float *weights, sub_weight = sub_weights; for (i = 0; i < count; ++i) { float weight = weights ? weights[i] : 1; - MTFace *src = sources[i]; + const MTFace *src = sources[i]; for (j = 0; j < 4; ++j) { if (sub_weights) { @@ -415,8 +463,9 @@ static void layerCopy_origspace_face(const void *source, void *dest, int count) dest_tf[i] = source_tf[i]; } -static void layerInterp_origspace_face(void **sources, const float *weights, - const float *sub_weights, int count, void *dest) +static void layerInterp_origspace_face( + const void **sources, const float *weights, + const float *sub_weights, int count, void *dest) { OrigSpaceFace *osf = dest; int i, j, k; @@ -428,7 +477,7 @@ static void layerInterp_origspace_face(void **sources, const float *weights, sub_weight = sub_weights; for (i = 0; i < count; ++i) { float weight = weights ? weights[i] : 1; - OrigSpaceFace *src = sources[i]; + const OrigSpaceFace *src = sources[i]; for (j = 0; j < 4; ++j) { if (sub_weights) { @@ -620,14 +669,53 @@ static void layerFree_grid_paint_mask(void *data, int count, int UNUSED(size)) } /* --------- */ -static void layerCopyValue_mloopcol(const void *source, void *dest) +static void layerCopyValue_mloopcol(const void *source, void *dest, const int mixmode, const float mixfactor) { const MLoopCol *m1 = source; MLoopCol *m2 = dest; - - m2->r = m1->r; - m2->g = m1->g; - m2->b = m1->b; + unsigned char tmp_col[4]; + + if (ELEM(mixmode, CDT_MIX_NOMIX, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) { + /* Modes that do a full copy or nothing. */ + if (ELEM(mixmode, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) { + /* TODO: Check for a real valid way to get 'factor' value of our dest color? */ + const float f = ((float)m2->r + (float)m2->g + (float)m2->b) / 3.0f; + if (mixmode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && f < mixfactor) { + return; /* Do Nothing! */ + } + else if (mixmode == CDT_MIX_REPLACE_BELOW_THRESHOLD && f > mixfactor) { + return; /* Do Nothing! */ + } + } + m2->r = m1->r; + m2->g = m1->g; + m2->b = m1->b; + } + else { /* Modes that support 'real' mix factor. */ + unsigned char src[4] = {m1->r, m1->g, m1->b, m1->a}; + unsigned char dst[4] = {m2->r, m2->g, m2->b, m2->a}; + + if (mixmode == CDT_MIX_MIX) { + blend_color_mix_byte(tmp_col, dst, src); + } + else if (mixmode == CDT_MIX_ADD) { + blend_color_add_byte(tmp_col, dst, src); + } + else if (mixmode == CDT_MIX_SUB) { + blend_color_sub_byte(tmp_col, dst, src); + } + else if (mixmode == CDT_MIX_MUL) { + blend_color_mul_byte(tmp_col, dst, src); + } + else { + memcpy(tmp_col, src, sizeof(tmp_col)); + } + blend_color_interpolate_byte(dst, dst, tmp_col, mixfactor); + + m2->r = (char)dst[0]; + m2->g = (char)dst[1]; + m2->b = (char)dst[2]; + } m2->a = m1->a; } @@ -706,8 +794,9 @@ static void layerDefault_mloopcol(void *data, int count) } -static void layerInterp_mloopcol(void **sources, const float *weights, - const float *sub_weights, int count, void *dest) +static void layerInterp_mloopcol( + const void **sources, const float *weights, + const float *sub_weights, int count, void *dest) { MLoopCol *mc = dest; int i; @@ -723,7 +812,7 @@ static void layerInterp_mloopcol(void **sources, const float *weights, sub_weight = sub_weights; for (i = 0; i < count; ++i) { float weight = weights ? weights[i] : 1; - MLoopCol *src = sources[i]; + const MLoopCol *src = sources[i]; if (sub_weights) { col.r += src->r * (*sub_weight) * weight; col.g += src->g * (*sub_weight) * weight; @@ -758,12 +847,19 @@ static int layerMaxNum_mloopcol(void) return MAX_MCOL; } -static void layerCopyValue_mloopuv(const void *source, void *dest) +static void layerCopyValue_mloopuv(const void *source, void *dest, const int mixmode, const float mixfactor) { const MLoopUV *luv1 = source; MLoopUV *luv2 = dest; - copy_v2_v2(luv2->uv, luv1->uv); + /* We only support a limited subset of advanced mixing here - namely the mixfactor interpolation. */ + + if (mixmode == CDT_MIX_NOMIX) { + copy_v2_v2(luv2->uv, luv1->uv); + } + else { + interp_v2_v2v2(luv2->uv, luv2->uv, luv1->uv, mixfactor); + } } static bool layerEqual_mloopuv(const void *data1, const void *data2) @@ -803,8 +899,9 @@ static void layerAdd_mloopuv(void *data1, const void *data2) add_v2_v2(l1->uv, l2->uv); } -static void layerInterp_mloopuv(void **sources, const float *weights, - const float *sub_weights, int count, void *dest) +static void layerInterp_mloopuv( + const void **sources, const float *weights, + const float *sub_weights, int count, void *dest) { float uv[2]; int i; @@ -815,7 +912,7 @@ static void layerInterp_mloopuv(void **sources, const float *weights, const float *sub_weight = sub_weights; for (i = 0; i < count; i++) { float weight = weights ? weights[i] : 1.0f; - MLoopUV *src = sources[i]; + const MLoopUV *src = sources[i]; madd_v2_v2fl(uv, src->uv, (*sub_weight) * weight); sub_weight++; } @@ -823,7 +920,7 @@ static void layerInterp_mloopuv(void **sources, const float *weights, else { for (i = 0; i < count; i++) { float weight = weights ? weights[i] : 1; - MLoopUV *src = sources[i]; + const MLoopUV *src = sources[i]; madd_v2_v2fl(uv, src->uv, weight); } } @@ -833,7 +930,8 @@ static void layerInterp_mloopuv(void **sources, const float *weights, } /* origspace is almost exact copy of mloopuv's, keep in sync */ -static void layerCopyValue_mloop_origspace(const void *source, void *dest) +static void layerCopyValue_mloop_origspace(const void *source, void *dest, + const int UNUSED(mixmode), const float UNUSED(mixfactor)) { const OrigSpaceLoop *luv1 = source; OrigSpaceLoop *luv2 = dest; @@ -878,8 +976,9 @@ static void layerAdd_mloop_origspace(void *data1, const void *data2) add_v2_v2(l1->uv, l2->uv); } -static void layerInterp_mloop_origspace(void **sources, const float *weights, - const float *sub_weights, int count, void *dest) +static void layerInterp_mloop_origspace( + const void **sources, const float *weights, + const float *sub_weights, int count, void *dest) { float uv[2]; int i; @@ -890,7 +989,7 @@ static void layerInterp_mloop_origspace(void **sources, const float *weights, const float *sub_weight = sub_weights; for (i = 0; i < count; i++) { float weight = weights ? weights[i] : 1.0f; - OrigSpaceLoop *src = sources[i]; + const OrigSpaceLoop *src = sources[i]; madd_v2_v2fl(uv, src->uv, (*sub_weight) * weight); sub_weight++; } @@ -898,7 +997,7 @@ static void layerInterp_mloop_origspace(void **sources, const float *weights, else { for (i = 0; i < count; i++) { float weight = weights ? weights[i] : 1.0f; - OrigSpaceLoop *src = sources[i]; + const OrigSpaceLoop *src = sources[i]; madd_v2_v2fl(uv, src->uv, weight); } } @@ -908,8 +1007,9 @@ static void layerInterp_mloop_origspace(void **sources, const float *weights, } /* --- end copy */ -static void layerInterp_mcol(void **sources, const float *weights, - const float *sub_weights, int count, void *dest) +static void layerInterp_mcol( + const void **sources, const float *weights, + const float *sub_weights, int count, void *dest) { MCol *mc = dest; int i, j, k; @@ -930,7 +1030,7 @@ static void layerInterp_mcol(void **sources, const float *weights, for (j = 0; j < 4; ++j) { if (sub_weights) { - MCol *src = sources[i]; + const MCol *src = sources[i]; for (k = 0; k < 4; ++k, ++sub_weight, ++src) { const float w = (*sub_weight) * weight; col[j].a += src->a * w; @@ -940,7 +1040,7 @@ static void layerInterp_mcol(void **sources, const float *weights, } } else { - MCol *src = sources[i]; + const MCol *src = sources[i]; col[j].a += src[j].a * weight; col[j].r += src[j].r * weight; col[j].g += src[j].g * weight; @@ -994,8 +1094,9 @@ static void layerDefault_origindex(void *data, int count) fill_vn_i((int *)data, count, ORIGINDEX_NONE); } -static void layerInterp_bweight(void **sources, const float *weights, - const float *UNUSED(sub_weights), int count, void *dest) +static void layerInterp_bweight( + const void **sources, const float *weights, + const float *UNUSED(sub_weights), int count, void *dest) { float f; float **in = (float **)sources; @@ -1020,8 +1121,9 @@ static void layerInterp_bweight(void **sources, const float *weights, *((float *)dest) = f; } -static void layerInterp_shapekey(void **sources, const float *weights, - const float *UNUSED(sub_weights), int count, void *dest) +static void layerInterp_shapekey( + const void **sources, const float *weights, + const float *UNUSED(sub_weights), int count, void *dest) { float co[3]; float **in = (float **)sources; @@ -1057,26 +1159,27 @@ static void layerDefault_mvert_skin(void *data, int count) } } -static void layerInterp_mvert_skin(void **sources, const float *weights, - const float *UNUSED(sub_weights), - int count, void *dest) +static void layerInterp_mvert_skin( + const void **sources, const float *weights, + const float *UNUSED(sub_weights), + int count, void *dest) { + MVertSkin *vs_dst = dest; float radius[3], w; - MVertSkin *vs; int i; zero_v3(radius); for (i = 0; i < count; i++) { + const MVertSkin *vs_src = sources[i]; w = weights ? weights[i] : 1.0f; - vs = sources[i]; - madd_v3_v3fl(radius, vs->radius, w); + madd_v3_v3fl(radius, vs_src->radius, w); } /* delay writing to the destination incase dest is in sources */ - vs = dest; - copy_v3_v3(vs->radius, radius); - vs->flag &= ~MVERT_SKIN_ROOT; + vs_dst = dest; + copy_v3_v3(vs_dst->radius, radius); + vs_dst->flag &= ~MVERT_SKIN_ROOT; } static void layerSwap_flnor(void *data, const int *corner_indices) @@ -1116,7 +1219,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_origindex}, /* 8: CD_NORMAL */ /* 3 floats per normal vector */ - {sizeof(float) * 3, "vec3f", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(float) * 3, "vec3f", 1, NULL, NULL, NULL, layerInterp_normal, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, layerCopyValue_normal}, /* 9: CD_POLYINDEX (deprecated) */ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, /* 10: CD_PROP_FLT */ @@ -1206,6 +1310,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(float[4]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, /* 40: CD_TESSLOOPNORMAL */ {sizeof(short[4][3]), "", 0, NULL, NULL, NULL, NULL, layerSwap_flnor, NULL}, + /* 41: CD_CUSTOMLOOPNORMAL */ + {sizeof(short[2]), "vec2s", 1, NULL, NULL, NULL, NULL, NULL, NULL}, }; /* note, numbers are from trunk and need updating for bmesh */ @@ -1221,7 +1327,8 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = { /* 25-29 */ "CDMPoly", "CDMLoop", "CDShapeKeyIndex", "CDShapeKey", "CDBevelWeight", /* 30-34 */ "CDSubSurfCrease", "CDOrigSpaceLoop", "CDPreviewLoopCol", "CDBMElemPyPtr", "CDPaintMask", /* 35-36 */ "CDGridPaintMask", "CDMVertSkin", - /* 37-40 */ "CDFreestyleEdge", "CDFreestyleFace", "CDMLoopTangent", "CDTessLoopNormal", + /* 37-38 */ "CDFreestyleEdge", "CDFreestyleFace", + /* 39-41 */ "CDMLoopTangent", "CDTessLoopNormal", "CDCustomLoopNormal", }; @@ -1233,26 +1340,29 @@ const CustomDataMask CD_MASK_MESH = CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MPOLY | CD_MASK_MLOOP | CD_MASK_MTEXPOLY | CD_MASK_RECAST | CD_MASK_PAINT_MASK | - CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE; + CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE | + CD_MASK_CUSTOMLOOPNORMAL; const CustomDataMask CD_MASK_EDITMESH = CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_MCOL | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS | CD_MASK_SHAPEKEY | CD_MASK_RECAST | CD_MASK_PAINT_MASK | - CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN; + CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_CUSTOMLOOPNORMAL; const CustomDataMask CD_MASK_DERIVEDMESH = CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_CLOTH_ORCO | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_ORCO | CD_MASK_TANGENT | CD_MASK_PREVIEW_MCOL | CD_MASK_SHAPEKEY | CD_MASK_RECAST | - CD_MASK_ORIGINDEX | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE; + CD_MASK_ORIGINDEX | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE | + CD_MASK_CUSTOMLOOPNORMAL; const CustomDataMask CD_MASK_BMESH = CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_MDISPS | CD_MASK_CREASE | CD_MASK_BWEIGHT | CD_MASK_RECAST | CD_MASK_PAINT_MASK | - CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE; + CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE | + CD_MASK_CUSTOMLOOPNORMAL; const CustomDataMask CD_MASK_FACECORNERS = /* XXX Not used anywhere! */ CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT; @@ -1267,7 +1377,7 @@ const CustomDataMask CD_MASK_EVERYTHING = /* BMESH ONLY END */ CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE | - CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL; + CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL; static const LayerTypeInfo *layerType_getInfo(int type) { @@ -1449,6 +1559,25 @@ void CustomData_free(CustomData *data, int totelem) CustomData_reset(data); } +void CustomData_free_typemask(struct CustomData *data, int totelem, CustomDataMask mask) +{ + int i; + + for (i = 0; i < data->totlayer; ++i) { + CustomDataLayer *layer = &data->layers[i]; + if (!(mask & CD_TYPE_AS_MASK(layer->type))) { + continue; + } + customData_free_layer__internal(layer, totelem); + } + + if (data->layers) + MEM_freeN(data->layers); + + CustomData_external_free(data); + CustomData_reset(data); +} + static void customData_update_offsets(CustomData *data) { const LayerTypeInfo *typeInfo; @@ -1504,7 +1633,7 @@ int CustomData_get_named_layer_index(const CustomData *data, int type, const cha for (i = 0; i < data->totlayer; ++i) if (data->layers[i].type == type) - if (strcmp(data->layers[i].name, name) == 0) + if (STREQ(data->layers[i].name, name)) return i; return -1; @@ -1680,7 +1809,8 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ int totelem, const char *name) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); - int size = typeInfo->size * totelem, flag = 0, index = data->totlayer; + const int size = totelem * typeInfo->size; + int flag = 0, index = data->totlayer; void *newlayerdata = NULL; /* Passing a layerdata to copy from with an alloctype that won't copy is @@ -1699,7 +1829,13 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ newlayerdata = layerdata; } else if (size > 0) { - newlayerdata = MEM_callocN(size, layerType_getName(type)); + if (alloctype == CD_DUPLICATE && layerdata) { + newlayerdata = MEM_mallocN(size, layerType_getName(type)); + } + else { + newlayerdata = MEM_callocN(size, layerType_getName(type)); + } + if (!newlayerdata) return NULL; } @@ -1712,7 +1848,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ } else if (alloctype == CD_DEFAULT) { if (typeInfo->set_default) - typeInfo->set_default((char *)newlayerdata, totelem); + typeInfo->set_default(newlayerdata, totelem); } else if (alloctype == CD_REFERENCE) flag |= CD_FLAG_NOFREE; @@ -1798,7 +1934,8 @@ bool CustomData_free_layer(CustomData *data, int type, int totelem, int index) const int n = index - CustomData_get_layer_index(data, type); int i; - if (index < 0) return 0; + if (index < 0) + return false; customData_free_layer__internal(&data->layers[index], totelem); @@ -1828,14 +1965,15 @@ bool CustomData_free_layer(CustomData *data, int type, int totelem, int index) customData_update_offsets(data); - return 1; + return true; } bool CustomData_free_layer_active(CustomData *data, int type, int totelem) { int index = 0; index = CustomData_get_active_layer_index(data, type); - if (index == -1) return 0; + if (index == -1) + return false; return CustomData_free_layer(data, type, totelem, index); } @@ -1873,14 +2011,13 @@ int CustomData_number_of_layers_typemask(const CustomData *data, CustomDataMask return number; } -void *CustomData_duplicate_referenced_layer(struct CustomData *data, const int type, const int totelem) +static void *customData_duplicate_referenced_layer_index(CustomData *data, const int layer_index, const int totelem) { CustomDataLayer *layer; - int layer_index; - /* get the layer index of the first layer of type */ - layer_index = CustomData_get_active_layer_index(data, type); - if (layer_index == -1) return NULL; + if (layer_index == -1) { + return NULL; + } layer = &data->layers[layer_index]; @@ -1892,12 +2029,13 @@ void *CustomData_duplicate_referenced_layer(struct CustomData *data, const int t const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if (typeInfo->copy) { - char *dest_data = MEM_mallocN(typeInfo->size * totelem, "CD duplicate ref layer"); - typeInfo->copy(layer->data, dest_data, totelem); - layer->data = dest_data; + void *dst_data = MEM_mallocN(totelem * typeInfo->size, "CD duplicate ref layer"); + typeInfo->copy(layer->data, dst_data, totelem); + layer->data = dst_data; } - else + else { layer->data = MEM_dupallocN(layer->data); + } layer->flag &= ~CD_FLAG_NOFREE; } @@ -1905,37 +2043,34 @@ void *CustomData_duplicate_referenced_layer(struct CustomData *data, const int t return layer->data; } -void *CustomData_duplicate_referenced_layer_named(struct CustomData *data, - const int type, const char *name, const int totelem) +void *CustomData_duplicate_referenced_layer(CustomData *data, const int type, const int totelem) { - CustomDataLayer *layer; int layer_index; - /* get the layer index of the desired layer */ - layer_index = CustomData_get_named_layer_index(data, type, name); - if (layer_index == -1) return NULL; + /* get the layer index of the first layer of type */ + layer_index = CustomData_get_active_layer_index(data, type); - layer = &data->layers[layer_index]; + return customData_duplicate_referenced_layer_index(data, layer_index, totelem); +} - if (layer->flag & CD_FLAG_NOFREE) { - /* MEM_dupallocN won't work in case of complex layers, like e.g. - * CD_MDEFORMVERT, which has pointers to allocated data... - * So in case a custom copy function is defined, use it! - */ - const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); +void *CustomData_duplicate_referenced_layer_n(CustomData *data, const int type, const int n, const int totelem) +{ + int layer_index; - if (typeInfo->copy) { - char *dest_data = MEM_mallocN(typeInfo->size * totelem, "CD duplicate ref layer"); - typeInfo->copy(layer->data, dest_data, totelem); - layer->data = dest_data; - } - else - layer->data = MEM_dupallocN(layer->data); + /* get the layer index of the desired layer */ + layer_index = CustomData_get_layer_index_n(data, type, n); - layer->flag &= ~CD_FLAG_NOFREE; - } + return customData_duplicate_referenced_layer_index(data, layer_index, totelem); +} - return layer->data; +void *CustomData_duplicate_referenced_layer_named(CustomData *data, const int type, const char *name, const int totelem) +{ + int layer_index; + + /* get the layer index of the desired layer */ + layer_index = CustomData_get_named_layer_index(data, type, name); + + return customData_duplicate_referenced_layer_index(data, layer_index, totelem); } bool CustomData_is_referenced_layer(struct CustomData *data, int type) @@ -1945,7 +2080,8 @@ bool CustomData_is_referenced_layer(struct CustomData *data, int type) /* get the layer index of the first layer of type */ layer_index = CustomData_get_active_layer_index(data, type); - if (layer_index == -1) return 0; + if (layer_index == -1) + return false; layer = &data->layers[layer_index]; @@ -1994,47 +2130,48 @@ void CustomData_set_only_copy(const struct CustomData *data, data->layers[i].flag |= CD_FLAG_NOCOPY; } -void CustomData_copy_elements(int type, void *source, void *dest, int count) +void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs, int count) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); if (typeInfo->copy) - typeInfo->copy(source, dest, count); + typeInfo->copy(src_data_ofs, dst_data_ofs, count); else - memcpy(dest, source, typeInfo->size * count); + memcpy(dst_data_ofs, src_data_ofs, count * typeInfo->size); } -static void CustomData_copy_data_layer(const CustomData *source, CustomData *dest, - int src_i, int dest_i, - int source_index, int dest_index, int count) { +static void CustomData_copy_data_layer( + const CustomData *source, CustomData *dest, + int src_i, int dst_i, + int src_index, int dst_index, int count) { const LayerTypeInfo *typeInfo; int src_offset; - int dest_offset; + int dst_offset; - const char *src_data = source->layers[src_i].data; - char *dest_data = dest->layers[dest_i].data; + const void *src_data = source->layers[src_i].data; + void *dst_data = dest->layers[dst_i].data; typeInfo = layerType_getInfo(source->layers[src_i].type); - src_offset = source_index * typeInfo->size; - dest_offset = dest_index * typeInfo->size; + src_offset = src_index * typeInfo->size; + dst_offset = dst_index * typeInfo->size; - if (!src_data || !dest_data) { - if (!(src_data == NULL && dest_data == NULL)) { + if (!src_data || !dst_data) { + if (!(src_data == NULL && dst_data == NULL)) { printf("%s: warning null data for %s type (%p --> %p), skipping\n", __func__, layerType_getName(source->layers[src_i].type), - (void *)src_data, (void *)dest_data); + (void *)src_data, (void *)dst_data); } return; } if (typeInfo->copy) - typeInfo->copy(src_data + src_offset, - dest_data + dest_offset, + typeInfo->copy(POINTER_OFFSET(src_data, src_offset), + POINTER_OFFSET(dst_data, dst_offset), count); else - memcpy(dest_data + dest_offset, - src_data + src_offset, + memcpy(POINTER_OFFSET(dst_data, dst_offset), + POINTER_OFFSET(src_data, src_offset), count * typeInfo->size); } @@ -2097,10 +2234,9 @@ void CustomData_free_elem(CustomData *data, int index, int count) typeInfo = layerType_getInfo(data->layers[i].type); if (typeInfo->free) { - int offset = typeInfo->size * index; + int offset = index * typeInfo->size; - typeInfo->free((char *)data->layers[i].data + offset, - count, typeInfo->size); + typeInfo->free(POINTER_OFFSET(data->layers[i].data, offset), count, typeInfo->size); } } } @@ -2113,17 +2249,15 @@ void CustomData_interp(const CustomData *source, CustomData *dest, int count, int dest_index) { int src_i, dest_i; - int dest_offset; int j; - void *source_buf[SOURCE_BUF_SIZE]; - void **sources = source_buf; + const void *source_buf[SOURCE_BUF_SIZE]; + const void **sources = source_buf; /* slow fallback in case we're interpolating a ridiculous number of * elements */ if (count > SOURCE_BUF_SIZE) - sources = MEM_callocN(sizeof(*sources) * count, - "CustomData_interp sources"); + sources = MEM_mallocN(sizeof(*sources) * count, __func__); /* interpolates a layer at a time */ dest_i = 0; @@ -2146,13 +2280,11 @@ void CustomData_interp(const CustomData *source, CustomData *dest, void *src_data = source->layers[src_i].data; for (j = 0; j < count; ++j) { - sources[j] = (char *)src_data + typeInfo->size * src_indices[j]; + sources[j] = POINTER_OFFSET(src_data, src_indices[j] * typeInfo->size); } - dest_offset = dest_index * typeInfo->size; - typeInfo->interp(sources, weights, sub_weights, count, - (char *)dest->layers[dest_i].data + dest_offset); + POINTER_OFFSET(dest->layers[dest_i].data, dest_index * typeInfo->size)); /* if there are multiple source & dest layers of the same type, * we don't want to copy all source layers to the same dest, so @@ -2174,9 +2306,9 @@ void CustomData_swap(struct CustomData *data, int index, const int *corner_indic typeInfo = layerType_getInfo(data->layers[i].type); if (typeInfo->swap) { - int offset = typeInfo->size * index; + const int offset = index * typeInfo->size; - typeInfo->swap((char *)data->layers[i].data + offset, corner_indices); + typeInfo->swap(POINTER_OFFSET(data->layers[i].data, offset), corner_indices); } } } @@ -2195,7 +2327,7 @@ void *CustomData_get(const CustomData *data, int index, int type) /* get the offset of the desired element */ offset = layerType_getInfo(type)->size * index; - return (char *)data->layers[layer_index].data + offset; + return POINTER_OFFSET(data->layers[layer_index].data, offset); } void *CustomData_get_n(const CustomData *data, int type, int index, int n) @@ -2210,7 +2342,7 @@ void *CustomData_get_n(const CustomData *data, int type, int index, int n) if (layer_index == -1) return NULL; offset = layerType_getInfo(type)->size * index; - return (char *)data->layers[layer_index + n].data + offset; + return POINTER_OFFSET(data->layers[layer_index + n].data, offset); } void *CustomData_get_layer(const CustomData *data, int type) @@ -2261,16 +2393,23 @@ int CustomData_get_n_offset(const CustomData *data, int type, int n) bool CustomData_set_layer_name(const CustomData *data, int type, int n, const char *name) { /* get the layer index of the first layer of type */ - int layer_index = CustomData_get_layer_index_n(data, type, n); + const int layer_index = CustomData_get_layer_index_n(data, type, n); - if (layer_index == -1) return false; - if (!name) return false; + if ((layer_index == -1) || !name) + return false; BLI_strncpy(data->layers[layer_index].name, name, sizeof(data->layers[layer_index].name)); return true; } +const char *CustomData_get_layer_name(const CustomData *data, int type, int n) +{ + const int layer_index = CustomData_get_layer_index_n(data, type, n); + + return (layer_index == -1) ? NULL : data->layers[layer_index].name; +} + void *CustomData_set_layer(const CustomData *data, int type, void *ptr) { /* get the layer index of the first layer of type */ @@ -2294,7 +2433,7 @@ void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, voi return ptr; } -void CustomData_set(const CustomData *data, int index, int type, void *source) +void CustomData_set(const CustomData *data, int index, int type, const void *source) { void *dest = CustomData_get(data, index, type); const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -2459,8 +2598,9 @@ void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype) } } -bool CustomData_bmesh_merge(CustomData *source, CustomData *dest, - CustomDataMask mask, int alloctype, BMesh *bm, const char htype) +bool CustomData_bmesh_merge( + const CustomData *source, CustomData *dest, + CustomDataMask mask, int alloctype, BMesh *bm, const char htype) { BMHeader *h; BMIter iter; @@ -2557,7 +2697,7 @@ void CustomData_bmesh_free_block(CustomData *data, void **block) if (typeInfo->free) { int offset = data->layers[i].offset; - typeInfo->free((char *)*block + offset, 1, typeInfo->size); + typeInfo->free(POINTER_OFFSET(*block, offset), 1, typeInfo->size); } } } @@ -2585,7 +2725,7 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block) if (typeInfo->free) { int offset = data->layers[i].offset; - typeInfo->free((char *)block + offset, 1, typeInfo->size); + typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size); } } } @@ -2634,10 +2774,10 @@ void CustomData_bmesh_copy_data(const CustomData *source, CustomData *dest, /* if we found a matching layer, copy the data */ if (dest->layers[dest_i].type == source->layers[src_i].type && - strcmp(dest->layers[dest_i].name, source->layers[src_i].name) == 0) + STREQ(dest->layers[dest_i].name, source->layers[src_i].name)) { - const char *src_data = (char *)src_block + source->layers[src_i].offset; - char *dest_data = (char *)*dest_block + dest->layers[dest_i].offset; + const void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset); + void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset); typeInfo = layerType_getInfo(source->layers[src_i].type); @@ -2664,7 +2804,7 @@ void *CustomData_bmesh_get(const CustomData *data, void *block, int type) layer_index = CustomData_get_active_layer_index(data, type); if (layer_index == -1) return NULL; - return (char *)block + data->layers[layer_index].offset; + return POINTER_OFFSET(block, data->layers[layer_index].offset); } void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int n) @@ -2675,7 +2815,7 @@ void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int layer_index = CustomData_get_layer_index(data, type); if (layer_index == -1) return NULL; - return (char *)block + data->layers[layer_index + n].offset; + return POINTER_OFFSET(block, data->layers[layer_index + n].offset); } /*gets from the layer at physical index n, note: doesn't check type.*/ @@ -2683,7 +2823,7 @@ void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n) { if (n < 0 || n >= data->totlayer) return NULL; - return (char *)block + data->layers[n].offset; + return POINTER_OFFSET(block, data->layers[n].offset); } bool CustomData_layer_has_math(const struct CustomData *data, int layer_n) @@ -2755,6 +2895,17 @@ bool CustomData_has_interp(const struct CustomData *data) return false; } +bool CustomData_has_referenced(const struct CustomData *data) +{ + int i; + for (i = 0; i < data->totlayer; ++i) { + if (data->layers[i].flag & CD_FLAG_NOFREE) { + return true; + } + } + return false; +} + /* copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to * another, while not overwriting anything else (e.g. flags)*/ void CustomData_data_copy_value(int type, const void *source, void *dest) @@ -2764,11 +2915,28 @@ void CustomData_data_copy_value(int type, const void *source, void *dest) if (!dest) return; if (typeInfo->copyvalue) - typeInfo->copyvalue(source, dest); + typeInfo->copyvalue(source, dest, CDT_MIX_NOMIX, 0.0f); else memcpy(dest, source, typeInfo->size); } +/* Mixes the "value" (e.g. mloopuv uv or mloopcol colors) from one block into + * another, while not overwriting anything else (e.g. flags)*/ +void CustomData_data_mix_value(int type, const void *source, void *dest, const int mixmode, const float mixfactor) +{ + const LayerTypeInfo *typeInfo = layerType_getInfo(type); + + if (!dest) return; + + if (typeInfo->copyvalue) { + typeInfo->copyvalue(source, dest, mixmode, mixfactor); + } + else { + /* Mere copy if no advanced interpolation is supported. */ + memcpy(dest, source, typeInfo->size); + } +} + bool CustomData_data_equals(int type, const void *data1, const void *data2) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -2813,7 +2981,7 @@ void CustomData_data_add(int type, void *data1, const void *data2) typeInfo->add(data1, data2); } -void CustomData_bmesh_set(const CustomData *data, void *block, int type, void *source) +void CustomData_bmesh_set(const CustomData *data, void *block, int type, const void *source) { void *dest = CustomData_bmesh_get(data, block, type); const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -2826,7 +2994,7 @@ void CustomData_bmesh_set(const CustomData *data, void *block, int type, void *s memcpy(dest, source, typeInfo->size); } -void CustomData_bmesh_set_n(CustomData *data, void *block, int type, int n, void *source) +void CustomData_bmesh_set_n(CustomData *data, void *block, int type, int n, const void *source) { void *dest = CustomData_bmesh_get_n(data, block, type, n); const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -2839,7 +3007,7 @@ void CustomData_bmesh_set_n(CustomData *data, void *block, int type, int n, void memcpy(dest, source, typeInfo->size); } -void CustomData_bmesh_set_layer_n(CustomData *data, void *block, int n, void *source) +void CustomData_bmesh_set_layer_n(CustomData *data, void *block, int n, const void *source) { void *dest = CustomData_bmesh_get_layer_n(data, block, n); const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type); @@ -2853,31 +3021,34 @@ void CustomData_bmesh_set_layer_n(CustomData *data, void *block, int n, void *so } /** - * \param src_blocks must be pointers to the data, offset by layer->offset already. + * \note src_blocks_ofs & dst_block_ofs + * must be pointers to the data, offset by layer->offset already. */ -void CustomData_bmesh_interp_n(CustomData *data, void **src_blocks, const float *weights, - const float *sub_weights, int count, void *dest_block, int n) +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) { CustomDataLayer *layer = &data->layers[n]; const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); - typeInfo->interp(src_blocks, weights, sub_weights, count, - (char *)dest_block + layer->offset); + typeInfo->interp(src_blocks_ofs, weights, sub_weights, count, dst_block_ofs); } -void CustomData_bmesh_interp(CustomData *data, void **src_blocks, const float *weights, - const float *sub_weights, int count, void *dest_block) +void CustomData_bmesh_interp( + CustomData *data, const void **src_blocks, + const float *weights, const float *sub_weights, + int count, void *dst_block) { int i, j; void *source_buf[SOURCE_BUF_SIZE]; - void **sources = source_buf; + const void **sources = (const void **)source_buf; /* slow fallback in case we're interpolating a ridiculous number of * elements */ if (count > SOURCE_BUF_SIZE) - sources = MEM_callocN(sizeof(*sources) * count, - "CustomData_interp sources"); + sources = MEM_mallocN(sizeof(*sources) * count, __func__); /* interpolates a layer at a time */ for (i = 0; i < data->totlayer; ++i) { @@ -2885,13 +3056,16 @@ void CustomData_bmesh_interp(CustomData *data, void **src_blocks, const float *w const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if (typeInfo->interp) { for (j = 0; j < count; ++j) { - sources[j] = (char *)src_blocks[j] + layer->offset; + sources[j] = POINTER_OFFSET(src_blocks[j], layer->offset); } - CustomData_bmesh_interp_n(data, sources, weights, sub_weights, count, dest_block, i); + CustomData_bmesh_interp_n( + data, sources, + weights, sub_weights, count, + POINTER_OFFSET(dst_block, layer->offset), i); } } - if (count > SOURCE_BUF_SIZE) MEM_freeN(sources); + if (count > SOURCE_BUF_SIZE) MEM_freeN((void *)sources); } static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n) @@ -2902,10 +3076,10 @@ static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n typeInfo = layerType_getInfo(data->layers[n].type); if (typeInfo->set_default) { - typeInfo->set_default((char *)*block + offset, 1); + typeInfo->set_default(POINTER_OFFSET(*block, offset), 1); } else { - memset((char *)*block + offset, 0, typeInfo->size); + memset(POINTER_OFFSET(*block, offset), 0, typeInfo->size); } } @@ -2955,16 +3129,16 @@ void CustomData_to_bmesh_block(const CustomData *source, CustomData *dest, /* if we found a matching layer, copy the data */ if (dest->layers[dest_i].type == source->layers[src_i].type) { int offset = dest->layers[dest_i].offset; - const char *src_data = source->layers[src_i].data; - char *dest_data = (char *)*dest_block + offset; + const void *src_data = source->layers[src_i].data; + void *dest_data = POINTER_OFFSET(*dest_block, offset); typeInfo = layerType_getInfo(dest->layers[dest_i].type); src_offset = src_index * typeInfo->size; if (typeInfo->copy) - typeInfo->copy(src_data + src_offset, dest_data, 1); + typeInfo->copy(POINTER_OFFSET(src_data, src_offset), dest_data, 1); else - memcpy(dest_data, src_data + src_offset, typeInfo->size); + memcpy(dest_data, POINTER_OFFSET(src_data, src_offset), typeInfo->size); /* if there are multiple source & dest layers of the same type, * we don't want to copy all source layers to the same dest, so @@ -2983,10 +3157,9 @@ void CustomData_to_bmesh_block(const CustomData *source, CustomData *dest, } void CustomData_from_bmesh_block(const CustomData *source, CustomData *dest, - void *src_block, int dest_index) + void *src_block, int dst_index) { - const LayerTypeInfo *typeInfo; - int dest_i, src_i, dest_offset; + int dest_i, src_i; /* copies a layer at a time */ dest_i = 0; @@ -3004,17 +3177,15 @@ void CustomData_from_bmesh_block(const CustomData *source, CustomData *dest, /* if we found a matching layer, copy the data */ if (dest->layers[dest_i].type == source->layers[src_i].type) { + const LayerTypeInfo *typeInfo = layerType_getInfo(dest->layers[dest_i].type); int offset = source->layers[src_i].offset; - const char *src_data = (char *)src_block + offset; - char *dest_data = dest->layers[dest_i].data; - - typeInfo = layerType_getInfo(dest->layers[dest_i].type); - dest_offset = dest_index * typeInfo->size; + const void *src_data = POINTER_OFFSET(src_block, offset); + void *dst_data = POINTER_OFFSET(dest->layers[dest_i].data, dst_index * typeInfo->size); if (typeInfo->copy) - typeInfo->copy(src_data, dest_data + dest_offset, 1); + typeInfo->copy(src_data, dst_data, 1); else - memcpy(dest_data + dest_offset, src_data, typeInfo->size); + memcpy(dst_data, src_data, typeInfo->size); /* if there are multiple source & dest layers of the same type, * we don't want to copy all source layers to the same dest, so @@ -3090,12 +3261,12 @@ static bool cd_layer_find_dupe(CustomData *data, const char *name, int type, int CustomDataLayer *layer = &data->layers[i]; if (CustomData_is_property_layer(type)) { - if (CustomData_is_property_layer(layer->type) && strcmp(layer->name, name) == 0) { + if (CustomData_is_property_layer(layer->type) && STREQ(layer->name, name)) { return true; } } else { - if (i != index && layer->type == type && strcmp(layer->name, name) == 0) { + if (i != index && layer->type == type && STREQ(layer->name, name)) { return true; } } @@ -3464,3 +3635,234 @@ void CustomData_external_remove_object(CustomData *data, ID *id) } #endif +/* ********** Mesh-to-mesh data transfer ********** */ +static void copy_bit_flag(void *dst, const void *src, const size_t data_size, const uint64_t flag) +{ +#define COPY_BIT_FLAG(_type, _dst, _src, _f) \ +{ \ + const _type _val = *((_type *)(_src)) & ((_type)(_f)); \ + *((_type *)(_dst)) &= ~((_type)(_f)); \ + *((_type *)(_dst)) |= _val; \ +} (void) 0 + + switch (data_size) { + case 1: + COPY_BIT_FLAG(uint8_t, dst, src, flag); + break; + case 2: + COPY_BIT_FLAG(uint16_t, dst, src, flag); + break; + case 4: + COPY_BIT_FLAG(uint32_t, dst, src, flag); + break; + case 8: + COPY_BIT_FLAG(uint64_t, dst, src, flag); + break; + default: + //printf("ERROR %s: Unknown flags-container size (%zu)\n", __func__, datasize); + break; + } + +#undef COPY_BIT_FLAG +} + +static bool check_bit_flag(const void *data, const size_t data_size, const uint64_t flag) +{ + switch (data_size) { + case 1: + return ((*((uint8_t *)data) & ((uint8_t)flag)) != 0); + case 2: + return ((*((uint16_t *)data) & ((uint16_t)flag)) != 0); + case 4: + return ((*((uint32_t *)data) & ((uint32_t)flag)) != 0); + case 8: + return ((*((uint64_t *)data) & ((uint64_t)flag)) != 0); + default: + //printf("ERROR %s: Unknown flags-container size (%zu)\n", __func__, datasize); + return false; + } +} + +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) +{ + /* Fake interpolation, we actually copy highest weighted source to dest. + * Note we also handle bitflags here, in which case we rather choose to transfer value of elements totaling + * more than 0.5 of weight. */ + + int best_src_idx = 0; + + const int data_type = laymap->data_type; + const int mix_mode = laymap->mix_mode; + + size_t data_size; + const uint64_t data_flag = laymap->data_flag; + + cd_interp interp_cd = NULL; + cd_copy copy_cd = NULL; + + void *tmp_dst; + + if (!sources) { + /* Not supported here, abort. */ + return; + } + + if (data_type & CD_FAKE) { + data_size = laymap->data_size; + } + else { + const LayerTypeInfo *type_info = layerType_getInfo(data_type); + + data_size = (size_t)type_info->size; + interp_cd = type_info->interp; + copy_cd = type_info->copy; + } + + tmp_dst = MEM_mallocN(data_size, __func__); + + if (count > 1 && !interp_cd) { + int i; + + if (data_flag) { + /* Boolean case, we can 'interpolate' in two groups, and choose value from highest weighted group. */ + float tot_weight_true = 0.0f; + int item_true_idx = -1, item_false_idx = -1; + + for (i = 0; i < count; i++) { + if (check_bit_flag(sources[i], data_size, data_flag)) { + tot_weight_true += weights[i]; + item_true_idx = i; + } + else { + item_false_idx = i; + } + } + best_src_idx = (tot_weight_true >= 0.5f) ? item_true_idx : item_false_idx; + } + else { + /* We just choose highest weighted source. */ + float max_weight = 0.0f; + + for (i = 0; i < count; i++) { + if (weights[i] > max_weight) { + max_weight = weights[i]; + best_src_idx = i; + } + } + } + } + + BLI_assert(best_src_idx >= 0); + + if (interp_cd) { + interp_cd(sources, weights, NULL, count, tmp_dst); + } + else if (data_flag) { + copy_bit_flag(tmp_dst, sources[best_src_idx], data_size, data_flag); + } + /* No interpolation, just copy highest weight source element's data. */ + else if (copy_cd) { + copy_cd(sources[best_src_idx], tmp_dst, 1); + } + else { + memcpy(tmp_dst, sources[best_src_idx], data_size); + } + + if (data_flag) { + /* Bool flags, only copy if dest data is set (resp. unset) - only 'advanced' modes we can support here! */ + if (mix_factor >= 0.5f && + ((mix_mode == CDT_MIX_TRANSFER) || + (mix_mode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && check_bit_flag(data_dst, data_size, data_flag)) || + (mix_mode == CDT_MIX_REPLACE_BELOW_THRESHOLD && !check_bit_flag(data_dst, data_size, data_flag)))) + { + copy_bit_flag(data_dst, tmp_dst, data_size, data_flag); + } + } + else if (!(data_type & CD_FAKE)) { + CustomData_data_mix_value(data_type, tmp_dst, data_dst, mix_mode, mix_factor); + } + /* Else we can do nothing by default, needs custom interp func! + * Note this is here only for sake of consistency, not expected to be used much actually? */ + else { + if (mix_factor >= 0.5f) { + memcpy(data_dst, tmp_dst, data_size); + } + } + + MEM_freeN(tmp_dst); +} + +void CustomData_data_transfer(const MeshPairRemap *me_remap, const CustomDataTransferLayerMap *laymap) +{ + MeshPairRemapItem *mapit = me_remap->items; + const int totelem = me_remap->items_num; + int i; + + const int data_type = laymap->data_type; + const void *data_src = laymap->data_src; + void *data_dst = laymap->data_dst; + + size_t data_step; + size_t data_size; + size_t data_offset; + + cd_datatransfer_interp interp = NULL; + + size_t tmp_buff_size = 32; + const void **tmp_data_src = NULL; + + /* Note: NULL data_src may happen and be valid (see vgroups...). */ + if (!data_dst) { + return; + } + + if (data_src) { + tmp_data_src = MEM_mallocN(sizeof(*tmp_data_src) * tmp_buff_size, __func__); + } + + if (data_type & CD_FAKE) { + data_step = laymap->elem_size; + data_size = laymap->data_size; + data_offset = laymap->data_offset; + } + else { + const LayerTypeInfo *type_info = layerType_getInfo(data_type); + + /* Note: we can use 'fake' CDLayers, like e.g. for crease, bweight, etc. :/ */ + data_size = (size_t)type_info->size; + data_step = laymap->elem_size ? laymap->elem_size : data_size; + data_offset = laymap->data_offset; + } + + interp = laymap->interp ? laymap->interp : customdata_data_transfer_interp_generic; + + for (i = 0; i < totelem; i++, data_dst = POINTER_OFFSET(data_dst, data_step), mapit++) { + const int sources_num = mapit->sources_num; + const float mix_factor = laymap->mix_weights ? laymap->mix_weights[i] : laymap->mix_factor; + int j; + + if (!sources_num) { + /* No sources for this element, skip it. */ + continue; + } + + if (tmp_data_src) { + if (UNLIKELY(sources_num > tmp_buff_size)) { + tmp_buff_size = (size_t)sources_num; + tmp_data_src = MEM_reallocN(tmp_data_src, sizeof(*tmp_data_src) * tmp_buff_size); + } + + for (j = 0; j < sources_num; j++) { + const size_t src_idx = (size_t)mapit->indices_src[j]; + tmp_data_src[j] = POINTER_OFFSET(data_src, (data_step * src_idx) + data_offset); + } + } + + interp(laymap, POINTER_OFFSET(data_dst, data_offset), tmp_data_src, mapit->weights_src, sources_num, mix_factor); + } + + MEM_SAFE_FREE(tmp_data_src); +} |