[Bf-blender-cvs] [e13e629f98f] temp-vert-normals-cleanup: Fix crash restoring undo step mesh to edit mesh

Hans Goudey noreply at git.blender.org
Wed Jan 5 18:11:27 CET 2022


Commit: e13e629f98f5dad32c33ffd571bafda71fd36388
Author: Hans Goudey
Date:   Wed Jan 5 11:11:18 2022 -0600
Branches: temp-vert-normals-cleanup
https://developer.blender.org/rBe13e629f98f5dad32c33ffd571bafda71fd36388

Fix crash restoring undo step mesh to edit mesh

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

M	source/blender/blenkernel/BKE_mesh.h
M	source/blender/blenkernel/intern/mesh_normals.cc
M	source/blender/bmesh/intern/bmesh_mesh_convert.c

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

diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 199beb3eef2..68d04778efa 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -373,6 +373,20 @@ void BKE_mesh_recalc_looptri_with_normals(const struct MLoop *mloop,
 
 /* *** mesh_normals.cc *** */
 
+/**
+ * Returns the normals for each vertex, which is defined as the weighted average of the normals
+ * from a vertices surrounding faces, or the normalized position of vertices connected to no faces.
+ * \warning May still return null if the mesh is empty.
+ */
+const float (*BKE_mesh_vertex_normals_ensure(const struct Mesh *mesh))[3];
+
+/**
+ * Return the normal direction of every polygon, which is defined by the winding direction of its
+ * corners.
+ * \warning May still return null if the mesh is empty or has no polygons.
+ */
+const float (*BKE_mesh_poly_normals_ensure(const struct Mesh *mesh))[3];
+
 /**
  * Tag mesh vertex and face normals to be recalculated when/if they are needed later.
  *
@@ -416,6 +430,18 @@ void BKE_mesh_vertex_normals_clear_dirty(struct Mesh *mesh);
  */
 void BKE_mesh_poly_normals_clear_dirty(struct Mesh *mesh);
 
+/**
+ * Return true if the mesh vertex normals either are not stored or are dirty.
+ * This can be used to help decide whether to transfer them when copying a mesh.
+ */
+bool BKE_mesh_vertex_normals_are_dirty(const struct Mesh *mesh);
+
+/**
+ * Return true if the mesh polygon normals either are not stored or are dirty.
+ * This can be used to help decide whether to transfer them when copying a mesh.
+ */
+bool BKE_mesh_poly_normals_are_dirty(const struct Mesh *mesh);
+
 /**
  * Calculate face normals directly into a result array.
  *
@@ -439,20 +465,6 @@ void BKE_mesh_calc_normals_poly(const struct MVert *mvert,
  */
 void BKE_mesh_calc_normals(struct Mesh *me);
 
-/**
- * Returns the normals for each vertex, which is defined as the weighted average of the normals
- * from a vertices surrounding faces, or the normalized position of vertices connected to no faces.
- * \warning May still return null if the mesh is empty.
- */
-const float (*BKE_mesh_vertex_normals_ensure(const struct Mesh *mesh))[3];
-
-/**
- * Return the normal direction of every polygon, which is defined by the winding direction of its
- * corners.
- * \warning May still return null if the mesh is empty or has no polygons.
- */
-const float (*BKE_mesh_poly_normals_ensure(const struct Mesh *mesh))[3];
-
 /**
  * Called after calculating all modifiers.
  */
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index ffe6db6a2ee..16241b0f0dd 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -146,6 +146,16 @@ void BKE_mesh_poly_normals_clear_dirty(Mesh *mesh)
   BKE_mesh_assert_normals_dirty_or_calculated(mesh);
 }
 
+bool BKE_mesh_vertex_normals_are_dirty(const Mesh *mesh)
+{
+  return mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL;
+}
+
+bool BKE_mesh_poly_normals_are_dirty(const Mesh *mesh)
+{
+  return mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL;
+}
+
 void BKE_mesh_assert_normals_dirty_or_calculated(const Mesh *mesh)
 {
   if (!(mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL)) {
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.c b/source/blender/bmesh/intern/bmesh_mesh_convert.c
index 9d0933b0aa5..d99fefbcd02 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.c
@@ -192,7 +192,6 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
   int totloops, i;
   CustomData_MeshMasks mask = CD_MASK_BMESH;
   CustomData_MeshMasks_update(&mask, &params->cd_mask_extra);
-  const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me);
 
   if (!me || !me->totvert) {
     if (me && is_new) { /* No verts? still copy custom-data layout. */
@@ -209,6 +208,14 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
     return; /* Sanity check. */
   }
 
+  /* Only copy normals to the new BMesh if they are not already dirty. This avoids unnecessary
+   * work, but also accessing normals on an incomplete mesh, for example when restoring undo steps
+   * in edit mode. */
+  const float(*vert_normals)[3] = NULL;
+  if (!BKE_mesh_vertex_normals_are_dirty(me)) {
+    vert_normals = BKE_mesh_vertex_normals_ensure(me);
+  }
+
   if (is_new) {
     CustomData_copy(&me->vdata, &bm->vdata, mask.vmask, CD_CALLOC, 0);
     CustomData_copy(&me->edata, &bm->edata, mask.emask, CD_CALLOC, 0);
@@ -335,7 +342,9 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
       BM_vert_select_set(bm, v, true);
     }
 
-    copy_v3_v3(v->no, vert_normals[i]);
+    if (vert_normals) {
+      copy_v3_v3(v->no, vert_normals[i]);
+    }
 
     /* Copy Custom Data */
     CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data, true);
@@ -640,6 +649,8 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
   CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, mloop, me->totloop);
   CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, mpoly, me->totpoly);
 
+  /* There is no way to tell if BMesh normals are dirty or not. Instead of calculating the normals
+   * on the BMesh possibly unnecessarily, just tag them dirty on the resulting mesh. */
   BKE_mesh_normals_tag_dirty(me);
 
   me->cd_flag = BM_mesh_cd_flag_from_bmesh(bm);



More information about the Bf-blender-cvs mailing list