diff options
author | Campbell Barton <campbell@blender.org> | 2022-03-17 10:07:07 +0300 |
---|---|---|
committer | Campbell Barton <campbell@blender.org> | 2022-03-17 10:21:47 +0300 |
commit | e0a8f9b78e7a3e5d8dcd3b490989401d461936ed (patch) | |
tree | fbf9c9a7d59f57f185c48562fcd828f1d1e9c4a2 /source/blender/editors | |
parent | bb735bd51807f2315558d8a2fa6fbd78a58f88f9 (diff) |
Fix unintended de-selection when selecting the object center
Selecting an object that was already active & selected would de-select
it when the cursor was over the objects center.
This was caused by [0] that added a check which assumed more than one
hits from GPU_select meant there were multiple objects to select from.
This is not necessarily the case since bones, camera tracks or the
objects own center can add additional hits.
Resolve by keeping track of the best hit with & without the
active-selected object, only using the non-active-selected if it's found.
[0] 1550573360241ef5be0839d2652e9e092f510b63
Diffstat (limited to 'source/blender/editors')
-rw-r--r-- | source/blender/editors/space_view3d/view3d_select.c | 45 |
1 files changed, 39 insertions, 6 deletions
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index f635bcf52b8..98cf222af17 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -2052,7 +2052,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, if (do_nearest) { uint min = 0xFFFFFFFF; - int selcol = 0, notcol = 0; + int selcol = 0; if (has_bones) { /* we skip non-bone hits */ @@ -2065,18 +2065,51 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, } } else { - /* only exclude active object when it is selected... */ + int select_id_exclude = 0; + /* Only exclude active object when it is selected. */ if (BASACT(view_layer) && (BASACT(view_layer)->flag & BASE_SELECTED) && hits > 1) { - notcol = BASACT(view_layer)->object->runtime.select_id; + select_id_exclude = BASACT(view_layer)->object->runtime.select_id; } + /* Find the best active & non-active hits. + * NOTE(@campbellbarton): Checking if `hits > 1` isn't a reliable way to know + * if there are multiple objects selected since it's possible the same object + * generates multiple hits, either from: + * - Multiple sub-components (bones & camera tracks). + * - Multiple selectable elements such as the object center and the geometry. + * + * For this reason, keep track of the best hit as well as the best hit that + * excludes the selected & active object, using this value when it's valid. */ + + uint min_not_active = min; + int hit_index = -1, hit_index_not_active = -1; + for (a = 0; a < hits; a++) { - if (min > buffer[a].depth && notcol != (buffer[a].id & 0xFFFF)) { + /* Any object. */ + if (min > buffer[a].depth) { min = buffer[a].depth; - selcol = buffer[a].id & 0xFFFF; - sub_selection_id = (buffer[a].id & 0xFFFF0000) >> 16; + hit_index = a; + } + /* Any object other than the active-selected. */ + if (select_id_exclude != 0) { + if (min_not_active > buffer[a].depth && select_id_exclude != (buffer[a].id & 0xFFFF)) { + min_not_active = buffer[a].depth; + hit_index_not_active = a; + } } } + + /* When the active was selected, first try to use the index + * for the best non-active hit that was found. */ + if (hit_index_not_active != -1) { + hit_index = hit_index_not_active; + } + + if (hit_index != -1) { + selcol = buffer[hit_index].id & 0xFFFF; + sub_selection_id = (buffer[hit_index].id & 0xFFFF0000) >> 16; + /* No need to set `min` to `buffer[hit_index].depth`, it's not used from now on. */ + } } base = FIRSTBASE(view_layer); |