diff options
author | Campbell Barton <ideasman42@gmail.com> | 2017-03-09 19:15:58 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2017-03-09 21:00:49 +0300 |
commit | 62cc226101fab61b5ae2f18f8cbe8f1e5ac6ce82 (patch) | |
tree | 52a6a05b1c103c0601b2465892163bc36325241d | |
parent | 9de9f25b2455808335b5373003695610599daab7 (diff) |
3D View: x-ray support for depth picking
Selection loop would draw the selection ignoring xray.
Now draw in a separate pass after clearing the depth buffer,
as with regular drawing.
Also disable depth sorting,
caller can sort the hit-list by depth if needed.
-rw-r--r-- | source/blender/editors/space_view3d/drawobject.c | 44 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_draw.c | 82 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_intern.h | 8 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_view.c | 77 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_select_pick.c | 44 |
5 files changed, 170 insertions, 85 deletions
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 90d33dc5995..898f155cc92 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -8174,6 +8174,50 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short ED_view3d_clear_mats_rv3d(rv3d); } + +/** + * Drawing for selection picking, + * caller must have called 'GPU_select_load_id(base->selcode)' first. + */ +void draw_object_select(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short dflag) +{ + BLI_assert(dflag & DRAW_PICKING && dflag & DRAW_CONSTCOLOR); + draw_object(scene, ar, v3d, base, dflag); + + /* we draw duplicators for selection too */ + if ((base->object->transflag & OB_DUPLI)) { + ListBase *lb; + DupliObject *dob; + Base tbase; + + tbase.flag = OB_FROMDUPLI; + lb = object_duplilist(G.main->eval_ctx, scene, base->object); + + for (dob = lb->first; dob; dob = dob->next) { + float omat[4][4]; + char dt; + short dtx; + + tbase.object = dob->ob; + copy_m4_m4(omat, dob->ob->obmat); + copy_m4_m4(dob->ob->obmat, dob->mat); + + /* extra service: draw the duplicator in drawtype of parent */ + /* MIN2 for the drawtype to allow bounding box objects in groups for lods */ + dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt); + dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx; + + draw_object(scene, ar, v3d, &tbase, dflag); + + tbase.object->dt = dt; + tbase.object->dtx = dtx; + + copy_m4_m4(dob->ob->obmat, omat); + } + free_object_duplilist(lb); + } +} + /* ***************** BACKBUF SEL (BBS) ********* */ static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const float co[3], diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 0c5cf1bd936..3fb2761d40e 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -100,6 +100,7 @@ #include "GPU_material.h" #include "GPU_compositing.h" #include "GPU_extensions.h" +#include "GPU_select.h" #include "view3d_intern.h" /* own include */ @@ -2023,6 +2024,35 @@ static void view3d_draw_xraytransp(Scene *scene, ARegion *ar, View3D *v3d, const glDepthMask(GL_TRUE); } +/* clears zbuffer and draws it over, + * note that in the select version we don't care about transparent flag as with regular drawing */ +static void view3d_draw_xray_select(Scene *scene, ARegion *ar, View3D *v3d, bool *clear) +{ + /* Not ideal, but we need to read from the previous depths before clearing + * otherwise we could have a function to load the depths after drawing. + * + * Clearing the depth buffer isn't all that common between drawing objects so accept this for now. + */ + if (U.gpu_select_pick_deph) { + GPU_select_load_id(-1); + } + + View3DAfter *v3da; + if (*clear && v3d->zbuf) { + glClear(GL_DEPTH_BUFFER_BIT); + *clear = false; + } + + v3d->xray = true; + while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) { + if (GPU_select_load_id(v3da->base->selcol)) { + draw_object_select(scene, ar, v3d, v3da->base, v3da->dflag); + } + MEM_freeN(v3da); + } + v3d->xray = false; +} + /* *********************** */ /* @@ -2487,6 +2517,58 @@ void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaover U.obcenter_dia = obcenter_dia; } +void ED_view3d_draw_select_loop( + ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar, + bool use_obedit_skip, bool use_nearest) +{ + short code = 1; + const short dflag = DRAW_PICKING | DRAW_CONSTCOLOR; + + if (vc->obedit && vc->obedit->type == OB_MBALL) { + draw_object(scene, ar, v3d, BASACT, dflag); + } + else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) { + /* if not drawing sketch, draw bones */ + if (!BDR_drawSketchNames(vc)) { + draw_object(scene, ar, v3d, BASACT, dflag); + } + } + else { + Base *base; + + for (base = scene->base.first; base; base = base->next) { + if (base->lay & v3d->lay) { + + if ((base->object->restrictflag & OB_RESTRICT_SELECT) || + (use_obedit_skip && (scene->obedit->data == base->object->data))) + { + base->selcol = 0; + } + else { + base->selcol = code; + + if (use_nearest && (base->object->dtx & OB_DRAWXRAY)) { + ED_view3d_after_add(&v3d->afterdraw_xray, base, dflag); + } + else { + if (GPU_select_load_id(code)) { + draw_object_select(scene, ar, v3d, base, dflag); + } + } + code++; + } + } + } + + if (use_nearest) { + bool xrayclear = true; + if (v3d->afterdraw_xray.first) { + view3d_draw_xray_select(scene, ar, v3d, &xrayclear); + } + } + } +} + typedef struct View3DShadow { struct View3DShadow *next, *prev; GPULamp *lamp; diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 87b3d95cd4e..c2b8d1f8bda 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -143,6 +143,8 @@ void draw_motion_paths_cleanup(View3D *v3d); /* drawobject.c */ void draw_object(Scene *scene, struct ARegion *ar, View3D *v3d, Base *base, const short dflag); +void draw_object_select(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short dflag); + bool draw_glsl_material(Scene *scene, struct Object *ob, View3D *v3d, const char dt); void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob, const char dt, int outline); void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob); @@ -195,7 +197,11 @@ void draw_sim_debug_data(Scene *scene, View3D *v3d, ARegion *ar); void view3d_main_region_draw(const struct bContext *C, struct ARegion *ar); void ED_view3d_draw_depth(Scene *scene, struct ARegion *ar, View3D *v3d, bool alphaoverride); void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d); -void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag); +void ED_view3d_draw_select_loop( + ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar, + bool use_obedit_skip, bool use_nearest); + +void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag);\ void circf(float x, float y, float rad); void circ(float x, float y, float rad); diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index e8deaabec7a..8230a0de6b9 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1091,78 +1091,6 @@ void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d) } } -static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar, bool use_obedit_skip) -{ - short code = 1; - char dt; - short dtx; - - if (vc->obedit && vc->obedit->type == OB_MBALL) { - draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR); - } - else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) { - /* if not drawing sketch, draw bones */ - if (!BDR_drawSketchNames(vc)) { - draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR); - } - } - else { - Base *base; - - v3d->xray = true; /* otherwise it postpones drawing */ - for (base = scene->base.first; base; base = base->next) { - if (base->lay & v3d->lay) { - - if ((base->object->restrictflag & OB_RESTRICT_SELECT) || - (use_obedit_skip && (scene->obedit->data == base->object->data))) - { - base->selcol = 0; - } - else { - base->selcol = code; - - if (GPU_select_load_id(code)) { - draw_object(scene, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR); - - /* we draw duplicators for selection too */ - if ((base->object->transflag & OB_DUPLI)) { - ListBase *lb; - DupliObject *dob; - Base tbase; - - tbase.flag = OB_FROMDUPLI; - lb = object_duplilist(G.main->eval_ctx, scene, base->object); - - for (dob = lb->first; dob; dob = dob->next) { - float omat[4][4]; - - tbase.object = dob->ob; - copy_m4_m4(omat, dob->ob->obmat); - copy_m4_m4(dob->ob->obmat, dob->mat); - - /* extra service: draw the duplicator in drawtype of parent */ - /* MIN2 for the drawtype to allow bounding box objects in groups for lods */ - dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt); - dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx; - - draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR); - - tbase.object->dt = dt; - tbase.object->dtx = dtx; - - copy_m4_m4(dob->ob->obmat, omat); - } - free_object_duplilist(lb); - } - } - code++; - } - } - } - v3d->xray = false; /* restore */ - } -} - /** * Optionally cache data for multiple calls to #view3d_opengl_select * @@ -1200,6 +1128,7 @@ int view3d_opengl_select( (is_pick_select == false) && (select_mode == VIEW3D_SELECT_PICK_NEAREST) && GPU_select_query_check_active()); + const bool use_nearest = (is_pick_select && select_mode == VIEW3D_SELECT_PICK_NEAREST); char gpu_select_mode; @@ -1256,7 +1185,7 @@ int view3d_opengl_select( GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0); - view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip); + ED_view3d_draw_select_loop(vc, scene, v3d, ar, use_obedit_skip, use_nearest); hits = GPU_select_end(); @@ -1264,7 +1193,7 @@ int view3d_opengl_select( if (do_passes) { GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits); - view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip); + ED_view3d_draw_select_loop(vc, scene, v3d, ar, use_obedit_skip, use_nearest); GPU_select_end(); } diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c index 31f82fd002d..07521dfa060 100644 --- a/source/blender/gpu/intern/gpu_select_pick.c +++ b/source/blender/gpu/intern/gpu_select_pick.c @@ -91,6 +91,15 @@ static void rect_subregion_stride_calc(const rcti *src, const rcti *dst, SubRect r_sub->skip = src_x - dst_x; } +/** + * Ignore depth clearing as a change, + * only check if its been changed _and_ filled in (ignore clearing since XRAY does this). + */ +BLI_INLINE bool depth_is_filled(const depth_t *prev, const depth_t *curr) +{ + return (*prev != *curr) && (*curr != DEPTH_MAX); +} + /* ---------------------------------------------------------------------------- * DepthBufCache * @@ -142,17 +151,28 @@ static bool depth_buf_subrect_depth_any( return false; } -static bool depth_buf_rect_not_equal( - const DepthBufCache *rect_depth_a, const DepthBufCache *rect_depth_b, +static bool depth_buf_rect_depth_any_filled( + const DepthBufCache *rect_prev, const DepthBufCache *rect_curr, unsigned int rect_len) { +#if 0 return memcmp(rect_depth_a->buf, rect_depth_b->buf, rect_len * sizeof(depth_t)) != 0; +#else + const depth_t *prev = rect_prev->buf; + const depth_t *curr = rect_curr->buf; + for (unsigned int i = 0; i < rect_len; i++, curr++, prev++) { + if (depth_is_filled(prev, curr)) { + return true; + } + } + return false; +#endif } /** * Both buffers are the same size, just check if the sub-rect contains any differences. */ -static bool depth_buf_subrect_not_equal( +static bool depth_buf_subrect_depth_any_filled( const DepthBufCache *rect_src, const DepthBufCache *rect_dst, const SubRectStride *sub_rect) { @@ -162,7 +182,7 @@ static bool depth_buf_subrect_not_equal( for (unsigned int i = 0; i < sub_rect->span_len; i++) { const depth_t *curr_end = curr + sub_rect->span; for (; curr < curr_end; prev++, curr++) { - if (*prev != *curr) { + if (depth_is_filled(prev, curr)) { return true; } } @@ -422,8 +442,11 @@ static void gpu_select_load_id_pass_nearest(const DepthBufCache *rect_prev, cons if (id != SELECT_ID_NONE) { unsigned int *id_ptr = ps->nearest.rect_id; + /* Check against DEPTH_MAX because XRAY will clear the buffer, + * so previously set values will become unset. + * In this case just leave those id's left as-is. */ #define EVAL_TEST() \ - if (*curr != *prev) { \ + if (depth_is_filled(prev, curr)) { \ *id_ptr = id; \ } ((void)0) @@ -472,7 +495,7 @@ bool gpu_select_pick_load_id(unsigned int id) } } else { - if (depth_buf_rect_not_equal(ps->gl.rect_depth, ps->gl.rect_depth_test, rect_len)) { + if (depth_buf_rect_depth_any_filled(ps->gl.rect_depth, ps->gl.rect_depth_test, rect_len)) { ps->gl.rect_depth_test->id = ps->gl.prev_id; gpu_select_load_id_pass_nearest(ps->gl.rect_depth, ps->gl.rect_depth_test); do_pass = true; @@ -623,16 +646,17 @@ unsigned int gpu_select_pick_end(void) hits = -1; } else { + /* leave sorting up to the caller */ qsort(depth_data, depth_data_len, sizeof(DepthID), depth_cmp); for (unsigned int i = 0; i < depth_data_len; i++) { #ifdef DEBUG_PRINT - printf(" hit: %d: depth %u\n", depth_data[i].id, depth_data[i].depth); + printf(" hit: %u: depth %u\n", depth_data[i].id, depth_data[i].depth); #endif /* first 3 are dummy values */ g_pick_state.buffer[hits][0] = 1; - g_pick_state.buffer[hits][1] = 0x0; - g_pick_state.buffer[hits][2] = 0x0; + g_pick_state.buffer[hits][1] = 0x0; /* depth_data[i].depth; */ /* unused */ + g_pick_state.buffer[hits][2] = 0x0; /* z-far is currently never used. */ g_pick_state.buffer[hits][3] = depth_data[i].id; hits++; } @@ -709,7 +733,7 @@ void gpu_select_pick_cache_load_id(void) } } else { - if (depth_buf_subrect_not_equal(rect_depth, rect_depth->next, &ps->cache.sub_rect)) { + if (depth_buf_subrect_depth_any_filled(rect_depth, rect_depth->next, &ps->cache.sub_rect)) { gpu_select_load_id_pass_nearest(rect_depth, rect_depth->next); } } |