diff options
Diffstat (limited to 'source/blender/bmesh/intern/bmesh_mesh_convert.c')
-rw-r--r-- | source/blender/bmesh/intern/bmesh_mesh_convert.c | 342 |
1 files changed, 332 insertions, 10 deletions
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.c b/source/blender/bmesh/intern/bmesh_mesh_convert.c index 9d29a90a7a4..e5ea4461119 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.c +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.c @@ -79,6 +79,7 @@ #include "MEM_guardedalloc.h" #include "BLI_alloca.h" +#include "BLI_array.h" #include "BLI_listbase.h" #include "BLI_math_vector.h" @@ -94,6 +95,23 @@ #include "bmesh.h" #include "intern/bmesh_private.h" /* For element checking. */ +#include "range_tree.h" + +static void bm_unmark_temp_cdlayers(BMesh *bm) +{ + CustomData_unmark_temporary_nocopy(&bm->vdata); + CustomData_unmark_temporary_nocopy(&bm->edata); + CustomData_unmark_temporary_nocopy(&bm->ldata); + CustomData_unmark_temporary_nocopy(&bm->pdata); +} + +static void bm_mark_temp_cdlayers(BMesh *bm) +{ + CustomData_mark_temporary_nocopy(&bm->vdata); + CustomData_mark_temporary_nocopy(&bm->edata); + CustomData_mark_temporary_nocopy(&bm->ldata); + CustomData_mark_temporary_nocopy(&bm->pdata); +} void BM_mesh_cd_flag_ensure(BMesh *bm, Mesh *mesh, const char cd_flag) { @@ -157,6 +175,7 @@ char BM_mesh_cd_flag_from_bmesh(BMesh *bm) if (CustomData_has_layer(&bm->edata, CD_CREASE)) { cd_flag |= ME_CDFLAG_EDGE_CREASE; } + return cd_flag; } @@ -173,11 +192,35 @@ static BMFace *bm_face_create_from_mpoly( edges[j] = etable[ml->e]; } - return BM_face_create(bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD); + return BM_face_create( + bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD | BM_CREATE_SKIP_ID); +} + +void BM_enter_multires_space(Object *ob, BMesh *bm, int space) +{ + if (!bm->haveMultiResSettings && ob) { + MultiresModifierData *mmd = get_multires_modifier(NULL, ob, true); + if (mmd) { + bm->multires = *mmd; + bm->haveMultiResSettings = true; + bm->multiresSpace = MULTIRES_SPACE_TANGENT; + } + } + + if (!bm->haveMultiResSettings || !CustomData_has_layer(&bm->ldata, CD_MDISPS) || + space == bm->multiresSpace) { + return; + } + + BKE_multires_bmesh_space_set(ob, bm, space); + bm->multiresSpace = space; } +#include "BLI_compiler_attrs.h" + /** * \brief Mesh -> BMesh + * \param ob: object that owns bm, may be NULL (which will disable multires space change) * \param bm: The mesh to write into, while this is typically a newly created BMesh, * merging into existing data is supported. * Note the custom-data layout isn't used. @@ -185,8 +228,16 @@ static BMFace *bm_face_create_from_mpoly( * since this should be kept fast for edit-mode switching and storing undo steps. * * \warning This function doesn't calculate face normals. + * + * Mesh IDs will be imported unless requested. If the bmesh was created + * with id map enabled then IDs will be checked for uniqueness, otherwise + * they are imported as is. */ -void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params) + +void BM_mesh_bm_from_me(Object *ob, + BMesh *bm, + const Mesh *me, + const struct BMeshFromMeshParams *params) { const bool is_new = !(bm->totvert || (bm->vdata.totlayer || bm->edata.totlayer || bm->pdata.totlayer || bm->ldata.totlayer)); @@ -203,6 +254,57 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar CustomData_MeshMasks mask = CD_MASK_BMESH; CustomData_MeshMasks_update(&mask, ¶ms->cd_mask_extra); + MultiresModifierData *mmd = ob ? get_multires_modifier(NULL, ob, true) : NULL; + const CustomData *cdatas[] = {&me->vdata, &me->edata, &me->ldata, &me->pdata}; + const CustomData *bmdatas[] = {&bm->vdata, &bm->edata, &bm->ldata, &bm->pdata}; + + bool check_id_unqiue = false; + + if (!params->ignore_id_layers) { + for (int i = 0; i < 4; i++) { + int type = 1 << i; + + if (CustomData_has_layer(cdatas[i], CD_MESH_ID)) { + bm->idmap.flag |= type | BM_HAS_IDS; + } + } + + bm_init_idmap_cdlayers(bm); + } + + // check_id_unqiue + if ((bm->idmap.flag & BM_HAS_IDS)) { +#ifndef WITH_BM_ID_FREELIST + if (!bm->idmap.idtree) { + bm->idmap.idtree = range_tree_uint_alloc(0, (uint)-1); + } +#endif + + if (bm->idmap.flag & BM_HAS_ID_MAP) { + check_id_unqiue = true; + } + } + + if (params->copy_temp_cdlayers) { + bm_unmark_temp_cdlayers(bm); + } + + if (params->copy_temp_cdlayers) { + mask.vmask |= CD_MASK_MESH_ID; + mask.emask |= CD_MASK_MESH_ID; + mask.lmask |= CD_MASK_MESH_ID; + mask.pmask |= CD_MASK_MESH_ID; + } + + if (mmd) { + bm->multires = *mmd; + bm->haveMultiResSettings = true; + bm->multiresSpace = MULTIRES_SPACE_TANGENT; + } + else { + bm->haveMultiResSettings = false; + } + if (!me || !me->totvert) { if (me && is_new) { /* No verts? still copy custom-data layout. */ CustomData_copy(&me->vdata, &bm->vdata, mask.vmask, CD_ASSIGN, 0); @@ -215,6 +317,15 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP); CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE); } + + if (params->copy_temp_cdlayers) { + bm_mark_temp_cdlayers(bm); + } + + if (bm->idmap.flag & BM_HAS_IDS) { + bm_init_idmap_cdlayers(bm); + } + return; /* Sanity check. */ } @@ -321,6 +432,28 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar BM_mesh_cd_flag_apply(bm, me->cd_flag); } + int *existing_id_layers[4] = {NULL, NULL, NULL, NULL}; + int use_exist_ids = 0; + int has_ids = bm->idmap.flag & BM_HAS_IDS ? + (bm->idmap.flag & (BM_VERT | BM_EDGE | BM_LOOP | BM_FACE)) : + 0; + + if (bm->idmap.flag & BM_HAS_IDS) { + if (!params->ignore_id_layers) { + for (int i = 0; i < 4; i++) { + existing_id_layers[i] = (int *)CustomData_get_layer(cdatas[i], CD_MESH_ID); + + if (existing_id_layers[i]) { + use_exist_ids |= 1 << i; + } + } + } + + use_exist_ids &= bm->idmap.flag; + + bm_init_idmap_cdlayers(bm); + } + const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); @@ -333,7 +466,8 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar vtable = MEM_mallocN(sizeof(BMVert **) * me->totvert, __func__); for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) { - v = vtable[i] = BM_vert_create(bm, keyco ? keyco[i] : mvert->co, NULL, BM_CREATE_SKIP_CD); + v = vtable[i] = BM_vert_create( + bm, keyco ? keyco[i] : mvert->co, NULL, BM_CREATE_SKIP_CD | BM_CREATE_SKIP_ID); BM_elem_index_set(v, i); /* set_ok */ /* Transfer flag. */ @@ -349,6 +483,15 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar /* Copy Custom Data */ CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data, true); + if (has_ids & BM_VERT) { + if (use_exist_ids & BM_VERT) { + bm_assign_id(bm, (BMElem *)v, existing_id_layers[0][i], false); + } + else { + bm_alloc_id(bm, (BMElem *)v); + } + } + if (cd_vert_bweight_offset != -1) { BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mvert->bweight / 255.0f); } @@ -389,6 +532,15 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar /* Copy Custom Data */ CustomData_to_bmesh_block(&me->edata, &bm->edata, i, &e->head.data, true); + if (has_ids & BM_EDGE) { + if (use_exist_ids & BM_EDGE) { + bm_assign_id(bm, (BMElem *)e, existing_id_layers[1][i], false); + } + else { + bm_alloc_id(bm, (BMElem *)e); + } + } + if (cd_edge_bweight_offset != -1) { BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)medge->bweight / 255.0f); } @@ -450,11 +602,29 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar /* Save index of corresponding #MLoop. */ CustomData_to_bmesh_block(&me->ldata, &bm->ldata, j++, &l_iter->head.data, true); + + if (has_ids & BM_LOOP) { + if (use_exist_ids & BM_LOOP) { + bm_assign_id(bm, (BMElem *)l_iter, existing_id_layers[2][j - 1], false); + } + else { + bm_alloc_id(bm, (BMElem *)l_iter); + } + } } while ((l_iter = l_iter->next) != l_first); /* Copy Custom Data */ CustomData_to_bmesh_block(&me->pdata, &bm->pdata, i, &f->head.data, true); + if (has_ids & BM_FACE) { + if (use_exist_ids & BM_FACE) { + bm_assign_id(bm, (BMElem *)f, existing_id_layers[3][i], false); + } + else { + bm_alloc_id(bm, (BMElem *)f); + } + } + if (params->calc_face_normal) { BM_face_normal_update(f); } @@ -463,6 +633,99 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* Added in order, clear dirty flag. */ } + if (check_id_unqiue) { + // validate IDs + + // first clear idmap, we want it to have the first elements + // in each id run, not the last + if (bm->idmap.map) { + memset(bm->idmap.map, 0, sizeof(void *) * bm->idmap.map_size); + } + else if (bm->idmap.ghash) { + BLI_ghash_free(bm->idmap.ghash, NULL, NULL); + bm->idmap.ghash = BLI_ghash_ptr_new("bm->idmap.ghash"); + } + + int iters[] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, -1, BM_FACES_OF_MESH}; + + // find first element in each id run and assign to map + for (int i = 0; i < 4; i++) { + int type = 1 << i; + int iter = iters[i]; + + if (!(bm->idmap.flag & type)) { + continue; + } + + if (iter == -1) { + iter = BM_FACES_OF_MESH; + } + + BMElem *elem; + BMIter iterstate; + BM_ITER_MESH (elem, &iterstate, bm, iter) { + if (i == 2) { // loops + BMFace *f = (BMFace *)elem; + BMLoop *l = f->l_first; + + do { + uint id = (uint)BM_ELEM_GET_ID(bm, (BMElem *)l); + + if (!BM_ELEM_FROM_ID(bm, id)) { + bm_assign_id_intern(bm, (BMElem *)l, id); + } + } while ((l = l->next) != f->l_first); + } + else { + uint id = (uint)BM_ELEM_GET_ID(bm, elem); + + if (!BM_ELEM_FROM_ID(bm, id)) { + bm_assign_id_intern(bm, elem, id); + } + } + } + } + + // now assign new IDs where necessary + + for (int i = 0; i < 4; i++) { + int type = 1 << i; + int iter = iters[i]; + + if (!(bm->idmap.flag & type)) { + continue; + } + + if (iter == -1) { + iter = BM_FACES_OF_MESH; + } + + BMElem *elem; + BMIter iterstate; + + BM_ITER_MESH (elem, &iterstate, bm, iter) { + if (i == 2) { // loops + BMFace *f = (BMFace *)elem; + BMLoop *l = f->l_first; + + do { + uint id = (uint)BM_ELEM_GET_ID(bm, (BMElem *)l); + + if (BM_ELEM_FROM_ID(bm, id) != (BMElem *)l) { + bm_alloc_id(bm, (BMElem *)l); + } + } while ((l = l->next) != f->l_first); + } + else { + uint id = (uint)BM_ELEM_GET_ID(bm, elem); + + if (BM_ELEM_FROM_ID(bm, id) != elem) { + bm_alloc_id(bm, elem); + } + } + } + } + } /* -------------------------------------------------------------------- */ /* MSelect clears the array elements (avoid adding multiple times). * @@ -502,12 +765,29 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar if (ftable) { MEM_freeN(ftable); } + + if (params->copy_temp_cdlayers) { + bm_mark_temp_cdlayers(bm); + } + + if (bm->idmap.flag & BM_HAS_IDS) { + CustomData *cdatas[] = {&bm->vdata, &bm->edata, &bm->ldata, &bm->pdata}; + + for (int i = 0; i < 4; i++) { + int idx = CustomData_get_layer_index(cdatas[i], CD_MESH_ID); + + if (idx >= 0) { + // set layer flags + cdatas[i]->layers[idx].flag |= CD_FLAG_TEMPORARY | CD_FLAG_ELEM_NOCOPY; + } + } + } } /** * \brief BMesh -> Mesh */ -static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert) +BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert) { const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX); BMVert **vertMap = NULL; @@ -549,7 +829,7 @@ static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert) * Returns custom-data shapekey index from a keyblock or -1 * \note could split this out into a more generic function. */ -static int bm_to_mesh_shape_layer_index_from_kb(BMesh *bm, KeyBlock *currkey) +int bm_to_mesh_shape_layer_index_from_kb(BMesh *bm, KeyBlock *currkey) { int i; int j = 0; @@ -586,7 +866,9 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e) * * \param bmain: May be NULL in case \a calc_object_remap parameter option is not set. */ -void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params) + +void BM_mesh_bm_to_me( + Main *bmain, Object *ob, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params) { MEdge *med; BMVert *v, *eve; @@ -595,6 +877,15 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh BMIter iter; int i, j; + if (params->copy_temp_cdlayers) { + bm_unmark_temp_cdlayers(bm); + } + + // ensure multires space is correct + if (bm->haveMultiResSettings && bm->multiresSpace != MULTIRES_SPACE_TANGENT) { + BM_enter_multires_space(ob, bm, MULTIRES_SPACE_TANGENT); + } + const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); @@ -634,13 +925,30 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh me->totface = 0; me->act_face = -1; + CustomData *srcdatas[] = {&bm->vdata, &bm->edata, &bm->ldata, &bm->pdata}; + int id_flags[4] = {-1, -1, -1, -1}; + { CustomData_MeshMasks mask = CD_MASK_MESH; CustomData_MeshMasks_update(&mask, ¶ms->cd_mask_extra); - CustomData_copy(&bm->vdata, &me->vdata, mask.vmask, CD_CALLOC, me->totvert); - CustomData_copy(&bm->edata, &me->edata, mask.emask, CD_CALLOC, me->totedge); - CustomData_copy(&bm->ldata, &me->ldata, mask.lmask, CD_CALLOC, me->totloop); - CustomData_copy(&bm->pdata, &me->pdata, mask.pmask, CD_CALLOC, me->totpoly); + CustomDataMask extra2 = !params->ignore_mesh_id_layers ? CD_MASK_MESH_ID : 0; + + // copy id layers? temporarily clear cd_temporary and cd_flag_elem_nocopy flags + if (!params->ignore_mesh_id_layers) { + for (int i = 0; i < 4; i++) { + int idx = CustomData_get_layer_index(srcdatas[i], CD_MESH_ID); + + if (idx >= 0) { + id_flags[i] = srcdatas[i]->layers[idx].flag; + srcdatas[i]->layers[idx].flag &= ~(CD_FLAG_TEMPORARY | CD_FLAG_ELEM_NOCOPY); + } + } + } + + CustomData_copy(&bm->vdata, &me->vdata, mask.vmask | extra2, CD_CALLOC, me->totvert); + CustomData_copy(&bm->edata, &me->edata, mask.emask | extra2, CD_CALLOC, me->totedge); + CustomData_copy(&bm->ldata, &me->ldata, mask.lmask | extra2, CD_CALLOC, me->totloop); + CustomData_copy(&bm->pdata, &me->pdata, mask.pmask | extra2, CD_CALLOC, me->totpoly); } MVert *mvert = bm->totvert ? MEM_callocN(sizeof(MVert) * bm->totvert, "bm_to_me.vert") : NULL; @@ -1003,6 +1311,20 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh /* To be removed as soon as COW is enabled by default. */ BKE_mesh_runtime_clear_geometry(me); + + // restore original cd layer flags to bmesh id layers + if (!params->ignore_mesh_id_layers) { + for (int i = 0; i < 4; i++) { + int idx = CustomData_get_layer_index(srcdatas[i], CD_MESH_ID); + if (idx >= 0) { + srcdatas[i]->layers[idx].flag = id_flags[i]; + } + } + } + + if (params && params->copy_temp_cdlayers) { + bm_mark_temp_cdlayers(bm); + } } /** |