[Bf-blender-cvs] [ad05e1100fd] blender-v2.90-release: Fix T77409: Crash showing vertex/face duplicators in edit-mode

Campbell Barton noreply at git.blender.org
Thu Aug 13 07:45:41 CEST 2020


Commit: ad05e1100fd02bcceb6d3b18efc146c0fcf98304
Author: Campbell Barton
Date:   Thu Aug 13 13:56:15 2020 +1000
Branches: blender-v2.90-release
https://developer.blender.org/rBad05e1100fd02bcceb6d3b18efc146c0fcf98304

Fix T77409: Crash showing vertex/face duplicators in edit-mode

This was a regression in deaff945d0b9 which skips copying a mesh.
Dupli-verts/faces were not updated to account for this.

This supports iterating over edit-mesh vertices & faces,
since falling back to a full copy (as we do in some places)
will be slow while transforming geometry.

This commit looks as if it would change behavior with orcos,
since any edit-mesh deformation causes them to be assigned.
However in practice there is no functional change, details in comments.

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

M	source/blender/blenkernel/intern/object_dupli.c

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

diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 6ec8c2fe89c..2c399183899 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -30,6 +30,7 @@
 #include "BLI_listbase.h"
 #include "BLI_string_utf8.h"
 
+#include "BLI_alloca.h"
 #include "BLI_math.h"
 #include "BLI_rand.h"
 
@@ -43,6 +44,7 @@
 #include "BKE_collection.h"
 #include "BKE_duplilist.h"
 #include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
 #include "BKE_font.h"
 #include "BKE_global.h"
 #include "BKE_idprop.h"
