diff --git a/source/blender/blenkernel/BKE_customdata.hh b/source/blender/blenkernel/BKE_customdata.hh index 7b052bbdd7d..db7b3f37a85 100644 --- a/source/blender/blenkernel/BKE_customdata.hh +++ b/source/blender/blenkernel/BKE_customdata.hh @@ -90,6 +90,8 @@ void customData_mask_layers__print(const CustomData_MeshMasks *mask); typedef void (*cd_interp)( const void **sources, const float *weights, const float *sub_weights, int count, void *dest); typedef void (*cd_copy)(const void *source, void *dest, int count); +typedef void (*cd_set_default_value)(void *data, int count); +typedef void (*cd_free)(void *data, int count); typedef bool (*cd_validate)(void *item, uint totitems, bool do_fixes); /** @@ -343,20 +345,57 @@ void CustomData_copy_elements(eCustomDataType type, void *src_data_ofs, void *dst_data_ofs, int count); -void CustomData_bmesh_copy_data(const CustomData *source, - CustomData *dest, - void *src_block, - void **dest_block); + /** * Copy all layers from the source to the destination block. * Allocate the result block if necessary, otherwise free its existing layer data. */ void CustomData_bmesh_copy_block(CustomData &data, void *src_block, void **dst_block); -void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source, - CustomData *dest, - void *src_block, - void **dest_block, - eCustomDataMask mask_exclude); + +/** Holds the minimal data necessary to copy data blocks from one custom data format to another. */ +struct BMCustomDataCopyMap { + struct TrivialCopy { + int size; + int src_offset; + int dst_offset; + }; + struct Copy { + cd_copy fn; + int src_offset; + int dst_offset; + }; + struct TrivialDefault { + int size; + int dst_offset; + }; + struct Default { + cd_set_default_value fn; + int dst_offset; + }; + struct Free { + cd_free fn; + int dst_offset; + }; + blender::Vector trivial_copies; + blender::Vector copies; + blender::Vector trivial_defaults; + blender::Vector defaults; + blender::Vector free; +}; + +/** Precalculate a map for more efficient copying between custom data formats. */ +BMCustomDataCopyMap CustomData_bmesh_copy_map_calc(const CustomData &src, + const CustomData &dst, + eCustomDataMask mask_exclude = 0); + +/** + * Copy custom data layers for one element between two potentially different formats with a + * precalculated map. + */ +void CustomData_bmesh_copy_block(CustomData &dst_data, + const BMCustomDataCopyMap &map, + const void *src_block, + void **dest_block); /** * Copies data of a single layer of a given type. diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 56a01566e9c..cd7920327b8 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -61,6 +61,7 @@ /* only for customdata_data_transfer_interp_normal_normals */ #include "data_transfer_intern.h" +using blender::Array; using blender::BitVector; using blender::float2; using blender::ImplicitSharingInfo; @@ -139,7 +140,7 @@ struct LayerTypeInfo { * size should be the size of one element of this layer's data (e.g. * LayerTypeInfo.size) */ - void (*free)(void *data, int count); + cd_free free; /** * a function to interpolate between count source elements of this @@ -165,7 +166,7 @@ struct LayerTypeInfo { * Set values to the type's default. If undefined, the default is assumed to be zeroes. * Memory pointed to by #data is expected to be uninitialized. */ - void (*set_default_value)(void *data, int count); + cd_set_default_value set_default_value; /** * Construct and fill a valid value for the type. Necessary for non-trivial types. * Memory pointed to by #data is expected to be uninitialized. @@ -3668,6 +3669,8 @@ bool CustomData_bmesh_merge_layout(const CustomData *source, return false; } + const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc(destold, *dest); + int iter_type; int totelem; switch (htype) { @@ -3703,7 +3706,7 @@ bool CustomData_bmesh_merge_layout(const CustomData *source, /* Ensure all current elements follow new customdata layout. */ BM_ITER_MESH (h, &iter, bm, iter_type) { void *tmp = nullptr; - CustomData_bmesh_copy_data(&destold, dest, h->data, &tmp); + CustomData_bmesh_copy_block(*dest, map, h->data, &tmp); CustomData_bmesh_free_block(&destold, &h->data); h->data = tmp; } @@ -3718,7 +3721,7 @@ bool CustomData_bmesh_merge_layout(const CustomData *source, BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { void *tmp = nullptr; - CustomData_bmesh_copy_data(&destold, dest, l->head.data, &tmp); + CustomData_bmesh_copy_block(*dest, map, l->head.data, &tmp); CustomData_bmesh_free_block(&destold, &l->head.data); l->head.data = tmp; } @@ -3835,68 +3838,76 @@ void CustomData_bmesh_set_default(CustomData *data, void **block) } } -static bool customdata_layer_copy_check(const CustomDataLayer &source, const CustomDataLayer &dest) +BMCustomDataCopyMap CustomData_bmesh_copy_map_calc(const CustomData &src, + const CustomData &dst, + const eCustomDataMask mask_exclude) { - return source.type == dest.type && STREQ(source.name, dest.name); -} + BMCustomDataCopyMap map; + for (const CustomDataLayer &layer_dst : Span(dst.layers, dst.totlayer)) { + const int dst_offset = layer_dst.offset; + const eCustomDataType dst_type = eCustomDataType(layer_dst.type); + const LayerTypeInfo &type_info = *layerType_getInfo(dst_type); -void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source, - CustomData *dest, - void *src_block, - void **dest_block, - const eCustomDataMask mask_exclude) -{ - if (*dest_block == nullptr) { - CustomData_bmesh_alloc_block(dest, dest_block); - if (*dest_block) { - memset(*dest_block, 0, dest->totsize); - } - } - - BitVector<> copied_layers(dest->totlayer); - - for (int layer_src_i : IndexRange(source->totlayer)) { - const CustomDataLayer &layer_src = source->layers[layer_src_i]; - - if (CD_TYPE_AS_MASK(layer_src.type) & mask_exclude) { - continue; - } - - for (int layer_dst_i : IndexRange(dest->totlayer)) { - CustomDataLayer &layer_dst = dest->layers[layer_dst_i]; - - if (!customdata_layer_copy_check(layer_src, layer_dst)) { - continue; - } - - copied_layers[layer_dst_i].set(true); - - const void *src_data = POINTER_OFFSET(src_block, layer_src.offset); - void *dest_data = POINTER_OFFSET(*dest_block, layer_dst.offset); - const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer_src.type)); - if (typeInfo->copy) { - typeInfo->copy(src_data, dest_data, 1); + const int src_offset = CustomData_get_offset_named(&src, dst_type, layer_dst.name); + if (src_offset == -1 || CD_TYPE_AS_MASK(dst_type) & mask_exclude) { + if (type_info.set_default_value) { + map.defaults.append({type_info.set_default_value, dst_offset}); } else { - memcpy(dest_data, src_data, typeInfo->size); + map.trivial_defaults.append({type_info.size, dst_offset}); + } + } + else { + if (type_info.copy) { + map.copies.append({type_info.copy, src_offset, dst_offset}); + } + else { + /* NOTE: A way to improve performance of copies (by reducing the number of `memcpy` + * calls) would be combining contiguous in the source and result format. */ + map.trivial_copies.append({type_info.size, src_offset, dst_offset}); } } - } - /* Initialize dest layers that weren't in source. */ - for (int layer_dst_i : IndexRange(dest->totlayer)) { - if (!copied_layers[layer_dst_i]) { - CustomData_bmesh_set_default_n(dest, dest_block, layer_dst_i); + if (type_info.free) { + map.free.append({type_info.free, dst_offset}); } } + return map; } -void CustomData_bmesh_copy_data(const CustomData *source, - CustomData *dest, - void *src_block, - void **dest_block) +void CustomData_bmesh_copy_block(CustomData &dst_data, + const BMCustomDataCopyMap ©_map, + const void *src_block, + void **dst_block) { - CustomData_bmesh_copy_data_exclude_by_type(source, dest, src_block, dest_block, 0); + if (*dst_block) { + for (const BMCustomDataCopyMap::Free &info : copy_map.free) { + info.fn(POINTER_OFFSET(*dst_block, info.dst_offset), 1); + } + } + else { + if (dst_data.totsize == 0) { + return; + } + *dst_block = BLI_mempool_alloc(dst_data.pool); + } + + for (const BMCustomDataCopyMap::TrivialCopy &info : copy_map.trivial_copies) { + memcpy(POINTER_OFFSET(*dst_block, info.dst_offset), + POINTER_OFFSET(src_block, info.src_offset), + info.size); + } + for (const BMCustomDataCopyMap::Copy &info : copy_map.copies) { + info.fn(POINTER_OFFSET(src_block, info.src_offset), + POINTER_OFFSET(*dst_block, info.dst_offset), + 1); + } + for (const BMCustomDataCopyMap::TrivialDefault &info : copy_map.trivial_defaults) { + memset(POINTER_OFFSET(*dst_block, info.dst_offset), 0, info.size); + } + for (const BMCustomDataCopyMap::Default &info : copy_map.defaults) { + info.fn(POINTER_OFFSET(*dst_block, info.dst_offset), 1); + } } void CustomData_bmesh_copy_block(CustomData &data, void *src_block, void **dst_block) diff --git a/source/blender/bmesh/intern/bmesh_construct.cc b/source/blender/bmesh/intern/bmesh_construct.cc index e33347a5642..dcc4447733a 100644 --- a/source/blender/bmesh/intern/bmesh_construct.cc +++ b/source/blender/bmesh/intern/bmesh_construct.cc @@ -317,149 +317,110 @@ void BM_verts_sort_radial_plane(BMVert **vert_arr, int len) /*************************************************************/ -static void bm_vert_attrs_copy( - BMesh *bm_src, BMesh *bm_dst, const BMVert *v_src, BMVert *v_dst, eCustomDataMask mask_exclude) +void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMVert *src, BMVert *dst) { - if ((bm_src == bm_dst) && (v_src == v_dst)) { - BLI_assert_msg(0, "BMVert: source and target match"); - return; - } - if ((mask_exclude & CD_MASK_NORMAL) == 0) { - copy_v3_v3(v_dst->no, v_src->no); - } - CustomData_bmesh_free_block_data_exclude_by_type(&bm_dst->vdata, v_dst->head.data, mask_exclude); - CustomData_bmesh_copy_data_exclude_by_type( - &bm_src->vdata, &bm_dst->vdata, v_src->head.data, &v_dst->head.data, mask_exclude); -} - -static void bm_edge_attrs_copy( - BMesh *bm_src, BMesh *bm_dst, const BMEdge *e_src, BMEdge *e_dst, eCustomDataMask mask_exclude) -{ - if ((bm_src == bm_dst) && (e_src == e_dst)) { - BLI_assert_msg(0, "BMEdge: source and target match"); - return; - } - CustomData_bmesh_free_block_data_exclude_by_type(&bm_dst->edata, e_dst->head.data, mask_exclude); - CustomData_bmesh_copy_data_exclude_by_type( - &bm_src->edata, &bm_dst->edata, e_src->head.data, &e_dst->head.data, mask_exclude); -} - -static void bm_loop_attrs_copy( - BMesh *bm_src, BMesh *bm_dst, const BMLoop *l_src, BMLoop *l_dst, eCustomDataMask mask_exclude) -{ - if ((bm_src == bm_dst) && (l_src == l_dst)) { - BLI_assert_msg(0, "BMLoop: source and target match"); - return; - } - CustomData_bmesh_free_block_data_exclude_by_type(&bm_dst->ldata, l_dst->head.data, mask_exclude); - CustomData_bmesh_copy_data_exclude_by_type( - &bm_src->ldata, &bm_dst->ldata, l_src->head.data, &l_dst->head.data, mask_exclude); -} - -static void bm_face_attrs_copy( - BMesh *bm_src, BMesh *bm_dst, const BMFace *f_src, BMFace *f_dst, eCustomDataMask mask_exclude) -{ - if ((bm_src == bm_dst) && (f_src == f_dst)) { - BLI_assert_msg(0, "BMFace: source and target match"); - return; - } - if ((mask_exclude & CD_MASK_NORMAL) == 0) { - copy_v3_v3(f_dst->no, f_src->no); - } - CustomData_bmesh_free_block_data_exclude_by_type(&bm_dst->pdata, f_dst->head.data, mask_exclude); - CustomData_bmesh_copy_data_exclude_by_type( - &bm_src->pdata, &bm_dst->pdata, f_src->head.data, &f_dst->head.data, mask_exclude); - f_dst->mat_nr = f_src->mat_nr; -} - -void BM_elem_attrs_copy_ex(BMesh *bm_src, - BMesh *bm_dst, - const void *ele_src_v, - void *ele_dst_v, - const char hflag_mask, - const uint64_t cd_mask_exclude) -{ - /* TODO: Special handling for hide flags? */ - /* TODO: swap src/dst args, everywhere else in bmesh does other way round. */ - - const BMHeader *ele_src = static_cast(ele_src_v); - BMHeader *ele_dst = static_cast(ele_dst_v); - - BLI_assert(ele_src->htype == ele_dst->htype); - BLI_assert(ele_src != ele_dst); - - if ((hflag_mask & BM_ELEM_SELECT) == 0) { - /* First we copy select */ - if (BM_elem_flag_test((BMElem *)ele_src, BM_ELEM_SELECT)) { - BM_elem_select_set(bm_dst, (BMElem *)ele_dst, true); - } - } - - /* Now we copy flags */ - if (hflag_mask == 0) { - ele_dst->hflag = ele_src->hflag; - } - else if (hflag_mask == 0xff) { - /* pass */ - } - else { - ele_dst->hflag = ((ele_dst->hflag & hflag_mask) | (ele_src->hflag & ~hflag_mask)); - } - - /* Copy specific attributes */ - switch (ele_dst->htype) { - case BM_VERT: - bm_vert_attrs_copy( - bm_src, bm_dst, (const BMVert *)ele_src, (BMVert *)ele_dst, cd_mask_exclude); - break; - case BM_EDGE: - bm_edge_attrs_copy( - bm_src, bm_dst, (const BMEdge *)ele_src, (BMEdge *)ele_dst, cd_mask_exclude); - break; - case BM_LOOP: - bm_loop_attrs_copy( - bm_src, bm_dst, (const BMLoop *)ele_src, (BMLoop *)ele_dst, cd_mask_exclude); - break; - case BM_FACE: - bm_face_attrs_copy( - bm_src, bm_dst, (const BMFace *)ele_src, (BMFace *)ele_dst, cd_mask_exclude); - break; - default: - BLI_assert(0); - break; - } -} - -void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMVert *src, BMVert *dst) -{ - CustomData_bmesh_free_block_data_exclude_by_type(&bm_dst->vdata, dst->head.data, 0); - CustomData_bmesh_copy_data_exclude_by_type( - &bm_src->vdata, &bm_dst->vdata, src->head.data, &dst->head.data, 0); + CustomData_bmesh_copy_block(bm->vdata, map, src->head.data, &dst->head.data); dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT; copy_v3_v3(dst->no, src->no); } -void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMEdge *src, BMEdge *dst) +void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMEdge *src, BMEdge *dst) { - CustomData_bmesh_free_block_data_exclude_by_type(&bm_dst->edata, dst->head.data, 0); - CustomData_bmesh_copy_data_exclude_by_type( - &bm_src->edata, &bm_dst->edata, src->head.data, &dst->head.data, 0); + CustomData_bmesh_copy_block(bm->vdata, map, src->head.data, &dst->head.data); dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT; } -void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMFace *src, BMFace *dst) +void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMFace *src, BMFace *dst) { - CustomData_bmesh_free_block_data_exclude_by_type(&bm_dst->pdata, dst->head.data, 0); - CustomData_bmesh_copy_data_exclude_by_type( - &bm_src->pdata, &bm_dst->pdata, src->head.data, &dst->head.data, 0); + CustomData_bmesh_copy_block(bm->vdata, map, src->head.data, &dst->head.data); dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT; copy_v3_v3(dst->no, src->no); dst->mat_nr = src->mat_nr; } +void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMLoop *src, BMLoop *dst) +{ + CustomData_bmesh_copy_block(bm->vdata, map, src->head.data, &dst->head.data); + 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) { - CustomData_bmesh_free_block_data_exclude_by_type(&bm_dst->ldata, dst->head.data, 0); - CustomData_bmesh_copy_data_exclude_by_type( - &bm_src->ldata, &bm_dst->ldata, src->head.data, &dst->head.data, 0); - dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT; + 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) @@ -503,8 +464,12 @@ void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v) } /* helper function for 'BM_mesh_copy' */ -static BMFace *bm_mesh_copy_new_face( - BMesh *bm_new, BMesh *bm_old, BMVert **vtable, BMEdge **etable, BMFace *f) +static BMFace *bm_mesh_copy_new_face(BMesh *bm_new, + const BMCustomDataCopyMap &face_map, + const BMCustomDataCopyMap &loop_map, + BMVert **vtable, + BMEdge **etable, + BMFace *f) { BMLoop **loops = BLI_array_alloca(loops, f->len); BMVert **verts = BLI_array_alloca(verts, f->len); @@ -532,13 +497,16 @@ static BMFace *bm_mesh_copy_new_face( /* use totface in case adding some faces fails */ BM_elem_index_set(f_new, (bm_new->totface - 1)); /* set_inline */ - BM_elem_attrs_copy_ex(bm_old, bm_new, f, f_new, 0xff, 0x0); + CustomData_bmesh_copy_block(bm_new->vdata, face_map, f->head.data, &f_new->head.data); + copy_v3_v3(f_new->no, f->no); + f_new->mat_nr = f->mat_nr; f_new->head.hflag = f->head.hflag; /* low level! don't do this for normal api use */ j = 0; l_iter = l_first = BM_FACE_FIRST_LOOP(f_new); do { - BM_elem_attrs_copy(bm_old, bm_new, loops[j], l_iter); + CustomData_bmesh_copy_block(bm_new->vdata, loop_map, loops[j]->head.data, &l_iter->head.data); + l_iter->head.hflag = loops[j]->head.hflag & ~BM_ELEM_SELECT; j++; } while ((l_iter = l_iter->next) != l_first); @@ -666,6 +634,15 @@ BMesh *BM_mesh_copy(BMesh *bm_old) BM_mesh_copy_init_customdata(bm_new, bm_old, &allocsize); + const BMCustomDataCopyMap vert_map = CustomData_bmesh_copy_map_calc(bm_old->vdata, + bm_new->vdata); + const BMCustomDataCopyMap edge_map = CustomData_bmesh_copy_map_calc(bm_old->edata, + bm_new->edata); + const BMCustomDataCopyMap face_map = CustomData_bmesh_copy_map_calc(bm_old->pdata, + bm_new->pdata); + const BMCustomDataCopyMap loop_map = CustomData_bmesh_copy_map_calc(bm_old->ldata, + bm_new->ldata); + vtable = static_cast( MEM_mallocN(sizeof(BMVert *) * bm_old->totvert, "BM_mesh_copy vtable")); etable = static_cast( @@ -676,7 +653,8 @@ BMesh *BM_mesh_copy(BMesh *bm_old) BM_ITER_MESH_INDEX (v, &iter, bm_old, BM_VERTS_OF_MESH, i) { /* copy between meshes so can't use 'example' argument */ v_new = BM_vert_create(bm_new, v->co, nullptr, BM_CREATE_SKIP_CD); - BM_elem_attrs_copy_ex(bm_old, bm_new, v, v_new, 0xff, 0x0); + CustomData_bmesh_copy_block(bm_new->vdata, vert_map, v->head.data, &v_new->head.data); + copy_v3_v3(v_new->no, v->no); v_new->head.hflag = v->head.hflag; /* low level! don't do this for normal api use */ vtable[i] = v_new; BM_elem_index_set(v, i); /* set_inline */ @@ -695,7 +673,7 @@ BMesh *BM_mesh_copy(BMesh *bm_old) e, BM_CREATE_SKIP_CD); - BM_elem_attrs_copy_ex(bm_old, bm_new, e, e_new, 0xff, 0x0); + CustomData_bmesh_copy_block(bm_new->edata, vert_map, e->head.data, &e_new->head.data); e_new->head.hflag = e->head.hflag; /* low level! don't do this for normal api use */ etable[i] = e_new; BM_elem_index_set(e, i); /* set_inline */ @@ -710,7 +688,7 @@ BMesh *BM_mesh_copy(BMesh *bm_old) BM_ITER_MESH_INDEX (f, &iter, bm_old, BM_FACES_OF_MESH, i) { BM_elem_index_set(f, i); /* set_inline */ - f_new = bm_mesh_copy_new_face(bm_new, bm_old, vtable, etable, f); + f_new = bm_mesh_copy_new_face(bm_new, face_map, loop_map, vtable, etable, f); ftable[i] = f_new; diff --git a/source/blender/bmesh/intern/bmesh_construct.hh b/source/blender/bmesh/intern/bmesh_construct.hh index 40c080a4e97..8bd2fc98dd1 100644 --- a/source/blender/bmesh/intern/bmesh_construct.hh +++ b/source/blender/bmesh/intern/bmesh_construct.hh @@ -122,17 +122,22 @@ BMFace *BM_face_create_ngon_verts(BMesh *bm, bool create_edges); /** - * Copies attributes, e.g. customdata, header flags, etc, from one element - * to another of the same type. + * Copy attributes between elements with a precalculated map of copy operations. This significantly + * improves performance when copying, since all the work of finding common layers doesn't have to + * be done for every element. */ -void BM_elem_attrs_copy_ex(BMesh *bm_src, - BMesh *bm_dst, - const void *ele_src_v, - void *ele_dst_v, - char hflag_mask, - uint64_t cd_mask_exclude); +void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMVert *src, BMVert *dst); +void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMEdge *src, BMEdge *dst); +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 (though they may match). */ +/** + * 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); @@ -144,6 +149,16 @@ 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_interp.cc b/source/blender/bmesh/intern/bmesh_interp.cc index 72ef46ec701..8014e99611a 100644 --- a/source/blender/bmesh/intern/bmesh_interp.cc +++ b/source/blender/bmesh/intern/bmesh_interp.cc @@ -768,6 +768,8 @@ void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src) static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data) { + const BMCustomDataCopyMap cd_map = CustomData_bmesh_copy_map_calc(*olddata, *data); + BMIter iter; BLI_mempool *oldpool = olddata->pool; void *block; @@ -779,8 +781,7 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data) BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { block = nullptr; - CustomData_bmesh_set_default(data, &block); - CustomData_bmesh_copy_data(olddata, data, eve->head.data, &block); + CustomData_bmesh_copy_block(*data, cd_map, eve->head.data, &block); CustomData_bmesh_free_block(olddata, &eve->head.data); eve->head.data = block; } @@ -792,8 +793,7 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data) BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { block = nullptr; - CustomData_bmesh_set_default(data, &block); - CustomData_bmesh_copy_data(olddata, data, eed->head.data, &block); + CustomData_bmesh_copy_block(*data, cd_map, eed->head.data, &block); CustomData_bmesh_free_block(olddata, &eed->head.data); eed->head.data = block; } @@ -807,8 +807,7 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data) BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { block = nullptr; - CustomData_bmesh_set_default(data, &block); - CustomData_bmesh_copy_data(olddata, data, l->head.data, &block); + CustomData_bmesh_copy_block(*data, cd_map, l->head.data, &block); CustomData_bmesh_free_block(olddata, &l->head.data); l->head.data = block; } @@ -821,8 +820,7 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data) BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { block = nullptr; - CustomData_bmesh_set_default(data, &block); - CustomData_bmesh_copy_data(olddata, data, efa->head.data, &block); + CustomData_bmesh_copy_block(*data, cd_map, efa->head.data, &block); CustomData_bmesh_free_block(olddata, &efa->head.data); efa->head.data = block; } diff --git a/source/blender/python/bmesh/bmesh_py_types.cc b/source/blender/python/bmesh/bmesh_py_types.cc index 7afd3b45ff9..f1554b3f9a6 100644 --- a/source/blender/python/bmesh/bmesh_py_types.cc +++ b/source/blender/python/bmesh/bmesh_py_types.cc @@ -1494,7 +1494,35 @@ static PyObject *bpy_bm_elem_copy_from(BPy_BMElem *self, BPy_BMElem *value) } if (value->ele != self->ele) { - BM_elem_attrs_copy_ex(value->bm, self->bm, value->ele, self->ele, 0xff, CD_MASK_BM_ELEM_PYPTR); + switch (self->ele->head.htype) { + case BM_VERT: + BM_elem_attrs_copy(value->bm, + self->bm, + CD_MASK_BM_ELEM_PYPTR, + 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)); + 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)); + 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)); + } } Py_RETURN_NONE;