diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-08-02 15:53:27 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-08-02 16:01:19 +0300 |
commit | 5cf6d7e2b0af67e29e52a0b8649129f31cb20e53 (patch) | |
tree | 33ebba52ae8a3a2df4886acc369c812827736c27 | |
parent | d8c610536624da48ade2967253d6ab2c30062073 (diff) |
Fix edge selection ignoring clipping in wire-frame display
-rw-r--r-- | source/blender/editors/include/ED_view3d.h | 10 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_iterators.c | 93 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_select.c | 25 |
3 files changed, 119 insertions, 9 deletions
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 081bcbf4746..afdbbeedff4 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -209,6 +209,16 @@ void mesh_foreachScreenEdge(struct ViewContext *vc, int index), void *userData, const eV3DProjTest clip_flag); + +void mesh_foreachScreenEdge_clip_bb_segment(struct ViewContext *vc, + void (*func)(void *userData, + struct BMEdge *eed, + const float screen_co_a[2], + const float screen_co_b[2], + int index), + void *userData, + const eV3DProjTest clip_flag); + void mesh_foreachScreenFace( struct ViewContext *vc, void (*func)(void *userData, struct BMFace *efa, const float screen_co[2], int index), diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c index a7215a3b7f7..f6fa6f6fb45 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.c +++ b/source/blender/editors/space_view3d/view3d_iterators.c @@ -29,6 +29,7 @@ #include "BLI_utildefines.h" #include "BLI_rect.h" +#include "BLI_math_geom.h" #include "BKE_action.h" #include "BKE_armature.h" @@ -259,6 +260,98 @@ void mesh_foreachScreenEdge(ViewContext *vc, /* ------------------------------------------------------------------------ */ +/** + * Only call for bound-box clipping. + * Otherwise call #mesh_foreachScreenEdge__mapFunc + */ +static void mesh_foreachScreenEdge_clip_bb_segment__mapFunc(void *userData, + int index, + const float v0co[3], + const float v1co[3]) +{ + foreachScreenEdge_userData *data = userData; + BMEdge *eed = BM_edge_at_index(data->vc.em->bm, index); + + BLI_assert(data->clip_flag & V3D_PROJ_TEST_CLIP_BB); + + if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + float v0co_clip[3]; + float v1co_clip[3]; + + if (!clip_segment_v3_plane_n(v0co, v1co, data->vc.rv3d->clip_local, 4, v0co_clip, v1co_clip)) { + return; + } + + float screen_co_a[2]; + float screen_co_b[2]; + + /* Clipping already handled, no need to check in projection. */ + eV3DProjTest clip_flag_nowin = data->clip_flag & + ~(V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_BB); + + if (ED_view3d_project_float_object(data->vc.ar, v0co_clip, screen_co_a, clip_flag_nowin) != + V3D_PROJ_RET_OK) { + return; + } + if (ED_view3d_project_float_object(data->vc.ar, v1co_clip, screen_co_b, clip_flag_nowin) != + V3D_PROJ_RET_OK) { + return; + } + + if (data->clip_flag & V3D_PROJ_TEST_CLIP_WIN) { + if (!BLI_rctf_isect_segment(&data->win_rect, screen_co_a, screen_co_b)) { + return; + } + } + + data->func(data->userData, eed, screen_co_a, screen_co_b, index); + } +} + +/** + * A version of #mesh_foreachScreenEdge that clips the segment when + * there is a clipping bounding box. + */ +void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc, + void (*func)(void *userData, + BMEdge *eed, + const float screen_co_a[2], + const float screen_co_b[2], + int index), + void *userData, + eV3DProjTest clip_flag) +{ + foreachScreenEdge_userData data; + + Mesh *me = editbmesh_get_eval_cage_from_orig( + vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH); + + ED_view3d_check_mats_rv3d(vc->rv3d); + + data.vc = *vc; + + data.win_rect.xmin = 0; + data.win_rect.ymin = 0; + data.win_rect.xmax = vc->ar->winx; + data.win_rect.ymax = vc->ar->winy; + + data.func = func; + data.userData = userData; + data.clip_flag = clip_flag; + + BM_mesh_elem_table_ensure(vc->em->bm, BM_EDGE); + + if ((clip_flag & V3D_PROJ_TEST_CLIP_BB) && (vc->rv3d->clipbb != NULL)) { + ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups. */ + BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge_clip_bb_segment__mapFunc, &data); + } + else { + BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge__mapFunc, &data); + } +} + +/* ------------------------------------------------------------------------ */ + static void mesh_foreachScreenFace__mapFunc(void *userData, int index, const float cent[3], diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 0fd76b2d6fd..de13bcbc6be 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -848,11 +848,14 @@ static bool do_lasso_select_mesh(ViewContext *vc, vc->obedit->runtime.select_id, SCE_SELECT_EDGE) : 0, }; - mesh_foreachScreenEdge( - vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, V3D_PROJ_TEST_CLIP_NEAR); + + const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR | + (use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB); + mesh_foreachScreenEdge_clip_bb_segment( + vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, clip_flag); if (data.is_done == false) { - mesh_foreachScreenEdge( - vc, do_lasso_select_mesh__doSelectEdge_pass1, &data_for_edge, V3D_PROJ_TEST_CLIP_NEAR); + mesh_foreachScreenEdge_clip_bb_segment( + vc, do_lasso_select_mesh__doSelectEdge_pass1, &data_for_edge, clip_flag); } } @@ -2824,11 +2827,14 @@ static bool do_mesh_box_select(ViewContext *vc, vc->obedit->runtime.select_id, SCE_SELECT_EDGE) : 0, }; - mesh_foreachScreenEdge( - vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, V3D_PROJ_TEST_CLIP_NEAR); + + const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR | + (use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB); + mesh_foreachScreenEdge_clip_bb_segment( + vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, clip_flag); if (data.is_done == false) { - mesh_foreachScreenEdge( - vc, do_mesh_box_select__doSelectEdge_pass1, &cb_data, V3D_PROJ_TEST_CLIP_NEAR); + mesh_foreachScreenEdge_clip_bb_segment( + vc, do_mesh_box_select__doSelectEdge_pass1, &cb_data, clip_flag); } } @@ -3410,7 +3416,8 @@ static bool mesh_circle_select(ViewContext *vc, } } else { - mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR); + mesh_foreachScreenEdge_clip_bb_segment( + vc, mesh_circle_doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); } } |