diff options
Diffstat (limited to 'source/blender/windowmanager')
-rw-r--r-- | source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c | 205 |
1 files changed, 53 insertions, 152 deletions
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index a61d73b9f0b..f481f19045d 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -492,7 +492,8 @@ void WM_gizmomap_draw(wmGizmoMap *gzmap, static void gizmo_draw_select_3d_loop(const bContext *C, wmGizmo **visible_gizmos, - const int visible_gizmos_len) + const int visible_gizmos_len, + bool *r_use_select_bias) { /* TODO(campbell): this depends on depth buffer being written to, @@ -528,6 +529,10 @@ static void gizmo_draw_select_3d_loop(const bContext *C, is_depth_skip_prev = is_depth_skip; } + if (gz->select_bias != 0.0) { + *r_use_select_bias = true; + } + /* pass the selection id shifted by 8 bits. Last 8 bits are used for selected gizmo part id */ gz->type->draw_select(C, gz, select_id << 8); @@ -545,10 +550,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos, const int visible_gizmos_len, const bContext *C, const int co[2], - const int hotspot, - const bool use_depth_test, - const bool has_3d_select_bias, - int *r_hits) + const int hotspot) { const wmWindowManager *wm = CTX_wm_manager(C); ScrArea *area = CTX_wm_area(C); @@ -562,76 +564,30 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos, BLI_rcti_init_pt_radius(&rect, co, hotspot); - /* The selection mode is assigned for the following reasons: - * - * - #GPU_SELECT_ALL: Use it to check if there is anything at the cursor location - * (only ever runs once). - * - #GPU_SELECT_PICK_NEAREST: Use if there are more than 1 item at the cursor location, - * pick the nearest one. - * - #GPU_SELECT_PICK_ALL: Use for the same purpose as #GPU_SELECT_PICK_NEAREST - * when the selection depths need to re-ordered based on a bias. - * */ - const eGPUSelectMode gpu_select_mode = - (use_depth_test ? (has_3d_select_bias ? - /* Using select bias means the depths need to be - * re-calculated based on the bias to pick the best. */ - GPU_SELECT_PICK_ALL : - /* No bias, just pick the closest. */ - GPU_SELECT_PICK_NEAREST) : - /* Fast-path (occlusion queries). */ - GPU_SELECT_ALL); - - /* When switching between modes and the mouse pointer is over a gizmo, the highlight test is - * performed before the viewport is fully initialized (region->draw_buffer = NULL). - * When this is the case we should not use depth testing. */ - GPUViewport *gpu_viewport = WM_draw_region_get_viewport(region); - if (use_depth_test && gpu_viewport == NULL) { - return -1; - } + ED_view3d_draw_setup_view( + wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, &rect); - if (GPU_select_is_cached()) { - GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, gpu_select_mode, 0); - GPU_select_cache_load_id(); - hits = GPU_select_end(); - } - else { - /* TODO: waiting for the GPU in the middle of the event loop for every - * mouse move is bad for performance, we need to find a solution to not - * use the GPU or draw something once. (see T61474) */ + bool use_select_bias = false; - ED_view3d_draw_setup_view( - wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, &rect); + /* TODO: waiting for the GPU in the middle of the event loop for every + * mouse move is bad for performance, we need to find a solution to not + * use the GPU or draw something once. (see T61474) */ + GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0); + /* do the drawing */ + gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len, &use_select_bias); - /* There is no need to bind to the depth buffer outside this function - * because all future passes the will use the cached depths. */ - GPUFrameBuffer *depth_read_fb = NULL; - if (use_depth_test) { - GPUTexture *depth_tx = GPU_viewport_depth_texture(gpu_viewport); - GPU_framebuffer_ensure_config(&depth_read_fb, - { - GPU_ATTACHMENT_TEXTURE(depth_tx), - GPU_ATTACHMENT_NONE, - }); - GPU_framebuffer_bind(depth_read_fb); - } + hits = GPU_select_end(); - GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, gpu_select_mode, 0); - gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len); - hits = GPU_select_end(); - - if (use_depth_test) { - GPU_framebuffer_restore(); - GPU_framebuffer_free(depth_read_fb); - } - - ED_view3d_draw_setup_view( - wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, NULL); + if (hits > 0) { + GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits); + gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len, &use_select_bias); + GPU_select_end(); } - /* When selection bias is needed, this function will run again with `use_depth_test` enabled. */ - int hit_found = -1; + ED_view3d_draw_setup_view( + wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, NULL); - if (has_3d_select_bias && use_depth_test && (hits > 1)) { + if (use_select_bias && (hits > 1)) { float co_direction[3]; float co_screen[3] = {co[0], co[1], 0.0f}; ED_view3d_win_to_vector(region, (float[2]){UNPACK2(co)}, co_direction); @@ -643,6 +599,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos, GPU_matrix_unproject_3fv(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d_origin); GPUSelectResult *buf_iter = buffer; + int hit_found = -1; float dot_best = FLT_MAX; for (int i = 0; i < hits; i++, buf_iter++) { @@ -662,16 +619,11 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos, hit_found = buf_iter->id; } } - } - else { - const GPUSelectResult *hit_near = GPU_select_buffer_near(buffer, hits); - if (hit_near) { - hit_found = hit_near->id; - } + return hit_found; } - *r_hits = hits; - return hit_found; + const GPUSelectResult *hit_near = GPU_select_buffer_near(buffer, hits); + return hit_near ? hit_near->id : -1; } /** @@ -694,7 +646,6 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C, /* Search for 3D gizmo's that use the 2D callback for checking intersections. */ bool has_3d = false; - bool has_3d_select_bias = false; { for (int select_id = 0; select_id < visible_gizmos_len; select_id++) { wmGizmo *gz = visible_gizmos[select_id]; @@ -710,9 +661,6 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C, } else if (gz->type->draw_select != NULL) { has_3d = true; - if (gz->select_bias != 0.0f) { - has_3d_select_bias = true; - } } } } @@ -721,86 +669,39 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C, * This way we always use the first hit. */ if (has_3d) { - /* NOTE(@campbellbarton): The selection logic here uses a fast-path that exits early - * where possible. This is important as this runs on cursor-motion in the 3D view-port. - * - * - First, don't use the depth buffer at all, use occlusion queries to detect any gizmos. - * If there are no gizmos or only one - early exit, otherwise. - * - * - Bind the depth buffer and use selection picking logic. - * This is much slower than occlusion queries (since it's reading depths while drawing). - * When there is a single gizmo under the cursor (quite common), early exit, otherwise. - * - * - Perform another pass at a reduced size (see: `hotspot_radii`), - * since the result depths are cached this pass is practically free. - * - * Other notes: - * - * - If any of these passes fail, use the nearest result from the previous pass. - * - * - Drawing is only ever done twice. - */ - - /* Order largest to smallest so the first pass can be used as cache for - * later passes (when `use_depth_test == true`). */ - const int hotspot_radii[] = { - 10 * U.pixelsize, - /* This runs on mouse move, careful doing too many tests! */ - 3 * U.pixelsize, - }; - - /* Narrowing may assign zero to `hit`, allow falling back to the previous test. */ - int hit_prev = -1; + /* The depth buffer is needed for for gizmos to obscure eachother. */ + GPUViewport *viewport = WM_draw_region_get_viewport(CTX_wm_region(C)); - bool use_depth_test = false; - bool use_depth_cache = false; - - /* Workaround for MS-Windows & NVidia failing to detect any gizmo undo the cursor unless the - * depth test is enabled, see: T97124. - * NOTE(@campbellbarton): Ideally the exact cause of this could be tracked down, - * disable as I don't have a system to test this configuration. */ - if (GPU_type_matches(GPU_DEVICE_NVIDIA | GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_ANY)) { - use_depth_test = true; + /* When switching between modes and the mouse pointer is over a gizmo, the highlight test is + * performed before the viewport is fully initialized (region->draw_buffer = NULL). + * When this is the case we should not use depth testing. */ + if (viewport == NULL) { + return NULL; } + GPUTexture *depth_tx = GPU_viewport_depth_texture(viewport); + GPUFrameBuffer *depth_read_fb = NULL; + GPU_framebuffer_ensure_config(&depth_read_fb, + { + GPU_ATTACHMENT_TEXTURE(depth_tx), + GPU_ATTACHMENT_NONE, + }); + GPU_framebuffer_bind(depth_read_fb); + const int hotspot_radii[] = { + 3 * U.pixelsize, + /* This runs on mouse move, careful doing too many tests! */ + 10 * U.pixelsize, + }; for (int i = 0; i < ARRAY_SIZE(hotspot_radii); i++) { - - if (use_depth_test && (use_depth_cache == false)) { - GPU_select_cache_begin(); - use_depth_cache = true; - } - - int hit_count; - hit = gizmo_find_intersected_3d_intern(visible_gizmos, - visible_gizmos_len_trim, - C, - co, - hotspot_radii[i], - use_depth_test, - has_3d_select_bias, - &hit_count); - /* Only continue searching when there are multiple options to narrow down. */ - if (hit_count < 2) { + hit = gizmo_find_intersected_3d_intern( + visible_gizmos, visible_gizmos_len_trim, C, co, hotspot_radii[i]); + if (hit != -1) { break; } - - /* Fast path for simple case, one item or nothing. */ - if (use_depth_test == false) { - /* Restart, using depth buffer (slower). */ - use_depth_test = true; - i = -1; - } - hit_prev = hit; - } - /* Narrowing the search area may yield no hits, - * in this case fall back to the previous search. */ - if (hit == -1) { - hit = hit_prev; } - if (use_depth_cache) { - GPU_select_cache_end(); - } + GPU_framebuffer_restore(); + GPU_framebuffer_free(depth_read_fb); if (hit != -1) { const int select_id = hit >> 8; |