3D View: improve selection locking
authorCampbell Barton <ideasman42@gmail.com>
Tue, 19 Jun 2018 14:41:18 +0000 (16:41 +0200)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 19 Jun 2018 14:43:01 +0000 (16:43 +0200)
Locked selection would still occlude with objects which could not be
selected.

source/blender/draw/DRW_engine.h
source/blender/draw/intern/draw_manager.c
source/blender/editors/armature/armature_select.c
source/blender/editors/include/ED_view3d.h
source/blender/editors/metaball/mball_edit.c
source/blender/editors/space_view3d/view3d_select.c
source/blender/editors/space_view3d/view3d_view.c

index 524a94e588641d9ba291886ac5a08633eb141481..d126dcb71aaadb2da529fb0ca1e88454e65a157f 100644 (file)
@@ -94,6 +94,8 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx);
 typedef enum eDRWSelectStage { DRW_SELECT_PASS_PRE = 1, DRW_SELECT_PASS_POST, } eDRWSelectStage;
 typedef bool (*DRW_SelectPassFn)(
         eDRWSelectStage stage, void *user_data);
+typedef bool (*DRW_ObjectFilterFn)(
+        struct Object *ob, void *user_data);
 
 void DRW_draw_view(const struct bContext *C);
 
@@ -118,7 +120,8 @@ void DRW_draw_select_loop(
         struct Depsgraph *depsgraph,
         struct ARegion *ar, struct View3D *v3d,
         bool use_obedit_skip, bool use_nearest, const struct rcti *rect,
-        DRW_SelectPassFn select_pass_fn, void *select_pass_user_data);
+        DRW_SelectPassFn select_pass_fn, void *select_pass_user_data,
+        DRW_ObjectFilterFn object_filter_fn, void *object_filter_user_data);
 void DRW_draw_depth_loop(
         struct Depsgraph *depsgraph,
         struct ARegion *ar, struct View3D *v3d);
index ef42b88fd72fb6d381efa24c321a52ace2587403..fcdc4a3a016ab27fab03a0b152ba8c15607a8cd0 100644 (file)
@@ -1634,7 +1634,8 @@ void DRW_draw_select_loop(
         struct Depsgraph *depsgraph,
         ARegion *ar, View3D *v3d,
         bool UNUSED(use_obedit_skip), bool UNUSED(use_nearest), const rcti *rect,
-        DRW_SelectPassFn select_pass_fn, void *select_pass_user_data)
+        DRW_SelectPassFn select_pass_fn, void *select_pass_user_data,
+        DRW_ObjectFilterFn object_filter_fn, void *object_filter_user_data)
 {
        Scene *scene = DEG_get_evaluated_scene(depsgraph);
        RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->drawtype);
