Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <campbell@blender.org>2022-10-11 07:47:40 +0300
committerPhilipp Oeser <info@graphics-engineer.com>2022-10-26 11:31:40 +0300
commit7881a797a063bb8ed0aa8c6b7329812c027b6fbf (patch)
treead4f734dfd624b42b34eef27c37aa78220d12d72
parent07ba515b21ac9eb5ff8b2acc65df474a56c76af7 (diff)
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
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c52
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c9
-rw-r--r--source/blender/editors/mesh/mesh_intern.h3
3 files changed, 50 insertions, 14 deletions
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);