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

Campbell Barton noreply at git.blender.org
Tue Aug 11 08:23:28 CEST 2020


Commit: 9adedb26055f03263fefba380980ee2abcb5327e
Author: Campbell Barton
Date:   Tue Aug 11 15:26:14 2020 +1000
Branches: blender-v2.90-release
https://developer.blender.org/rB9adedb26055f03263fefba380980ee2abcb5327e

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

Support duplicators in edit-mode without creating a mesh copy.

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

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 452c1657ed5..2c71ef3f471 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"
@@ -299,6 +301,55 @@ 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,
+                                              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) {
+    /* 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)) {
+      *r_em = em;
+      if (me_eval != NULL) {
+        EditMeshData *emd = me_eval->runtime.edit_data;
+        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);
+  }
+  return me_eval;
+}
+
+/** \} */
+
 /* -------------------------------------------------------------------- */
 /** \name Dupli-Collection Implementation (#OB_DUPLICOLLECTION)
  * \{ */
@@ -348,124 +399,178 @@ static const DupliGenerator gen_dupli_collection = {
 /** \name Dupli-Vertices Implementation (#OB_DUPLIVERTS for Geometry)
  * \{ */
 
-typedef struct VertexDupliData {
+typedef struct VertexDupliData_Mesh {
   Mesh *me_eval;
-  BMEditMesh *edit_mesh;
+
   int totvert;
+  MVert *mvert;
+
   float (*orco)[3];
+
   bool use_rotation;
+} VertexDupliData_Mesh;
 
-  const DupliContext *ctx;
-  Object *inst_ob; /* object to instantiate (argument for vertex map callback) */
-  float child_imat[4][4];
-} VertexDupliData;
+typedef struct VertexDupliData_BMesh {
+  BMEditMesh *em;
+
+  /* Can be NULL. */
+  const float (*vert_coords)[3];
+  const float (*vert_normals)[3];
+
+  bool has_orco;
+  bool use_rotation;
+} VertexDupliData_BMesh;
 
 static void get_duplivert_transform(const float co[3],
-                                    const short no[3],
-                                    bool use_rotation,
+                                    const float no[3],
+                                    const bool use_rotation,
                                     short axis,
                                     short upflag,
-                                    float mat[4][4])
+                                    float r_mat[4][4])
 {
   float quat[4];
   const float size[3] = {1.0f, 1.0f, 1.0f};
 
   if (use_rotation) {
-    /* construct rotation matrix from normals */
-    float nor_f[3];
-    nor_f[0] = (float)-no[0];
-    nor_f[1] = (float)-no[1];
-    nor_f[2] = (float)-no[2];
-    vec_to_quat(quat, nor_f, axis, upflag);
+    /* Construct rotation matrix from normals. */
+    float no_flip[3];
+    negate_v3_v3(no_flip, no);
+    vec_to_quat(quat, no_flip, axis, upflag);
   }
   else {
     unit_qt(quat);
   }
 
-  loc_quat_size_to_mat4(mat, co, quat, size);
+  loc_quat_size_to_mat4(r_mat, co, quat, size);
 }
 
-static void vertex_dupli(const VertexDupliData *vdd,
-                         int index,
-                         const float co[3],
-                         const short no[3])
+/**
+ * \param no: The direction, doesn't need to be normalized.
+ */
+static DupliObject *vertex_dupli(const DupliContext *ctx,
+                                 Object *child,
+                                 const float child_imat[4][4],
+                                 int index,
+                                 float space_mat[4][4])
 {
-  Object *inst_ob = vdd->inst_ob;
-  DupliObject *dob;
-  float obmat[4][4], space_mat[4][4];
+  float obmat[4][4];
 
-  /* obmat is transform to vertex */
-  get_duplivert_transform(co, no, vdd->use_rotation, inst_ob->trackflag, inst_ob->upflag, obmat);
-  /* make offset relative to inst_ob using relative child transform */
-  mul_mat3_m4_v3((float(*)[4])vdd->child_imat, obmat[3]);
-  /* apply obmat _after_ the local vertex transform */
-  mul_m4_m4m4(obmat, inst_ob->obmat, obmat);
+  /* Make offset relative to child using relative child transform. */
+  mul_mat3_m4_v3(child_imat, space_mat[3]);
 
-  /* space matrix is constructed by removing obmat transform,
-   * this yields the worldspace transform for recursive duplis
-   */
-  mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
+  /* Apply `obmat` _after_ the local vertex transform. */
+  mul_m4_m4m4(obmat, child->obmat, space_mat);
 
-  dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index);
+  DupliObject *dob = make_dupli(ctx, child, obmat, index);
 
-  if (vdd->orco) {
-    copy_v3_v3(dob->orco, vdd->orco[index]);
-  }
+  /* Recursion. */
+  make_recursive_duplis(ctx, child, space_mat, index);
 
-  /* recursion */
-  make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index);
+  return dob;
 }
 
