[Bf-blender-cvs] [7881a797a06] blender-v3.3-release: Fix T101721: Knife project crashes

Campbell Barton noreply at git.blender.org
Wed Oct 26 10:55:07 CEST 2022


Commit: 7881a797a063bb8ed0aa8c6b7329812c027b6fbf
Author: Campbell Barton
Date:   Tue Oct 11 15:47:40 2022 +1100
Branches: blender-v3.3-release
https://developer.blender.org/rB7881a797a063bb8ed0aa8c6b7329812c027b6fbf

Fix T101721: Knife project crashes

The crash was caused by [0] however knife-project functionality has been
incorrect since [1] which would loop over each edit-mode object and run
the knife project function which operated on all edit-mode objects too.

- Resolve the crash by postponing face-tessellation recalculation
  until the knife tool has cut all objects

- Objects occluding each other is now supported
  (an old TODO and something that was never supported).

[0]: 690ecaae208d5f72217c165621d0d036e4029e86
[1]: 6e77afe6ec7b6a73f218f1fef264758abcbc778a

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

M	source/blender/editors/mesh/editmesh_knife.c
M	source/blender/editors/mesh/editmesh_knife_project.c
M	source/blender/editors/mesh/mesh_intern.h

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

diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 5680865ae67..a3398da0998 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -218,6 +218,7 @@ typedef struct KnifeTool_OpData {
   /* Used for swapping current object when in multi-object edit mode. */
   Object **objects;
   uint objects_len;
+  bool objects_free;
 
   /** Array `objects_len` length of additional per-object data. */
   KnifeObjectInfo *objects_info;
@@ -4081,6 +4082,8 @@ static void knife_init_colors(KnifeColors *colors)
 /* called when modal loop selection gets set up... */
 static void knifetool_init(ViewContext *vc,
                            KnifeTool_OpData *kcd,
+                           Object **objects,
+                           const int objects_len,
                            const bool only_select,
                            const bool cut_through,
                            const bool xray,
@@ -4101,8 +4104,16 @@ static void knifetool_init(ViewContext *vc,
   kcd->scene = scene;
   kcd->region = vc->region;
 
-  kcd->objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
-      vc->view_layer, vc->v3d, &kcd->objects_len);
+  if (objects) {
+    kcd->objects = objects;
+    kcd->objects_len = objects_len;
+    kcd->objects_free = false;
+  }
+  else {
+    kcd->objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+        vc->view_layer, vc->v3d, &kcd->objects_len);
+    kcd->objects_free = true;
+  }
 
   Object *ob;
   BMEditMesh *em;
@@ -4225,7 +4236,9 @@ static void knifetool_exit_ex(KnifeTool_OpData *kcd)
   }
 
   /* Free object bases. */
-  MEM_freeN(kcd->objects);
+  if (kcd->objects_free) {
+    MEM_freeN(kcd->objects);
+  }
 
   /* Destroy kcd itself. */
   MEM_freeN(kcd);
@@ -4318,9 +4331,15 @@ static void knifetool_finish_single_post(KnifeTool_OpData *UNUSED(kcd), Object *
 /* Called on tool confirmation. */
 static void knifetool_finish_ex(KnifeTool_OpData *kcd)
 {
+  /* Separate pre/post passes are needed because `em->looptris` recalculation from the 'post' pass
+   * causes causes triangle indices in #KnifeTool_OpData.bvh to get out of sync.
+   * So perform all the cuts before doing any mesh recalculation, see: T101721. */
   for (uint b = 0; b < kcd->objects_len; b++) {
     Object *ob = kcd->objects[b];
     knifetool_finish_single_pre(kcd, ob);
+  }
+  for (uint b = 0; b < kcd->objects_len; b++) {
+    Object *ob = kcd->objects[b];
     knifetool_finish_single_post(kcd, ob);
   }
 }
@@ -4789,6 +4808,8 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 
   knifetool_init(&vc,
                  kcd,
+                 NULL,
+                 0,
                  only_select,
                  cut_through,
                  xray,
@@ -4941,7 +4962,12 @@ static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2])
   return false;
 }
 
