diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index f6b4240a026..1d344c6e810 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -121,9 +121,9 @@ int CustomData_number_of_layers(const struct CustomData *data, int type); /* duplicate data of a layer with flag NOFREE, and remove that flag. * returns the layer data */ -void *CustomData_duplicate_referenced_layer(struct CustomData *data, int type); +void *CustomData_duplicate_referenced_layer(struct CustomData *data, const int type, const int totelem); void *CustomData_duplicate_referenced_layer_named(struct CustomData *data, - int type, const char *name); + const int type, const char *name, const int totelem); /* set the CD_FLAG_NOCOPY flag in custom data layers where the mask is * zero for the layer type, so only layer types specified by the mask diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 2cf2225607e..6f088b8abf7 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -1870,7 +1870,7 @@ void CDDM_apply_vert_coords(DerivedMesh *dm, float (*vertCoords)[3]) int i; /* this will just return the pointer if it wasn't a referenced layer */ - vert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT); + vert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData); cddm->mvert = vert; for(i = 0; i < dm->numVertData; ++i, ++vert) @@ -1884,7 +1884,7 @@ void CDDM_apply_vert_normals(DerivedMesh *dm, short (*vertNormals)[3]) int i; /* this will just return the pointer if it wasn't a referenced layer */ - vert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT); + vert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData); cddm->mvert = vert; for(i = 0; i < dm->numVertData; ++i, ++vert) @@ -1899,7 +1899,7 @@ void CDDM_calc_normals(DerivedMesh *dm) if(dm->numVertData == 0) return; /* we don't want to overwrite any referenced layers */ - cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT); + cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData); /* make a face normal layer if not present */ face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL); diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index c88b21e2813..5305372402b 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1404,7 +1404,7 @@ int CustomData_number_of_layers(const CustomData *data, int type) return number; } -void *CustomData_duplicate_referenced_layer(struct CustomData *data, int type) +void *CustomData_duplicate_referenced_layer(struct CustomData *data, const int type, const int totelem) { CustomDataLayer *layer; int layer_index; @@ -1416,7 +1416,20 @@ void *CustomData_duplicate_referenced_layer(struct CustomData *data, int type) layer = &data->layers[layer_index]; if (layer->flag & CD_FLAG_NOFREE) { - layer->data = MEM_dupallocN(layer->data); + /* 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); + + 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); + layer->flag &= ~CD_FLAG_NOFREE; } @@ -1424,7 +1437,7 @@ void *CustomData_duplicate_referenced_layer(struct CustomData *data, int type) } void *CustomData_duplicate_referenced_layer_named(struct CustomData *data, - int type, const char *name) + const int type, const char *name, const int totelem) { CustomDataLayer *layer; int layer_index; @@ -1436,7 +1449,20 @@ void *CustomData_duplicate_referenced_layer_named(struct CustomData *data, layer = &data->layers[layer_index]; if (layer->flag & CD_FLAG_NOFREE) { - layer->data = MEM_dupallocN(layer->data); + /* 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); + + 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); + layer->flag &= ~CD_FLAG_NOFREE; } diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index 347af0066c6..067d66fc82c 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -75,8 +75,8 @@ static void dm_calc_normal(DerivedMesh *dm, float (*temp_nors)[3]) /* we don't want to overwrite any referenced layers */ /* - Dosnt work here! - mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT); + Doesn't work here! + mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, numVerts); cddm->mvert = mv; */ diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index acf65a56561..3146d1c9d5d 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -259,11 +259,12 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal); } + numFaces = dm->getNumFaces(dm); + /* make sure we are not modifying the original UV map */ tface = CustomData_duplicate_referenced_layer_named(&dm->faceData, - CD_MTFACE, uvname); + CD_MTFACE, uvname, numFaces); - numVerts = dm->getNumVerts(dm); coords = MEM_callocN(sizeof(*coords) * numVerts, @@ -280,7 +281,6 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, mul_project_m4_v3(projectors[0].projmat, *co); mface = dm->getFaceArray(dm); - numFaces = dm->getNumFaces(dm); /* apply coords as UVs, and apply image if tfaces are new */ for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tface) {