3D View: improve selection locking

Locked selection would still occlude with objects which could not be
selected.
This commit is contained in:
Campbell Barton 2018-06-19 16:41:18 +02:00
parent 0116c95d4c
commit 750a78be9c
7 changed files with 96 additions and 20 deletions

View 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);

View 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);

View 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);

View 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);

View 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;
}

View 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

View 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 */