BMesh: Optimize copying attributes from many elements at once #115824

Merged
Hans Goudey merged 9 commits from HooglyBoogly/blender:bmesh-cd-copy-performance-fix into main 2023-12-09 05:37:47 +01:00
6 changed files with 286 additions and 217 deletions

View File

@ -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<TrivialCopy> trivial_copies;
blender::Vector<Copy> copies;
blender::Vector<TrivialDefault> trivial_defaults;
blender::Vector<Default> defaults;
blender::Vector<Free> 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.

View File

@ -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 &copy_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)

View File

@ -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<const BMHeader *>(ele_src_v);
BMHeader *ele_dst = static_cast<BMHeader *>(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<BMVert **>(
MEM_mallocN(sizeof(BMVert *) * bm_old->totvert, "BM_mesh_copy vtable"));
etable = static_cast<BMEdge **>(
@ -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;

View File

@ -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);
/**

View File

@ -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;
}

View File

@ -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<const BMVert *>(value->ele),
reinterpret_cast<BMVert *>(self->ele));
break;
case BM_EDGE:
BM_elem_attrs_copy(value->bm,
self->bm,
CD_MASK_BM_ELEM_PYPTR,
reinterpret_cast<const BMVert *>(value->ele),
reinterpret_cast<BMVert *>(self->ele));
break;
case BM_FACE:
BM_elem_attrs_copy(value->bm,
self->bm,
CD_MASK_BM_ELEM_PYPTR,
reinterpret_cast<const BMVert *>(value->ele),
reinterpret_cast<BMVert *>(self->ele));
break;
case BM_LOOP:
BM_elem_attrs_copy(value->bm,
self->bm,
CD_MASK_BM_ELEM_PYPTR,
reinterpret_cast<const BMVert *>(value->ele),
reinterpret_cast<BMVert *>(self->ele));
}
}
Py_RETURN_NONE;