diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/editors/armature/armature_select.c | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/editors/armature/armature_select.c')
-rw-r--r-- | source/blender/editors/armature/armature_select.c | 3046 |
1 files changed, 1529 insertions, 1517 deletions
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index 4aab80bcbdd..0c493672d9e 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -60,695 +60,713 @@ /* **************** PoseMode & EditMode Selection Buffer Queries *************************** */ -Base *ED_armature_base_and_ebone_from_select_buffer( - Base **bases, uint bases_len, int hit, EditBone **r_ebone) +Base *ED_armature_base_and_ebone_from_select_buffer(Base **bases, + uint bases_len, + int hit, + EditBone **r_ebone) { - const uint hit_object = hit & 0xFFFF; - Base *base = NULL; - EditBone *ebone = NULL; - /* TODO(campbell): optimize, eg: sort & binary search. */ - for (uint base_index = 0; base_index < bases_len; base_index++) { - if (bases[base_index]->object->select_id == hit_object) { - base = bases[base_index]; - break; - } - } - if (base != NULL) { - const uint hit_bone = (hit & ~BONESEL_ANY) >> 16; - bArmature *arm = base->object->data; - ebone = BLI_findlink(arm->edbo, hit_bone); - } - *r_ebone = ebone; - return base; + const uint hit_object = hit & 0xFFFF; + Base *base = NULL; + EditBone *ebone = NULL; + /* TODO(campbell): optimize, eg: sort & binary search. */ + for (uint base_index = 0; base_index < bases_len; base_index++) { + if (bases[base_index]->object->select_id == hit_object) { + base = bases[base_index]; + break; + } + } + if (base != NULL) { + const uint hit_bone = (hit & ~BONESEL_ANY) >> 16; + bArmature *arm = base->object->data; + ebone = BLI_findlink(arm->edbo, hit_bone); + } + *r_ebone = ebone; + return base; } -Object *ED_armature_object_and_ebone_from_select_buffer( - Object **objects, uint objects_len, int hit, EditBone **r_ebone) +Object *ED_armature_object_and_ebone_from_select_buffer(Object **objects, + uint objects_len, + int hit, + EditBone **r_ebone) { - const uint hit_object = hit & 0xFFFF; - Object *ob = NULL; - EditBone *ebone = NULL; - /* TODO(campbell): optimize, eg: sort & binary search. */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - if (objects[ob_index]->select_id == hit_object) { - ob = objects[ob_index]; - break; - } - } - if (ob != NULL) { - const uint hit_bone = (hit & ~BONESEL_ANY) >> 16; - bArmature *arm = ob->data; - ebone = BLI_findlink(arm->edbo, hit_bone); - } - *r_ebone = ebone; - return ob; + const uint hit_object = hit & 0xFFFF; + Object *ob = NULL; + EditBone *ebone = NULL; + /* TODO(campbell): optimize, eg: sort & binary search. */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + if (objects[ob_index]->select_id == hit_object) { + ob = objects[ob_index]; + break; + } + } + if (ob != NULL) { + const uint hit_bone = (hit & ~BONESEL_ANY) >> 16; + bArmature *arm = ob->data; + ebone = BLI_findlink(arm->edbo, hit_bone); + } + *r_ebone = ebone; + return ob; } -Base *ED_armature_base_and_bone_from_select_buffer( - Base **bases, uint bases_len, int hit, Bone **r_bone) +Base *ED_armature_base_and_bone_from_select_buffer(Base **bases, + uint bases_len, + int hit, + Bone **r_bone) { - const uint hit_object = hit & 0xFFFF; - Base *base = NULL; - Bone *bone = NULL; - /* TODO(campbell): optimize, eg: sort & binary search. */ - for (uint base_index = 0; base_index < bases_len; base_index++) { - if (bases[base_index]->object->select_id == hit_object) { - base = bases[base_index]; - break; - } - } - if (base != NULL) { - if (base->object->pose != NULL) { - const uint hit_bone = (hit & ~BONESEL_ANY) >> 16; - bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone); - bone = pchan ? pchan->bone : NULL; - } - } - *r_bone = bone; - return base; + const uint hit_object = hit & 0xFFFF; + Base *base = NULL; + Bone *bone = NULL; + /* TODO(campbell): optimize, eg: sort & binary search. */ + for (uint base_index = 0; base_index < bases_len; base_index++) { + if (bases[base_index]->object->select_id == hit_object) { + base = bases[base_index]; + break; + } + } + if (base != NULL) { + if (base->object->pose != NULL) { + const uint hit_bone = (hit & ~BONESEL_ANY) >> 16; + bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone); + bone = pchan ? pchan->bone : NULL; + } + } + *r_bone = bone; + return base; } /* See if there are any selected bones in this buffer */ /* only bones from base are checked on */ -void *get_bone_from_selectbuffer( - Base **bases, uint bases_len, bool is_editmode, const unsigned int *buffer, short hits, - bool findunsel, bool do_nearest, Base **r_base) +void *get_bone_from_selectbuffer(Base **bases, + uint bases_len, + bool is_editmode, + const unsigned int *buffer, + short hits, + bool findunsel, + bool do_nearest, + Base **r_base) { - Bone *bone; - EditBone *ebone; - void *firstunSel = NULL, *firstSel = NULL, *data; - Base *firstunSel_base = NULL, *firstSel_base = NULL; - unsigned int hitresult; - short i; - bool takeNext = false; - int minsel = 0xffffffff, minunsel = 0xffffffff; - - for (i = 0; i < hits; i++) { - hitresult = buffer[3 + (i * 4)]; - - if (!(hitresult & BONESEL_NOSEL)) { - if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */ - Base *base = NULL; - bool sel; - - hitresult &= ~(BONESEL_ANY); - /* Determine what the current bone is */ - if (is_editmode == false) { - base = ED_armature_base_and_bone_from_select_buffer(bases, bases_len, hitresult, &bone); - if (bone != NULL) { - if (findunsel) - sel = (bone->flag & BONE_SELECTED); - else - sel = !(bone->flag & BONE_SELECTED); - - data = bone; - } - else { - data = NULL; - sel = 0; - } - } - else { - base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone); - if (findunsel) - sel = (ebone->flag & BONE_SELECTED); - else - sel = !(ebone->flag & BONE_SELECTED); - - data = ebone; - } - - if (data) { - if (sel) { - if (do_nearest) { - if (minsel > buffer[4 * i + 1]) { - firstSel = data; - firstSel_base = base; - minsel = buffer[4 * i + 1]; - } - } - else { - if (!firstSel) { - firstSel = data; - firstSel_base = base; - } - takeNext = 1; - } - } - else { - if (do_nearest) { - if (minunsel > buffer[4 * i + 1]) { - firstunSel = data; - firstunSel_base = base; - minunsel = buffer[4 * i + 1]; - } - } - else { - if (!firstunSel) { - firstunSel = data; - firstunSel_base = base; - } - if (takeNext) { - *r_base = base; - return data; - } - } - } - } - } - } - } - - if (firstunSel) { - *r_base = firstunSel_base; - return firstunSel; - } - else { - *r_base = firstSel_base; - return firstSel; - } + Bone *bone; + EditBone *ebone; + void *firstunSel = NULL, *firstSel = NULL, *data; + Base *firstunSel_base = NULL, *firstSel_base = NULL; + unsigned int hitresult; + short i; + bool takeNext = false; + int minsel = 0xffffffff, minunsel = 0xffffffff; + + for (i = 0; i < hits; i++) { + hitresult = buffer[3 + (i * 4)]; + + if (!(hitresult & BONESEL_NOSEL)) { + if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */ + Base *base = NULL; + bool sel; + + hitresult &= ~(BONESEL_ANY); + /* Determine what the current bone is */ + if (is_editmode == false) { + base = ED_armature_base_and_bone_from_select_buffer(bases, bases_len, hitresult, &bone); + if (bone != NULL) { + if (findunsel) + sel = (bone->flag & BONE_SELECTED); + else + sel = !(bone->flag & BONE_SELECTED); + + data = bone; + } + else { + data = NULL; + sel = 0; + } + } + else { + base = ED_armature_base_and_ebone_from_select_buffer( + bases, bases_len, hitresult, &ebone); + if (findunsel) + sel = (ebone->flag & BONE_SELECTED); + else + sel = !(ebone->flag & BONE_SELECTED); + + data = ebone; + } + + if (data) { + if (sel) { + if (do_nearest) { + if (minsel > buffer[4 * i + 1]) { + firstSel = data; + firstSel_base = base; + minsel = buffer[4 * i + 1]; + } + } + else { + if (!firstSel) { + firstSel = data; + firstSel_base = base; + } + takeNext = 1; + } + } + else { + if (do_nearest) { + if (minunsel > buffer[4 * i + 1]) { + firstunSel = data; + firstunSel_base = base; + minunsel = buffer[4 * i + 1]; + } + } + else { + if (!firstunSel) { + firstunSel = data; + firstunSel_base = base; + } + if (takeNext) { + *r_base = base; + return data; + } + } + } + } + } + } + } + + if (firstunSel) { + *r_base = firstunSel_base; + return firstunSel; + } + else { + *r_base = firstSel_base; + return firstSel; + } } /* used by posemode as well editmode */ /* only checks scene->basact! */ /* x and y are mouse coords (area space) */ -void *get_nearest_bone( - bContext *C, const int xy[2], bool findunsel, - Base **r_base) +void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel, Base **r_base) { - ViewContext vc; - rcti rect; - unsigned int buffer[MAXPICKBUF]; - short hits; - - ED_view3d_viewcontext_init(C, &vc); - - // rect.xmin = ... mouseco! - rect.xmin = rect.xmax = xy[0]; - rect.ymin = rect.ymax = xy[1]; - - hits = view3d_opengl_select( - &vc, buffer, MAXPICKBUF, &rect, - VIEW3D_SELECT_PICK_NEAREST, VIEW3D_SELECT_FILTER_NOP); - - *r_base = NULL; - - if (hits > 0) { - uint bases_len = 0; - Base **bases; - - if (vc.obedit != NULL) { - bases = BKE_view_layer_array_from_bases_in_mode( - vc.view_layer, vc.v3d, &bases_len, { - .object_mode = OB_MODE_EDIT, - }); - } - else { - bases = BKE_object_pose_base_array_get(vc.view_layer, vc.v3d, &bases_len); - } - - void *bone = get_bone_from_selectbuffer( - bases, bases_len, vc.obedit != NULL, buffer, hits, findunsel, true, r_base); - - MEM_freeN(bases); - return bone; - } - return NULL; + ViewContext vc; + rcti rect; + unsigned int buffer[MAXPICKBUF]; + short hits; + + ED_view3d_viewcontext_init(C, &vc); + + // rect.xmin = ... mouseco! + rect.xmin = rect.xmax = xy[0]; + rect.ymin = rect.ymax = xy[1]; + + hits = view3d_opengl_select( + &vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST, VIEW3D_SELECT_FILTER_NOP); + + *r_base = NULL; + + if (hits > 0) { + uint bases_len = 0; + Base **bases; + + if (vc.obedit != NULL) { + bases = BKE_view_layer_array_from_bases_in_mode(vc.view_layer, + vc.v3d, + &bases_len, + { + .object_mode = OB_MODE_EDIT, + }); + } + else { + bases = BKE_object_pose_base_array_get(vc.view_layer, vc.v3d, &bases_len); + } + + void *bone = get_bone_from_selectbuffer( + bases, bases_len, vc.obedit != NULL, buffer, hits, findunsel, true, r_base); + + MEM_freeN(bases); + return bone; + } + return NULL; } /* **************** EditMode stuff ********************** */ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - bArmature *arm; - EditBone *bone, *curBone, *next; - const bool sel = !RNA_boolean_get(op->ptr, "deselect"); - - view3d_operator_needs_opengl(C); - - Base *base = NULL; - bone = get_nearest_bone(C, event->mval, true, &base); - - if (!bone) - return OPERATOR_CANCELLED; - - arm = base->object->data; - - /* Select parents */ - for (curBone = bone; curBone; curBone = next) { - if ((curBone->flag & BONE_UNSELECTABLE) == 0) { - if (sel) { - curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - else { - curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - } - - if (curBone->flag & BONE_CONNECTED) - next = curBone->parent; - else - next = NULL; - } - - /* Select children */ - while (bone) { - for (curBone = arm->edbo->first; curBone; curBone = next) { - next = curBone->next; - if ((curBone->parent == bone) && (curBone->flag & BONE_UNSELECTABLE) == 0) { - if (curBone->flag & BONE_CONNECTED) { - if (sel) { - curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - else { - curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - bone = curBone; - break; - } - else { - bone = NULL; - break; - } - } - } - if (!curBone) - bone = NULL; - } - - ED_armature_edit_sync_selection(arm->edbo); - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object); - - return OPERATOR_FINISHED; + bArmature *arm; + EditBone *bone, *curBone, *next; + const bool sel = !RNA_boolean_get(op->ptr, "deselect"); + + view3d_operator_needs_opengl(C); + + Base *base = NULL; + bone = get_nearest_bone(C, event->mval, true, &base); + + if (!bone) + return OPERATOR_CANCELLED; + + arm = base->object->data; + + /* Select parents */ + for (curBone = bone; curBone; curBone = next) { + if ((curBone->flag & BONE_UNSELECTABLE) == 0) { + if (sel) { + curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + else { + curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + } + + if (curBone->flag & BONE_CONNECTED) + next = curBone->parent; + else + next = NULL; + } + + /* Select children */ + while (bone) { + for (curBone = arm->edbo->first; curBone; curBone = next) { + next = curBone->next; + if ((curBone->parent == bone) && (curBone->flag & BONE_UNSELECTABLE) == 0) { + if (curBone->flag & BONE_CONNECTED) { + if (sel) { + curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + else { + curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + bone = curBone; + break; + } + else { + bone = NULL; + break; + } + } + } + if (!curBone) + bone = NULL; + } + + ED_armature_edit_sync_selection(arm->edbo); + + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object); + + return OPERATOR_FINISHED; } static bool armature_select_linked_poll(bContext *C) { - return (ED_operator_view3d_active(C) && ED_operator_editarmature(C)); + return (ED_operator_view3d_active(C) && ED_operator_editarmature(C)); } void ARMATURE_OT_select_linked(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Connected"; - ot->idname = "ARMATURE_OT_select_linked"; - ot->description = "Select bones related to selected ones by parent/child relationships"; + /* identifiers */ + ot->name = "Select Connected"; + ot->idname = "ARMATURE_OT_select_linked"; + ot->description = "Select bones related to selected ones by parent/child relationships"; - /* api callbacks */ - /* leave 'exec' unset */ - ot->invoke = armature_select_linked_invoke; - ot->poll = armature_select_linked_poll; + /* api callbacks */ + /* leave 'exec' unset */ + ot->invoke = armature_select_linked_invoke; + ot->poll = armature_select_linked_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", ""); + RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", ""); } /* utility function for get_nearest_editbonepoint */ static int selectbuffer_ret_hits_12(unsigned int *UNUSED(buffer), const int hits12) { - return hits12; + return hits12; } static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits12, const int hits5) { - const int offs = 4 * hits12; - memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int)); - return hits5; + const int offs = 4 * hits12; + memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int)); + return hits5; } /* does bones and points */ /* note that BONE ROOT only gets drawn for root bones (or without IK) */ static EditBone *get_nearest_editbonepoint( - ViewContext *vc, - bool findunsel, bool use_cycle, - Base **r_base, int *r_selmask) + ViewContext *vc, bool findunsel, bool use_cycle, Base **r_base, int *r_selmask) { - uint buffer[MAXPICKBUF]; - struct { - uint hitresult; - Base *base; - EditBone *ebone; - } best = { - .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; - } - } - - 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; - } - } - copy_v2_v2_int(last_mval, vc->mval); - } - else { - if (!XRAY_ACTIVE(vc->v3d)) { - do_nearest = true; - } - } - - /* matching logic from 'mixed_bones_object_selectbuffer' */ - int hits = 0; - - /* we _must_ end cache before return, use 'goto cache_end' */ - 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; - - rcti rect; - BLI_rcti_init_pt_radius(&rect, vc->mval, 12); - const int hits12 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter); - if (hits12 == 1) { - hits = selectbuffer_ret_hits_12(buffer, hits12); - goto cache_end; - } - else if (hits12 > 0) { - int offs; - - offs = 4 * hits12; - BLI_rcti_init_pt_radius(&rect, vc->mval, 5); - const int hits5 = view3d_opengl_select( - vc, buffer + offs, MAXPICKBUF - offs, &rect, - select_mode, select_filter); - - if (hits5 == 1) { - hits = selectbuffer_ret_hits_5(buffer, hits12, hits5); - goto cache_end; - } - - if (hits5 > 0) { hits = selectbuffer_ret_hits_5(buffer, hits12, hits5); goto cache_end; } - else { hits = selectbuffer_ret_hits_12(buffer, hits12); goto cache_end; } - } - } + uint buffer[MAXPICKBUF]; + struct { + uint hitresult; + Base *base; + EditBone *ebone; + } best = { + .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; + } + } + + 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; + } + } + copy_v2_v2_int(last_mval, vc->mval); + } + else { + if (!XRAY_ACTIVE(vc->v3d)) { + do_nearest = true; + } + } + + /* matching logic from 'mixed_bones_object_selectbuffer' */ + int hits = 0; + + /* we _must_ end cache before return, use 'goto cache_end' */ + 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; + + rcti rect; + BLI_rcti_init_pt_radius(&rect, vc->mval, 12); + const int hits12 = view3d_opengl_select( + vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter); + if (hits12 == 1) { + hits = selectbuffer_ret_hits_12(buffer, hits12); + goto cache_end; + } + else if (hits12 > 0) { + int offs; + + offs = 4 * hits12; + BLI_rcti_init_pt_radius(&rect, vc->mval, 5); + const int hits5 = view3d_opengl_select( + vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode, select_filter); + + if (hits5 == 1) { + hits = selectbuffer_ret_hits_5(buffer, hits12, hits5); + goto cache_end; + } + + if (hits5 > 0) { + hits = selectbuffer_ret_hits_5(buffer, hits12, hits5); + goto cache_end; + } + else { + hits = selectbuffer_ret_hits_12(buffer, hits12); + goto cache_end; + } + } + } cache_end: - view3d_opengl_select_cache_end(); - - uint bases_len; - Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(vc->view_layer, vc->v3d, &bases_len); - - /* See if there are any selected bones in this group */ - 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); - } - } - else { - int dep_min = 5; - for (int i = 0; i < hits; i++) { - const uint hitresult = buffer[3 + (i * 4)]; - if (!(hitresult & BONESEL_NOSEL)) { - Base *base = NULL; - EditBone *ebone; - base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone); - /* 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; - else - dep = 2; - } - else { - dep = 1; - } - } - else { - /* bone found */ - if (findunsel) { - if ((ebone->flag & BONE_SELECTED) == 0) - dep = 3; - else - dep = 4; - } - else { - dep = 3; - } - } - - if (ebone == ebone_next_act) { - dep -= 1; - } - - if (dep < dep_min) { - dep_min = dep; - best.hitresult = hitresult; - best.base = base; - best.ebone = ebone; - } - } - } - } - - if (!(best.hitresult & BONESEL_NOSEL)) { - *r_base = best.base; - - *r_selmask = 0; - if (best.hitresult & BONESEL_ROOT) { - *r_selmask |= BONE_ROOTSEL; - } - if (best.hitresult & BONESEL_TIP) { - *r_selmask |= BONE_TIPSEL; - } - if (best.hitresult & BONESEL_BONE) { - *r_selmask |= BONE_SELECTED; - } - MEM_freeN(bases); - return best.ebone; - } - } - *r_selmask = 0; - *r_base = NULL; - MEM_freeN(bases); - return NULL; + view3d_opengl_select_cache_end(); + + uint bases_len; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( + vc->view_layer, vc->v3d, &bases_len); + + /* See if there are any selected bones in this group */ + 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); + } + } + else { + int dep_min = 5; + for (int i = 0; i < hits; i++) { + const uint hitresult = buffer[3 + (i * 4)]; + if (!(hitresult & BONESEL_NOSEL)) { + Base *base = NULL; + EditBone *ebone; + base = ED_armature_base_and_ebone_from_select_buffer( + bases, bases_len, hitresult, &ebone); + /* 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; + else + dep = 2; + } + else { + dep = 1; + } + } + else { + /* bone found */ + if (findunsel) { + if ((ebone->flag & BONE_SELECTED) == 0) + dep = 3; + else + dep = 4; + } + else { + dep = 3; + } + } + + if (ebone == ebone_next_act) { + dep -= 1; + } + + if (dep < dep_min) { + dep_min = dep; + best.hitresult = hitresult; + best.base = base; + best.ebone = ebone; + } + } + } + } + + if (!(best.hitresult & BONESEL_NOSEL)) { + *r_base = best.base; + + *r_selmask = 0; + if (best.hitresult & BONESEL_ROOT) { + *r_selmask |= BONE_ROOTSEL; + } + if (best.hitresult & BONESEL_TIP) { + *r_selmask |= BONE_TIPSEL; + } + if (best.hitresult & BONESEL_BONE) { + *r_selmask |= BONE_SELECTED; + } + MEM_freeN(bases); + return best.ebone; + } + } + *r_selmask = 0; + *r_base = NULL; + MEM_freeN(bases); + return NULL; } bool ED_armature_edit_deselect_all(Object *obedit) { - bArmature *arm = obedit->data; - bool changed = false; - for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) { - ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - changed = true; - } - } - return changed; + bArmature *arm = obedit->data; + bool changed = false; + for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) { + ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + changed = true; + } + } + return changed; } bool ED_armature_edit_deselect_all_visible(Object *obedit) { - bArmature *arm = obedit->data; - bool changed = false; - for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { - /* first and foremost, bone must be visible and selected */ - if (EBONE_VISIBLE(arm, ebone)) { - if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) { - ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - changed = true; - } - } - } - - if (changed) { - ED_armature_edit_sync_selection(arm->edbo); - } - return changed; + bArmature *arm = obedit->data; + bool changed = false; + for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { + /* first and foremost, bone must be visible and selected */ + if (EBONE_VISIBLE(arm, ebone)) { + if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) { + ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + changed = true; + } + } + } + + if (changed) { + ED_armature_edit_sync_selection(arm->edbo); + } + return changed; } - bool ED_armature_edit_deselect_all_multi_ex(struct Base **bases, uint bases_len) { - bool changed_multi = false; - for (uint base_index = 0; base_index < bases_len; base_index++) { - Object *obedit = bases[base_index]->object; - changed_multi |= ED_armature_edit_deselect_all(obedit); - } - return changed_multi; + bool changed_multi = false; + for (uint base_index = 0; base_index < bases_len; base_index++) { + Object *obedit = bases[base_index]->object; + changed_multi |= ED_armature_edit_deselect_all(obedit); + } + return changed_multi; } bool ED_armature_edit_deselect_all_visible_multi_ex(struct Base **bases, uint bases_len) { - bool changed_multi = false; - for (uint base_index = 0; base_index < bases_len; base_index++) { - Object *obedit = bases[base_index]->object; - changed_multi |= ED_armature_edit_deselect_all_visible(obedit); - } - return changed_multi; + bool changed_multi = false; + for (uint base_index = 0; base_index < bases_len; base_index++) { + Object *obedit = bases[base_index]->object; + changed_multi |= ED_armature_edit_deselect_all_visible(obedit); + } + return changed_multi; } bool ED_armature_edit_deselect_all_visible_multi(bContext *C) { - ViewContext vc; - ED_view3d_viewcontext_init(C, &vc); - uint bases_len = 0; - Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(vc.view_layer, vc.v3d, &bases_len); - bool changed_multi = ED_armature_edit_deselect_all_multi_ex(bases, bases_len); - MEM_freeN(bases); - return changed_multi; + ViewContext vc; + ED_view3d_viewcontext_init(C, &vc); + uint bases_len = 0; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( + vc.view_layer, vc.v3d, &bases_len); + bool changed_multi = ED_armature_edit_deselect_all_multi_ex(bases, bases_len); + MEM_freeN(bases); + return changed_multi; } /* accounts for connected parents */ static int ebone_select_flag(EditBone *ebone) { - if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { - return ((ebone->parent->flag & BONE_TIPSEL) ? BONE_ROOTSEL : 0) | (ebone->flag & (BONE_SELECTED | BONE_TIPSEL)); - } - else { - return ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL); - } + if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { + return ((ebone->parent->flag & BONE_TIPSEL) ? BONE_ROOTSEL : 0) | + (ebone->flag & (BONE_SELECTED | BONE_TIPSEL)); + } + else { + return ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL); + } } /* context: editmode armature in view3d */ -bool ED_armature_edit_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) +bool ED_armature_edit_select_pick( + bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) { - ViewContext vc; - EditBone *nearBone = NULL; - int selmask; - Base *basact = NULL; - - ED_view3d_viewcontext_init(C, &vc); - vc.mval[0] = mval[0]; - vc.mval[1] = mval[1]; - - nearBone = get_nearest_editbonepoint(&vc, true, true, &basact, &selmask); - if (nearBone) { - ED_view3d_viewcontext_init_object(&vc, basact->object); - bArmature *arm = vc.obedit->data; - - if (!EBONE_SELECTABLE(arm, nearBone)) { - return false; - } - - if (!extend && !deselect && !toggle) { - uint bases_len = 0; - Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(vc.view_layer, vc.v3d, &bases_len); - ED_armature_edit_deselect_all_multi_ex(bases, bases_len); - MEM_freeN(bases); - } - - /* by definition the non-root connected bones have no root point drawn, - * so a root selection needs to be delivered to the parent tip */ - - if (selmask & BONE_SELECTED) { - if (nearBone->parent && (nearBone->flag & BONE_CONNECTED)) { - /* click in a chain */ - if (extend) { - /* select this bone */ - nearBone->flag |= BONE_TIPSEL; - nearBone->parent->flag |= BONE_TIPSEL; - } - else if (deselect) { - /* deselect this bone */ - nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED); - /* only deselect parent tip if it is not selected */ - if (!(nearBone->parent->flag & BONE_SELECTED)) - nearBone->parent->flag &= ~BONE_TIPSEL; - } - else if (toggle) { - /* hold shift inverts this bone's selection */ - if (nearBone->flag & BONE_SELECTED) { - /* deselect this bone */ - nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED); - /* only deselect parent tip if it is not selected */ - if (!(nearBone->parent->flag & BONE_SELECTED)) - nearBone->parent->flag &= ~BONE_TIPSEL; - } - else { - /* select this bone */ - nearBone->flag |= BONE_TIPSEL; - nearBone->parent->flag |= BONE_TIPSEL; - } - } - else { - /* select this bone */ - nearBone->flag |= BONE_TIPSEL; - nearBone->parent->flag |= BONE_TIPSEL; - } - } - else { - if (extend) { - nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL); - } - else if (deselect) { - nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL); - } - else if (toggle) { - /* hold shift inverts this bone's selection */ - if (nearBone->flag & BONE_SELECTED) - nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL); - else - nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL); - } - else - nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL); - } - } - else { - if (extend) - nearBone->flag |= selmask; - else if (deselect) - nearBone->flag &= ~selmask; - else if (toggle && (nearBone->flag & selmask)) - nearBone->flag &= ~selmask; - else - nearBone->flag |= selmask; - } - - ED_armature_edit_sync_selection(arm->edbo); - - /* then now check for active status */ - if (ebone_select_flag(nearBone)) { - arm->act_edbone = nearBone; - } - - if (vc.view_layer->basact != basact) { - ED_object_base_activate(C, basact); - } - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object); - return true; - } - - return false; + ViewContext vc; + EditBone *nearBone = NULL; + int selmask; + Base *basact = NULL; + + ED_view3d_viewcontext_init(C, &vc); + vc.mval[0] = mval[0]; + vc.mval[1] = mval[1]; + + nearBone = get_nearest_editbonepoint(&vc, true, true, &basact, &selmask); + if (nearBone) { + ED_view3d_viewcontext_init_object(&vc, basact->object); + bArmature *arm = vc.obedit->data; + + if (!EBONE_SELECTABLE(arm, nearBone)) { + return false; + } + + if (!extend && !deselect && !toggle) { + uint bases_len = 0; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( + vc.view_layer, vc.v3d, &bases_len); + ED_armature_edit_deselect_all_multi_ex(bases, bases_len); + MEM_freeN(bases); + } + + /* by definition the non-root connected bones have no root point drawn, + * so a root selection needs to be delivered to the parent tip */ + + if (selmask & BONE_SELECTED) { + if (nearBone->parent && (nearBone->flag & BONE_CONNECTED)) { + /* click in a chain */ + if (extend) { + /* select this bone */ + nearBone->flag |= BONE_TIPSEL; + nearBone->parent->flag |= BONE_TIPSEL; + } + else if (deselect) { + /* deselect this bone */ + nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED); + /* only deselect parent tip if it is not selected */ + if (!(nearBone->parent->flag & BONE_SELECTED)) + nearBone->parent->flag &= ~BONE_TIPSEL; + } + else if (toggle) { + /* hold shift inverts this bone's selection */ + if (nearBone->flag & BONE_SELECTED) { + /* deselect this bone */ + nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED); + /* only deselect parent tip if it is not selected */ + if (!(nearBone->parent->flag & BONE_SELECTED)) + nearBone->parent->flag &= ~BONE_TIPSEL; + } + else { + /* select this bone */ + nearBone->flag |= BONE_TIPSEL; + nearBone->parent->flag |= BONE_TIPSEL; + } + } + else { + /* select this bone */ + nearBone->flag |= BONE_TIPSEL; + nearBone->parent->flag |= BONE_TIPSEL; + } + } + else { + if (extend) { + nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL); + } + else if (deselect) { + nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL); + } + else if (toggle) { + /* hold shift inverts this bone's selection */ + if (nearBone->flag & BONE_SELECTED) + nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL); + else + nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL); + } + else + nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL); + } + } + else { + if (extend) + nearBone->flag |= selmask; + else if (deselect) + nearBone->flag &= ~selmask; + else if (toggle && (nearBone->flag & selmask)) + nearBone->flag &= ~selmask; + else + nearBone->flag |= selmask; + } + + ED_armature_edit_sync_selection(arm->edbo); + + /* then now check for active status */ + if (ebone_select_flag(nearBone)) { + arm->act_edbone = nearBone; + } + + if (vc.view_layer->basact != basact) { + ED_object_base_activate(C, basact); + } + + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object); + return true; + } + + return false; } /* -------------------------------------------------------------------- */ @@ -757,69 +775,73 @@ bool ED_armature_edit_select_pick(bContext *C, const int mval[2], bool extend, b * Implements #ED_armature_edit_select_op_from_tagged * \{ */ -static bool armature_edit_select_op_apply( - bArmature *arm, EditBone *ebone, const eSelectOp sel_op, int is_ignore_flag, int is_inside_flag) +static bool armature_edit_select_op_apply(bArmature *arm, + EditBone *ebone, + const eSelectOp sel_op, + int is_ignore_flag, + int is_inside_flag) { - BLI_assert(!(is_ignore_flag & ~(BONESEL_ROOT | BONESEL_TIP))); - BLI_assert(!(is_inside_flag & ~(BONESEL_ROOT | BONESEL_TIP | BONESEL_BONE))); - BLI_assert(EBONE_VISIBLE(arm, ebone)); - bool changed = false; - bool is_point_done = false; - int points_proj_tot = 0; - BLI_assert(ebone->flag == ebone->temp.i); - const int ebone_flag_prev = ebone->flag; - - if ((is_ignore_flag & BONE_ROOTSEL) == 0) { - points_proj_tot++; - const bool is_select = ebone->flag & BONE_ROOTSEL; - const bool is_inside = is_inside_flag & BONESEL_ROOT; - const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); - if (sel_op_result != -1) { - if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) { - SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_ROOTSEL); - } - } - is_point_done |= is_inside; - } - - if ((is_ignore_flag & BONE_TIPSEL) == 0) { - points_proj_tot++; - const bool is_select = ebone->flag & BONE_TIPSEL; - const bool is_inside = is_inside_flag & BONESEL_TIP; - const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); - if (sel_op_result != -1) { - if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) { - SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_TIPSEL); - } - } - is_point_done |= is_inside; - } - - /* if one of points selected, we skip the bone itself */ - if ((is_point_done == false) && (points_proj_tot == 2)) { - const bool is_select = ebone->flag & BONE_SELECTED; - { - const bool is_inside = is_inside_flag & BONESEL_BONE; - const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); - if (sel_op_result != -1) { - if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) { - SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL); - } - } - } - - changed = true; - } - changed |= is_point_done; - - if (ebone_flag_prev != ebone->flag) { - ebone->temp.i = ebone->flag; - ebone->flag = ebone_flag_prev; - ebone->flag = ebone_flag_prev | BONE_DONE; - changed = true; - } - - return changed; + BLI_assert(!(is_ignore_flag & ~(BONESEL_ROOT | BONESEL_TIP))); + BLI_assert(!(is_inside_flag & ~(BONESEL_ROOT | BONESEL_TIP | BONESEL_BONE))); + BLI_assert(EBONE_VISIBLE(arm, ebone)); + bool changed = false; + bool is_point_done = false; + int points_proj_tot = 0; + BLI_assert(ebone->flag == ebone->temp.i); + const int ebone_flag_prev = ebone->flag; + + if ((is_ignore_flag & BONE_ROOTSEL) == 0) { + points_proj_tot++; + const bool is_select = ebone->flag & BONE_ROOTSEL; + const bool is_inside = is_inside_flag & BONESEL_ROOT; + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) { + SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_ROOTSEL); + } + } + is_point_done |= is_inside; + } + + if ((is_ignore_flag & BONE_TIPSEL) == 0) { + points_proj_tot++; + const bool is_select = ebone->flag & BONE_TIPSEL; + const bool is_inside = is_inside_flag & BONESEL_TIP; + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) { + SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_TIPSEL); + } + } + is_point_done |= is_inside; + } + + /* if one of points selected, we skip the bone itself */ + if ((is_point_done == false) && (points_proj_tot == 2)) { + const bool is_select = ebone->flag & BONE_SELECTED; + { + const bool is_inside = is_inside_flag & BONESEL_BONE; + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) { + SET_FLAG_FROM_TEST( + ebone->flag, sel_op_result, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL); + } + } + } + + changed = true; + } + changed |= is_point_done; + + if (ebone_flag_prev != ebone->flag) { + ebone->temp.i = ebone->flag; + ebone->flag = ebone_flag_prev; + ebone->flag = ebone_flag_prev | BONE_DONE; + changed = true; + } + + return changed; } /** @@ -836,101 +858,97 @@ static bool armature_edit_select_op_apply( */ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op) { - bool changed = false; - - /* Initialize flags. */ - { - for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { - - /* Flush the parent flag to this bone - * so we don't need to check the parent when adjusting the selection. */ - if ((ebone->flag & BONE_CONNECTED) && ebone->parent) { - if (ebone->parent->flag & BONE_TIPSEL) { - ebone->flag |= BONE_ROOTSEL; - } - else { - ebone->flag &= ~BONE_ROOTSEL; - } - - /* Flush the 'temp.i' flag. */ - if (ebone->parent->temp.i & BONESEL_TIP) { - ebone->temp.i |= BONESEL_ROOT; - } - } - ebone->flag &= ~BONE_DONE; - } - } - - /* Apply selection from bone selection flags. */ - for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (ebone->temp.i != 0) { - int is_ignore_flag = ((ebone->temp.i << 16) & (BONESEL_ROOT | BONESEL_TIP)); - int is_inside_flag = (ebone->temp.i & (BONESEL_ROOT | BONESEL_TIP | BONESEL_BONE)); - - /* Use as previous bone flag from now on. */ - ebone->temp.i = ebone->flag; - - /* When there is a partial selection without both endpoints, only select an endpoint. */ - if ((is_inside_flag & BONESEL_BONE) && - (is_inside_flag & (BONESEL_ROOT | BONESEL_TIP)) && - ((is_inside_flag & (BONESEL_ROOT | BONESEL_TIP)) != (BONESEL_ROOT | BONESEL_TIP))) - { - is_inside_flag &= ~BONESEL_BONE; - } - - changed |= armature_edit_select_op_apply(arm, ebone, sel_op, is_ignore_flag, is_inside_flag); - } - } - - if (changed) { - /* Cleanup flags. */ - for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (ebone->flag & BONE_DONE) { - SWAP(int, ebone->temp.i, ebone->flag); - ebone->flag |= BONE_DONE; - if ((ebone->flag & BONE_CONNECTED) && ebone->parent) { - if ((ebone->parent->flag & BONE_DONE) == 0) { - /* Checked below. */ - ebone->parent->temp.i = ebone->parent->flag; - } - } - } - } - - for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (ebone->flag & BONE_DONE) { - if ((ebone->flag & BONE_CONNECTED) && ebone->parent) { - bool is_parent_tip_changed = (ebone->parent->flag & BONE_TIPSEL) != (ebone->parent->temp.i & BONE_TIPSEL); - if ((ebone->temp.i & BONE_ROOTSEL) == 0) { - if ((ebone->flag & BONE_ROOTSEL) != 0) { - ebone->parent->flag |= BONE_TIPSEL; - } - } - else { - if ((ebone->flag & BONE_ROOTSEL) == 0) { - ebone->parent->flag &= ~BONE_TIPSEL; - - } - } - - - if (is_parent_tip_changed == false) { - /* Keep tip selected if the parent remains selected. */ - if (ebone->parent->flag & BONE_SELECTED) { - ebone->parent->flag |= BONE_TIPSEL; - } - } - - } - ebone->flag &= ~BONE_DONE; - } - } - - ED_armature_edit_sync_selection(arm->edbo); - ED_armature_edit_validate_active(arm); - } - - return changed; + bool changed = false; + + /* Initialize flags. */ + { + for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { + + /* Flush the parent flag to this bone + * so we don't need to check the parent when adjusting the selection. */ + if ((ebone->flag & BONE_CONNECTED) && ebone->parent) { + if (ebone->parent->flag & BONE_TIPSEL) { + ebone->flag |= BONE_ROOTSEL; + } + else { + ebone->flag &= ~BONE_ROOTSEL; + } + + /* Flush the 'temp.i' flag. */ + if (ebone->parent->temp.i & BONESEL_TIP) { + ebone->temp.i |= BONESEL_ROOT; + } + } + ebone->flag &= ~BONE_DONE; + } + } + + /* Apply selection from bone selection flags. */ + for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (ebone->temp.i != 0) { + int is_ignore_flag = ((ebone->temp.i << 16) & (BONESEL_ROOT | BONESEL_TIP)); + int is_inside_flag = (ebone->temp.i & (BONESEL_ROOT | BONESEL_TIP | BONESEL_BONE)); + + /* Use as previous bone flag from now on. */ + ebone->temp.i = ebone->flag; + + /* When there is a partial selection without both endpoints, only select an endpoint. */ + if ((is_inside_flag & BONESEL_BONE) && (is_inside_flag & (BONESEL_ROOT | BONESEL_TIP)) && + ((is_inside_flag & (BONESEL_ROOT | BONESEL_TIP)) != (BONESEL_ROOT | BONESEL_TIP))) { + is_inside_flag &= ~BONESEL_BONE; + } + + changed |= armature_edit_select_op_apply(arm, ebone, sel_op, is_ignore_flag, is_inside_flag); + } + } + + if (changed) { + /* Cleanup flags. */ + for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (ebone->flag & BONE_DONE) { + SWAP(int, ebone->temp.i, ebone->flag); + ebone->flag |= BONE_DONE; + if ((ebone->flag & BONE_CONNECTED) && ebone->parent) { + if ((ebone->parent->flag & BONE_DONE) == 0) { + /* Checked below. */ + ebone->parent->temp.i = ebone->parent->flag; + } + } + } + } + + for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (ebone->flag & BONE_DONE) { + if ((ebone->flag & BONE_CONNECTED) && ebone->parent) { + bool is_parent_tip_changed = (ebone->parent->flag & BONE_TIPSEL) != + (ebone->parent->temp.i & BONE_TIPSEL); + if ((ebone->temp.i & BONE_ROOTSEL) == 0) { + if ((ebone->flag & BONE_ROOTSEL) != 0) { + ebone->parent->flag |= BONE_TIPSEL; + } + } + else { + if ((ebone->flag & BONE_ROOTSEL) == 0) { + ebone->parent->flag &= ~BONE_TIPSEL; + } + } + + if (is_parent_tip_changed == false) { + /* Keep tip selected if the parent remains selected. */ + if (ebone->parent->flag & BONE_SELECTED) { + ebone->parent->flag |= BONE_TIPSEL; + } + } + } + ebone->flag &= ~BONE_DONE; + } + } + + ED_armature_edit_sync_selection(arm->edbo); + ED_armature_edit_validate_active(arm); + } + + return changed; } /** \} */ @@ -939,613 +957,612 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op) static int armature_de_select_all_exec(bContext *C, wmOperator *op) { - int action = RNA_enum_get(op->ptr, "action"); - - if (action == SEL_TOGGLE) { - /* Determine if there are any selected bones - * And therefore whether we are selecting or deselecting */ - action = SEL_SELECT; - CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones) - { - if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) { - action = SEL_DESELECT; - break; - } - } - CTX_DATA_END; - } - - /* Set the flags */ - CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones) - { - /* ignore bone if selection can't change */ - switch (action) { - case SEL_SELECT: - if ((ebone->flag & BONE_UNSELECTABLE) == 0) { - ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - if (ebone->parent) { - ebone->parent->flag |= (BONE_TIPSEL); - } - } - break; - case SEL_DESELECT: - ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - break; - case SEL_INVERT: - if (ebone->flag & BONE_SELECTED) { - ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - else { - if ((ebone->flag & BONE_UNSELECTABLE) == 0) { - ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - if (ebone->parent) { - ebone->parent->flag |= (BONE_TIPSEL); - } - } - } - break; - } - } - CTX_DATA_END; - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL); - - return OPERATOR_FINISHED; + int action = RNA_enum_get(op->ptr, "action"); + + if (action == SEL_TOGGLE) { + /* Determine if there are any selected bones + * And therefore whether we are selecting or deselecting */ + action = SEL_SELECT; + CTX_DATA_BEGIN (C, EditBone *, ebone, visible_bones) { + if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) { + action = SEL_DESELECT; + break; + } + } + CTX_DATA_END; + } + + /* Set the flags */ + CTX_DATA_BEGIN (C, EditBone *, ebone, visible_bones) { + /* ignore bone if selection can't change */ + switch (action) { + case SEL_SELECT: + if ((ebone->flag & BONE_UNSELECTABLE) == 0) { + ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + if (ebone->parent) { + ebone->parent->flag |= (BONE_TIPSEL); + } + } + break; + case SEL_DESELECT: + ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + break; + case SEL_INVERT: + if (ebone->flag & BONE_SELECTED) { + ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + else { + if ((ebone->flag & BONE_UNSELECTABLE) == 0) { + ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + if (ebone->parent) { + ebone->parent->flag |= (BONE_TIPSEL); + } + } + } + break; + } + } + CTX_DATA_END; + + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL); + + return OPERATOR_FINISHED; } void ARMATURE_OT_select_all(wmOperatorType *ot) { - /* identifiers */ - ot->name = "(De)select All"; - ot->idname = "ARMATURE_OT_select_all"; - ot->description = "Toggle selection status of all bones"; + /* identifiers */ + ot->name = "(De)select All"; + ot->idname = "ARMATURE_OT_select_all"; + ot->description = "Toggle selection status of all bones"; - /* api callbacks */ - ot->exec = armature_de_select_all_exec; - ot->poll = ED_operator_editarmature; + /* api callbacks */ + ot->exec = armature_de_select_all_exec; + ot->poll = ED_operator_editarmature; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - WM_operator_properties_select_all(ot); + WM_operator_properties_select_all(ot); } /**************** Select more/less **************/ static void armature_select_more(bArmature *arm, EditBone *ebone) { - if ((EBONE_PREV_FLAG_GET(ebone) & (BONE_ROOTSEL | BONE_TIPSEL)) != 0) { - if (EBONE_SELECTABLE(arm, ebone)) { - ED_armature_ebone_select_set(ebone, true); - } - } - - if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { - /* to parent */ - if ((EBONE_PREV_FLAG_GET(ebone) & BONE_ROOTSEL) != 0) { - if (EBONE_SELECTABLE(arm, ebone->parent)) { - ED_armature_ebone_selectflag_enable(ebone->parent, (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)); - } - } - - /* from parent (difference from select less) */ - if ((EBONE_PREV_FLAG_GET(ebone->parent) & BONE_TIPSEL) != 0) { - if (EBONE_SELECTABLE(arm, ebone)) { - ED_armature_ebone_selectflag_enable(ebone, (BONE_SELECTED | BONE_ROOTSEL)); - } - } - } + if ((EBONE_PREV_FLAG_GET(ebone) & (BONE_ROOTSEL | BONE_TIPSEL)) != 0) { + if (EBONE_SELECTABLE(arm, ebone)) { + ED_armature_ebone_select_set(ebone, true); + } + } + + if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { + /* to parent */ + if ((EBONE_PREV_FLAG_GET(ebone) & BONE_ROOTSEL) != 0) { + if (EBONE_SELECTABLE(arm, ebone->parent)) { + ED_armature_ebone_selectflag_enable(ebone->parent, + (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)); + } + } + + /* from parent (difference from select less) */ + if ((EBONE_PREV_FLAG_GET(ebone->parent) & BONE_TIPSEL) != 0) { + if (EBONE_SELECTABLE(arm, ebone)) { + ED_armature_ebone_selectflag_enable(ebone, (BONE_SELECTED | BONE_ROOTSEL)); + } + } + } } static void armature_select_less(bArmature *UNUSED(arm), EditBone *ebone) { - if ((EBONE_PREV_FLAG_GET(ebone) & (BONE_ROOTSEL | BONE_TIPSEL)) != (BONE_ROOTSEL | BONE_TIPSEL)) { - ED_armature_ebone_select_set(ebone, false); - } - - if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { - /* to parent */ - if ((EBONE_PREV_FLAG_GET(ebone) & BONE_SELECTED) == 0) { - ED_armature_ebone_selectflag_disable(ebone->parent, (BONE_SELECTED | BONE_TIPSEL)); - } - - /* from parent (difference from select more) */ - if ((EBONE_PREV_FLAG_GET(ebone->parent) & BONE_SELECTED) == 0) { - ED_armature_ebone_selectflag_disable(ebone, (BONE_SELECTED | BONE_ROOTSEL)); - } - } + if ((EBONE_PREV_FLAG_GET(ebone) & (BONE_ROOTSEL | BONE_TIPSEL)) != + (BONE_ROOTSEL | BONE_TIPSEL)) { + ED_armature_ebone_select_set(ebone, false); + } + + if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { + /* to parent */ + if ((EBONE_PREV_FLAG_GET(ebone) & BONE_SELECTED) == 0) { + ED_armature_ebone_selectflag_disable(ebone->parent, (BONE_SELECTED | BONE_TIPSEL)); + } + + /* from parent (difference from select more) */ + if ((EBONE_PREV_FLAG_GET(ebone->parent) & BONE_SELECTED) == 0) { + ED_armature_ebone_selectflag_disable(ebone, (BONE_SELECTED | BONE_ROOTSEL)); + } + } } static void armature_select_more_less(Object *ob, bool more) { - bArmature *arm = (bArmature *)ob->data; - EditBone *ebone; - - /* XXX, eventually we shouldn't need this - campbell */ - ED_armature_edit_sync_selection(arm->edbo); - - /* count bones & store selection state */ - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - EBONE_PREV_FLAG_SET(ebone, ED_armature_ebone_selectflag_get(ebone)); - } - - /* do selection */ - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone)) { - if (more) { - armature_select_more(arm, ebone); - } - else { - armature_select_less(arm, ebone); - } - } - } - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone)) { - if (more == false) { - if (ebone->flag & BONE_SELECTED) { - ED_armature_ebone_select_set(ebone, true); - } - } - } - ebone->temp.p = NULL; - } - - ED_armature_edit_sync_selection(arm->edbo); + bArmature *arm = (bArmature *)ob->data; + EditBone *ebone; + + /* XXX, eventually we shouldn't need this - campbell */ + ED_armature_edit_sync_selection(arm->edbo); + + /* count bones & store selection state */ + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + EBONE_PREV_FLAG_SET(ebone, ED_armature_ebone_selectflag_get(ebone)); + } + + /* do selection */ + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (EBONE_VISIBLE(arm, ebone)) { + if (more) { + armature_select_more(arm, ebone); + } + else { + armature_select_less(arm, ebone); + } + } + } + + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (EBONE_VISIBLE(arm, ebone)) { + if (more == false) { + if (ebone->flag & BONE_SELECTED) { + ED_armature_ebone_select_set(ebone, true); + } + } + } + ebone->temp.p = NULL; + } + + ED_armature_edit_sync_selection(arm->edbo); } static int armature_de_select_more_exec(bContext *C, wmOperator *UNUSED(op)) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - armature_select_more_less(ob, true); - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - } - MEM_freeN(objects); - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + armature_select_more_less(ob, true); + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + } + MEM_freeN(objects); + return OPERATOR_FINISHED; } void ARMATURE_OT_select_more(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select More"; - ot->idname = "ARMATURE_OT_select_more"; - ot->description = "Select those bones connected to the initial selection"; + /* identifiers */ + ot->name = "Select More"; + ot->idname = "ARMATURE_OT_select_more"; + ot->description = "Select those bones connected to the initial selection"; - /* api callbacks */ - ot->exec = armature_de_select_more_exec; - ot->poll = ED_operator_editarmature; + /* api callbacks */ + ot->exec = armature_de_select_more_exec; + ot->poll = ED_operator_editarmature; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int armature_de_select_less_exec(bContext *C, wmOperator *UNUSED(op)) { - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - armature_select_more_less(ob, false); - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - } - MEM_freeN(objects); - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + armature_select_more_less(ob, false); + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + } + MEM_freeN(objects); + return OPERATOR_FINISHED; } void ARMATURE_OT_select_less(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Less"; - ot->idname = "ARMATURE_OT_select_less"; - ot->description = "Deselect those bones at the boundary of each selection region"; + /* identifiers */ + ot->name = "Select Less"; + ot->idname = "ARMATURE_OT_select_less"; + ot->description = "Deselect those bones at the boundary of each selection region"; - /* api callbacks */ - ot->exec = armature_de_select_less_exec; - ot->poll = ED_operator_editarmature; + /* api callbacks */ + ot->exec = armature_de_select_less_exec; + ot->poll = ED_operator_editarmature; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } enum { - SIMEDBONE_CHILDREN = 1, - SIMEDBONE_CHILDREN_IMMEDIATE, - SIMEDBONE_SIBLINGS, - SIMEDBONE_LENGTH, - SIMEDBONE_DIRECTION, - SIMEDBONE_PREFIX, - SIMEDBONE_SUFFIX, - SIMEDBONE_LAYER, - SIMEDBONE_GROUP, - SIMEDBONE_SHAPE, + SIMEDBONE_CHILDREN = 1, + SIMEDBONE_CHILDREN_IMMEDIATE, + SIMEDBONE_SIBLINGS, + SIMEDBONE_LENGTH, + SIMEDBONE_DIRECTION, + SIMEDBONE_PREFIX, + SIMEDBONE_SUFFIX, + SIMEDBONE_LAYER, + SIMEDBONE_GROUP, + SIMEDBONE_SHAPE, }; static const EnumPropertyItem prop_similar_types[] = { - {SIMEDBONE_CHILDREN, "CHILDREN", 0, "Children", ""}, - {SIMEDBONE_CHILDREN_IMMEDIATE, "CHILDREN_IMMEDIATE", 0, "Immediate children", ""}, - {SIMEDBONE_SIBLINGS, "SIBLINGS", 0, "Siblings", ""}, - {SIMEDBONE_LENGTH, "LENGTH", 0, "Length", ""}, - {SIMEDBONE_DIRECTION, "DIRECTION", 0, "Direction (Y axis)", ""}, - {SIMEDBONE_PREFIX, "PREFIX", 0, "Prefix", ""}, - {SIMEDBONE_SUFFIX, "SUFFIX", 0, "Suffix", ""}, - {SIMEDBONE_LAYER, "LAYER", 0, "Layer", ""}, - {SIMEDBONE_GROUP, "GROUP", 0, "Group", ""}, - {SIMEDBONE_SHAPE, "SHAPE", 0, "Shape", ""}, - {0, NULL, 0, NULL, NULL}, + {SIMEDBONE_CHILDREN, "CHILDREN", 0, "Children", ""}, + {SIMEDBONE_CHILDREN_IMMEDIATE, "CHILDREN_IMMEDIATE", 0, "Immediate children", ""}, + {SIMEDBONE_SIBLINGS, "SIBLINGS", 0, "Siblings", ""}, + {SIMEDBONE_LENGTH, "LENGTH", 0, "Length", ""}, + {SIMEDBONE_DIRECTION, "DIRECTION", 0, "Direction (Y axis)", ""}, + {SIMEDBONE_PREFIX, "PREFIX", 0, "Prefix", ""}, + {SIMEDBONE_SUFFIX, "SUFFIX", 0, "Suffix", ""}, + {SIMEDBONE_LAYER, "LAYER", 0, "Layer", ""}, + {SIMEDBONE_GROUP, "GROUP", 0, "Group", ""}, + {SIMEDBONE_SHAPE, "SHAPE", 0, "Shape", ""}, + {0, NULL, 0, NULL, NULL}, }; static float bone_length_squared_worldspace_get(Object *ob, EditBone *ebone) { - float v1[3], v2[3]; - mul_v3_mat3_m4v3(v1, ob->obmat, ebone->head); - mul_v3_mat3_m4v3(v2, ob->obmat, ebone->tail); - return len_squared_v3v3(v1, v2); + float v1[3], v2[3]; + mul_v3_mat3_m4v3(v1, ob->obmat, ebone->head); + mul_v3_mat3_m4v3(v2, ob->obmat, ebone->tail); + return len_squared_v3v3(v1, v2); } static void select_similar_length(bContext *C, const float thresh) { - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob_act = CTX_data_edit_object(C); - EditBone *ebone_act = CTX_data_active_bone(C); - - /* Thresh is always relative to current length. */ - const float len = bone_length_squared_worldspace_get(ob_act, ebone_act); - const float len_min = len / (1.0f + (thresh - FLT_EPSILON)); - const float len_max = len * (1.0f + (thresh + FLT_EPSILON)); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - bArmature *arm = ob->data; - bool changed = false; - - for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_SELECTABLE(arm, ebone)) { - const float len_iter = bone_length_squared_worldspace_get(ob, ebone); - if ((len_iter > len_min) && - (len_iter < len_max)) - { - ED_armature_ebone_select_set(ebone, true); - changed = true; - } - } - } - - if (changed) { - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - } - } - MEM_freeN(objects); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob_act = CTX_data_edit_object(C); + EditBone *ebone_act = CTX_data_active_bone(C); + + /* Thresh is always relative to current length. */ + const float len = bone_length_squared_worldspace_get(ob_act, ebone_act); + const float len_min = len / (1.0f + (thresh - FLT_EPSILON)); + const float len_max = len * (1.0f + (thresh + FLT_EPSILON)); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + bArmature *arm = ob->data; + bool changed = false; + + for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (EBONE_SELECTABLE(arm, ebone)) { + const float len_iter = bone_length_squared_worldspace_get(ob, ebone); + if ((len_iter > len_min) && (len_iter < len_max)) { + ED_armature_ebone_select_set(ebone, true); + changed = true; + } + } + } + + if (changed) { + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + } + } + MEM_freeN(objects); } static void bone_direction_worldspace_get(Object *ob, EditBone *ebone, float *r_dir) { - float v1[3], v2[3]; - copy_v3_v3(v1, ebone->head); - copy_v3_v3(v2, ebone->tail); + float v1[3], v2[3]; + copy_v3_v3(v1, ebone->head); + copy_v3_v3(v2, ebone->tail); - mul_m4_v3(ob->obmat, v1); - mul_m4_v3(ob->obmat, v2); + mul_m4_v3(ob->obmat, v1); + mul_m4_v3(ob->obmat, v2); - sub_v3_v3v3(r_dir, v1, v2); - normalize_v3(r_dir); + sub_v3_v3v3(r_dir, v1, v2); + normalize_v3(r_dir); } static void select_similar_direction(bContext *C, const float thresh) { - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob_act = CTX_data_edit_object(C); - EditBone *ebone_act = CTX_data_active_bone(C); - - float dir_act[3]; - bone_direction_worldspace_get(ob_act, ebone_act, dir_act); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - bArmature *arm = ob->data; - bool changed = false; - - for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_SELECTABLE(arm, ebone)) { - float dir[3]; - bone_direction_worldspace_get(ob, ebone, dir); - - if (angle_v3v3(dir_act, dir) / (float)M_PI < (thresh + FLT_EPSILON)) { - ED_armature_ebone_select_set(ebone, true); - changed = true; - } - } - } - - if (changed) { - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - } - } - MEM_freeN(objects); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob_act = CTX_data_edit_object(C); + EditBone *ebone_act = CTX_data_active_bone(C); + + float dir_act[3]; + bone_direction_worldspace_get(ob_act, ebone_act, dir_act); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + bArmature *arm = ob->data; + bool changed = false; + + for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (EBONE_SELECTABLE(arm, ebone)) { + float dir[3]; + bone_direction_worldspace_get(ob, ebone, dir); + + if (angle_v3v3(dir_act, dir) / (float)M_PI < (thresh + FLT_EPSILON)) { + ED_armature_ebone_select_set(ebone, true); + changed = true; + } + } + } + + if (changed) { + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + } + } + MEM_freeN(objects); } static void select_similar_layer(bContext *C) { - ViewLayer *view_layer = CTX_data_view_layer(C); - EditBone *ebone_act = CTX_data_active_bone(C); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - bArmature *arm = ob->data; - bool changed = false; - - for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_SELECTABLE(arm, ebone)) { - if (ebone->layer & ebone_act->layer) { - ED_armature_ebone_select_set(ebone, true); - changed = true; - } - } - } - - if (changed) { - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - } - } - MEM_freeN(objects); + ViewLayer *view_layer = CTX_data_view_layer(C); + EditBone *ebone_act = CTX_data_active_bone(C); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + bArmature *arm = ob->data; + bool changed = false; + + for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (EBONE_SELECTABLE(arm, ebone)) { + if (ebone->layer & ebone_act->layer) { + ED_armature_ebone_select_set(ebone, true); + changed = true; + } + } + } + + if (changed) { + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + } + } + MEM_freeN(objects); } static void select_similar_prefix(bContext *C) { - ViewLayer *view_layer = CTX_data_view_layer(C); - EditBone *ebone_act = CTX_data_active_bone(C); - - char body_tmp[MAXBONENAME]; - char prefix_act[MAXBONENAME]; - - BLI_string_split_prefix(ebone_act->name, prefix_act, body_tmp, sizeof(ebone_act->name)); - - if (prefix_act[0] == '\0') { - return; - } - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - bArmature *arm = ob->data; - bool changed = false; - - /* Find matches */ - for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_SELECTABLE(arm, ebone)) { - char prefix_other[MAXBONENAME]; - BLI_string_split_prefix(ebone->name, prefix_other, body_tmp, sizeof(ebone->name)); - if (STREQ(prefix_act, prefix_other)) { - ED_armature_ebone_select_set(ebone, true); - changed = true; - } - } - } - - if (changed) { - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - } - } - MEM_freeN(objects); + ViewLayer *view_layer = CTX_data_view_layer(C); + EditBone *ebone_act = CTX_data_active_bone(C); + + char body_tmp[MAXBONENAME]; + char prefix_act[MAXBONENAME]; + + BLI_string_split_prefix(ebone_act->name, prefix_act, body_tmp, sizeof(ebone_act->name)); + + if (prefix_act[0] == '\0') { + return; + } + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + bArmature *arm = ob->data; + bool changed = false; + + /* Find matches */ + for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (EBONE_SELECTABLE(arm, ebone)) { + char prefix_other[MAXBONENAME]; + BLI_string_split_prefix(ebone->name, prefix_other, body_tmp, sizeof(ebone->name)); + if (STREQ(prefix_act, prefix_other)) { + ED_armature_ebone_select_set(ebone, true); + changed = true; + } + } + } + + if (changed) { + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + } + } + MEM_freeN(objects); } static void select_similar_suffix(bContext *C) { - ViewLayer *view_layer = CTX_data_view_layer(C); - EditBone *ebone_act = CTX_data_active_bone(C); - - char body_tmp[MAXBONENAME]; - char suffix_act[MAXBONENAME]; - - BLI_string_split_suffix(ebone_act->name, body_tmp, suffix_act, sizeof(ebone_act->name)); - - if (suffix_act[0] == '\0') - return; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - bArmature *arm = ob->data; - bool changed = false; - - /* Find matches */ - for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_SELECTABLE(arm, ebone)) { - char suffix_other[MAXBONENAME]; - BLI_string_split_suffix(ebone->name, body_tmp, suffix_other, sizeof(ebone->name)); - if (STREQ(suffix_act, suffix_other)) { - ED_armature_ebone_select_set(ebone, true); - changed = true; - } - } - } - - if (changed) { - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - } - } - MEM_freeN(objects); + ViewLayer *view_layer = CTX_data_view_layer(C); + EditBone *ebone_act = CTX_data_active_bone(C); + + char body_tmp[MAXBONENAME]; + char suffix_act[MAXBONENAME]; + + BLI_string_split_suffix(ebone_act->name, body_tmp, suffix_act, sizeof(ebone_act->name)); + + if (suffix_act[0] == '\0') + return; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + bArmature *arm = ob->data; + bool changed = false; + + /* Find matches */ + for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (EBONE_SELECTABLE(arm, ebone)) { + char suffix_other[MAXBONENAME]; + BLI_string_split_suffix(ebone->name, body_tmp, suffix_other, sizeof(ebone->name)); + if (STREQ(suffix_act, suffix_other)) { + ED_armature_ebone_select_set(ebone, true); + changed = true; + } + } + } + + if (changed) { + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + } + } + MEM_freeN(objects); } /** Use for matching any pose channel data. */ -static void select_similar_data_pchan( - bContext *C, - const size_t bytes_size, const int offset) +static void select_similar_data_pchan(bContext *C, const size_t bytes_size, const int offset) { - Object *obedit = CTX_data_edit_object(C); - bArmature *arm = obedit->data; - EditBone *ebone_act = CTX_data_active_bone(C); - - const bPoseChannel *pchan_active = BKE_pose_channel_find_name(obedit->pose, ebone_act->name); - const char *data_active = (const char *)POINTER_OFFSET(pchan_active, offset); - for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_SELECTABLE(arm, ebone)) { - const bPoseChannel *pchan = BKE_pose_channel_find_name(obedit->pose, ebone->name); - if (pchan) { - const char *data_test = (const char *)POINTER_OFFSET(pchan, offset); - if (memcmp(data_active, data_test, bytes_size) == 0) { - ED_armature_ebone_select_set(ebone, true); - } - } - } - } - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); + Object *obedit = CTX_data_edit_object(C); + bArmature *arm = obedit->data; + EditBone *ebone_act = CTX_data_active_bone(C); + + const bPoseChannel *pchan_active = BKE_pose_channel_find_name(obedit->pose, ebone_act->name); + const char *data_active = (const char *)POINTER_OFFSET(pchan_active, offset); + for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (EBONE_SELECTABLE(arm, ebone)) { + const bPoseChannel *pchan = BKE_pose_channel_find_name(obedit->pose, ebone->name); + if (pchan) { + const char *data_test = (const char *)POINTER_OFFSET(pchan, offset); + if (memcmp(data_active, data_test, bytes_size) == 0) { + ED_armature_ebone_select_set(ebone, true); + } + } + } + } + + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); } static void is_ancestor(EditBone *bone, EditBone *ancestor) { - if (bone->temp.ebone == ancestor || bone->temp.ebone == NULL) - return; + if (bone->temp.ebone == ancestor || bone->temp.ebone == NULL) + return; - if (bone->temp.ebone->temp.ebone != NULL && bone->temp.ebone->temp.ebone != ancestor) - is_ancestor(bone->temp.ebone, ancestor); + if (bone->temp.ebone->temp.ebone != NULL && bone->temp.ebone->temp.ebone != ancestor) + is_ancestor(bone->temp.ebone, ancestor); - bone->temp.ebone = bone->temp.ebone->temp.ebone; + bone->temp.ebone = bone->temp.ebone->temp.ebone; } static void select_similar_children(bContext *C) { - Object *obedit = CTX_data_edit_object(C); - bArmature *arm = obedit->data; - EditBone *ebone_act = CTX_data_active_bone(C); + Object *obedit = CTX_data_edit_object(C); + bArmature *arm = obedit->data; + EditBone *ebone_act = CTX_data_active_bone(C); - for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { - ebone_iter->temp.ebone = ebone_iter->parent; - } + for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { + ebone_iter->temp.ebone = ebone_iter->parent; + } - for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { - is_ancestor(ebone_iter, ebone_act); + for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { + is_ancestor(ebone_iter, ebone_act); - if (ebone_iter->temp.ebone == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) - ED_armature_ebone_select_set(ebone_iter, true); - } + if (ebone_iter->temp.ebone == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) + ED_armature_ebone_select_set(ebone_iter, true); + } - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); } static void select_similar_children_immediate(bContext *C) { - Object *obedit = CTX_data_edit_object(C); - bArmature *arm = obedit->data; - EditBone *ebone_act = CTX_data_active_bone(C); + Object *obedit = CTX_data_edit_object(C); + bArmature *arm = obedit->data; + EditBone *ebone_act = CTX_data_active_bone(C); - for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { - if (ebone_iter->parent == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) { - ED_armature_ebone_select_set(ebone_iter, true); - } - } + for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { + if (ebone_iter->parent == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) { + ED_armature_ebone_select_set(ebone_iter, true); + } + } - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); } static void select_similar_siblings(bContext *C) { - Object *obedit = CTX_data_edit_object(C); - bArmature *arm = obedit->data; - EditBone *ebone_act = CTX_data_active_bone(C); + Object *obedit = CTX_data_edit_object(C); + bArmature *arm = obedit->data; + EditBone *ebone_act = CTX_data_active_bone(C); - if (ebone_act->parent == NULL) { - return; - } + if (ebone_act->parent == NULL) { + return; + } - for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { - if (ebone_iter->parent == ebone_act->parent && EBONE_SELECTABLE(arm, ebone_iter)) { - ED_armature_ebone_select_set(ebone_iter, true); - } - } + for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { + if (ebone_iter->parent == ebone_act->parent && EBONE_SELECTABLE(arm, ebone_iter)) { + ED_armature_ebone_select_set(ebone_iter, true); + } + } - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); } static int armature_select_similar_exec(bContext *C, wmOperator *op) { - /* Get props */ - int type = RNA_enum_get(op->ptr, "type"); - float thresh = RNA_float_get(op->ptr, "threshold"); + /* Get props */ + int type = RNA_enum_get(op->ptr, "type"); + float thresh = RNA_float_get(op->ptr, "threshold"); - /* Check for active bone */ - if (CTX_data_active_bone(C) == NULL) { - BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone"); - return OPERATOR_CANCELLED; - } + /* Check for active bone */ + if (CTX_data_active_bone(C) == NULL) { + BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone"); + return OPERATOR_CANCELLED; + } #define STRUCT_SIZE_AND_OFFSET(_struct, _member) \ - sizeof(((_struct *)NULL)->_member), offsetof(_struct, _member) - - switch (type) { - case SIMEDBONE_CHILDREN: - select_similar_children(C); - break; - case SIMEDBONE_CHILDREN_IMMEDIATE: - select_similar_children_immediate(C); - break; - case SIMEDBONE_SIBLINGS: - select_similar_siblings(C); - break; - case SIMEDBONE_LENGTH: - select_similar_length(C, thresh); - break; - case SIMEDBONE_DIRECTION: - select_similar_direction(C, thresh); - break; - case SIMEDBONE_PREFIX: - select_similar_prefix(C); - break; - case SIMEDBONE_SUFFIX: - select_similar_suffix(C); - break; - case SIMEDBONE_LAYER: - select_similar_layer(C); - break; - case SIMEDBONE_GROUP: - select_similar_data_pchan( - C, - STRUCT_SIZE_AND_OFFSET(bPoseChannel, agrp_index)); - break; - case SIMEDBONE_SHAPE: - select_similar_data_pchan( - C, - STRUCT_SIZE_AND_OFFSET(bPoseChannel, custom)); - break; - } + sizeof(((_struct *)NULL)->_member), offsetof(_struct, _member) + + switch (type) { + case SIMEDBONE_CHILDREN: + select_similar_children(C); + break; + case SIMEDBONE_CHILDREN_IMMEDIATE: + select_similar_children_immediate(C); + break; + case SIMEDBONE_SIBLINGS: + select_similar_siblings(C); + break; + case SIMEDBONE_LENGTH: + select_similar_length(C, thresh); + break; + case SIMEDBONE_DIRECTION: + select_similar_direction(C, thresh); + break; + case SIMEDBONE_PREFIX: + select_similar_prefix(C); + break; + case SIMEDBONE_SUFFIX: + select_similar_suffix(C); + break; + case SIMEDBONE_LAYER: + select_similar_layer(C); + break; + case SIMEDBONE_GROUP: + select_similar_data_pchan(C, STRUCT_SIZE_AND_OFFSET(bPoseChannel, agrp_index)); + break; + case SIMEDBONE_SHAPE: + select_similar_data_pchan(C, STRUCT_SIZE_AND_OFFSET(bPoseChannel, custom)); + break; + } #undef STRUCT_SIZE_AND_OFFSET - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ARMATURE_OT_select_similar(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Similar"; - ot->idname = "ARMATURE_OT_select_similar"; - - /* callback functions */ - ot->invoke = WM_menu_invoke; - ot->exec = armature_select_similar_exec; - ot->poll = ED_operator_editarmature; - ot->description = "Select similar bones by property types"; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMEDBONE_LENGTH, "Type", ""); - RNA_def_float(ot->srna, "threshold", 0.1f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f); + /* identifiers */ + ot->name = "Select Similar"; + ot->idname = "ARMATURE_OT_select_similar"; + + /* callback functions */ + ot->invoke = WM_menu_invoke; + ot->exec = armature_select_similar_exec; + ot->poll = ED_operator_editarmature; + ot->description = "Select similar bones by property types"; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMEDBONE_LENGTH, "Type", ""); + RNA_def_float(ot->srna, "threshold", 0.1f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f); } /* ********************* select hierarchy operator ************** */ @@ -1554,103 +1571,101 @@ void ARMATURE_OT_select_similar(wmOperatorType *ot) * selected we then keep the non-active objects untouched (selected/unselected). */ static int armature_select_hierarchy_exec(bContext *C, wmOperator *op) { - Object *ob = CTX_data_edit_object(C); - EditBone *ebone_active; - int direction = RNA_enum_get(op->ptr, "direction"); - const bool add_to_sel = RNA_boolean_get(op->ptr, "extend"); - bool changed = false; - bArmature *arm = (bArmature *)ob->data; - - ebone_active = arm->act_edbone; - if (ebone_active == NULL) { - return OPERATOR_CANCELLED; - } - - if (direction == BONE_SELECT_PARENT) { - if (ebone_active->parent) { - EditBone *ebone_parent; - - ebone_parent = ebone_active->parent; - - if (EBONE_SELECTABLE(arm, ebone_parent)) { - arm->act_edbone = ebone_parent; - - if (!add_to_sel) { - ED_armature_ebone_select_set(ebone_active, false); - } - ED_armature_ebone_select_set(ebone_parent, true); - - changed = true; - } - } - - } - else { /* BONE_SELECT_CHILD */ - EditBone *ebone_iter, *ebone_child = NULL; - int pass; - - /* first pass, only connected bones (the logical direct child) */ - for (pass = 0; pass < 2 && (ebone_child == NULL); pass++) { - for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { - /* possible we have multiple children, some invisible */ - if (EBONE_SELECTABLE(arm, ebone_iter)) { - if (ebone_iter->parent == ebone_active) { - if ((pass == 1) || (ebone_iter->flag & BONE_CONNECTED)) { - ebone_child = ebone_iter; - break; - } - } - } - } - } - - if (ebone_child) { - arm->act_edbone = ebone_child; - - if (!add_to_sel) { - ED_armature_ebone_select_set(ebone_active, false); - } - ED_armature_ebone_select_set(ebone_child, true); - - changed = true; - } - } - - if (changed == false) { - return OPERATOR_CANCELLED; - } - - ED_armature_edit_sync_selection(arm->edbo); - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - - return OPERATOR_FINISHED; + Object *ob = CTX_data_edit_object(C); + EditBone *ebone_active; + int direction = RNA_enum_get(op->ptr, "direction"); + const bool add_to_sel = RNA_boolean_get(op->ptr, "extend"); + bool changed = false; + bArmature *arm = (bArmature *)ob->data; + + ebone_active = arm->act_edbone; + if (ebone_active == NULL) { + return OPERATOR_CANCELLED; + } + + if (direction == BONE_SELECT_PARENT) { + if (ebone_active->parent) { + EditBone *ebone_parent; + + ebone_parent = ebone_active->parent; + + if (EBONE_SELECTABLE(arm, ebone_parent)) { + arm->act_edbone = ebone_parent; + + if (!add_to_sel) { + ED_armature_ebone_select_set(ebone_active, false); + } + ED_armature_ebone_select_set(ebone_parent, true); + + changed = true; + } + } + } + else { /* BONE_SELECT_CHILD */ + EditBone *ebone_iter, *ebone_child = NULL; + int pass; + + /* first pass, only connected bones (the logical direct child) */ + for (pass = 0; pass < 2 && (ebone_child == NULL); pass++) { + for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { + /* possible we have multiple children, some invisible */ + if (EBONE_SELECTABLE(arm, ebone_iter)) { + if (ebone_iter->parent == ebone_active) { + if ((pass == 1) || (ebone_iter->flag & BONE_CONNECTED)) { + ebone_child = ebone_iter; + break; + } + } + } + } + } + + if (ebone_child) { + arm->act_edbone = ebone_child; + + if (!add_to_sel) { + ED_armature_ebone_select_set(ebone_active, false); + } + ED_armature_ebone_select_set(ebone_child, true); + + changed = true; + } + } + + if (changed == false) { + return OPERATOR_CANCELLED; + } + + ED_armature_edit_sync_selection(arm->edbo); + + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + + return OPERATOR_FINISHED; } void ARMATURE_OT_select_hierarchy(wmOperatorType *ot) { - static const EnumPropertyItem direction_items[] = { - {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""}, - {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Select Hierarchy"; - ot->idname = "ARMATURE_OT_select_hierarchy"; - ot->description = "Select immediate parent/children of selected bones"; - - /* api callbacks */ - ot->exec = armature_select_hierarchy_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - RNA_def_enum(ot->srna, "direction", direction_items, - BONE_SELECT_PARENT, "Direction", ""); - RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); + static const EnumPropertyItem direction_items[] = { + {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""}, + {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Select Hierarchy"; + ot->idname = "ARMATURE_OT_select_hierarchy"; + ot->description = "Select immediate parent/children of selected bones"; + + /* api callbacks */ + ot->exec = armature_select_hierarchy_exec; + ot->poll = ED_operator_editarmature; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + RNA_def_enum(ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", ""); + RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); } /****************** Mirror Select ****************/ @@ -1660,202 +1675,199 @@ void ARMATURE_OT_select_hierarchy(wmOperatorType *ot) */ static int armature_select_mirror_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - const bool active_only = RNA_boolean_get(op->ptr, "only_active"); - const bool extend = RNA_boolean_get(op->ptr, "extend"); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - bArmature *arm = ob->data; - - EditBone *ebone, *ebone_mirror_act = NULL; - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - const int flag = ED_armature_ebone_selectflag_get(ebone); - EBONE_PREV_FLAG_SET(ebone, flag); - } - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_SELECTABLE(arm, ebone)) { - EditBone *ebone_mirror; - int flag_new = extend ? EBONE_PREV_FLAG_GET(ebone) : 0; - - if ((ebone_mirror = ED_armature_ebone_get_mirrored(arm->edbo, ebone)) && - (EBONE_VISIBLE(arm, ebone_mirror))) - { - const int flag_mirror = EBONE_PREV_FLAG_GET(ebone_mirror); - flag_new |= flag_mirror; - - if (ebone == arm->act_edbone) { - ebone_mirror_act = ebone_mirror; - } - - /* skip all but the active or its mirror */ - if (active_only && !ELEM(arm->act_edbone, ebone, ebone_mirror)) { - continue; - } - } - - ED_armature_ebone_selectflag_set(ebone, flag_new); - } - } - - if (ebone_mirror_act) { - arm->act_edbone = ebone_mirror_act; - } - - ED_armature_edit_sync_selection(arm->edbo); - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + const bool active_only = RNA_boolean_get(op->ptr, "only_active"); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + bArmature *arm = ob->data; + + EditBone *ebone, *ebone_mirror_act = NULL; + + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + const int flag = ED_armature_ebone_selectflag_get(ebone); + EBONE_PREV_FLAG_SET(ebone, flag); + } + + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (EBONE_SELECTABLE(arm, ebone)) { + EditBone *ebone_mirror; + int flag_new = extend ? EBONE_PREV_FLAG_GET(ebone) : 0; + + if ((ebone_mirror = ED_armature_ebone_get_mirrored(arm->edbo, ebone)) && + (EBONE_VISIBLE(arm, ebone_mirror))) { + const int flag_mirror = EBONE_PREV_FLAG_GET(ebone_mirror); + flag_new |= flag_mirror; + + if (ebone == arm->act_edbone) { + ebone_mirror_act = ebone_mirror; + } + + /* skip all but the active or its mirror */ + if (active_only && !ELEM(arm->act_edbone, ebone, ebone_mirror)) { + continue; + } + } + + ED_armature_ebone_selectflag_set(ebone, flag_new); + } + } + + if (ebone_mirror_act) { + arm->act_edbone = ebone_mirror_act; + } + + ED_armature_edit_sync_selection(arm->edbo); + + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void ARMATURE_OT_select_mirror(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Flip Active/Selected Bone"; - ot->idname = "ARMATURE_OT_select_mirror"; - ot->description = "Mirror the bone selection"; - - /* api callbacks */ - ot->exec = armature_select_mirror_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean(ot->srna, "only_active", false, "Active Only", "Only operate on the active bone"); - RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); + /* identifiers */ + ot->name = "Flip Active/Selected Bone"; + ot->idname = "ARMATURE_OT_select_mirror"; + ot->description = "Mirror the bone selection"; + + /* api callbacks */ + ot->exec = armature_select_mirror_exec; + ot->poll = ED_operator_editarmature; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean( + ot->srna, "only_active", false, "Active Only", "Only operate on the active bone"); + RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); } - /****************** Select Path ****************/ -static bool armature_shortest_path_select(bArmature *arm, EditBone *ebone_parent, EditBone *ebone_child, - bool use_parent, bool is_test) +static bool armature_shortest_path_select( + bArmature *arm, EditBone *ebone_parent, EditBone *ebone_child, bool use_parent, bool is_test) { - do { + do { - if (!use_parent && (ebone_child == ebone_parent)) - break; + if (!use_parent && (ebone_child == ebone_parent)) + break; - if (is_test) { - if (!EBONE_SELECTABLE(arm, ebone_child)) { - return false; - } - } - else { - ED_armature_ebone_selectflag_set(ebone_child, (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)); - } + if (is_test) { + if (!EBONE_SELECTABLE(arm, ebone_child)) { + return false; + } + } + else { + ED_armature_ebone_selectflag_set(ebone_child, (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)); + } - if (ebone_child == ebone_parent) - break; + if (ebone_child == ebone_parent) + break; - ebone_child = ebone_child->parent; - } while (true); + ebone_child = ebone_child->parent; + } while (true); - return true; + return true; } static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - Object *obedit = CTX_data_edit_object(C); - bArmature *arm = obedit->data; - EditBone *ebone_src, *ebone_dst; - EditBone *ebone_isect_parent = NULL; - EditBone *ebone_isect_child[2]; - bool changed; - Base *base_dst = NULL; - - view3d_operator_needs_opengl(C); - - ebone_src = arm->act_edbone; - ebone_dst = get_nearest_bone(C, event->mval, false, &base_dst); - - /* fallback to object selection */ - if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) { - return OPERATOR_PASS_THROUGH; - } - - if (base_dst && base_dst->object != obedit) { - /* Disconnected, ignore. */ - return OPERATOR_CANCELLED; - } - - ebone_isect_child[0] = ebone_src; - ebone_isect_child[1] = ebone_dst; - - - /* ensure 'ebone_src' is the parent of 'ebone_dst', or set 'ebone_isect_parent' */ - if (ED_armature_ebone_is_child_recursive(ebone_src, ebone_dst)) { - /* pass */ - } - else if (ED_armature_ebone_is_child_recursive(ebone_dst, ebone_src)) { - SWAP(EditBone *, ebone_src, ebone_dst); - } - else if ((ebone_isect_parent = ED_armature_ebone_find_shared_parent(ebone_isect_child, 2))) { - /* pass */ - } - else { - /* disconnected bones */ - return OPERATOR_CANCELLED; - } - - - if (ebone_isect_parent) { - if (armature_shortest_path_select(arm, ebone_isect_parent, ebone_src, false, true) && - armature_shortest_path_select(arm, ebone_isect_parent, ebone_dst, false, true)) - { - armature_shortest_path_select(arm, ebone_isect_parent, ebone_src, false, false); - armature_shortest_path_select(arm, ebone_isect_parent, ebone_dst, false, false); - changed = true; - } - else { - /* unselectable */ - changed = false; - } - } - else { - if (armature_shortest_path_select(arm, ebone_src, ebone_dst, true, true)) { - armature_shortest_path_select(arm, ebone_src, ebone_dst, true, false); - changed = true; - } - else { - /* unselectable */ - changed = false; - } - } - - if (changed) { - arm->act_edbone = ebone_dst; - ED_armature_edit_sync_selection(arm->edbo); - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); - - return OPERATOR_FINISHED; - } - else { - BKE_report(op->reports, RPT_WARNING, "Unselectable bone in chain"); - return OPERATOR_CANCELLED; - } + Object *obedit = CTX_data_edit_object(C); + bArmature *arm = obedit->data; + EditBone *ebone_src, *ebone_dst; + EditBone *ebone_isect_parent = NULL; + EditBone *ebone_isect_child[2]; + bool changed; + Base *base_dst = NULL; + + view3d_operator_needs_opengl(C); + + ebone_src = arm->act_edbone; + ebone_dst = get_nearest_bone(C, event->mval, false, &base_dst); + + /* fallback to object selection */ + if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) { + return OPERATOR_PASS_THROUGH; + } + + if (base_dst && base_dst->object != obedit) { + /* Disconnected, ignore. */ + return OPERATOR_CANCELLED; + } + + ebone_isect_child[0] = ebone_src; + ebone_isect_child[1] = ebone_dst; + + /* ensure 'ebone_src' is the parent of 'ebone_dst', or set 'ebone_isect_parent' */ + if (ED_armature_ebone_is_child_recursive(ebone_src, ebone_dst)) { + /* pass */ + } + else if (ED_armature_ebone_is_child_recursive(ebone_dst, ebone_src)) { + SWAP(EditBone *, ebone_src, ebone_dst); + } + else if ((ebone_isect_parent = ED_armature_ebone_find_shared_parent(ebone_isect_child, 2))) { + /* pass */ + } + else { + /* disconnected bones */ + return OPERATOR_CANCELLED; + } + + if (ebone_isect_parent) { + if (armature_shortest_path_select(arm, ebone_isect_parent, ebone_src, false, true) && + armature_shortest_path_select(arm, ebone_isect_parent, ebone_dst, false, true)) { + armature_shortest_path_select(arm, ebone_isect_parent, ebone_src, false, false); + armature_shortest_path_select(arm, ebone_isect_parent, ebone_dst, false, false); + changed = true; + } + else { + /* unselectable */ + changed = false; + } + } + else { + if (armature_shortest_path_select(arm, ebone_src, ebone_dst, true, true)) { + armature_shortest_path_select(arm, ebone_src, ebone_dst, true, false); + changed = true; + } + else { + /* unselectable */ + changed = false; + } + } + + if (changed) { + arm->act_edbone = ebone_dst; + ED_armature_edit_sync_selection(arm->edbo); + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); + + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_WARNING, "Unselectable bone in chain"); + return OPERATOR_CANCELLED; + } } void ARMATURE_OT_shortest_path_pick(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Pick Shortest Path"; - ot->idname = "ARMATURE_OT_shortest_path_pick"; - ot->description = "Select shortest path between two bones"; + /* identifiers */ + ot->name = "Pick Shortest Path"; + ot->idname = "ARMATURE_OT_shortest_path_pick"; + ot->description = "Select shortest path between two bones"; - /* api callbacks */ - ot->invoke = armature_shortest_path_pick_invoke; - ot->poll = ED_operator_editarmature; + /* api callbacks */ + ot->invoke = armature_shortest_path_pick_invoke; + ot->poll = ED_operator_editarmature; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } |