Fix edge selection ignoring clipping in wire-frame display
authorCampbell Barton <ideasman42@gmail.com>
Fri, 2 Aug 2019 12:53:27 +0000 (22:53 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 2 Aug 2019 13:01:19 +0000 (23:01 +1000)
source/blender/editors/include/ED_view3d.h
source/blender/editors/space_view3d/view3d_iterators.c
source/blender/editors/space_view3d/view3d_select.c

index 081bcbf4746d7e785e0b85dc2b4654c05890a9af..afdbbeedff4d4ed4a8b84b6a86d7fa7cc8ac2111 100644 (file)
@@ -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),
index a7215a3b7f771453798fd03d7174df105b72a21d..f6fa6f6fb45cf607ea7735958c61ae6784b5e3f6 100644 (file)
@@ -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],
index 0fd76b2d6fd18496e0f3fe8514a48ea6ea821d65..de13bcbc6be7bfe1849c69662eef984cdb94d5c9 100644 (file)
@@ -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);
     }
   }