@@ -303,24 +305,44 @@ static void make_child_duplis(const DupliContext *ctx,
 /** \name Internal Data Access Utilities
  * \{ */
 
-static Mesh *mesh_data_from_duplicator_object(Object *ob, BMEditMesh **r_em)
+static Mesh *mesh_data_from_duplicator_object(Object *ob,
+                                              BMEditMesh **r_em,
+                                              const float (**r_vert_coords)[3],
+                                              const float (**r_vert_normals)[3])
 {
   /* Gather mesh info. */
   BMEditMesh *em = BKE_editmesh_from_object(ob);
   Mesh *me_eval;
 
   *r_em = NULL;
+  *r_vert_coords = NULL;
+  if (r_vert_normals != NULL) {
+    *r_vert_normals = NULL;
+  }
 
   /* We do not need any render-specific handling anymore, depsgraph takes care of that. */
   /* NOTE: Do direct access to the evaluated mesh: this function is used
    * during meta balls evaluation. But even without those all the objects
    * which are needed for correct instancing are already evaluated. */
   if (em != NULL) {
-    *r_em = em;
-
     /* Note that this will only show deformation if #eModifierMode_OnCage is enabled.
      * We could change this but it matches 2.7x behavior. */
     me_eval = em->mesh_eval_cage;
+    if ((me_eval == NULL) || (me_eval->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
+      EditMeshData *emd = me_eval ? me_eval->runtime.edit_data : NULL;
+
+      /* Only assign edit-mesh in the case we can't use `me_eval`. */
+      *r_em = em;
+      me_eval = NULL;
+
+      if ((emd != NULL) && (emd->vertexCos != NULL)) {
+        *r_vert_coords = emd->vertexCos;
+        if (r_vert_normals != NULL) {
+          BKE_editmesh_cache_ensure_vert_normals(em, emd);
+          *r_vert_normals = emd->vertexNos;
+        }
+      }
+    }
   }
   else {
     me_eval = BKE_object_get_evaluated_mesh(ob);
@@ -379,22 +401,49 @@ static const DupliGenerator gen_dupli_collection = {
 /** \name Dupli-Vertices Implementation (#OB_DUPLIVERTS for Geometry)
  * \{ */
 
-typedef struct VertexDupliData {
+/** Values shared between different mesh types. */
+typedef struct VertexDupliData_Params {
+  /**
+   * It's important we use this context instead of the `ctx` passed into #make_child_duplis
+   * since these won't match in the case of recursion.
+   */
+  const DupliContext *ctx;
+
+  bool use_rotation;
+} VertexDupliData_Params;
+
+typedef struct VertexDupliData_Mesh {
+  VertexDupliData_Params params;
+
   int totvert;
   const MVert *mvert;
 
   const float (*orco)[3];
-  bool use_rotation;
+} VertexDupliData_Mesh;
 
-  const DupliContext *ctx;
-  /* Object to instantiate (argument for vertex map callback). */
-  Object *inst_ob;
-  float child_imat[4][4];
-} VertexDupliData;
+typedef struct VertexDupliData_EditMesh {
+  VertexDupliData_Params params;
+
+  BMEditMesh *em;
+
+  /* Can be NULL. */
+  const float (*vert_coords)[3];
+  const float (*vert_normals)[3];
+
+  /**
+   * \note The edit-mesh may assign #DupliObject.orco in cases when a regular mesh wouldn't.
+   * For edit-meshes we only check for deformation, for regular meshes we check if #CD_ORCO exists.
+   *
+   * At the moment this isn't a meaningful difference since requesting #CD_ORCO causes the
+   * edit-mesh to be converted into a mesh.
+   */
+  bool has_orco;
+} VertexDupliData_EditMesh;
 
 /**
  * \param no: The direction,
  * currently this is copied from a `short[3]` normal without division.
+ * Can be null when \a use_rotation is false.
  */
 static void get_duplivert_transform(const float co[3],
                                     const float no[3],
@@ -419,19 +468,22 @@ static void get_duplivert_transform(const float co[3],
   loc_quat_size_to_mat4(r_mat, co, quat, size);
 }
 
-static void vertex_dupli(const VertexDupliData *vdd,
-                         int index,
-                         const float co[3],
-                         const float no[3])
+static DupliObject *vertex_dupli(const DupliContext *ctx,
+                                 Object *inst_ob,
+                                 const float child_imat[4][4],
+                                 int index,
+                                 const float co[3],
+                                 const float no[3],
+                                 const bool use_rotation)
 {
-  Object *inst_ob = vdd->inst_ob;
-  DupliObject *dob;
-  float obmat[4][4], space_mat[4][4];
-
   /* `obmat` is transform to vertex. */
-  get_duplivert_transform(co, no, vdd->use_rotation, inst_ob->trackflag, inst_ob->upflag, obmat);
+  float obmat[4][4];
+  get_duplivert_transform(co, no, use_rotation, inst_ob->trackflag, inst_ob->upflag, obmat);
+
+  float space_mat[4][4];
+
   /* Make offset relative to inst_ob using relative child transform. */
-  mul_mat3_m4_v3(vdd->child_imat, obmat[3]);
+  mul_mat3_m4_v3(child_imat, obmat[3]);
   /* Apply `obmat` _after_ the local vertex transform. */
   mul_m4_m4m4(obmat, inst_ob->obmat, obmat);
 
@@ -439,54 +491,117 @@ static void vertex_dupli(const VertexDupliData *vdd,
    * this yields the world-space transform for recursive duplis. */
   mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
 
-  dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index);
-
-  if (vdd->orco) {
-    copy_v3_v3(dob->orco, vdd->orco[index]);
-  }
+  DupliObject *dob = make_dupli(ctx, inst_ob, obmat, index);
 
   /* Recursion. */
-  make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index);
+  make_recursive_duplis(ctx, inst_ob, space_mat, index);
+
+  return dob;
+}
+
+static void make_child_duplis_verts_from_mesh(const DupliContext *ctx,
+                                              void *userdata,
+                                              Object *inst_ob)
+{
+  VertexDupliData_Mesh *vdd = userdata;
+  const bool use_rotation = vdd->params.use_rotation;
+
+  const MVert *mvert = vdd->mvert;
+  const int totvert = vdd->totvert;
+
+  invert_m4_m4(inst_ob->imat, inst_ob->obmat);
+  /* Relative transform from parent to child space. */
+  float child_imat[4][4];
+  mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat);
+
+  const MVert *mv = mvert;
+  for (int i = 0; i < totvert; i++, mv++) {
+    const float *co = mv->co;
+    const float no[3] = {UNPACK3(mv->no)};
+    DupliObject *dob = vertex_dupli(vdd->params.ctx, inst_ob, child_imat, i, co, no, use_rotation);
+    if (vdd->orco) {
+      copy_v3_v3(dob->orco, vdd->orco[i]);
+    }
+  }
 }
 
-static void make_child_duplis_verts(const DupliContext *ctx, void *userdata, Object *inst_ob)
+static void make_child_duplis_verts_from_editmesh(const DupliContext *ctx,
+                                                  void *userdata,
+                                                  Object *inst_ob)
 {
-  VertexDupliData *vdd = userdata;
+  VertexDupliData_EditMesh *vdd = userdata;
+  BMEditMesh *em = vdd->em;
+  const bool use_rotation = vdd->params.use_rotation;
 
-  vdd->inst_ob = inst_ob;
   invert_m4_m4(inst_ob->imat, inst_ob->obmat);
   /* Relative transform from parent to child space. */
-  mul_m4_m4m4(vdd->child_imat, inst_ob->imat, ctx->object->obmat);
+  float child_imat[4][4];
+  mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat);
+
+  BMVert *v;
+  BMIter iter;
+  int i;
+
+  const float(*vert_coords)[3] = vdd->vert_coords;
+  const float(*vert_normals)[3] = vdd->vert_normals;
+
+  BM_ITER_MESH_INDEX (v, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+    const float *co, *no;
+    if (vert_coords != NULL) {
+      co = vert_coords[i];
+      no = vert_normals ? vert_normals[i] : NULL;
+    }
+    else {
+      co = v->co;
+      no = v->no;
+    }
 
-  const MVert *mv = vdd->mvert;
-  for (int i = 0; i < vdd->totvert; i++, mv++) {
-    const float no[3] = {mv->no[0], mv->no[1], mv->no[2]};
-    vertex_dupli(vdd, i, mv->co, no);
+    DupliObject *dob = vertex_dupli(vdd->params.ctx, inst_ob, child_imat, i, co, no, use_rotation);
+    if (vdd->has_orco) {
+      copy_v3_v3(dob->orco, v->co);
+    }
   }
 }
 
 static void make_duplis_verts(const DupliContext *ctx)
 {
   Object *parent = ctx->object;
-  VertexDupliData vdd;
-
-  vdd.ctx = ctx;
-  vdd.use_rotation = parent->transflag & OB_DUPLIROT;
+  const bool use_rotation = parent->transflag & OB_DUPLIROT;
 
   /* Gather mesh info. */
   BMEditMesh *em = NULL;
-  Mesh *me_eval = mesh_data_from_duplicator_object(parent, &em);
-  if (me_eval == NULL) {
+  const float(*vert_coords)[3] = NULL;
+  const float(*vert_normals)[3] = NULL;
+  Mesh *me_eval = mesh_data_from_duplicator_object(
+      parent, &em, &vert_coords, use_rotation ? &vert_normals : NULL);
+  if (em == NULL && me_eval == NULL) {
     return;
   }
 
-  {
-    vdd.orco = CustomData_get_layer(&me_eval->vdata, CD_ORCO);
-    vdd.mvert = me_eval->mvert;
-    vdd.totvert = me_eval->totvert;
-  }
+  VertexDupliData_Params vdd_params = {
+      .ctx = ctx,
+      .use_rotation = use_rotation,
+  };
 
-  make_child_duplis(ctx, &vdd, make_child_duplis_verts);
+  if (em != NULL) {
+    VertexDupliData_EditMesh vdd = {
+        .params = vdd_params,
+        .em = em,
+        .vert_coords = vert_coords,
+        .vert_normals = vert_normals,
+        .has_orco = (vert_coords != NULL),
+    };
+    make_child_duplis(ctx, &vdd, make_child_duplis_verts_from_editmesh);
+  }
+  else {
+    VertexDupliData_Mesh vdd = {
+        .params = vdd_params,
+        .totvert = me_eval->totvert,
+        .mvert = me_eval->mvert,
+        .orco = CustomData_get_layer(&me_eval->vdata, CD_ORCO),
+    };
+    make_child_duplis(ctx, &vdd, make_child_duplis_verts_from_mesh);
+  }
 }
 
 static const DupliGenerator gen_dupli_verts = {
@@ -632,40 +747,65 @

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list