From 71879d665d69bd1e96dab0dc089785a43d1d42fd Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 18 Jan 2022 21:44:08 +1100 Subject: BMesh: improve handling of custom-data flag (Mesh.cd_flag) Code that handled merging & initializing custom-data from other meshes sometimes missed checks for this flag, causing bevel weights to lost when the mesh was converted to a BMesh. The following changes are a more general fix for T94197. - Add BM_mesh_copy_init_customdata_from_mesh_array which initializes custom-data from multiple meshes at once. As well as initializing custom-data layers from Mesh.cd_flag. This isn't essential for boolean, however it avoids the overhead of resizing custom-data layers. - Loading mesh data into a BMesh now respects Mesh.cd_flag instead of only checking if the BMesh custom-data-layer exists. Without this, the order of meshes passed to BM_mesh_bm_from_me could give different (incorrect) results. - Copying mesh data now copies `cd_flag` too. This is a precaution as in my tests evaluating modifiers these values always matched. Nevertheless it's correct to copy this value as custom-data it's self is being copied. --- source/blender/bmesh/intern/bmesh_construct.c | 42 ++++++++++++++++++++---- source/blender/bmesh/intern/bmesh_construct.h | 13 ++++++++ source/blender/bmesh/intern/bmesh_mesh_convert.c | 19 +++++++---- 3 files changed, 61 insertions(+), 13 deletions(-) (limited to 'source/blender/bmesh') diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 5a9d1ba7bc4..a127089ad2c 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -510,23 +510,51 @@ static BMFace *bm_mesh_copy_new_face( return f_new; } -void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst, - const Mesh *me_src, - const BMAllocTemplate *allocsize) +void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst, + const Mesh *me_src_array[], + const int me_src_array_len, + const BMAllocTemplate *allocsize) + { if (allocsize == NULL) { allocsize = &bm_mesh_allocsize_default; } - CustomData_copy(&me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0); - CustomData_copy(&me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0); - CustomData_copy(&me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0); - CustomData_copy(&me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0); + char cd_flag = 0; + + for (int i = 0; i < me_src_array_len; i++) { + const Mesh *me_src = me_src_array[i]; + if (i == 0) { + CustomData_copy(&me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0); + CustomData_copy(&me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0); + CustomData_copy(&me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0); + CustomData_copy(&me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0); + } + else { + CustomData_merge(&me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0); + CustomData_merge(&me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0); + CustomData_merge(&me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0); + CustomData_merge(&me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0); + } + + cd_flag |= me_src->cd_flag; + } + + cd_flag |= BM_mesh_cd_flag_from_bmesh(bm_dst); CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT); CustomData_bmesh_init_pool(&bm_dst->edata, allocsize->totedge, BM_EDGE); CustomData_bmesh_init_pool(&bm_dst->ldata, allocsize->totloop, BM_LOOP); CustomData_bmesh_init_pool(&bm_dst->pdata, allocsize->totface, BM_FACE); + + BM_mesh_cd_flag_apply(bm_dst, cd_flag); +} + +void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst, + const Mesh *me_src, + const BMAllocTemplate *allocsize) +{ + BM_mesh_copy_init_customdata_from_mesh_array(bm_dst, &me_src, 1, allocsize); } void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTemplate *allocsize) diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h index 7b25a5b5a2a..008219165a8 100644 --- a/source/blender/bmesh/intern/bmesh_construct.h +++ b/source/blender/bmesh/intern/bmesh_construct.h @@ -146,6 +146,19 @@ void BM_elem_attrs_copy_ex(BMesh *bm_src, void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v); void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v); +/** + * Initialize the `bm_dst` layers in preparation for populating it's contents with multiple meshes. + * Typically done using multiple calls to #BM_mesh_bm_from_me with the same `bm` argument). + * + * \note While the custom-data layers of all meshes are created, the active layers are set + * by the first instance mesh containing that layer type. + * This means the first mesh should always be the main mesh (from the user perspective), + * as this is the mesh they have control over (active UV layer for rendering for example). + */ +void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst, + const struct Mesh *me_src_array[], + int me_src_array_len, + const struct BMAllocTemplate *allocsize); void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst, const struct Mesh *me_src, const struct BMAllocTemplate *allocsize); diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.c b/source/blender/bmesh/intern/bmesh_mesh_convert.c index d99fefbcd02..6b44fe2c9ff 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.c +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.c @@ -315,13 +315,20 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE); CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP); CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE); - - BM_mesh_cd_flag_apply(bm, me->cd_flag); } - - const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); - const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); - const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); + BM_mesh_cd_flag_apply(bm, me->cd_flag | (is_new ? 0 : BM_mesh_cd_flag_from_bmesh(bm))); + + /* Only copy these values over if the source mesh is flagged to be using them. + * Even if `bm` has these layers, they may have been added from another mesh, when `!is_new`. */ + const int cd_vert_bweight_offset = (me->cd_flag & ME_CDFLAG_VERT_BWEIGHT) ? + CustomData_get_offset(&bm->vdata, CD_BWEIGHT) : + -1; + const int cd_edge_bweight_offset = (me->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) ? + CustomData_get_offset(&bm->edata, CD_BWEIGHT) : + -1; + const int cd_edge_crease_offset = (me->cd_flag & ME_CDFLAG_EDGE_CREASE) ? + CustomData_get_offset(&bm->edata, CD_CREASE) : + -1; const int cd_shape_key_offset = tot_shape_keys ? CustomData_get_offset(&bm->vdata, CD_SHAPEKEY) : -1; const int cd_shape_keyindex_offset = is_new && (tot_shape_keys || params->add_key_index) ? -- cgit v1.2.3