Fix crash selecting edit-mesh

The base and the vert/edge/face could be out of sync.
This commit is contained in:
Campbell Barton 2018-05-04 19:01:53 +02:00
parent d9c5a35587
commit 9cb397238d
1 changed files with 62 additions and 28 deletions

View File

@ -921,7 +921,7 @@ BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
* selected vertices and edges get disadvantage
* return 1 if found one
*/
static int unified_findnearest(
static bool unified_findnearest(
ViewContext *vc,
Base **r_base, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
{
@ -933,12 +933,21 @@ static int unified_findnearest(
/* since edges select lines, we give dots advantage of ~20 pix */
const float dist_margin = (dist_init / 2);
float dist = dist_init;
BMFace *efa_zbuf = NULL;
BMEdge *eed_zbuf = NULL;
BMVert *eve = NULL;
BMEdge *eed = NULL;
BMFace *efa = NULL;
struct {
struct {
BMVert *ele;
Base *base;
} v;
struct {
BMEdge *ele;
Base *base;
} e, e_zbuf;
struct {
BMFace *ele;
Base *base;
} f, f_zbuf;
} hit = {{NULL}};
/* TODO(campbell): perform selection as one pass
* instead of many smaller passes (which doesn't work for zbuf occlusion). */
@ -956,14 +965,18 @@ static int unified_findnearest(
Object *obedit = base_iter->object;
ED_view3d_viewcontext_init_object(vc, obedit);
ED_view3d_backbuf_validate(vc);
BMFace *efa_zbuf = NULL;
BMFace *efa_test = EDBM_face_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf);
if (efa && dist_center_p) {
if (hit.f.ele && dist_center_p) {
dist = min_ff(dist_margin, dist_center);
}
if (efa_test) {
*r_base = base_iter;
efa = efa_test;
hit.f.base = base_iter;
hit.f.ele = efa_test;
}
if (efa_zbuf) {
hit.f_zbuf.base = base_iter;
hit.f_zbuf.ele = efa_zbuf;
}
} /* bases */
}
@ -977,13 +990,18 @@ static int unified_findnearest(
Object *obedit = base_iter->object;
ED_view3d_viewcontext_init_object(vc, obedit);
ED_view3d_backbuf_validate(vc);
BMEdge *eed_zbuf = NULL;
BMEdge *eed_test = EDBM_edge_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf);
if (eed && dist_center_p) {
if (hit.e.ele && dist_center_p) {
dist = min_ff(dist_margin, dist_center);
}
if (eed_test) {
*r_base = base_iter;
eed = eed_test;
hit.e.base = base_iter;
hit.e.ele = eed_test;
}
if (eed_zbuf) {
hit.e_zbuf.base = base_iter;
hit.e_zbuf.ele = eed_zbuf;
}
} /* bases */
}
@ -996,8 +1014,8 @@ static int unified_findnearest(
ED_view3d_backbuf_validate(vc);
BMVert *eve_test = EDBM_vert_find_nearest_ex(vc, &dist, true, use_cycle);
if (eve_test) {
*r_base = base_iter;
eve = eve_test;
hit.v.base = base_iter;
hit.v.ele = eve_test;
}
} /* bases */
}
@ -1005,32 +1023,48 @@ static int unified_findnearest(
MEM_SAFE_FREE(bases);
/* return only one of 3 pointers, for frontbuffer redraws */
if (eve) {
efa = NULL; eed = NULL;
if (hit.v.ele) {
hit.f.ele = NULL;
hit.e.ele = NULL;
}
else if (eed) {
efa = NULL;
else if (hit.e.ele) {
hit.f.ele = NULL;
}
/* there may be a face under the cursor, who's center if too far away
* use this if all else fails, it makes sense to select this */
if ((eve || eed || efa) == 0) {
if (eed_zbuf) {
eed = eed_zbuf;
if ((hit.v.ele || hit.e.ele || hit.f.ele) == 0) {
if (hit.e_zbuf.ele) {
hit.e.base = hit.e_zbuf.base;
hit.e.ele = hit.e_zbuf.ele;
}
else if (efa_zbuf) {
efa = efa_zbuf;
else if (hit.f_zbuf.ele) {
hit.f.base = hit.f_zbuf.base;
hit.f.ele = hit.f_zbuf.ele;
}
}
mval_prev[0] = vc->mval[0];
mval_prev[1] = vc->mval[1];
/* Only one element type will be non-null. */
BLI_assert(((hit.v.ele != NULL) + (hit.e.ele != NULL) + (hit.f.ele != NULL)) <= 1);
*r_eve = eve;
*r_eed = eed;
*r_efa = efa;
if (hit.v.ele) {
*r_base = hit.v.base;
}
if (hit.e.ele) {
*r_base = hit.e.base;
}
if (hit.f.ele) {
*r_base = hit.f.base;
}
return (eve || eed || efa);
*r_eve = hit.v.ele;
*r_eed = hit.e.ele;
*r_efa = hit.f.ele;
return (hit.v.ele || hit.e.ele || hit.f.ele);
}
/** \} */