Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2020-04-09 11:35:01 +0300
committerCampbell Barton <ideasman42@gmail.com>2020-04-09 11:46:47 +0300
commitbd59781c66e15617b5c0cccfb07b2c0e3079b210 (patch)
treec7c405f21f623573feab23fe5043602a2bb42dae
parent19352bca163dbd832ffc93ec5925736e4f25c959 (diff)
Fix T75425: Bone selection cycling not working
Edit-mode bone selection now cycles on successive clicks. This now cycles through multiple edit-objects & bones.
-rw-r--r--source/blender/editors/armature/armature_select.c176
1 files changed, 107 insertions, 69 deletions
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 4b938fb0072..98f067af148 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -657,45 +657,28 @@ static EditBone *get_nearest_editbonepoint(
uint hitresult;
Base *base;
EditBone *ebone;
- } best = {
- .hitresult = BONESEL_NOSEL,
- .base = NULL,
- .ebone = NULL,
- };
+ } *result = NULL,
+
+ result_cycle = {.hitresult = BONESEL_NOSEL, .base = NULL, .ebone = NULL},
+ result_bias = {.hitresult = BONESEL_NOSEL, .base = NULL, .ebone = NULL};
/* find the bone after the current active bone, so as to bump up its chances in selection.
* this way overlapping bones will cycle selection state as with objects. */
- EditBone *ebone_next_act = ((bArmature *)vc->obedit->data)->act_edbone;
- {
- bArmature *arm = (bArmature *)vc->obedit->data;
- if (ebone_next_act && EBONE_VISIBLE(arm, ebone_next_act) &&
- ebone_next_act->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) {
- ebone_next_act = ebone_next_act->next ? ebone_next_act->next : arm->edbo->first;
- }
- else {
- ebone_next_act = NULL;
- }
+ Object *obedit_orig = vc->obedit;
+ EditBone *ebone_active_orig = ((bArmature *)obedit_orig->data)->act_edbone;
+ if (ebone_active_orig == NULL) {
+ use_cycle = false;
}
- bool do_nearest = false;
-
- /* define if we use solid nearest select or not */
if (use_cycle) {
static int last_mval[2] = {-100, -100};
-
- if (!XRAY_ACTIVE(vc->v3d)) {
- do_nearest = true;
- if (len_manhattan_v2v2_int(vc->mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) {
- do_nearest = false;
- }
+ if ((len_manhattan_v2v2_int(vc->mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) == 0) {
+ use_cycle = false;
}
copy_v2_v2_int(last_mval, vc->mval);
}
- else {
- if (!XRAY_ACTIVE(vc->v3d)) {
- do_nearest = true;
- }
- }
+
+ const bool do_nearest = !(XRAY_ACTIVE(vc->v3d) || use_cycle);
/* matching logic from 'mixed_bones_object_selectbuffer' */
int hits = 0;
@@ -750,13 +733,39 @@ cache_end:
if (hits > 0) {
if (hits == 1) {
if (!(buffer[3] & BONESEL_NOSEL)) {
- best.hitresult = buffer[3];
- best.base = ED_armature_base_and_ebone_from_select_buffer(
- bases, bases_len, best.hitresult, &best.ebone);
+ result_bias.hitresult = buffer[3];
+ result_bias.base = ED_armature_base_and_ebone_from_select_buffer(
+ bases, bases_len, result_bias.hitresult, &result_bias.ebone);
}
}
else {
- int dep_min = 5;
+ int bias_max = INT_MIN;
+
+ /* Track cycle variables. */
+ struct {
+ union {
+ uint32_t cmp;
+ struct {
+#ifdef __BIG_ENDIAN__
+ uint16_t ob;
+ uint16_t bone;
+#else
+ uint16_t bone;
+ uint16_t ob;
+#endif
+ } index;
+ } active, test, best;
+ } cycle_order;
+
+ if (use_cycle) {
+ bArmature *arm = obedit_orig->data;
+ int ob_index = obedit_orig->runtime.select_id & 0xFFFF;
+ int bone_index = BLI_findindex(arm->edbo, ebone_active_orig);
+ cycle_order.active.index.ob = ob_index;
+ cycle_order.active.index.bone = bone_index;
+ cycle_order.best.cmp = 0xffffffff;
+ }
+
for (int i = 0; i < hits; i++) {
const uint hitresult = buffer[3 + (i * 4)];
if (!(hitresult & BONESEL_NOSEL)) {
@@ -767,69 +776,98 @@ cache_end:
/* If this fails, selection code is setting the selection ID's incorrectly. */
BLI_assert(base && ebone);
- int dep;
- /* clicks on bone points get advantage */
- if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
- /* but also the unselected one */
- if (findunsel) {
- if ((hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0) {
- dep = 1;
- }
- else if ((hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0) {
- dep = 1;
+ /* Prioritized selection. */
+ {
+ int bias;
+ /* clicks on bone points get advantage */
+ if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
+ /* but also the unselected one */
+ if (findunsel) {
+ if ((hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0) {
+ bias = 4;
+ }
+ else if ((hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0) {
+ bias = 4;
+ }
+ else {
+ bias = 3;
+ }
}
else {
- dep = 2;
+ bias = 4;
}
}
else {
- dep = 1;
- }
- }
- else {
- /* bone found */
- if (findunsel) {
- if ((ebone->flag & BONE_SELECTED) == 0) {
- dep = 3;
+ /* bone found */
+ if (findunsel) {
+ if ((ebone->flag & BONE_SELECTED) == 0) {
+ bias = 2;
+ }
+ else {
+ bias = 1;
+ }
}
else {
- dep = 4;
+ bias = 2;
}
}
- else {
- dep = 3;
+
+ if (bias > bias_max) {
+ bias_max = bias;
+
+ result_bias.hitresult = hitresult;
+ result_bias.base = base;
+ result_bias.ebone = ebone;
}
}
- if (ebone == ebone_next_act) {
- dep -= 1;
- }
+ /* Cycle selected items (objects & bones). */
+ if (use_cycle) {
+ bool found = false;
+ cycle_order.test.index.ob = hitresult & 0xFFFF;
+ cycle_order.test.index.bone = (hitresult & ~BONESEL_ANY) >> 16;
+ if (ebone == ebone_active_orig) {
+ BLI_assert(cycle_order.test.index.ob == cycle_order.active.index.ob);
+ BLI_assert(cycle_order.test.index.bone == cycle_order.active.index.bone);
+ }
+ cycle_order.test.cmp -= cycle_order.active.cmp;
- if (dep < dep_min) {
- dep_min = dep;
- best.hitresult = hitresult;
- best.base = base;
- best.ebone = ebone;
+ if (cycle_order.test.cmp < cycle_order.best.cmp && ebone != ebone_active_orig) {
+ cycle_order.best.cmp = cycle_order.test.cmp;
+ found = true;
+ }
+ else if (ELEM(result_cycle.ebone, NULL, ebone_active_orig)) {
+ /* Let the active bone become selected, but don't set the cycle order. */
+ found = true;
+ }
+
+ if (found) {
+ result_cycle.hitresult = hitresult;
+ result_cycle.base = base;
+ result_cycle.ebone = ebone;
+ }
}
}
}
}
- if (!(best.hitresult & BONESEL_NOSEL)) {
- *r_base = best.base;
+ result = (use_cycle && result_cycle.ebone) ? &result_cycle : &result_bias;
+
+ if (!(result->hitresult & BONESEL_NOSEL)) {
+ *r_base = result->base;
*r_selmask = 0;
- if (best.hitresult & BONESEL_ROOT) {
+ if (result->hitresult & BONESEL_ROOT) {
*r_selmask |= BONE_ROOTSEL;
}
- if (best.hitresult & BONESEL_TIP) {
+ if (result->hitresult & BONESEL_TIP) {
*r_selmask |= BONE_TIPSEL;
}
- if (best.hitresult & BONESEL_BONE) {
+ if (result->hitresult & BONESEL_BONE) {
*r_selmask |= BONE_SELECTED;
}
MEM_freeN(bases);
- return best.ebone;
+ return result->ebone;
}
}
*r_selmask = 0;