-static void make_child_duplis_verts(const DupliContext *ctx, void *userdata, Object *child)
+static void make_child_duplis_verts_from_mesh(const DupliContext *ctx,
+                                              void *userdata,
+                                              Object *child)
 {
-  VertexDupliData *vdd = userdata;
-  Mesh *me_eval = vdd->me_eval;
+  VertexDupliData_Mesh *vdd = userdata;
 
-  vdd->inst_ob = child;
-  invert_m4_m4(child->imat, child->obmat);
-  /* relative transform from parent to child space */
-  mul_m4_m4m4(vdd->child_imat, child->imat, ctx->object->obmat);
+  const MVert *mvert = vdd->mvert;
+  const int totvert = vdd->totvert;
 
-  const MVert *mvert = me_eval->mvert;
-  for (int i = 0; i < me_eval->totvert; i++) {
-    vertex_dupli(vdd, i, mvert[i].co, mvert[i].no);
+  invert_m4_m4(child->imat, child->obmat);
+  /* Relative transform from parent to child space. */
+  float child_imat[4][4];
+  mul_m4_m4m4(child_imat, child->imat, ctx->object->obmat);
+
+  const MVert *mv = mvert;
+  for (int i = 0; i < totvert; i++, mv++) {
+    const float no[3] = {mv->no[0], mv->no[1], mv->no[2]};
+    /* space_mat is transform to vertex. */
+    float space_mat[4][4];
+    get_duplivert_transform(
+        mv->co, no, vdd->use_rotation, child->trackflag, child->upflag, space_mat);
+    DupliObject *dob = vertex_dupli(ctx, child, child_imat, i, space_mat);
+    if (vdd->orco) {
+      copy_v3_v3(dob->orco, vdd->orco[i]);
+    }
   }
 }
 
-static void make_duplis_verts(const DupliContext *ctx)
+static void make_child_duplis_verts_from_bmesh(const DupliContext *ctx,
+                                               void *userdata,
+                                               Object *child)
 {
-  Object *parent = ctx->object;
-  VertexDupliData vdd;
+  VertexDupliData_BMesh *vdd = userdata;
+  BMEditMesh *em = vdd->em;
 
-  vdd.ctx = ctx;
-  vdd.use_rotation = parent->transflag & OB_DUPLIROT;
+  invert_m4_m4(child->imat, child->obmat);
+  /* Relative transform from parent to child space. */
+  float child_imat[4][4];
+  mul_m4_m4m4(child_imat, child->imat, ctx->object->obmat);
 
-  /* gather mesh info */
-  {
-    vdd.edit_mesh = BKE_editmesh_from_object(parent);
-
-    /* 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 (vdd.edit_mesh != NULL) {
-      vdd.me_eval = vdd.edit_mesh->mesh_eval_cage;
+  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[i];
     }
     else {
-      vdd.me_eval = BKE_object_get_evaluated_mesh(parent);
+      co = v->co;
+      no = v->no;
     }
 
-    if (vdd.me_eval == NULL) {
-      return;
+    /* space_mat is transform to vertex. */
+    float space_mat[4][4];
+    get_duplivert_transform(co, no, vdd->use_rotation, child->trackflag, child->upflag, space_mat);
+    DupliObject *dob = vertex_dupli(ctx, child, child_imat, i, space_mat);
+    if (vdd->has_orco) {
+      copy_v3_v3(dob->orco, v->co);
     }
-
-    vdd.orco = CustomData_get_layer(&vdd.me_eval->vdata, CD_ORCO);
-    vdd.totvert = vdd.me_eval->totvert;
   }
+}
+
+static void make_duplis_verts(const DupliContext *ctx)
+{
+  Object *parent = ctx->object;
+
+  const bool use_rotation = parent->transflag & OB_DUPLIROT;
 
-  make_child_duplis(ctx, &vdd, make_child_duplis_verts);
+  /* Gather mesh info. */
+  BMEditMesh *em = NULL;
+  const float(*vert_coords)[3] = NULL;
+  const float(*vert_normals)[3] = NULL;
+  Mesh *me_eval = mesh_data_from_duplicator_object(par

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list