diff options
-rw-r--r-- | source/blender/makesrna/intern/rna_wm_gizmo.c | 7 | ||||
-rw-r--r-- | source/blender/windowmanager/gizmo/WM_gizmo_types.h | 4 | ||||
-rw-r--r-- | source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c | 63 |
3 files changed, 68 insertions, 6 deletions
diff --git a/source/blender/makesrna/intern/rna_wm_gizmo.c b/source/blender/makesrna/intern/rna_wm_gizmo.c index a473f97d554..22162aa017b 100644 --- a/source/blender/makesrna/intern/rna_wm_gizmo.c +++ b/source/blender/makesrna/intern/rna_wm_gizmo.c @@ -384,6 +384,7 @@ static void rna_Gizmo_matrix_world_get(PointerRNA *ptr, float value[16]) RNA_GIZMO_GENERIC_FLOAT_RW_DEF(scale_basis, scale_basis); RNA_GIZMO_GENERIC_FLOAT_RW_DEF(line_width, line_width); +RNA_GIZMO_GENERIC_FLOAT_RW_DEF(select_bias, select_bias); RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_draw_hover, flag, WM_GIZMO_DRAW_HOVER); RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_draw_modal, flag, WM_GIZMO_DRAW_MODAL); @@ -1159,6 +1160,12 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + prop = RNA_def_property(srna, "select_bias", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Select Bias", "Depth bias used for selection"); + RNA_def_property_float_funcs( + prop, "rna_Gizmo_select_bias_get", "rna_Gizmo_select_bias_set", NULL); + RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); + /* wmGizmo.flag */ /* WM_GIZMO_HIDDEN */ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h index 1c298f378a4..7d38194db1b 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h @@ -198,6 +198,10 @@ struct wmGizmo { /** For single click button gizmos, use a different part as a fallback, -1 when unused. */ int drag_part; + /** Distance to bias this gizmo above others when picking + * (in worldspace, scaled by the gizmo scale - when used). */ + float select_bias; + /** * Transformation of the gizmo in 2d or 3d space. * - Matrix axis are expected to be unit length (scale is applied after). diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index 31c5e1fb94c..9f36af8b616 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -25,8 +25,10 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLI_math_bits.h" #include "BLI_rect.h" #include "BLI_ghash.h" +#include "BLI_array.h" #include "BKE_context.h" #include "BKE_global.h" @@ -470,7 +472,8 @@ void WM_gizmomap_draw(wmGizmoMap *gzmap, static void gizmo_draw_select_3D_loop(const bContext *C, ListBase *visible_gizmos, - const wmGizmo *gz_stop) + const wmGizmo *gz_stop, + bool *r_use_select_bias) { int select_id = 0; wmGizmo *gz; @@ -511,6 +514,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); @@ -543,24 +550,68 @@ static int gizmo_find_intersected_3d_intern(ListBase *visible_gizmos, ED_view3d_draw_setup_view( CTX_wm_window(C), CTX_data_depsgraph(C), CTX_data_scene(C), ar, v3d, NULL, NULL, &rect); + bool use_select_bias = false; + 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, gz_stop); + gizmo_draw_select_3D_loop(C, visible_gizmos, gz_stop, &use_select_bias); hits = GPU_select_end(); 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, gz_stop); + gizmo_draw_select_3D_loop(C, visible_gizmos, gz_stop, &use_select_bias); GPU_select_end(); } ED_view3d_draw_setup_view( CTX_wm_window(C), CTX_data_depsgraph(C), CTX_data_scene(C), ar, v3d, NULL, NULL, NULL); - const GLuint *hit_near = GPU_select_buffer_near(buffer, hits); - - return hit_near ? hit_near[3] : -1; + if (use_select_bias && (hits > 1)) { + wmGizmo **gizmo_table = NULL; + BLI_array_staticdeclare(gizmo_table, 1024); + for (LinkData *link = visible_gizmos->first; link; link = link->next) { + BLI_array_append(gizmo_table, link->data); + } + float co_direction[3]; + float co_screen[3] = {co[0], co[1], 0.0f}; + ED_view3d_win_to_vector(ar, (float[2]){UNPACK2(co)}, co_direction); + + RegionView3D *rv3d = ar->regiondata; + const int viewport[4] = {0, 0, ar->winx, ar->winy}; + float co_3d_origin[3]; + + GPU_matrix_unproject_model_inverted( + co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d_origin); + + GLuint *buf_iter = buffer; + int hit_found = -1; + float dot_best = FLT_MAX; + + for (int i = 0; i < hits; i++, buf_iter += 4) { + BLI_assert(buf_iter[3] != -1); + wmGizmo *gz = gizmo_table[buf_iter[3] >> 8]; + float co_3d[3]; + co_screen[2] = int_as_float(buf_iter[1]); + GPU_matrix_unproject_model_inverted(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d); + float select_bias = gz->select_bias; + if ((gz->flag & WM_GIZMO_DRAW_NO_SCALE) == 0) { + select_bias *= gz->scale_final; + } + sub_v3_v3(co_3d, co_3d_origin); + const float dot_test = dot_v3v3(co_3d, co_direction) - select_bias; + if (dot_best > dot_test) { + dot_best = dot_test; + hit_found = buf_iter[3]; + } + } + BLI_array_free(gizmo_table); + return hit_found; + } + else { + const GLuint *hit_near = GPU_select_buffer_near(buffer, hits); + return hit_near ? hit_near[3] : -1; + } } /** |