-void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_through)
+void EDBM_mesh_knife(ViewContext *vc,
+                     Object **objects,
+                     const int objects_len,
+                     LinkNode *polys,
+                     bool use_tag,
+                     bool cut_through)
 {
   KnifeTool_OpData *kcd;
 
@@ -4958,6 +4984,8 @@ void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_th
 
     knifetool_init(vc,
                    kcd,
+                   objects,
+                   objects_len,
                    only_select,
                    cut_through,
                    xray,
@@ -4999,18 +5027,21 @@ void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_th
 
   /* Finish. */
   {
-    Object *ob;
-    BMEditMesh *em;
+    /* See #knifetool_finish_ex for why multiple passes are needed. */
     for (uint b = 0; b < kcd->objects_len; b++) {
-
-      ob = kcd->objects[b];
-      em = BKE_editmesh_from_object(ob);
+      Object *ob = kcd->objects[b];
+      BMEditMesh *em = BKE_editmesh_from_object(ob);
 
       if (use_tag) {
         BM_mesh_elem_hflag_enable_all(em->bm, BM_EDGE, BM_ELEM_TAG, false);
       }
 
       knifetool_finish_single_pre(kcd, ob);
+    }
+
+    for (uint b = 0; b < kcd->objects_len; b++) {
+      Object *ob = kcd->objects[b];
+      BMEditMesh *em = BKE_editmesh_from_object(ob);
 
       /* Tag faces inside! */
       if (use_tag) {
@@ -5103,9 +5134,12 @@ void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_th
 #undef F_ISECT_SET_UNKNOWN
 #undef F_ISECT_SET_OUTSIDE
       }
+    }
 
+    for (uint b = 0; b < kcd->objects_len; b++) {
       /* Defer freeing data until the BVH tree is finished with, see: #point_is_visible and
        * the doc-string for #knifetool_finish_single_post. */
+      Object *ob = kcd->objects[b];
       knifetool_finish_single_post(kcd, ob);
     }
 
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index c32b1fa99c0..a99cb38601e 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -132,22 +132,21 @@ static int knifeproject_exec(bContext *C, wmOperator *op)
   ViewContext vc;
   em_setup_viewcontext(C, &vc);
 
-  /* TODO: Ideally meshes would occlude each other, currently they don't
-   * since each knife-project runs as a separate operation. */
   uint objects_len;
   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
       vc.view_layer, vc.v3d, &objects_len);
+
+  EDBM_mesh_knife(&vc, objects, objects_len, polys, true, cut_through);
+
   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
     Object *obedit = objects[ob_index];
     ED_view3d_viewcontext_init_object(&vc, obedit);
     BMEditMesh *em = BKE_editmesh_from_object(obedit);
 
-    EDBM_mesh_knife(&vc, polys, true, cut_through);
-
     /* select only tagged faces */
     BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
 
-    EDBM_selectmode_disable_multi(C, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
+    EDBM_selectmode_disable(scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
 
     BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
 
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 303234df48c..826b34bbaa1 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -18,6 +18,7 @@ struct BMElem;
 struct BMOperator;
 struct EnumPropertyItem;
 struct LinkNode;
+struct Object;
 struct bContext;
 struct wmKeyConfig;
 struct wmKeyMap;
@@ -175,6 +176,8 @@ void MESH_OT_knife_project(struct wmOperatorType *ot);
  * \param use_tag: When set, tag all faces inside the polylines.
  */
 void EDBM_mesh_knife(struct ViewContext *vc,
+                     struct Object **objects,
+                     int objects_len,
                      struct LinkNode *polys,
                      bool use_tag,
                      bool cut_through);



More information about the Bf-blender-cvs mailing list