diff options
-rw-r--r-- | source/blender/draw/DRW_engine.h | 8 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager.c | 22 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_view.c | 84 |
3 files changed, 83 insertions, 31 deletions
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h index 9ed8f776f34..4043f39b46d 100644 --- a/source/blender/draw/DRW_engine.h +++ b/source/blender/draw/DRW_engine.h @@ -88,6 +88,11 @@ typedef struct DRWUpdateContext { void DRW_notify_view_update(const DRWUpdateContext *update_ctx); void DRW_notify_id_update(const DRWUpdateContext *update_ctx, struct ID *id); + +typedef enum eDRWSelectStage { DRW_SELECT_PASS_PRE = 1, DRW_SELECT_PASS_POST, } eDRWSelectStage; +typedef bool (*DRW_SelectPassFn)( + eDRWSelectStage stage, void *user_data); + void DRW_draw_view(const struct bContext *C); void DRW_draw_render_loop_ex( @@ -108,7 +113,8 @@ void DRW_draw_render_loop_offscreen( void DRW_draw_select_loop( struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d, const eObjectMode object_mode, - bool use_obedit_skip, bool use_nearest, const struct rcti *rect); + bool use_obedit_skip, bool use_nearest, const struct rcti *rect, + DRW_SelectPassFn select_pass_fn, void *select_pass_user_data); void DRW_draw_depth_loop( struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d, const eObjectMode object_mode); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 62042a44434..037053399c7 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1384,7 +1384,8 @@ void DRW_render_instance_buffer_finish(void) void DRW_draw_select_loop( struct Depsgraph *depsgraph, ARegion *ar, View3D *v3d, const eObjectMode object_mode, - bool UNUSED(use_obedit_skip), bool UNUSED(use_nearest), const rcti *rect) + bool UNUSED(use_obedit_skip), bool UNUSED(use_nearest), const rcti *rect, + DRW_SelectPassFn select_pass_fn, void *select_pass_user_data) { Scene *scene = DEG_get_evaluated_scene(depsgraph); RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id); @@ -1484,12 +1485,21 @@ void DRW_draw_select_loop( /* Start Drawing */ DRW_state_reset(); DRW_draw_callbacks_pre_scene(); - drw_engines_draw_scene(); - DRW_draw_callbacks_post_scene(); -#ifdef USE_GPU_SELECT - GPU_select_finalize(); -#endif + /* Only 1-2 passes. */ + while (true) { + if (!select_pass_fn(DRW_SELECT_PASS_PRE, select_pass_user_data)) { + break; + } + + drw_engines_draw_scene(); + + if (!select_pass_fn(DRW_SELECT_PASS_POST, select_pass_user_data)) { + break; + } + } + + DRW_draw_callbacks_post_scene(); DRW_state_reset(); drw_engines_disable(); diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index cb329e62e96..0afef34194c 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -861,6 +861,45 @@ void view3d_opengl_select_cache_end(void) GPU_select_cache_end(); } +#ifndef WITH_OPENGL_LEGACY +struct DrawSelectLoopUserData { + uint pass; + uint hits; + uint *buffer; + uint buffer_len; + const rcti *rect; + char gpu_select_mode; +}; + +static bool drw_select_loop_pass(eDRWSelectStage stage, void *user_data) +{ + bool continue_pass = false; + struct DrawSelectLoopUserData *data = user_data; + if (stage == DRW_SELECT_PASS_PRE) { + GPU_select_begin(data->buffer, data->buffer_len, data->rect, data->gpu_select_mode, data->hits); + /* always run POST after PRE. */ + continue_pass = true; + } + else if (stage == DRW_SELECT_PASS_POST) { + int hits = GPU_select_end(); + if (data->pass == 0) { + /* quirk of GPU_select_end, only take hits value from first call. */ + data->hits = hits; + } + if (data->gpu_select_mode == GPU_SELECT_NEAREST_FIRST_PASS) { + data->gpu_select_mode = GPU_SELECT_NEAREST_SECOND_PASS; + continue_pass = true; + } + data->pass += 1; + } + else { + BLI_assert(0); + } + return continue_pass; + +} +#endif /* WITH_OPENGL_LEGACY */ + /** * \warning be sure to account for a negative return value * This is an error, "Too many objects in select buffer" @@ -950,43 +989,40 @@ int view3d_opengl_select( if (vc->rv3d->rflag & RV3D_CLIPPING) ED_view3d_clipping_set(vc->rv3d); - GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0); #ifdef WITH_OPENGL_LEGACY if (IS_VIEWPORT_LEGACY(vc->v3d)) { + GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0); ED_view3d_draw_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip, use_nearest); + hits = GPU_select_end(); + + if (do_passes && (hits > 0)) { + GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits); + ED_view3d_draw_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip, use_nearest); + GPU_select_end(); + } } else #else { + /* We need to call "GPU_select_*" API's inside DRW_draw_select_loop + * because the OpenGL context created & destroyed inside this function. */ + struct DrawSelectLoopUserData drw_select_loop_user_data = { + .pass = 0, + .hits = 0, + .buffer = buffer, + .buffer_len = bufsize, + .rect = &rect, + .gpu_select_mode = gpu_select_mode, + }; DRW_draw_select_loop( graph, ar, v3d, eval_ctx->object_mode, - use_obedit_skip, use_nearest, &rect); + use_obedit_skip, use_nearest, &rect, + drw_select_loop_pass, &drw_select_loop_user_data); + hits = drw_select_loop_user_data.hits; } #endif /* WITH_OPENGL_LEGACY */ - hits = GPU_select_end(); - - /* second pass, to get the closest object to camera */ - if (do_passes && (hits > 0)) { - GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits); - -#ifdef WITH_OPENGL_LEGACY - if (IS_VIEWPORT_LEGACY(vc->v3d)) { - ED_view3d_draw_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip, use_nearest); - } - else -#else - { - DRW_draw_select_loop( - graph, ar, v3d, eval_ctx->object_mode, - use_obedit_skip, use_nearest, &rect); - } -#endif /* WITH_OPENGL_LEGACY */ - - GPU_select_end(); - } - G.f &= ~G_PICKSEL; ED_view3d_draw_setup_view(vc->win, eval_ctx, scene, ar, v3d, vc->rv3d->viewmat, NULL, NULL); |