Cleanup: various improvements to ed_object_select_pick

- Document parameters.
- Add code-comments.
- Remove some historic/unhelpful code-comments.
- Rename argument names that were ambiguous
  (object was a boolean for e.g.).
- Move `gpu` picking into an allocated struct which is only
  allocated & used when using GPU picking.
- Move variable declarations after menu picking has been handled.
This commit is contained in:
Campbell Barton 2022-03-23 13:15:45 +11:00
parent 4822153b85
commit 5f350a4acd
1 changed files with 138 additions and 89 deletions

View File

@ -2419,76 +2419,95 @@ static bool ed_object_select_pick_camera_track(bContext *C,
return changed || found;
}
/**
* Cursor selection picking for object & pose-mode.
*
* \param mval: Region relative cursor coordinates.
* \param params: Selection parameters.
* \param center: Select by the cursors on-screen distances to the center/origin
* instead of the geometry any other contents of the item being selected.
* This could be used to select by bones by their origin too, currently it's only used for objects.
* \param enumerate: Show a menu for objects at the cursor location.
* Otherwise fall-through to non-menu selection.
* \param object_only: Only select objects (not bones / track markers).
*/
static bool ed_object_select_pick(bContext *C,
const int mval[2],
const struct SelectPick_Params *params,
bool obcenter,
bool enumerate,
bool object)
const bool center,
const bool enumerate,
const bool object_only)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
/* Setup view context for argument to callbacks. */
ED_view3d_viewcontext_init(C, &vc, depsgraph);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
/* Don't set when the context has no active object (hidden), see: T60807. */
const Base *oldbasact = vc.obact ? BASACT(view_layer) : NULL;
Base *startbase = NULL, *basact = NULL, *basact_override = NULL;
const eObjectMode object_mode = oldbasact ? oldbasact->object->mode : OB_MODE_OBJECT;
Scene *scene = vc.scene;
View3D *v3d = vc.v3d;
/* Menu activation may find a base to make active (if it only finds a single item to select). */
Base *basact_override = NULL;
const bool is_obedit = (vc.obedit != NULL);
/* Handle setting the new base active */
bool use_activate_selected_base = false;
/* When enabled, don't attempt any further selection. */
bool handled = false;
bool changed = false;
if (object) {
if (object_only) {
/* Signal for #view3d_opengl_select to skip edit-mode objects. */
vc.obedit = NULL;
}
/* Always start list from `basact` when cycling the selection. */
startbase = FIRSTBASE(view_layer);
if (oldbasact && oldbasact->next) {
startbase = oldbasact->next;
}
/* Set for GPU depth buffer picking, leave NULL when selecting by center. */
struct {
GPUSelectResult buffer[MAXPICKELEMS];
int hits;
bool do_nearest;
bool has_bones;
} *gpu = NULL;
GPUSelectResult buffer[MAXPICKELEMS];
int hits = 0;
bool do_nearest = false;
bool has_bones = false;
/* First handle menu selection, early exit if a menu opens
* since this takes ownership of the selection action.
*
* Even when there is no menu `basact_override` may be set to avoid having to re-find
* the item under the cursor. */
if (center == false) {
gpu = MEM_mallocN(sizeof(*gpu), __func__);
gpu->do_nearest = false;
gpu->has_bones = false;
if (obcenter == false) {
/* If objects have pose-mode set, the bones are in the same selection buffer. */
const eV3DSelectObjectFilter select_filter = ((object == false) ?
const eV3DSelectObjectFilter select_filter = ((object_only == false) ?
ED_view3d_select_filter_from_mode(scene,
vc.obact) :
VIEW3D_SELECT_FILTER_NOP);
hits = mixed_bones_object_selectbuffer_extended(
&vc, buffer, ARRAY_SIZE(buffer), mval, select_filter, true, enumerate, &do_nearest);
has_bones = (object && hits > 0) ? false : selectbuffer_has_bones(buffer, hits);
gpu->hits = mixed_bones_object_selectbuffer_extended(&vc,
gpu->buffer,
ARRAY_SIZE(gpu->buffer),
mval,
select_filter,
true,
enumerate,
&gpu->do_nearest);
gpu->has_bones = (object_only && gpu->hits > 0) ?
false :
selectbuffer_has_bones(gpu->buffer, gpu->hits);
}
/* First handle menu selection, early exit when a menu was opened.
* Otherwise fall through to regular selection. */
if (enumerate) {
bool has_menu = false;
if (obcenter) {
if (center) {
if (object_mouse_select_menu(C, &vc, NULL, 0, mval, params, &basact_override)) {
has_menu = true;
}
}
else {
if (hits != 0) {
if (has_bones && bone_mouse_select_menu(C, buffer, hits, false, params)) {
if (gpu->hits != 0) {
if (gpu->has_bones && bone_mouse_select_menu(C, gpu->buffer, gpu->hits, false, params)) {
has_menu = true;
}
else if (object_mouse_select_menu(C, &vc, buffer, hits, mval, params, &basact_override)) {
else if (object_mouse_select_menu(
C, &vc, gpu->buffer, gpu->hits, mval, params, &basact_override)) {
has_menu = true;
}
}
@ -2496,15 +2515,33 @@ static bool ed_object_select_pick(bContext *C,
/* Let the menu handle any further actions. */
if (has_menu) {
if (gpu != NULL) {
MEM_freeN(gpu);
}
return false;
}
}
/* This block uses the control key to make the object selected
* by its center point rather than its contents */
/* No menu, continue with selection. */
/* In edit-mode do not activate. */
if (obcenter) {
ViewLayer *view_layer = vc.view_layer;
/* Don't set when the context has no active object (hidden), see: T60807. */
const Base *oldbasact = vc.obact ? BASACT(view_layer) : NULL;
/* Always start list from `basact` when cycling the selection. */
Base *startbase = (oldbasact && oldbasact->next) ? oldbasact->next : FIRSTBASE(view_layer);
/* The next object's base to make active. */
Base *basact = NULL;
const eObjectMode object_mode = oldbasact ? oldbasact->object->mode : OB_MODE_OBJECT;
/* When enabled, don't attempt any further selection. */
bool handled = false;
bool changed = false;
/* Handle setting the new base active (even when `handled == true`). */
bool use_activate_selected_base = false;
if (center) {
if (basact_override) {
basact = basact_override;
}
@ -2517,19 +2554,23 @@ static bool ed_object_select_pick(bContext *C,
basact = basact_override;
}
else {
basact = (hits > 0) ? mouse_select_eval_buffer(
&vc, buffer, hits, startbase, has_bones, do_nearest, NULL) :
NULL;
basact =
(gpu->hits > 0) ?
mouse_select_eval_buffer(
&vc, gpu->buffer, gpu->hits, startbase, gpu->has_bones, gpu->do_nearest, NULL) :
NULL;
}
if (((hits > 0) && has_bones) ||
/* Select pose-bones or camera-tracks. */
if (((gpu->hits > 0) && gpu->has_bones) ||
/* Special case, even when there are no hits, pose logic may de-select all bones. */
((hits == 0) && (object_mode & OB_MODE_POSE))) {
((gpu->hits == 0) && (object_mode & OB_MODE_POSE))) {
if (basact && (has_bones && (basact->object->type == OB_CAMERA))) {
if (basact && (gpu->has_bones && (basact->object->type == OB_CAMERA))) {
MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false);
if (clip != NULL) {
if (ed_object_select_pick_camera_track(C, scene, basact, clip, buffer, hits, params)) {
if (ed_object_select_pick_camera_track(
C, scene, basact, clip, gpu->buffer, gpu->hits, params)) {
ED_object_base_select(basact, BA_SELECT);
/* Don't set `handled` here as the object activation may be necessary. */
@ -2539,31 +2580,32 @@ static bool ed_object_select_pick(bContext *C,
/* Fallback to regular object selection if no new bundles were selected,
* allows to select object parented to reconstruction object. */
basact = mouse_select_eval_buffer(
&vc, buffer, hits, startbase, false, do_nearest, NULL);
&vc, gpu->buffer, gpu->hits, startbase, false, gpu->do_nearest, NULL);
}
}
}
else if (ED_armature_pose_select_pick_with_buffer(view_layer,
v3d,
basact ? basact : (Base *)oldbasact,
buffer,
hits,
gpu->buffer,
gpu->hits,
params,
do_nearest)) {
gpu->do_nearest)) {
/* When there is no `baseact` this will have operated on `oldbasact`,
* no object operations are needed. */
* allowing #SelectPick_Params.deselect_all work in pose-mode.
* In this case no object operations are needed. */
if (basact != NULL) {
/* then bone is found */
/* we make the armature selected:
* not-selected active object in pose-mode won't work well for tools */
/* By convention the armature-object is selected when in pose-mode.
* While leaving it unselected will work, leaving pose-mode would leave the object
* active + unselected which isn't ideal when performing other actions on the object. */
ED_object_base_select(basact, BA_SELECT);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, basact->object);
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
/* In weight-paint, we use selected bone to select vertex-group,
* so don't switch to new active object. */
/* In weight-paint, we use selected bone to select vertex-group.
* In this case the active object mustn't change as it would leave weight-paint mode. */
if (oldbasact) {
if (oldbasact->object->mode & OB_MODE_ALL_WEIGHT_PAINT) {
/* Prevent activating.
@ -2601,33 +2643,34 @@ static bool ed_object_select_pick(bContext *C,
}
}
if ((scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) &&
/* No further selection should take place. */
(handled == false) &&
if (handled == false) {
if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
/* No special logic in edit-mode. */
(is_obedit == false)) {
if (is_obedit == false) {
if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) {
if (object_mode == OB_MODE_OBJECT) {
struct Main *bmain = vc.bmain;
ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object);
}
if (!BKE_object_is_mode_compat(basact->object, object_mode)) {
basact = NULL;
}
}
if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) {
if (object_mode == OB_MODE_OBJECT) {
struct Main *bmain = CTX_data_main(C);
ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object);
}
if (!BKE_object_is_mode_compat(basact->object, object_mode)) {
basact = NULL;
}
}
/* Disallow switching modes,
* special exception for edit-mode - vertex-parent operator. */
if (basact && oldbasact) {
if ((oldbasact->object->mode != basact->object->mode) &&
(oldbasact->object->mode & basact->object->mode) == 0) {
basact = NULL;
/* Disallow switching modes,
* special exception for edit-mode - vertex-parent operator. */
if (basact && oldbasact) {
if ((oldbasact->object->mode != basact->object->mode) &&
(oldbasact->object->mode & basact->object->mode) == 0) {
basact = NULL;
}
}
}
}
}
/* Ensure code above doesn't change the active base. */
/* Ensure code above doesn't change the active base. This code is already fairly involved,
* it's best if changing the active object is localized to a single place. */
BLI_assert(oldbasact == (vc.obact ? BASACT(view_layer) : NULL));
bool found = (basact != NULL);
@ -2646,12 +2689,12 @@ static bool ed_object_select_pick(bContext *C,
}
}
/* so, do we have something selected? */
if ((handled == false) && found) {
changed = true;
if (vc.obedit) {
/* Only do the select (use for setting vertex parents & hooks). */
/* Only do the select (use for setting vertex parents & hooks).
* In edit-mode do not activate. */
object_deselect_all_except(view_layer, basact);
ED_object_base_select(basact, BA_SELECT);
}
@ -2696,6 +2739,8 @@ static bool ed_object_select_pick(bContext *C,
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
/* Perform the activation even when 'handled', since this is used to ensure
* the object from the pose-bone selected is also activated. */
if (use_activate_selected_base && (basact != NULL)) {
changed = true;
ED_object_base_activate(C, basact); /* adds notifier */
@ -2713,6 +2758,10 @@ static bool ed_object_select_pick(bContext *C,
}
}
if (gpu != NULL) {
MEM_freeN(gpu);
}
return changed;
}
@ -2810,11 +2859,11 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
bool enumerate = RNA_boolean_get(op->ptr, "enumerate");
/* Only force object select for edit-mode to support vertex parenting,
* or paint-select to allow pose bone select with vert/face select. */
bool object = (RNA_boolean_get(op->ptr, "object") &&
(obedit || BKE_paint_select_elem_test(obact) ||
/* so its possible to select bones in weight-paint mode (LMB select) */
(obact && (obact->mode & OB_MODE_ALL_WEIGHT_PAINT) &&
BKE_object_pose_armature_get(obact))));
bool object_only = (RNA_boolean_get(op->ptr, "object") &&
(obedit || BKE_paint_select_elem_test(obact) ||
/* so its possible to select bones in weight-paint mode (LMB select) */
(obact && (obact->mode & OB_MODE_ALL_WEIGHT_PAINT) &&
BKE_object_pose_armature_get(obact))));
/* This could be called "changed_or_found" since this is true when there is an element
* under the cursor to select, even if it happens that the selection & active state doesn't
@ -2827,7 +2876,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
view3d_operator_needs_opengl(C);
BKE_object_update_select_id(CTX_data_main(C));
if (object) {
if (object_only) {
obedit = NULL;
obact = NULL;
@ -2837,7 +2886,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
center = false;
}
if (obedit && object == false) {
if (obedit && object_only == false) {
if (obedit->type == OB_MESH) {
changed = EDBM_select_pick(C, mval, &params);
}
@ -2879,7 +2928,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
changed = ed_wpaint_vertex_select_pick(C, mval, &params, obact);
}
else {
changed = ed_object_select_pick(C, mval, &params, center, enumerate, object);
changed = ed_object_select_pick(C, mval, &params, center, enumerate, object_only);
}
/* Pass-through flag may be cleared, see #WM_operator_flag_only_pass_through_on_press. */