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] 1550573360
This commit is contained in:
Campbell Barton 2022-03-17 18:07:07 +11:00
parent bb735bd518
commit e0a8f9b78e
1 changed files with 39 additions and 6 deletions

View File

@ -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,17 +2065,50 @@ 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. */
}
}