BMesh: Optimize copying attributes from many elements at once #115824
|
@ -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.
|
||||
*/
|
||||
HooglyBoogly marked this conversation as resolved
Outdated
|
||||
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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
HooglyBoogly marked this conversation as resolved
Outdated
Campbell Barton
commented
Prefer use a utility function for each type instead of copying each type & it's members here. Prefer use a utility function for each type instead of copying each type & it's members here.
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue
Prefer to order the helper argument (map in this case) last, since it's the convention to have containers first
bm
in this case.