Fix T65809: Blender crash while using the Normal's "merge" option in edit mode.

Merge code will generate temp normal editing data for affected loops,
but since it will later (by setting some edges/faces to smooth) alter
and extend affected clnor spaces, it will also need temp normal editing
data for some other loops around those vertices...

Using those clnor editing data in that code is a bit of an abuse, but on
the other hand that struct stores exactly what we need.

So simply added an option to generate that editing data for all clnors
of affected vertices.
This commit is contained in:
Bastien Montagne 2019-06-16 18:04:57 +02:00
parent b1b0781c1e
commit 5767dcbe60
Notes: blender-bot 2023-02-14 08:25:14 +01:00
Referenced by issue #65809, Blender crash while using the Normal's "merge" option in edit mode (in the normal editing section)
4 changed files with 53 additions and 23 deletions

View File

@ -1395,32 +1395,49 @@ void BM_lnorspace_err(BMesh *bm)
static void bm_loop_normal_mark_indiv_do_loop(BMLoop *l,
BLI_bitmap *loops,
MLoopNorSpaceArray *lnor_spacearr,
int *totloopsel)
int *totloopsel,
const bool do_all_loops_of_vert)
{
if (l != NULL) {
const int l_idx = BM_elem_index_get(l);
if (!BLI_BITMAP_TEST(loops, BM_elem_index_get(l))) {
if (!BLI_BITMAP_TEST(loops, l_idx)) {
/* If vert and face selected share a loop, mark it for editing. */
BLI_BITMAP_ENABLE(loops, l_idx);
(*totloopsel)++;
/* Mark all loops in same loop normal space (aka smooth fan). */
if ((lnor_spacearr->lspacearr[l_idx]->flags & MLNOR_SPACE_IS_SINGLE) == 0) {
for (LinkNode *node = lnor_spacearr->lspacearr[l_idx]->loops; node; node = node->next) {
const int lfan_idx = BM_elem_index_get((BMLoop *)node->link);
if (do_all_loops_of_vert) {
/* If required, also mark all loops shared by that vertex.
* This is needed when loop spaces may change
* (i.e. when some faces or edges might change of smooth/sharp status). */
BMIter liter;
BMLoop *lfan;
BM_ITER_ELEM (lfan, &liter, l->v, BM_LOOPS_OF_VERT) {
const int lfan_idx = BM_elem_index_get(lfan);
if (!BLI_BITMAP_TEST(loops, lfan_idx)) {
BLI_BITMAP_ENABLE(loops, lfan_idx);
(*totloopsel)++;
}
}
}
else {
/* Mark all loops in same loop normal space (aka smooth fan). */
if ((lnor_spacearr->lspacearr[l_idx]->flags & MLNOR_SPACE_IS_SINGLE) == 0) {
for (LinkNode *node = lnor_spacearr->lspacearr[l_idx]->loops; node; node = node->next) {
const int lfan_idx = BM_elem_index_get((BMLoop *)node->link);
if (!BLI_BITMAP_TEST(loops, lfan_idx)) {
BLI_BITMAP_ENABLE(loops, lfan_idx);
(*totloopsel)++;
}
}
}
}
}
}
}
/* Mark the individual clnors to be edited, if multiple selection methods are used. */
static int bm_loop_normal_mark_indiv(BMesh *bm, BLI_bitmap *loops)
static int bm_loop_normal_mark_indiv(BMesh *bm, BLI_bitmap *loops, const bool do_all_loops_of_vert)
{
BMEditSelection *ese, *ese_prev;
int totloopsel = 0;
@ -1451,19 +1468,22 @@ static int bm_loop_normal_mark_indiv(BMesh *bm, BLI_bitmap *loops)
BM_face_vert_share_loop((BMFace *)ese->ele, (BMVert *)ese_prev->ele),
loops,
bm->lnor_spacearr,
&totloopsel);
&totloopsel,
do_all_loops_of_vert);
}
else if (ese_prev->htype == BM_EDGE) {
BMEdge *e = (BMEdge *)ese_prev->ele;
bm_loop_normal_mark_indiv_do_loop(BM_face_vert_share_loop((BMFace *)ese->ele, e->v1),
loops,
bm->lnor_spacearr,
&totloopsel);
&totloopsel,
do_all_loops_of_vert);
bm_loop_normal_mark_indiv_do_loop(BM_face_vert_share_loop((BMFace *)ese->ele, e->v2),
loops,
bm->lnor_spacearr,
&totloopsel);
&totloopsel,
do_all_loops_of_vert);
}
}
}
@ -1478,7 +1498,8 @@ static int bm_loop_normal_mark_indiv(BMesh *bm, BLI_bitmap *loops)
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
bm_loop_normal_mark_indiv_do_loop(l, loops, bm->lnor_spacearr, &totloopsel);
bm_loop_normal_mark_indiv_do_loop(
l, loops, bm->lnor_spacearr, &totloopsel, do_all_loops_of_vert);
}
}
}
@ -1491,15 +1512,18 @@ static int bm_loop_normal_mark_indiv(BMesh *bm, BLI_bitmap *loops)
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
bm_loop_normal_mark_indiv_do_loop(l, loops, bm->lnor_spacearr, &totloopsel);
bm_loop_normal_mark_indiv_do_loop(
l, loops, bm->lnor_spacearr, &totloopsel, do_all_loops_of_vert);
/* Loops actually 'have' two edges, or said otherwise, a selected edge actually selects
* *two* loops in each of its faces. We have to find the other one too. */
if (BM_vert_in_edge(e, l->next->v)) {
bm_loop_normal_mark_indiv_do_loop(l->next, loops, bm->lnor_spacearr, &totloopsel);
bm_loop_normal_mark_indiv_do_loop(
l->next, loops, bm->lnor_spacearr, &totloopsel, do_all_loops_of_vert);
}
else {
BLI_assert(BM_vert_in_edge(e, l->prev->v));
bm_loop_normal_mark_indiv_do_loop(l->prev, loops, bm->lnor_spacearr, &totloopsel);
bm_loop_normal_mark_indiv_do_loop(
l->prev, loops, bm->lnor_spacearr, &totloopsel, do_all_loops_of_vert);
}
}
}
@ -1513,7 +1537,8 @@ static int bm_loop_normal_mark_indiv(BMesh *bm, BLI_bitmap *loops)
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
bm_loop_normal_mark_indiv_do_loop(l, loops, bm->lnor_spacearr, &totloopsel);
bm_loop_normal_mark_indiv_do_loop(
l, loops, bm->lnor_spacearr, &totloopsel, do_all_loops_of_vert);
}
}
}
@ -1546,7 +1571,8 @@ static void loop_normal_editdata_init(
lnor_ed->loc = v->co;
}
BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm)
BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm,
const bool do_all_loops_of_vert)
{
BMLoop *l;
BMVert *v;
@ -1570,7 +1596,7 @@ BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm)
BLI_bitmap *loops = BLI_BITMAP_NEW(bm->totloop, __func__);
/* This function define loop normals to edit, based on selection modes and history. */
totloopsel = bm_loop_normal_mark_indiv(bm, loops);
totloopsel = bm_loop_normal_mark_indiv(bm, loops, do_all_loops_of_vert);
if (totloopsel) {
BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata = MEM_mallocN(

View File

@ -67,7 +67,8 @@ void BM_lnorspace_err(BMesh *bm);
#endif
/* Loop Generics */
struct BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm);
struct BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm,
const bool do_all_loops_of_vert);
void BM_loop_normal_editdata_array_free(struct BMLoopNorEditDataArray *lnors_ed_arr);
int BM_total_loop_select(BMesh *bm);