@@ -1721,6 +1722,7 @@ void DRW_draw_select_loop(
 #endif
                }
                else {
+                       bool filter_exclude = false;
                        DEG_OBJECT_ITER_BEGIN(
                                depsgraph, ob,
                                DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
@@ -1728,6 +1730,19 @@ void DRW_draw_select_loop(
                                DEG_ITER_OBJECT_FLAG_DUPLI)
                        {
                                if ((ob->base_flag & BASE_SELECTABLED) != 0) {
+
+                                       if (object_filter_fn != NULL) {
+                                               if (ob->base_flag & BASE_FROMDUPLI) {
+                                                       /* pass (use previous filter_exclude value) */
+                                               }
+                                               else {
+                                                       filter_exclude = (object_filter_fn(ob, object_filter_user_data) == false);
+                                               }
+                                               if (filter_exclude) {
+                                                       continue;
+                                               }
+                                       }
+
                                        /* This relies on dupli instances being after their instancing object. */
                                        if ((ob->base_flag & BASE_FROMDUPLI) == 0) {
                                                Object *ob_orig = DEG_get_original_object(ob);
index cd5a4ced26f75d6cfac45cf1a2c50971ecd86c4b..e295e1fd35a9750bdc065e327106e0e6f5325e90 100644 (file)
@@ -254,7 +254,9 @@ void *get_nearest_bone(
        rect.xmin = rect.xmax = xy[0];
        rect.ymin = rect.ymax = xy[1];
 
-       hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
+       hits = view3d_opengl_select(
+               &vc, buffer, MAXPICKBUF, &rect,
+               VIEW3D_SELECT_PICK_NEAREST, VIEW3D_SELECT_FILTER_NOP);
 
        *r_base = NULL;
 
@@ -446,9 +448,11 @@ static EditBone *get_nearest_editbonepoint(
 
        {
                const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
+               const eV3DSelectObjectFilter select_filter = VIEW3D_SELECT_FILTER_NOP;
+
                rcti rect;
                BLI_rcti_init_pt_radius(&rect, vc->mval, 12);
-               const int hits12 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode);
+               const int hits12 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter);
                if (hits12 == 1) {
                        hits = selectbuffer_ret_hits_12(buffer, hits12);
                        goto cache_end;
@@ -458,7 +462,9 @@ static EditBone *get_nearest_editbonepoint(
 
                        offs = 4 * hits12;
                        BLI_rcti_init_pt_radius(&rect, vc->mval, 5);
-                       const int hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode);
+                       const int hits5 = view3d_opengl_select(
+                               vc, buffer + offs, MAXPICKBUF - offs, &rect,
+                               select_mode, select_filter);
 
                        if (hits5 == 1) {
                                hits = selectbuffer_ret_hits_5(buffer, hits12, hits5);
index 24e5b3e26624f80ce93f019d295860ce0107e4a8..343bffa0082ae1e1bf1a31ad3e72b8dbf3837ace 100644 (file)
@@ -351,12 +351,19 @@ typedef enum {
        VIEW3D_SELECT_PICK_NEAREST = 2,
 } eV3DSelectMode;
 
+typedef enum {
+       /* Don't exclude anything. */
+       VIEW3D_SELECT_FILTER_NOP = 0,
+       /* Don't select objects outside the current mode. */
+       VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK = 1,
+} eV3DSelectObjectFilter;
+
 void view3d_opengl_select_cache_begin(void);
 void view3d_opengl_select_cache_end(void);
 
 int view3d_opengl_select(
         struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const struct rcti *input,
-        eV3DSelectMode select_mode);
+        eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter);
 
 /* view3d_select.c */
 float ED_view3d_select_dist_px(void);
index aea125ce4b9f67f8c269615b4382dc94c15c578a..1ae122a38013c982e70e8ec9ad1a23b5c9f734ac 100644 (file)
@@ -617,7 +617,9 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese
 
        BLI_rcti_init_pt_radius(&rect, mval, 12);
 
-       hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
+       hits = view3d_opengl_select(
+               &vc, buffer, MAXPICKBUF, &rect,
+               VIEW3D_SELECT_PICK_NEAREST, VIEW3D_SELECT_FILTER_NOP);
 
        /* does startelem exist? */
        ml = mb->editelems->first;
@@ -682,5 +684,3 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese
 
        return false;
 }
-
-
index 9b40f03a54a795b6801200e6565af5827d940b0e..b4f3be178aa36f0cdb6930a8a4b2ded6a47f93f7 100644 (file)
@@ -1172,7 +1172,7 @@ static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits15, const
 /* so check three selection levels and compare */
 static int mixed_bones_object_selectbuffer(
         ViewContext *vc, unsigned int *buffer, const int mval[2],
-        bool use_cycle, bool enumerate,
+        bool use_cycle, bool enumerate, eV3DSelectObjectFilter select_filter,
         bool *r_do_nearest)
 {
        rcti rect;
@@ -1211,7 +1211,7 @@ static int mixed_bones_object_selectbuffer(
        view3d_opengl_select_cache_begin();
 
        BLI_rcti_init_pt_radius(&rect, mval, 14);
-       hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode);
+       hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter);
        if (hits15 == 1) {
                hits = selectbuffer_ret_hits_15(buffer, hits15);
                goto finally;
@@ -1222,7 +1222,7 @@ static int mixed_bones_object_selectbuffer(
 
                offs = 4 * hits15;
                BLI_rcti_init_pt_radius(&rect, mval, 9);
-               hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode);
+               hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode, select_filter);
                if (hits9 == 1) {
                        hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
                        goto finally;
@@ -1232,7 +1232,7 @@ static int mixed_bones_object_selectbuffer(
 
                        offs += 4 * hits9;
                        BLI_rcti_init_pt_radius(&rect, mval, 5);
-                       hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode);
+                       hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode, select_filter);
                        if (hits5 == 1) {
                                hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
                                goto finally;
@@ -1373,7 +1373,10 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
 
        ED_view3d_viewcontext_init(C, &vc);
 
-       hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, false, false, &do_nearest);
+       hits = mixed_bones_object_selectbuffer(
+               &vc, buffer, mval,
+               false, false, VIEW3D_SELECT_FILTER_NOP,
+               &do_nearest);
 
        if (hits > 0) {
                const bool has_bones = selectbuffer_has_bones(buffer, hits);
@@ -1487,7 +1490,13 @@ static bool ed_object_select_pick(
                // TIMEIT_START(select_time);
 
                /* if objects have posemode set, the bones are in the same selection buffer */
-               hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, true, enumerate, &do_nearest);
+               const eV3DSelectObjectFilter select_filter = (
+                       (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) ?
+                       VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK : VIEW3D_SELECT_FILTER_NOP);
+               hits = mixed_bones_object_selectbuffer(
+                       &vc, buffer, mval,
+                       true, enumerate, select_filter,
+                       &do_nearest);
 
                // TIMEIT_END(select_time);
 
@@ -1968,7 +1977,9 @@ static int do_meta_box_select(
        unsigned int buffer[MAXPICKBUF];
        int hits;
 
-       hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL);
+       hits = view3d_opengl_select(
+               vc, buffer, MAXPICKBUF, rect,
+               VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP);
 
        if (extend == false && select)
                BKE_mball_deselect_all(mb);
@@ -2002,7 +2013,9 @@ static int do_armature_box_select(
        unsigned int buffer[MAXPICKBUF];
        int hits;
 
-       hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL);
+       hits = view3d_opengl_select(
+               vc, buffer, MAXPICKBUF, rect,
+               VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP);
 
        uint objects_len = 0;
        Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc->view_layer, &objects_len);
@@ -2150,7 +2163,12 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b
 
        /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
        vbuffer = MEM_mallocN(4 * (totobj + MAXPICKELEMS) * sizeof(unsigned int), "selection buffer");
-       hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL);
+       const eV3DSelectObjectFilter select_filter = (
+               (vc->scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) ?
+               VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK : VIEW3D_SELECT_FILTER_NOP);
+       hits = view3d_opengl_select(
+               vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect,
+               VIEW3D_SELECT_ALL, select_filter);
        /*
         * LOGIC NOTES (theeth):
         * The buffer and ListBase have the same relative order, which makes the selection
index 73b9a67ac566db9a95ce96e2051e136fa94c68cd..abb8c688e05074819f8330c331de2a59baf836c8 100644 (file)
@@ -896,6 +896,13 @@ static bool drw_select_loop_pass(eDRWSelectStage stage, void *user_data)
 }
 #endif /* WITH_OPENGL_LEGACY */
 
+/** Implement #VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK. */
+static bool drw_select_filter_object_mode_lock(Object *ob, void *user_data)
+{
+       const Object *obact = user_data;
+       return BKE_object_is_mode_compat(ob, obact->mode);
+}
+
 /**
  * \warning be sure to account for a negative return value
  * This is an error, "Too many objects in select buffer"
@@ -905,7 +912,7 @@ static bool drw_select_loop_pass(eDRWSelectStage stage, void *user_data)
  */
 int view3d_opengl_select(
         ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input,
-        eV3DSelectMode select_mode)
+        eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter)
 {
        struct bThemeState theme_state;
        Depsgraph *depsgraph = vc->depsgraph;
@@ -953,6 +960,25 @@ int view3d_opengl_select(
                }
        }
 
+       struct {
+               DRW_ObjectFilterFn fn;
+               void *user_data;
+       } object_filter = {NULL, NULL};
+       switch (select_filter) {
+               case VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK:
+               {
+                       Object *obact = OBACT(vc->view_layer);
+                       if (obact && obact->mode != OB_MODE_OBJECT) {
+                               object_filter.fn = drw_select_filter_object_mode_lock;
+                               object_filter.user_data = obact;
+                       }
+                       break;
+               }
+               case VIEW3D_SELECT_FILTER_NOP:
+                       break;
+
+       }
+
        /* Tools may request depth outside of regular drawing code. */
        UI_Theme_Store(&theme_state);
        UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
@@ -1014,7 +1040,8 @@ int view3d_opengl_select(
                DRW_draw_select_loop(
                        depsgraph, ar, v3d,
                        use_obedit_skip, use_nearest, &rect,
-                       drw_select_loop_pass, &drw_select_loop_user_data);
+                       drw_select_loop_pass, &drw_select_loop_user_data,
+                       object_filter.fn, object_filter.user_data);
                hits = drw_select_loop_user_data.hits;
        }
 #endif /* WITH_OPENGL_LEGACY */