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]:690ecaae20
[1]:6e77afe6ec
This commit is contained in:
parent
07ba515b21
commit
7881a797a0
Notes:
blender-bot
2023-02-14 10:29:32 +01:00
Referenced by issue #100749, Blender LTS: Maintenance Task 3.3 Referenced by issue #101721, Regression: Knife Project crashes Blender 3.4 and 3.3
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue