From 328ec2b172e8954307f5f7d92b9880c033ec8cdf Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 17 Oct 2024 12:13:35 +0200 Subject: [PATCH] Fix #123963: Unable to select through unselectable bones When trying to select bones that are inside other bones which are not selectable, the selection would fail. This is inconsistent with object mode, where unselectable things are just ignored. This patch fixes it for pose mode and edit mode. Note that there are two areas for edit mode that were modified. The one in `ed_armature_pick_bone_from_selectbuffer/202` is never actually reached, but I added the code there for completeness. The code in `get_nearest_editbonepoint` had to be modified some more to implement a similar logic as `armature_select.cc/220` Pull Request: https://projects.blender.org/blender/blender/pulls/129120 --- .../editors/armature/armature_select.cc | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/armature/armature_select.cc b/source/blender/editors/armature/armature_select.cc index edb49f70d7e..b9a0f12648f 100644 --- a/source/blender/editors/armature/armature_select.cc +++ b/source/blender/editors/armature/armature_select.cc @@ -180,6 +180,9 @@ static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode if (is_editmode == false) { base = ED_armature_base_and_pchan_from_select_buffer(bases, hit_id, &pchan); if (pchan != nullptr) { + if (pchan->bone->flag & BONE_UNSELECTABLE) { + continue; + } if (findunsel) { sel = (pchan->bone->flag & BONE_SELECTED); } @@ -196,6 +199,9 @@ static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode } else { base = ED_armature_base_and_ebone_from_select_buffer(bases, hit_id, &ebone); + if (ebone->flag & BONE_UNSELECTABLE) { + continue; + } if (findunsel) { sel = (ebone->flag & BONE_SELECTED); } @@ -673,14 +679,15 @@ static EditBone *get_nearest_editbonepoint( view3d_opengl_select_cache_begin(); { - const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL); const eV3DSelectObjectFilter select_filter = VIEW3D_SELECT_FILTER_NOP; GPUSelectStorage &storage = buffer.storage; rcti rect; BLI_rcti_init_pt_radius(&rect, vc->mval, 12); + /* VIEW3D_SELECT_PICK_ALL needs to be used or unselectable bones can block selectability of + * bones further back. See #123963. */ const int hits12 = view3d_opengl_select_with_id_filter( - vc, &buffer, &rect, eV3DSelectMode(select_mode), select_filter, select_id_ignore); + vc, &buffer, &rect, VIEW3D_SELECT_PICK_ALL, select_filter, select_id_ignore); if (hits12 == 1) { hits = selectbuffer_ret_hits_12(storage.as_mutable_span(), hits12); @@ -689,7 +696,7 @@ static EditBone *get_nearest_editbonepoint( else if (hits12 > 0) { BLI_rcti_init_pt_radius(&rect, vc->mval, 5); const int hits5 = view3d_opengl_select_with_id_filter( - vc, &buffer, &rect, eV3DSelectMode(select_mode), select_filter, select_id_ignore); + vc, &buffer, &rect, VIEW3D_SELECT_PICK_ALL, select_filter, select_id_ignore); if (hits5 == 1) { hits = selectbuffer_ret_hits_5(storage.as_mutable_span(), hits12, hits5); @@ -754,8 +761,10 @@ cache_end: cycle_order.best.as_u32 = 0; } + int min_depth = INT_MAX; for (int i = 0; i < hits; i++) { - const uint hitresult = buffer.storage[i].id; + const GPUSelectResult &result = buffer.storage[i]; + const uint hitresult = result.id; Base *base = nullptr; EditBone *ebone; @@ -763,6 +772,10 @@ cache_end: /* If this fails, selection code is setting the selection ID's incorrectly. */ BLI_assert(base && ebone); + if (ebone->flag & BONE_UNSELECTABLE) { + continue; + } + /* Prioritized selection. */ { int bias; @@ -806,6 +819,14 @@ cache_end: result_bias.base = base; result_bias.ebone = ebone; } + else if (bias == bias_max && do_nearest) { + if (min_depth > result.depth) { + min_depth = result.depth; + result_bias.hitresult = hitresult; + result_bias.base = base; + result_bias.ebone = ebone; + } + } } /* Cycle selected items (objects & bones). */