From 15cff1fddbe3181c0460ee715d231cd0f1241d07 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 9 Dec 2023 23:16:21 +1100 Subject: [PATCH] BMesh: optimize attribute copying by reusing BMCustomDataCopyMap Continuation of fix for #115776. Removes attribute copy functions that calculate the map inline, this is error prone as it's easy to call these functions from a loop which may result in poor performance. --- .../blender/bmesh/intern/bmesh_construct.cc | 82 ------------------- .../blender/bmesh/intern/bmesh_construct.hh | 22 ----- source/blender/bmesh/intern/bmesh_core.cc | 47 +++++++++-- source/blender/bmesh/intern/bmesh_core.hh | 12 ++- .../bmesh/intern/bmesh_mesh_duplicate.cc | 68 ++++++++++++--- source/blender/bmesh/intern/bmesh_mods.cc | 6 +- source/blender/bmesh/operators/bmo_dupe.cc | 64 ++++++++++++--- source/blender/bmesh/operators/bmo_extrude.cc | 2 +- .../transform/transform_convert_mesh.cc | 20 ++++- source/blender/python/bmesh/bmesh_py_types.cc | 73 +++++++++++------ 10 files changed, 226 insertions(+), 170 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_construct.cc b/source/blender/bmesh/intern/bmesh_construct.cc index dcc4447733a..f6711ce1567 100644 --- a/source/blender/bmesh/intern/bmesh_construct.cc +++ b/source/blender/bmesh/intern/bmesh_construct.cc @@ -341,88 +341,6 @@ void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMLoop dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT; } -void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMVert *src, BMVert *dst) -{ - if (bm_src == bm_dst) { - BM_elem_attrs_copy(*bm_dst, src, dst); - } - else { - const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc(bm_src->vdata, bm_dst->vdata); - BM_elem_attrs_copy(bm_dst, map, src, dst); - } -} -void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMEdge *src, BMEdge *dst) -{ - if (bm_src == bm_dst) { - BM_elem_attrs_copy(*bm_dst, src, dst); - } - else { - const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc(bm_src->edata, bm_dst->edata); - BM_elem_attrs_copy(bm_dst, map, src, dst); - } -} -void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMFace *src, BMFace *dst) -{ - if (bm_src == bm_dst) { - BM_elem_attrs_copy(*bm_dst, src, dst); - } - else { - const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc(bm_src->pdata, bm_dst->pdata); - BM_elem_attrs_copy(bm_dst, map, src, dst); - } -} -void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMLoop *src, BMLoop *dst) -{ - if (bm_src == bm_dst) { - BM_elem_attrs_copy(*bm_dst, src, dst); - } - else { - const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc(bm_src->ldata, bm_dst->ldata); - BM_elem_attrs_copy(bm_dst, map, src, dst); - } -} - -void BM_elem_attrs_copy(const BMesh *bm_src, - BMesh *bm_dst, - const eCustomDataMask exclude, - const BMVert *src, - BMVert *dst) -{ - const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc( - bm_src->vdata, bm_dst->vdata, exclude); - BM_elem_attrs_copy(bm_dst, map, src, dst); -} -void BM_elem_attrs_copy(const BMesh *bm_src, - BMesh *bm_dst, - const eCustomDataMask exclude, - const BMEdge *src, - BMEdge *dst) -{ - const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc( - bm_src->edata, bm_dst->edata, exclude); - BM_elem_attrs_copy(bm_dst, map, src, dst); -} -void BM_elem_attrs_copy(const BMesh *bm_src, - BMesh *bm_dst, - const eCustomDataMask exclude, - const BMFace *src, - BMFace *dst) -{ - const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc( - bm_src->pdata, bm_dst->pdata, exclude); - BM_elem_attrs_copy(bm_dst, map, src, dst); -} -void BM_elem_attrs_copy(const BMesh *bm_src, - BMesh *bm_dst, - const eCustomDataMask exclude, - const BMLoop *src, - BMLoop *dst) -{ - const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc( - bm_src->ldata, bm_dst->ldata, exclude); - BM_elem_attrs_copy(bm_dst, map, src, dst); -} - void BM_elem_attrs_copy(BMesh &bm, const BMVert *src, BMVert *dst) { BLI_assert(src != dst); diff --git a/source/blender/bmesh/intern/bmesh_construct.hh b/source/blender/bmesh/intern/bmesh_construct.hh index 8bd2fc98dd1..b904a651288 100644 --- a/source/blender/bmesh/intern/bmesh_construct.hh +++ b/source/blender/bmesh/intern/bmesh_construct.hh @@ -131,34 +131,12 @@ void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMEdge void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMFace *src, BMFace *dst); void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMLoop *src, BMLoop *dst); -/** - * Copy attributes between elements in two BMeshes. These functions are often called with both - * pointing to the same BMesh though, so they check for that and use a simpler copy in that case. - * - * \note For better performance when copying more than one block, use the overload with a - * #BMCustomDataCopyMap precalculated map argument. - */ -void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMVert *src, BMVert *dst); -void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMEdge *src, BMEdge *dst); -void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMFace *src, BMFace *dst); -void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMLoop *src, BMLoop *dst); - /** Copy attributes between elements in the same BMesh. */ void BM_elem_attrs_copy(BMesh &bm, const BMVert *src, BMVert *dst); void BM_elem_attrs_copy(BMesh &bm, const BMEdge *src, BMEdge *dst); void BM_elem_attrs_copy(BMesh &bm, const BMFace *src, BMFace *dst); void BM_elem_attrs_copy(BMesh &bm, const BMLoop *src, BMLoop *dst); -/** Copy attributes between two BMesh elements, excluding certain custom data types. */ -void BM_elem_attrs_copy( - const BMesh *bm_src, BMesh *bm_dst, eCustomDataMask exclude, const BMVert *src, BMVert *dst); -void BM_elem_attrs_copy( - const BMesh *bm_src, BMesh *bm_dst, eCustomDataMask exclude, const BMEdge *src, BMEdge *dst); -void BM_elem_attrs_copy( - const BMesh *bm_src, BMesh *bm_dst, eCustomDataMask exclude, const BMFace *src, BMFace *dst); -void BM_elem_attrs_copy( - const BMesh *bm_src, BMesh *bm_dst, eCustomDataMask exclude, const BMLoop *src, BMLoop *dst); - void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v); /** diff --git a/source/blender/bmesh/intern/bmesh_core.cc b/source/blender/bmesh/intern/bmesh_core.cc index c2afdbaf172..b0e634380c2 100644 --- a/source/blender/bmesh/intern/bmesh_core.cc +++ b/source/blender/bmesh/intern/bmesh_core.cc @@ -280,19 +280,18 @@ static BMLoop *bm_face_boundary_add( return l; } -BMFace *BM_face_copy( - BMesh *bm_dst, BMesh *bm_src, BMFace *f, const bool copy_verts, const bool copy_edges) +static BMFace *bm_face_copy_impl(BMesh *bm_dst, + BMFace *f, + const bool copy_verts, + const bool copy_edges) { BMVert **verts = BLI_array_alloca(verts, f->len); BMEdge **edges = BLI_array_alloca(edges, f->len); BMLoop *l_iter; BMLoop *l_first; - BMLoop *l_copy; BMFace *f_copy; int i; - BLI_assert((bm_dst == bm_src) || (copy_verts && copy_edges)); - l_iter = l_first = BM_FACE_FIRST_LOOP(f); i = 0; do { @@ -330,15 +329,45 @@ BMFace *BM_face_copy( f_copy = BM_face_create(bm_dst, verts, edges, f->len, nullptr, BM_CREATE_SKIP_CD); - BM_elem_attrs_copy(bm_src, bm_dst, f, f_copy); + return f_copy; +} - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - l_copy = BM_FACE_FIRST_LOOP(f_copy); +BMFace *BM_face_copy(BMesh *bm_dst, + const BMCustomDataCopyMap &cd_face_map, + const BMCustomDataCopyMap &cd_loop_map, + BMFace *f, + const bool copy_verts, + const bool copy_edges) +{ + BMFace *f_copy = bm_face_copy_impl(bm_dst, f, copy_verts, copy_edges); + + /* Copy custom-data. */ + BM_elem_attrs_copy(bm_dst, cd_face_map, f, f_copy); + + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_copy = BM_FACE_FIRST_LOOP(f_copy); + BMLoop *l_iter = l_first; do { - BM_elem_attrs_copy(bm_src, bm_dst, l_iter, l_copy); + BM_elem_attrs_copy(bm_dst, cd_loop_map, l_iter, l_copy); l_copy = l_copy->next; } while ((l_iter = l_iter->next) != l_first); + return f_copy; +} +BMFace *BM_face_copy(BMesh *bm_dst, BMFace *f, const bool copy_verts, const bool copy_edges) +{ + BMFace *f_copy = bm_face_copy_impl(bm_dst, f, copy_verts, copy_edges); + + /* Copy custom-data. */ + BM_elem_attrs_copy(*bm_dst, f, f_copy); + + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_copy = BM_FACE_FIRST_LOOP(f_copy); + BMLoop *l_iter = l_first; + do { + BM_elem_attrs_copy(*bm_dst, l_iter, l_copy); + l_copy = l_copy->next; + } while ((l_iter = l_iter->next) != l_first); return f_copy; } diff --git a/source/blender/bmesh/intern/bmesh_core.hh b/source/blender/bmesh/intern/bmesh_core.hh index 8787813b8cb..ceaf3be2cf7 100644 --- a/source/blender/bmesh/intern/bmesh_core.hh +++ b/source/blender/bmesh/intern/bmesh_core.hh @@ -8,7 +8,17 @@ * \ingroup bmesh */ -BMFace *BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f, bool copy_verts, bool copy_edges); +/** + * When copying between different BMesh objects, + * `copy_verts` & `copy_edges` should always be true. + */ +BMFace *BM_face_copy(BMesh *bm, + const BMCustomDataCopyMap &cd_face_map, + const BMCustomDataCopyMap &cd_loop_map, + BMFace *f, + bool copy_verts, + bool copy_edges); +BMFace *BM_face_copy(BMesh *bm, BMFace *f, bool copy_verts, bool copy_edges); typedef enum eBMCreateFlag { BM_CREATE_NOP = 0, diff --git a/source/blender/bmesh/intern/bmesh_mesh_duplicate.cc b/source/blender/bmesh/intern/bmesh_mesh_duplicate.cc index 48e0e8cd041..1f574f536b4 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_duplicate.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_duplicate.cc @@ -18,27 +18,43 @@ #include "bmesh.hh" #include "intern/bmesh_private.hh" /* for element checking */ -static BMVert *bm_vert_copy(BMesh *bm_src, BMesh *bm_dst, BMVert *v_src) +static BMVert *bm_vert_copy(BMesh *bm_dst, + const std::optional &cd_vert_map, + BMVert *v_src) { BMVert *v_dst = BM_vert_create(bm_dst, v_src->co, nullptr, BM_CREATE_SKIP_CD); - BM_elem_attrs_copy(bm_src, bm_dst, v_src, v_dst); + if (cd_vert_map.has_value()) { + BM_elem_attrs_copy(bm_dst, cd_vert_map.value(), v_src, v_dst); + } + else { + BM_elem_attrs_copy(*bm_dst, v_src, v_dst); + } return v_dst; } -static BMEdge *bm_edge_copy_with_arrays(BMesh *bm_src, - BMesh *bm_dst, +static BMEdge *bm_edge_copy_with_arrays(BMesh *bm_dst, + const std::optional &cd_edge_map, BMEdge *e_src, BMVert **verts_dst) { BMVert *e_dst_v1 = verts_dst[BM_elem_index_get(e_src->v1)]; BMVert *e_dst_v2 = verts_dst[BM_elem_index_get(e_src->v2)]; BMEdge *e_dst = BM_edge_create(bm_dst, e_dst_v1, e_dst_v2, nullptr, BM_CREATE_SKIP_CD); - BM_elem_attrs_copy(bm_src, bm_dst, e_src, e_dst); + if (cd_edge_map.has_value()) { + BM_elem_attrs_copy(bm_dst, cd_edge_map.value(), e_src, e_dst); + } + else { + BM_elem_attrs_copy(*bm_dst, e_src, e_dst); + } return e_dst; } -static BMFace *bm_face_copy_with_arrays( - BMesh *bm_src, BMesh *bm_dst, BMFace *f_src, BMVert **verts_dst, BMEdge **edges_dst) +static BMFace *bm_face_copy_with_arrays(BMesh *bm_dst, + const std::optional cd_face_map, + const std::optional &cd_loop_map, + BMFace *f_src, + BMVert **verts_dst, + BMEdge **edges_dst) { BMFace *f_dst; BMVert **vtar = BLI_array_alloca(vtar, f_src->len); @@ -61,13 +77,23 @@ static BMFace *bm_face_copy_with_arrays( f_dst = BM_face_create(bm_dst, vtar, edar, f_src->len, nullptr, BM_CREATE_SKIP_CD); /* Copy attributes. */ - BM_elem_attrs_copy(bm_src, bm_dst, f_src, f_dst); + if (cd_face_map.has_value()) { + BM_elem_attrs_copy(bm_dst, cd_face_map.value(), f_src, f_dst); + } + else { + BM_elem_attrs_copy(*bm_dst, f_src, f_dst); + } /* Copy per-loop custom data. */ l_iter_src = l_first_src; l_iter_dst = BM_FACE_FIRST_LOOP(f_dst); do { - BM_elem_attrs_copy(bm_src, bm_dst, l_iter_src, l_iter_dst); + if (cd_loop_map.has_value()) { + BM_elem_attrs_copy(bm_dst, cd_loop_map.value(), l_iter_src, l_iter_dst); + } + else { + BM_elem_attrs_copy(*bm_dst, l_iter_src, l_iter_dst); + } } while ((void)(l_iter_dst = l_iter_dst->next), (l_iter_src = l_iter_src->next) != l_first_src); return f_dst; @@ -82,6 +108,23 @@ void BM_mesh_copy_arrays(BMesh *bm_src, BMFace **faces_src, uint faces_src_len) { + const std::optional cd_vert_map = + (bm_src == bm_dst) ? std::nullopt : + std::optional{ + CustomData_bmesh_copy_map_calc(bm_src->vdata, bm_dst->vdata)}; + const std::optional cd_edge_map = + (bm_src == bm_dst) ? std::nullopt : + std::optional{ + CustomData_bmesh_copy_map_calc(bm_src->edata, bm_dst->edata)}; + const std::optional cd_face_map = + (bm_src == bm_dst) ? std::nullopt : + std::optional{ + CustomData_bmesh_copy_map_calc(bm_src->pdata, bm_dst->pdata)}; + const std::optional cd_loop_map = + (bm_src == bm_dst) ? std::nullopt : + std::optional{ + CustomData_bmesh_copy_map_calc(bm_src->ldata, bm_dst->ldata)}; + /* Vertices. */ BMVert **verts_dst = static_cast( MEM_mallocN(sizeof(*verts_dst) * verts_src_len, __func__)); @@ -89,7 +132,7 @@ void BM_mesh_copy_arrays(BMesh *bm_src, BMVert *v_src = verts_src[i]; BM_elem_index_set(v_src, i); /* set_dirty! */ - BMVert *v_dst = bm_vert_copy(bm_src, bm_dst, v_src); + BMVert *v_dst = bm_vert_copy(bm_dst, cd_vert_map, v_src); BM_elem_index_set(v_dst, i); /* set_ok */ verts_dst[i] = v_dst; } @@ -103,7 +146,7 @@ void BM_mesh_copy_arrays(BMesh *bm_src, BMEdge *e_src = edges_src[i]; BM_elem_index_set(e_src, i); /* set_dirty! */ - BMEdge *e_dst = bm_edge_copy_with_arrays(bm_src, bm_dst, e_src, verts_dst); + BMEdge *e_dst = bm_edge_copy_with_arrays(bm_dst, cd_edge_map, e_src, verts_dst); BM_elem_index_set(e_dst, i); edges_dst[i] = e_dst; } @@ -113,7 +156,8 @@ void BM_mesh_copy_arrays(BMesh *bm_src, /* Faces. */ for (uint i = 0; i < faces_src_len; i++) { BMFace *f_src = faces_src[i]; - BMFace *f_dst = bm_face_copy_with_arrays(bm_src, bm_dst, f_src, verts_dst, edges_dst); + BMFace *f_dst = bm_face_copy_with_arrays( + bm_dst, cd_face_map, cd_loop_map, f_src, verts_dst, edges_dst); BM_elem_index_set(f_dst, i); } bm_dst->elem_index_dirty &= ~BM_FACE; diff --git a/source/blender/bmesh/intern/bmesh_mods.cc b/source/blender/bmesh/intern/bmesh_mods.cc index 67c103485da..4fa67818d75 100644 --- a/source/blender/bmesh/intern/bmesh_mods.cc +++ b/source/blender/bmesh/intern/bmesh_mods.cc @@ -205,7 +205,7 @@ BMFace *BM_face_split(BMesh *bm, /* do we have a multires layer? */ if (cd_loop_mdisp_offset != -1) { - f_tmp = BM_face_copy(bm, bm, f, false, false); + f_tmp = BM_face_copy(bm, f, false, false); } #ifdef USE_BMESH_HOLES @@ -273,7 +273,7 @@ BMFace *BM_face_split_n(BMesh *bm, return nullptr; } - f_tmp = BM_face_copy(bm, bm, f, true, true); + f_tmp = BM_face_copy(bm, f, true, true); #ifdef USE_BMESH_HOLES f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, &l_new, nullptr, example, false); @@ -467,7 +467,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) /* flag existing faces so we can differentiate oldfaces from new faces */ for (int64_t i = 0; i < oldfaces.size(); i++) { BM_ELEM_API_FLAG_ENABLE(oldfaces[i], _FLAG_OVERLAP); - oldfaces[i] = BM_face_copy(bm, bm, oldfaces[i], true, true); + oldfaces[i] = BM_face_copy(bm, oldfaces[i], true, true); BM_ELEM_API_FLAG_DISABLE(oldfaces[i], _FLAG_OVERLAP); } } diff --git a/source/blender/bmesh/operators/bmo_dupe.cc b/source/blender/bmesh/operators/bmo_dupe.cc index 69faab212fd..69683f4efcd 100644 --- a/source/blender/bmesh/operators/bmo_dupe.cc +++ b/source/blender/bmesh/operators/bmo_dupe.cc @@ -33,7 +33,7 @@ static BMVert *bmo_vert_copy(BMOperator *op, BMOpSlot *slot_vertmap_out, BMesh *bm_dst, - BMesh *bm_src, + const std::optional &cd_vert_map, BMVert *v_src, GHash *vhash) { @@ -48,7 +48,12 @@ static BMVert *bmo_vert_copy(BMOperator *op, BLI_ghash_insert(vhash, v_src, v_dst); /* Copy attributes */ - BM_elem_attrs_copy(bm_src, bm_dst, v_src, v_dst); + if (cd_vert_map.has_value()) { + BM_elem_attrs_copy(bm_dst, cd_vert_map.value(), v_src, v_dst); + } + else { + BM_elem_attrs_copy(*bm_dst, v_src, v_dst); + } /* Mark the vert for output */ BMO_vert_flag_enable(bm_dst, v_dst, DUPE_NEW); @@ -66,6 +71,7 @@ static BMEdge *bmo_edge_copy(BMOperator *op, BMOpSlot *slot_boundarymap_out, BMesh *bm_dst, BMesh *bm_src, + const std::optional &cd_edge_map, BMEdge *e_src, GHash *vhash, GHash *ehash, @@ -110,7 +116,12 @@ static BMEdge *bmo_edge_copy(BMOperator *op, BLI_ghash_insert(ehash, e_src, e_dst); /* Copy attributes */ - BM_elem_attrs_copy(bm_src, bm_dst, e_src, e_dst); + if (cd_edge_map.has_value()) { + BM_elem_attrs_copy(bm_dst, cd_edge_map.value(), e_src, e_dst); + } + else { + BM_elem_attrs_copy(*bm_dst, e_src, e_dst); + } /* Mark the edge for output */ BMO_edge_flag_enable(bm_dst, e_dst, DUPE_NEW); @@ -134,7 +145,8 @@ static BMEdge *bmo_edge_copy(BMOperator *op, static BMFace *bmo_face_copy(BMOperator *op, BMOpSlot *slot_facemap_out, BMesh *bm_dst, - BMesh *bm_src, + const std::optional &cd_face_map, + const std::optional &cd_loop_map, BMFace *f_src, GHash *vhash, GHash *ehash) @@ -162,13 +174,23 @@ static BMFace *bmo_face_copy(BMOperator *op, BMO_slot_map_elem_insert(op, slot_facemap_out, f_dst, f_src); /* Copy attributes */ - BM_elem_attrs_copy(bm_src, bm_dst, f_src, f_dst); + if (cd_face_map.has_value()) { + BM_elem_attrs_copy(bm_dst, cd_face_map.value(), f_src, f_dst); + } + else { + BM_elem_attrs_copy(*bm_dst, f_src, f_dst); + } /* copy per-loop custom data */ l_iter_src = l_first_src; l_iter_dst = BM_FACE_FIRST_LOOP(f_dst); do { - BM_elem_attrs_copy(bm_src, bm_dst, l_iter_src, l_iter_dst); + if (cd_loop_map.has_value()) { + BM_elem_attrs_copy(bm_dst, cd_loop_map.value(), l_iter_src, l_iter_dst); + } + else { + BM_elem_attrs_copy(*bm_dst, l_iter_src, l_iter_dst); + } } while ((void)(l_iter_dst = l_iter_dst->next), (l_iter_src = l_iter_src->next) != l_first_src); /* Mark the face for output */ @@ -205,6 +227,23 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) vhash = BLI_ghash_ptr_new("bmesh dupeops v"); ehash = BLI_ghash_ptr_new("bmesh dupeops e"); + const std::optional cd_vert_map = + (bm_src == bm_dst) ? std::nullopt : + std::optional{ + CustomData_bmesh_copy_map_calc(bm_src->vdata, bm_dst->vdata)}; + const std::optional cd_edge_map = + (bm_src == bm_dst) ? std::nullopt : + std::optional{ + CustomData_bmesh_copy_map_calc(bm_src->edata, bm_dst->edata)}; + const std::optional cd_face_map = + (bm_src == bm_dst) ? std::nullopt : + std::optional{ + CustomData_bmesh_copy_map_calc(bm_src->pdata, bm_dst->pdata)}; + const std::optional cd_loop_map = + (bm_src == bm_dst) ? std::nullopt : + std::optional{ + CustomData_bmesh_copy_map_calc(bm_src->ldata, bm_dst->ldata)}; + /* duplicate flagged vertices */ BM_ITER_MESH (v, &viter, bm_src, BM_VERTS_OF_MESH) { if (BMO_vert_flag_test(bm_src, v, DUPE_INPUT) && @@ -212,7 +251,7 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) BMIter iter; bool isolated = true; - v2 = bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash); + v2 = bmo_vert_copy(op, slot_vert_map_out, bm_dst, cd_vert_map, v, vhash); BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) { @@ -244,11 +283,11 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) BMO_edge_flag_test(bm_src, e, DUPE_DONE) == false) { /* make sure that verts are copied */ if (!BMO_vert_flag_test(bm_src, e->v1, DUPE_DONE)) { - bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v1, vhash); + bmo_vert_copy(op, slot_vert_map_out, bm_dst, cd_vert_map, e->v1, vhash); BMO_vert_flag_enable(bm_src, e->v1, DUPE_DONE); } if (!BMO_vert_flag_test(bm_src, e->v2, DUPE_DONE)) { - bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v2, vhash); + bmo_vert_copy(op, slot_vert_map_out, bm_dst, cd_vert_map, e->v2, vhash); BMO_vert_flag_enable(bm_src, e->v2, DUPE_DONE); } /* now copy the actual edge */ @@ -257,6 +296,7 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) slot_boundary_map_out, bm_dst, bm_src, + cd_edge_map, e, vhash, ehash, @@ -271,7 +311,7 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) /* vertex pass */ BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) { if (!BMO_vert_flag_test(bm_src, v, DUPE_DONE)) { - bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash); + bmo_vert_copy(op, slot_vert_map_out, bm_dst, cd_vert_map, v, vhash); BMO_vert_flag_enable(bm_src, v, DUPE_DONE); } } @@ -284,6 +324,7 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) slot_boundary_map_out, bm_dst, bm_src, + cd_edge_map, e, vhash, ehash, @@ -291,8 +332,7 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) BMO_edge_flag_enable(bm_src, e, DUPE_DONE); } } - - bmo_face_copy(op, slot_face_map_out, bm_dst, bm_src, f, vhash, ehash); + bmo_face_copy(op, slot_face_map_out, bm_dst, cd_face_map, cd_loop_map, f, vhash, ehash); BMO_face_flag_enable(bm_src, f, DUPE_DONE); } } diff --git a/source/blender/bmesh/operators/bmo_extrude.cc b/source/blender/bmesh/operators/bmo_extrude.cc index 2e7ebb476d2..f3cb13906ea 100644 --- a/source/blender/bmesh/operators/bmo_extrude.cc +++ b/source/blender/bmesh/operators/bmo_extrude.cc @@ -56,7 +56,7 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op) BMO_face_flag_enable(bm, f_org, EXT_DEL); - f_new = BM_face_copy(bm, bm, f_org, true, true); + f_new = BM_face_copy(bm, f_org, true, true); BMO_face_flag_enable(bm, f_new, EXT_KEEP); if (select_history_map) { diff --git a/source/blender/editors/transform/transform_convert_mesh.cc b/source/blender/editors/transform/transform_convert_mesh.cc index 2bfe20dde48..0a88081787a 100644 --- a/source/blender/editors/transform/transform_convert_mesh.cc +++ b/source/blender/editors/transform/transform_convert_mesh.cc @@ -216,6 +216,12 @@ static void mesh_customdatacorrect_face_substitute_set(TransCustomDataLayer *tcl { BLI_assert(is_zero_v3(f->no)); BMesh *bm = tcld->bm; + + const BMCustomDataCopyMap cd_face_map = CustomData_bmesh_copy_map_calc(tcld->bm_origfaces->pdata, + bm->pdata); + const BMCustomDataCopyMap cd_loop_map = CustomData_bmesh_copy_map_calc(tcld->bm_origfaces->ldata, + bm->ldata); + /* It is impossible to calculate the loops weights of a face without area. * Find a substitute. */ BMFace *f_substitute = mesh_customdatacorrect_find_best_face_substitute(f); @@ -228,7 +234,8 @@ static void mesh_customdatacorrect_face_substitute_set(TransCustomDataLayer *tcl } while ((l_iter = l_iter->next) != l_first); /* Use the substitute face as the reference during the transformation. */ - BMFace *f_substitute_copy = BM_face_copy(tcld->bm_origfaces, bm, f_substitute, true, true); + BMFace *f_substitute_copy = BM_face_copy( + bm, cd_face_map, cd_loop_map, f_substitute, true, true); /* Hack: reference substitute face in `f_copy->no`. * `tcld->origfaces` is already used to restore the initial value. */ @@ -255,6 +262,11 @@ static void mesh_customdatacorrect_init_vert(TransCustomDataLayer *tcld, int j, l_num; float *loop_weights; + const BMCustomDataCopyMap cd_face_map = CustomData_bmesh_copy_map_calc(tcld->bm_origfaces->pdata, + bm->pdata); + const BMCustomDataCopyMap cd_loop_map = CustomData_bmesh_copy_map_calc(tcld->bm_origfaces->ldata, + bm->ldata); + // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) { BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, v); l_num = liter.count; @@ -268,7 +280,7 @@ static void mesh_customdatacorrect_init_vert(TransCustomDataLayer *tcld, /* Generic custom-data correction. Copy face data. */ void **val_p; if (!BLI_ghash_ensure_p(tcld->origfaces, l->f, &val_p)) { - BMFace *f_copy = BM_face_copy(tcld->bm_origfaces, bm, l->f, true, true); + BMFace *f_copy = BM_face_copy(bm, cd_face_map, cd_loop_map, l->f, true, true); *val_p = f_copy; #ifdef USE_FACE_SUBSTITUTE if (is_zero_v3(l->f->no)) { @@ -697,6 +709,8 @@ static void mesh_customdatacorrect_restore(TransInfo *t) BMesh *bm = tcld->bm; BMesh *bm_copy = tcld->bm_origfaces; + const BMCustomDataCopyMap cd_loop_map = CustomData_bmesh_copy_map_calc(bm_copy->ldata, + bm->ldata); GHashIterator gh_iter; GHASH_ITER (gh_iter, tcld->origfaces) { @@ -709,7 +723,7 @@ static void mesh_customdatacorrect_restore(TransInfo *t) l_copy = BM_FACE_FIRST_LOOP(f_copy); do { /* TODO: Restore only the elements that transform. */ - BM_elem_attrs_copy(bm_copy, bm, l_copy, l_iter); + BM_elem_attrs_copy(bm, cd_loop_map, l_copy, l_iter); l_copy = l_copy->next; } while ((l_iter = l_iter->next) != l_first); } diff --git a/source/blender/python/bmesh/bmesh_py_types.cc b/source/blender/python/bmesh/bmesh_py_types.cc index f1554b3f9a6..4b136647c8d 100644 --- a/source/blender/python/bmesh/bmesh_py_types.cc +++ b/source/blender/python/bmesh/bmesh_py_types.cc @@ -1495,33 +1495,42 @@ static PyObject *bpy_bm_elem_copy_from(BPy_BMElem *self, BPy_BMElem *value) if (value->ele != self->ele) { switch (self->ele->head.htype) { - case BM_VERT: - BM_elem_attrs_copy(value->bm, - self->bm, - CD_MASK_BM_ELEM_PYPTR, + case BM_VERT: { + const BMCustomDataCopyMap cd_vert_map = CustomData_bmesh_copy_map_calc( + value->bm->vdata, self->bm->vdata, CD_MASK_BM_ELEM_PYPTR); + BM_elem_attrs_copy(self->bm, + cd_vert_map, reinterpret_cast(value->ele), reinterpret_cast(self->ele)); break; - case BM_EDGE: - BM_elem_attrs_copy(value->bm, - self->bm, - CD_MASK_BM_ELEM_PYPTR, - reinterpret_cast(value->ele), - reinterpret_cast(self->ele)); + } + case BM_EDGE: { + const BMCustomDataCopyMap cd_edge_map = CustomData_bmesh_copy_map_calc( + value->bm->edata, self->bm->edata, CD_MASK_BM_ELEM_PYPTR); + BM_elem_attrs_copy(self->bm, + cd_edge_map, + reinterpret_cast(value->ele), + reinterpret_cast(self->ele)); break; - case BM_FACE: - BM_elem_attrs_copy(value->bm, - self->bm, - CD_MASK_BM_ELEM_PYPTR, - reinterpret_cast(value->ele), - reinterpret_cast(self->ele)); + } + case BM_FACE: { + const BMCustomDataCopyMap cd_face_map = CustomData_bmesh_copy_map_calc( + value->bm->pdata, self->bm->pdata, CD_MASK_BM_ELEM_PYPTR); + BM_elem_attrs_copy(self->bm, + cd_face_map, + reinterpret_cast(value->ele), + reinterpret_cast(self->ele)); break; - case BM_LOOP: - BM_elem_attrs_copy(value->bm, - self->bm, - CD_MASK_BM_ELEM_PYPTR, - reinterpret_cast(value->ele), - reinterpret_cast(self->ele)); + } + case BM_LOOP: { + const BMCustomDataCopyMap cd_loop_map = CustomData_bmesh_copy_map_calc( + value->bm->ldata, self->bm->ldata, CD_MASK_BM_ELEM_PYPTR); + BM_elem_attrs_copy(self->bm, + cd_loop_map, + reinterpret_cast(value->ele), + reinterpret_cast(self->ele)); + break; + } } } @@ -1918,7 +1927,7 @@ static PyObject *bpy_bmface_copy(BPy_BMFace *self, PyObject *args, PyObject *kw) return nullptr; } - f_cpy = BM_face_copy(bm, bm, self->f, do_verts, do_edges); + f_cpy = BM_face_copy(bm, self->f, do_verts, do_edges); if (f_cpy) { return BPy_BMFace_CreatePyObject(bm, f_cpy); @@ -2233,7 +2242,14 @@ static PyObject *bpy_bmvertseq_new(BPy_BMElemSeq *self, PyObject *args) } if (py_vert_example) { - BM_elem_attrs_copy(py_vert_example->bm, bm, py_vert_example->v, v); + if (py_vert_example->bm == bm) { + BM_elem_attrs_copy(*bm, py_vert_example->v, v); + } + else { + const BMCustomDataCopyMap cd_vert_map = CustomData_bmesh_copy_map_calc( + py_vert_example->bm->vdata, bm->vdata); + BM_elem_attrs_copy(bm, cd_vert_map, py_vert_example->v, v); + } } return BPy_BMVert_CreatePyObject(bm, v); @@ -2294,7 +2310,14 @@ static PyObject *bpy_bmedgeseq_new(BPy_BMElemSeq *self, PyObject *args) } if (py_edge_example) { - BM_elem_attrs_copy(py_edge_example->bm, bm, py_edge_example->e, e); + if (py_edge_example->bm == bm) { + BM_elem_attrs_copy(*bm, py_edge_example->e, e); + } + else { + const BMCustomDataCopyMap cd_edge_map = CustomData_bmesh_copy_map_calc( + py_edge_example->bm->edata, bm->edata); + BM_elem_attrs_copy(bm, cd_edge_map, py_edge_example->e, e); + } } ret = BPy_BMEdge_CreatePyObject(bm, e);