[Bf-blender-cvs] [71879d665d6] master: BMesh: improve handling of custom-data flag (Mesh.cd_flag)

Campbell Barton noreply at git.blender.org
Wed Jan 19 04:31:13 CET 2022


Commit: 71879d665d69bd1e96dab0dc089785a43d1d42fd
Author: Campbell Barton
Date:   Tue Jan 18 21:44:08 2022 +1100
Branches: master
https://developer.blender.org/rB71879d665d69bd1e96dab0dc089785a43d1d42fd

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.

===================================================================

M	source/blender/blenkernel/intern/mesh.cc
M	source/blender/bmesh/intern/bmesh_construct.c
M	source/blender/bmesh/intern/bmesh_construct.h
M	source/blender/bmesh/intern/bmesh_mesh_convert.c
M	source/blender/modifiers/intern/MOD_boolean.cc

===================================================================

diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 1aa3477437a..9b0cf17a424 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -150,6 +150,8 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
 
   BKE_mesh_update_customdata_pointers(mesh_dst, do_tessface);
 
+  mesh_dst->cd_flag = mesh_src->cd_flag;
+
   mesh_dst->edit_mesh = nullptr;
 
   mesh_dst->mselect = (MSelect *)MEM_dupallocN(mesh_dst->mselect);
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) ?
diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc
index 2a303c7741c..bb05ae3e1b3 100644
--- a/source/blender/modifiers/intern/MOD_boolean.cc
+++ b/source/blender/modifiers/intern/MOD_boolean.cc
@@ -248,13 +248,14 @@ static BMesh *BMD_mesh_bm_create(
   BMeshCreateParams bmesh_create_params{};
   BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params);
 
-  /* Needed so active layers are set based on `mesh` not `mesh_operand_ob`,
-   * otherwise the wrong active render layer is used, see T92384. */
-  BM_mesh_copy_init_customdata_from_mesh(bm, mesh, &allocsize);
-
-  /* NOTE(@campbellbarton): Handle in #BM_mesh_bm_from_me, this is a local fix for T94197. */
-  BM_mesh_cd_flag_apply(bm,
-                        mesh->cd_flag | mesh_operand_ob->cd_flag | BM_mesh_cd_flag_from_bmesh(bm));
+  /* Keep `mesh` first, needed so active layers are set based on `mesh` not `mesh_operand_ob`,
+   * otherwise the wrong active render layer is used, see T92384.
+   *
+   * NOTE: while initializing customer data layers the is not essential,
+   * it avoids the overhead of having to re-allocate #BMHeader.data when the 2nd mesh is added
+   * (if it contains additional custom-data layers). */
+  const Mesh *mesh_array[2] = {mesh, mesh_operand_ob};
+  BM_mesh_copy_init_customdata_from_mesh_array(bm, mesh_array, ARRAY_SIZE(mesh_array), &allocsize);
 
   BMeshFromMeshParams bmesh_from_mesh_params{};
   bmesh_from_mesh_params.calc_face_normal = true;



More information about the Bf-blender-cvs mailing list