diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_mesh.h | 14 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh_convert.c | 347 | ||||
-rw-r--r-- | source/blender/editors/object/object_modifier.c | 18 |
3 files changed, 370 insertions, 9 deletions
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index d3b492983de..efbc00c456f 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -34,6 +34,9 @@ /* defines BLI_INLINE */ #include "BLI_utildefines.h" +/* defines CustomDataMask */ +#include "BKE_customdata.h" + struct ID; struct BMeshCreateParams; struct BMeshFromMeshParams; @@ -46,9 +49,11 @@ struct LinkNode; struct BLI_Stack; struct MemArena; struct BMesh; +struct KeyBlock; struct MLoopTri; struct Main; struct Mesh; +struct ModifierData; struct MPoly; struct MLoop; struct MFace; @@ -168,6 +173,15 @@ void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals); struct Mesh *BKE_mesh_new_from_object( struct Depsgraph *depsgraph, struct Main *bmain, struct Scene *sce, struct Object *ob, const bool apply_modifiers, const bool calc_tessface, const bool calc_undeformed); +struct Mesh *BKE_mesh_create_derived_for_modifier( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, + struct ModifierData *md, int build_shapekey_layers); + +/* Copies a nomain-Mesh into an existing Mesh. */ +void BKE_nomain_mesh_to_mesh(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct Object *ob, + CustomDataMask mask, bool take_ownership); +void BKE_nomain_mesh_to_meshkey(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct KeyBlock *kb); + /* vertex level transformations & checks (no derived mesh) */ diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index b2ff79cd933..a3eef7b17b2 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -26,6 +26,7 @@ #include "MEM_guardedalloc.h" #include "DNA_scene_types.h" +#include "DNA_key_types.h" #include "DNA_material_types.h" #include "DNA_meta_types.h" #include "DNA_object_types.h" @@ -40,7 +41,9 @@ #include "BKE_main.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" +#include "BKE_key.h" #include "BKE_mesh.h" +#include "BKE_modifier.h" #include "BKE_displist.h" #include "BKE_library.h" #include "BKE_material.h" @@ -58,6 +61,12 @@ */ // #undef VALIDATE_MESH +#ifdef VALIDATE_MESH +# define ASSERT_IS_VALID_MESH(mesh) (BLI_assert((mesh == NULL) || (BKE_mesh_is_valid(mesh) == true))) +#else +# define ASSERT_IS_VALID_MESH(mesh) +#endif + void BKE_mesh_from_metaball(ListBase *lb, Mesh *me) { DispList *dl; @@ -1088,3 +1097,341 @@ Mesh *BKE_mesh_new_from_object( return tmpmesh; } + + +static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src) +{ + KeyBlock *kb; + Key *key = mesh_src->key; + int i; + + if (!mesh_src->key) + return; + + /* ensure we can use mesh vertex count for derived mesh custom data */ + if (mesh_src->totvert != mesh_dest->totvert) { + fprintf(stderr, + "%s: vertex size mismatch (mesh/dm) '%s' (%d != %d)\n", + __func__, mesh_src->id.name + 2, mesh_src->totvert, mesh_dest->totvert); + return; + } + + for (i = 0, kb = key->block.first; kb; kb = kb->next, i++) { + int ci; + float *array; + + if (mesh_src->totvert != kb->totelem) { + fprintf(stderr, + "%s: vertex size mismatch (Mesh '%s':%d != KeyBlock '%s':%d)\n", + __func__, mesh_src->id.name + 2, mesh_src->totvert, kb->name, kb->totelem); + array = MEM_calloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__); + } + else { + array = MEM_malloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__); + memcpy(array, kb->data, (size_t)mesh_src->totvert * 3 * sizeof(float)); + } + + CustomData_add_layer_named(&mesh_dest->vdata, CD_SHAPEKEY, CD_ASSIGN, array, mesh_dest->totvert, kb->name); + ci = CustomData_get_layer_index_n(&mesh_dest->vdata, CD_SHAPEKEY, i); + + mesh_dest->vdata.layers[ci].uid = kb->uid; + } +} + + +Mesh *BKE_mesh_create_derived_for_modifier( + struct Depsgraph *depsgraph, Scene *scene, Object *ob, + ModifierData *md, int build_shapekey_layers) +{ + Mesh *me = ob->data; + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + Mesh *result; + KeyBlock *kb; + ModifierEvalContext mectx = {depsgraph, ob, 0}; + + md->scene = scene; + + if (!(md->mode & eModifierMode_Realtime)) { + return NULL; + } + + if (mti->isDisabled && mti->isDisabled(md, 0)) { + return NULL; + } + + if (build_shapekey_layers && me->key && (kb = BLI_findlink(&me->key->block, ob->shapenr - 1))) { + BKE_keyblock_convert_to_mesh(kb, me); + } + + if (mti->type == eModifierTypeType_OnlyDeform) { + int numVerts; + float (*deformedVerts)[3] = BKE_mesh_vertexCos_get(me, &numVerts); + + modifier_deformVerts(md, &mectx, NULL, deformedVerts, numVerts); + BKE_id_copy_ex(NULL, &me->id, (ID **)&result, + LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | + LIB_ID_COPY_NO_PREVIEW, + false); + BKE_mesh_apply_vert_coords(result, deformedVerts); + + if (build_shapekey_layers) + add_shapekey_layers(result, me); + + MEM_freeN(deformedVerts); + } + else { + Mesh *mesh_temp; + BKE_id_copy_ex(NULL, &me->id, (ID **)&mesh_temp, + LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | + LIB_ID_COPY_NO_PREVIEW, + false); + + if (build_shapekey_layers) + add_shapekey_layers(mesh_temp, me); + + result = modifier_applyModifier(md, &mectx, mesh_temp); + ASSERT_IS_VALID_MESH(result); + + if (mesh_temp != result) { + BKE_id_free(NULL, mesh_temp); + } + } + + return result; +} + +/* This is a Mesh-based copy of the same function in DerivedMesh.c */ +static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int actshape_uid) +{ + KeyBlock *kb; + int i, j, tot; + + if (!mesh_dst->key) + return; + + tot = CustomData_number_of_layers(&mesh_src->vdata, CD_SHAPEKEY); + for (i = 0; i < tot; i++) { + CustomDataLayer *layer = &mesh_src->vdata.layers[CustomData_get_layer_index_n(&mesh_src->vdata, CD_SHAPEKEY, i)]; + float (*cos)[3], (*kbcos)[3]; + + for (kb = mesh_dst->key->block.first; kb; kb = kb->next) { + if (kb->uid == layer->uid) + break; + } + + if (!kb) { + kb = BKE_keyblock_add(mesh_dst->key, layer->name); + kb->uid = layer->uid; + } + + if (kb->data) + MEM_freeN(kb->data); + + cos = CustomData_get_layer_n(&mesh_src->vdata, CD_SHAPEKEY, i); + kb->totelem = mesh_src->totvert; + + kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, 3 * sizeof(float), "kbcos DerivedMesh.c"); + if (kb->uid == actshape_uid) { + MVert *mvert = mesh_src->mvert; + + for (j = 0; j < mesh_src->totvert; j++, kbcos++, mvert++) { + copy_v3_v3(*kbcos, mvert->co); + } + } + else { + for (j = 0; j < kb->totelem; j++, cos++, kbcos++) { + copy_v3_v3(*kbcos, *cos); + } + } + } + + for (kb = mesh_dst->key->block.first; kb; kb = kb->next) { + if (kb->totelem != mesh_src->totvert) { + if (kb->data) + MEM_freeN(kb->data); + + kb->totelem = mesh_src->totvert; + kb->data = MEM_calloc_arrayN(kb->totelem, 3 * sizeof(float), "kb->data derivedmesh.c"); + fprintf(stderr, "%s: lost a shapekey layer: '%s'! (bmesh internal error)\n", __func__, kb->name); + } + } +} + + +/* This is a Mesh-based copy of DM_to_mesh() */ +void BKE_nomain_mesh_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob, CustomDataMask mask, bool take_ownership) +{ + /* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */ + /* TODO(Sybren): the above claim came from DM_to_mesh(); check whether it is still true with Mesh */ + Mesh tmp = *mesh_dst; + int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly; + int did_shapekeys = 0; + eCDAllocType alloctype = CD_DUPLICATE; + + if (take_ownership /* && dm->type == DM_TYPE_CDDM && dm->needsFree */) { + bool has_any_referenced_layers = + CustomData_has_referenced(&mesh_src->vdata) || + CustomData_has_referenced(&mesh_src->edata) || + CustomData_has_referenced(&mesh_src->ldata) || + CustomData_has_referenced(&mesh_src->fdata) || + CustomData_has_referenced(&mesh_src->pdata); + if (!has_any_referenced_layers) { + alloctype = CD_ASSIGN; + } + } + CustomData_reset(&tmp.vdata); + CustomData_reset(&tmp.edata); + CustomData_reset(&tmp.fdata); + CustomData_reset(&tmp.ldata); + CustomData_reset(&tmp.pdata); + + BKE_mesh_ensure_normals(mesh_src); + + totvert = tmp.totvert = mesh_src->totvert; + totedge = tmp.totedge = mesh_src->totedge; + totloop = tmp.totloop = mesh_src->totloop; + totpoly = tmp.totpoly = mesh_src->totpoly; + tmp.totface = 0; + + CustomData_copy(&mesh_src->vdata, &tmp.vdata, mask, alloctype, totvert); + CustomData_copy(&mesh_src->edata, &tmp.edata, mask, alloctype, totedge); + CustomData_copy(&mesh_src->ldata, &tmp.ldata, mask, alloctype, totloop); + CustomData_copy(&mesh_src->pdata, &tmp.pdata, mask, alloctype, totpoly); + tmp.cd_flag = mesh_src->cd_flag; + tmp.runtime.deformed_only = mesh_src->runtime.deformed_only; + + if (CustomData_has_layer(&mesh_src->vdata, CD_SHAPEKEY)) { + KeyBlock *kb; + int uid; + + if (ob) { + kb = BLI_findlink(&mesh_dst->key->block, ob->shapenr - 1); + if (kb) { + uid = kb->uid; + } + else { + printf("%s: error - could not find active shapekey %d!\n", + __func__, ob->shapenr - 1); + + uid = INT_MAX; + } + } + else { + /* if no object, set to INT_MAX so we don't mess up any shapekey layers */ + uid = INT_MAX; + } + + shapekey_layers_to_keyblocks(mesh_src, mesh_dst, uid); + did_shapekeys = 1; + } + + /* copy texture space */ + if (ob) { + BKE_mesh_texspace_copy_from_object(&tmp, ob); + } + + /* not all DerivedMeshes store their verts/edges/faces in CustomData, so + * we set them here in case they are missing */ + /* TODO(Sybren): we could probably replace CD_ASSIGN with alloctype and always directly pass mesh_src->mxxx, + * instead of using a ternary operator. */ + if (!CustomData_has_layer(&tmp.vdata, CD_MVERT)) { + CustomData_add_layer(&tmp.vdata, CD_MVERT, CD_ASSIGN, + (alloctype == CD_ASSIGN) ? mesh_src->mvert : MEM_dupallocN(mesh_src->mvert), + totvert); + } + if (!CustomData_has_layer(&tmp.edata, CD_MEDGE)) { + CustomData_add_layer(&tmp.edata, CD_MEDGE, CD_ASSIGN, + (alloctype == CD_ASSIGN) ? mesh_src->medge : MEM_dupallocN(mesh_src->medge), + totedge); + } + if (!CustomData_has_layer(&tmp.pdata, CD_MPOLY)) { + /* TODO(Sybren): assigment to tmp.mxxx is probably not necessary due to the + * BKE_mesh_update_customdata_pointers() call below. */ + tmp.mloop = (alloctype == CD_ASSIGN) ? mesh_src->mloop : MEM_dupallocN(mesh_src->mloop); + tmp.mpoly = (alloctype == CD_ASSIGN) ? mesh_src->mpoly : MEM_dupallocN(mesh_src->mpoly); + + CustomData_add_layer(&tmp.ldata, CD_MLOOP, CD_ASSIGN, tmp.mloop, tmp.totloop); + CustomData_add_layer(&tmp.pdata, CD_MPOLY, CD_ASSIGN, tmp.mpoly, tmp.totpoly); + } + + /* object had got displacement layer, should copy this layer to save sculpted data */ + /* NOTE: maybe some other layers should be copied? nazgul */ + if (CustomData_has_layer(&mesh_dst->ldata, CD_MDISPS)) { + if (totloop == mesh_dst->totloop) { + MDisps *mdisps = CustomData_get_layer(&mesh_dst->ldata, CD_MDISPS); + CustomData_add_layer(&tmp.ldata, CD_MDISPS, alloctype, mdisps, totloop); + } + } + + /* yes, must be before _and_ after tessellate */ + BKE_mesh_update_customdata_pointers(&tmp, false); + + /* since 2.65 caller must do! */ + // BKE_mesh_tessface_calc(&tmp); + + CustomData_free(&mesh_dst->vdata, mesh_dst->totvert); + CustomData_free(&mesh_dst->edata, mesh_dst->totedge); + CustomData_free(&mesh_dst->fdata, mesh_dst->totface); + CustomData_free(&mesh_dst->ldata, mesh_dst->totloop); + CustomData_free(&mesh_dst->pdata, mesh_dst->totpoly); + + /* ok, this should now use new CD shapekey data, + * which should be fed through the modifier + * stack */ + if (tmp.totvert != mesh_dst->totvert && !did_shapekeys && mesh_dst->key) { + printf("%s: YEEK! this should be recoded! Shape key loss!: ID '%s'\n", __func__, tmp.id.name); + if (tmp.key && !(tmp.id.tag & LIB_TAG_NO_MAIN)) { + id_us_min(&tmp.key->id); + } + tmp.key = NULL; + } + + /* Clear selection history */ + MEM_SAFE_FREE(tmp.mselect); + tmp.totselect = 0; + BLI_assert(ELEM(tmp.bb, NULL, mesh_dst->bb)); + if (mesh_dst->bb) { + MEM_freeN(mesh_dst->bb); + tmp.bb = NULL; + } + + /* skip the listbase */ + MEMCPY_STRUCT_OFS(mesh_dst, &tmp, id.prev); + + if (take_ownership) { + if (alloctype == CD_ASSIGN) { + CustomData_free_typemask(&mesh_src->vdata, mesh_src->totvert, ~mask); + CustomData_free_typemask(&mesh_src->edata, mesh_src->totedge, ~mask); + CustomData_free_typemask(&mesh_src->ldata, mesh_src->totloop, ~mask); + CustomData_free_typemask(&mesh_src->pdata, mesh_src->totpoly, ~mask); + } + BKE_id_free(NULL, mesh_src); + } +} + +/* This is a Mesh-based copy of DM_to_meshkey() */ +void BKE_nomain_mesh_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb) +{ + int a, totvert = mesh_src->totvert; + float *fp; + MVert *mvert; + + if (totvert == 0 || mesh_dst->totvert == 0 || mesh_dst->totvert != totvert) { + return; + } + + if (kb->data) MEM_freeN(kb->data); + kb->data = MEM_malloc_arrayN(mesh_dst->key->elemsize, mesh_dst->totvert, "kb->data"); + kb->totelem = totvert; + + fp = kb->data; + mvert = mesh_src->mvert; + + for (a = 0; a < kb->totelem; a++, fp += 3, mvert++) { + copy_v3_v3(fp, mvert->co); + } +} diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index a49896617d2..87cb1afbe38 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -546,7 +546,7 @@ static int modifier_apply_shape(ReportList *reports, Depsgraph *depsgraph, Scene */ if (ob->type == OB_MESH) { - DerivedMesh *dm; + Mesh *mesh_applied; Mesh *me = ob->data; Key *key = me->key; KeyBlock *kb; @@ -556,8 +556,8 @@ static int modifier_apply_shape(ReportList *reports, Depsgraph *depsgraph, Scene return 0; } - dm = mesh_create_derived_for_modifier(depsgraph, scene, ob, md, 0); - if (!dm) { + mesh_applied = BKE_mesh_create_derived_for_modifier(depsgraph, scene, ob, md, 0); + if (!mesh_applied) { BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply"); return 0; } @@ -572,9 +572,9 @@ static int modifier_apply_shape(ReportList *reports, Depsgraph *depsgraph, Scene } kb = BKE_keyblock_add(key, md->name); - DM_to_meshkey(dm, me, kb); + BKE_nomain_mesh_to_meshkey(mesh_applied, me, kb); - dm->release(dm); + BKE_id_free(NULL, mesh_applied); } else { BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type"); @@ -595,7 +595,7 @@ static int modifier_apply_obdata(ReportList *reports, Depsgraph *depsgraph, Scen } if (ob->type == OB_MESH) { - DerivedMesh *dm; + Mesh *mesh_applied; Mesh *me = ob->data; MultiresModifierData *mmd = find_multires_modifier_before(scene, md); @@ -615,13 +615,13 @@ static int modifier_apply_obdata(ReportList *reports, Depsgraph *depsgraph, Scen } } else { - dm = mesh_create_derived_for_modifier(depsgraph, scene, ob, md, 1); - if (!dm) { + mesh_applied = BKE_mesh_create_derived_for_modifier(depsgraph, scene, ob, md, 1); + if (!mesh_applied) { BKE_report(reports, RPT_ERROR, "Modifier returned error, skipping apply"); return 0; } - DM_to_mesh(dm, me, ob, CD_MASK_MESH, true); + BKE_nomain_mesh_to_mesh(mesh_applied, me, ob, CD_MASK_MESH, true); if (md->type == eModifierType_Multires) multires_customdata_delete(me); |