View File

@ -7689,7 +7689,7 @@ static int point_normals_init(bContext *C, wmOperator *op, const wmEvent *UNUSED
BKE_editmesh_ensure_autosmooth(em);
BKE_editmesh_lnorspace_update(em);
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm);
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
op->customdata = lnors_ed_arr;
@ -8246,7 +8246,10 @@ static int normals_split_merge(bContext *C, const bool do_merge)
BKE_editmesh_ensure_autosmooth(em);
BKE_editmesh_lnorspace_update(em);
BMLoopNorEditDataArray *lnors_ed_arr = do_merge ? BM_loop_normal_editdata_array_init(bm) : NULL;
/* Note that we need temp lnor editing data for all loops of all affected vertices, since by
* setting some faces/edges as smooth we are going to change clnors spaces... See also T65809. */
BMLoopNorEditDataArray *lnors_ed_arr = do_merge ? BM_loop_normal_editdata_array_init(bm, true) :
NULL;
mesh_set_smooth_faces(em, do_merge);
@ -8573,7 +8576,7 @@ static int edbm_normals_tools_exec(bContext *C, wmOperator *op)
BKE_editmesh_ensure_autosmooth(em);
BKE_editmesh_lnorspace_update(em);
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm);
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
float *normal_vector = scene->toolsettings->normal_vector;
@ -8867,7 +8870,7 @@ static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op)
BKE_editmesh_ensure_autosmooth(em);
BKE_editmesh_lnorspace_update(em);
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm);
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
float(*smooth_normal)[3] = MEM_callocN(sizeof(*smooth_normal) * lnors_ed_arr->totloop, __func__);

View File

@ -4784,7 +4784,7 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
static void storeCustomLNorValue(TransDataContainer *tc, BMesh *bm)
{
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm);
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
// BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
tc->custom.mode.data = lnors_ed_arr;