Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/armature/armature_select.c
| Show All 23 Lines | |||||
| * | * | ||||
| * API's and Operators for selecting armature bones in EditMode | * API's and Operators for selecting armature bones in EditMode | ||||
| */ | */ | ||||
| /** \file blender/editors/armature/armature_select.c | /** \file blender/editors/armature/armature_select.c | ||||
| * \ingroup edarmature | * \ingroup edarmature | ||||
| */ | */ | ||||
| #include "MEM_guardedalloc.h" | |||||
| #include "DNA_armature_types.h" | #include "DNA_armature_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "BLI_blenlib.h" | #include "BLI_blenlib.h" | ||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_string_utils.h" | #include "BLI_string_utils.h" | ||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_action.h" | #include "BKE_action.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| #include "BKE_layer.h" | |||||
| #include "BIF_gl.h" | #include "BIF_gl.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "RNA_define.h" | #include "RNA_define.h" | ||||
| #include "WM_api.h" | #include "WM_api.h" | ||||
| #include "WM_types.h" | #include "WM_types.h" | ||||
| #include "ED_armature.h" | #include "ED_armature.h" | ||||
| #include "ED_screen.h" | #include "ED_screen.h" | ||||
| #include "ED_view3d.h" | #include "ED_view3d.h" | ||||
| #include "DEG_depsgraph.h" | #include "DEG_depsgraph.h" | ||||
| #include "armature_intern.h" | #include "armature_intern.h" | ||||
| /* utility macros for storing a temp int in the bone (selection flag) */ | /* utility macros for storing a temp int in the bone (selection flag) */ | ||||
| #define EBONE_PREV_FLAG_GET(ebone) ((void)0, (ebone)->temp.i) | #define EBONE_PREV_FLAG_GET(ebone) ((void)0, (ebone)->temp.i) | ||||
| #define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp.i = val) | #define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp.i = val) | ||||
| /* **************** PoseMode & EditMode Selection Buffer Queries *************************** */ | /* **************** PoseMode & EditMode Selection Buffer Queries *************************** */ | ||||
| /* only for opengl selection indices */ | Base *ED_armature_base_and_ebone_from_select_buffer( | ||||
| Bone *ED_armature_bone_find_index(Object *ob, int index) | Base **bases, uint bases_len, int hit, EditBone **r_ebone) | ||||
| { | { | ||||
| bPoseChannel *pchan; | const uint hit_object = hit & 0xFFFF; | ||||
| if (ob->pose == NULL) return NULL; | Base *base = NULL; | ||||
| index >>= 16; // bone selection codes use left 2 bytes | EditBone *ebone = NULL; | ||||
| /* TODO(campbell): optimize, eg: sort & binary search. */ | |||||
| pchan = BLI_findlink(&ob->pose->chanbase, index); | for (uint base_index = 0; base_index < bases_len; base_index++) { | ||||
| return pchan ? pchan->bone : NULL; | if (bases[base_index]->object->select_color == 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) | |||||
| { | |||||
| 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_color == 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) | |||||
| { | |||||
| 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_color == 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 */ | /* See if there are any selected bones in this buffer */ | ||||
| /* only bones from base are checked on */ | /* only bones from base are checked on */ | ||||
| void *get_bone_from_selectbuffer( | void *get_bone_from_selectbuffer( | ||||
| Base *base, Object *obedit, const unsigned int *buffer, short hits, | Base **bases, uint bases_len, bool is_editmode, const unsigned int *buffer, short hits, | ||||
| bool findunsel, bool do_nearest) | bool findunsel, bool do_nearest, Base **r_base) | ||||
| { | { | ||||
| Bone *bone; | Bone *bone; | ||||
| EditBone *ebone; | EditBone *ebone; | ||||
| void *firstunSel = NULL, *firstSel = NULL, *data; | void *firstunSel = NULL, *firstSel = NULL, *data; | ||||
| Base *firstunSel_base = NULL, *firstSel_base = NULL; | |||||
| unsigned int hitresult; | unsigned int hitresult; | ||||
| short i; | short i; | ||||
| bool takeNext = false; | bool takeNext = false; | ||||
| int minsel = 0xffffffff, minunsel = 0xffffffff; | int minsel = 0xffffffff, minunsel = 0xffffffff; | ||||
| for (i = 0; i < hits; i++) { | for (i = 0; i < hits; i++) { | ||||
| hitresult = buffer[3 + (i * 4)]; | hitresult = buffer[3 + (i * 4)]; | ||||
| if (!(hitresult & BONESEL_NOSEL)) { | if (!(hitresult & BONESEL_NOSEL)) { | ||||
| if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */ | if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */ | ||||
| Base *base = NULL; | |||||
| bool sel; | bool sel; | ||||
| hitresult &= ~(BONESEL_ANY); | hitresult &= ~(BONESEL_ANY); | ||||
| /* Determine what the current bone is */ | /* Determine what the current bone is */ | ||||
| if (obedit == NULL || base->object != obedit) { | if (is_editmode == false) { | ||||
| /* no singular posemode, so check for correct object */ | base = ED_armature_base_and_bone_from_select_buffer(bases, bases_len, hitresult, &bone); | ||||
| if (base->object->select_color == (hitresult & 0xFFFF)) { | if (bone != NULL) { | ||||
| bone = ED_armature_bone_find_index(base->object, hitresult); | |||||
| if (findunsel) | if (findunsel) | ||||
| sel = (bone->flag & BONE_SELECTED); | sel = (bone->flag & BONE_SELECTED); | ||||
| else | else | ||||
| sel = !(bone->flag & BONE_SELECTED); | sel = !(bone->flag & BONE_SELECTED); | ||||
| data = bone; | data = bone; | ||||
| } | } | ||||
| else { | else { | ||||
| data = NULL; | data = NULL; | ||||
| sel = 0; | sel = 0; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| bArmature *arm = obedit->data; | base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone); | ||||
| ebone = BLI_findlink(arm->edbo, hitresult); | |||||
| if (findunsel) | if (findunsel) | ||||
| sel = (ebone->flag & BONE_SELECTED); | sel = (ebone->flag & BONE_SELECTED); | ||||
| else | else | ||||
| sel = !(ebone->flag & BONE_SELECTED); | sel = !(ebone->flag & BONE_SELECTED); | ||||
| data = ebone; | data = ebone; | ||||
| } | } | ||||
| if (data) { | if (data) { | ||||
| if (sel) { | if (sel) { | ||||
| if (do_nearest) { | if (do_nearest) { | ||||
| if (minsel > buffer[4 * i + 1]) { | if (minsel > buffer[4 * i + 1]) { | ||||
| firstSel = data; | firstSel = data; | ||||
| firstSel_base = base; | |||||
| minsel = buffer[4 * i + 1]; | minsel = buffer[4 * i + 1]; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| if (!firstSel) firstSel = data; | if (!firstSel) { | ||||
| firstSel = data; | |||||
| firstSel_base = base; | |||||
| } | |||||
| takeNext = 1; | takeNext = 1; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| if (do_nearest) { | if (do_nearest) { | ||||
| if (minunsel > buffer[4 * i + 1]) { | if (minunsel > buffer[4 * i + 1]) { | ||||
| firstunSel = data; | firstunSel = data; | ||||
| firstunSel_base = base; | |||||
| minunsel = buffer[4 * i + 1]; | minunsel = buffer[4 * i + 1]; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| if (!firstunSel) firstunSel = data; | if (!firstunSel) { | ||||
| if (takeNext) return data; | firstunSel = data; | ||||
| firstunSel_base = base; | |||||
| } | |||||
| if (takeNext) { | |||||
| *r_base = base; | |||||
| return data; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (firstunSel) | if (firstunSel) { | ||||
| *r_base = firstunSel_base; | |||||
| return firstunSel; | return firstunSel; | ||||
| else | } | ||||
| else { | |||||
| *r_base = firstSel_base; | |||||
| return firstSel; | return firstSel; | ||||
| } | } | ||||
| } | |||||
| /* used by posemode as well editmode */ | /* used by posemode as well editmode */ | ||||
| /* only checks scene->basact! */ | /* only checks scene->basact! */ | ||||
| /* x and y are mouse coords (area space) */ | /* x and y are mouse coords (area space) */ | ||||
| void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel) | void *get_nearest_bone( | ||||
| bContext *C, const int xy[2], bool findunsel, | |||||
| Base **r_base) | |||||
| { | { | ||||
| EvaluationContext eval_ctx; | EvaluationContext eval_ctx; | ||||
| ViewContext vc; | ViewContext vc; | ||||
| rcti rect; | rcti rect; | ||||
| unsigned int buffer[MAXPICKBUF]; | unsigned int buffer[MAXPICKBUF]; | ||||
| short hits; | short hits; | ||||
| CTX_data_eval_ctx(C, &eval_ctx); | CTX_data_eval_ctx(C, &eval_ctx); | ||||
| ED_view3d_viewcontext_init(C, &vc); | ED_view3d_viewcontext_init(C, &vc); | ||||
| // rect.xmin = ... mouseco! | // rect.xmin = ... mouseco! | ||||
| rect.xmin = rect.xmax = xy[0]; | rect.xmin = rect.xmax = xy[0]; | ||||
| rect.ymin = rect.ymax = xy[1]; | rect.ymin = rect.ymax = xy[1]; | ||||
| hits = view3d_opengl_select(&eval_ctx, &vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST); | hits = view3d_opengl_select(&eval_ctx, &vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST); | ||||
| *r_base = NULL; | |||||
| if (hits > 0) { | if (hits > 0) { | ||||
| return get_bone_from_selectbuffer(vc.view_layer->basact, vc.obedit, buffer, hits, findunsel, true); | uint bases_len = 0; | ||||
| Base **bases = BKE_view_layer_array_from_bases_in_mode( | |||||
| eval_ctx.view_layer, &bases_len, { | |||||
| .object_mode = vc.obedit ? OB_MODE_EDIT : OB_MODE_POSE, | |||||
| .no_dup_data = true}); | |||||
| 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; | return NULL; | ||||
| } | } | ||||
| /* **************** EditMode stuff ********************** */ | /* **************** EditMode stuff ********************** */ | ||||
| /* called in space.c */ | /* called in space.c */ | ||||
| /* previously "selectconnected_armature" */ | /* previously "selectconnected_armature" */ | ||||
| static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event) | static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| bArmature *arm; | bArmature *arm; | ||||
| EditBone *bone, *curBone, *next; | EditBone *bone, *curBone, *next; | ||||
| const bool extend = RNA_boolean_get(op->ptr, "extend"); | const bool extend = RNA_boolean_get(op->ptr, "extend"); | ||||
| Object *obedit = CTX_data_edit_object(C); | |||||
| arm = obedit->data; | |||||
| view3d_operator_needs_opengl(C); | view3d_operator_needs_opengl(C); | ||||
| bone = get_nearest_bone(C, event->mval, !extend); | Base *base = NULL; | ||||
| bone = get_nearest_bone(C, event->mval, !extend, &base); | |||||
| if (!bone) | if (!bone) | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| arm = base->object->data; | |||||
| /* Select parents */ | /* Select parents */ | ||||
| for (curBone = bone; curBone; curBone = next) { | for (curBone = bone; curBone; curBone = next) { | ||||
| if ((curBone->flag & BONE_UNSELECTABLE) == 0) { | if ((curBone->flag & BONE_UNSELECTABLE) == 0) { | ||||
| if (extend) { | if (extend) { | ||||
| curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); | curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); | ||||
| } | } | ||||
| else { | else { | ||||
| curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); | curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); | ||||
| Show All 26 Lines | for (curBone = arm->edbo->first; curBone; curBone = next) { | ||||
| } | } | ||||
| } | } | ||||
| if (!curBone) | if (!curBone) | ||||
| bone = NULL; | bone = NULL; | ||||
| } | } | ||||
| ED_armature_edit_sync_selection(arm->edbo); | ED_armature_edit_sync_selection(arm->edbo); | ||||
| WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); | WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static int armature_select_linked_poll(bContext *C) | static int 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)); | ||||
| } | } | ||||
| Show All 29 Lines | static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits12, const int hits5) | ||||
| memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int)); | memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int)); | ||||
| return hits5; | return hits5; | ||||
| } | } | ||||
| /* does bones and points */ | /* does bones and points */ | ||||
| /* note that BONE ROOT only gets drawn for root bones (or without IK) */ | /* note that BONE ROOT only gets drawn for root bones (or without IK) */ | ||||
| static EditBone *get_nearest_editbonepoint( | static EditBone *get_nearest_editbonepoint( | ||||
| const EvaluationContext *eval_ctx, ViewContext *vc, | const EvaluationContext *eval_ctx, ViewContext *vc, | ||||
| bool findunsel, bool use_cycle, int *r_selmask) | bool findunsel, bool use_cycle, | ||||
| Base **r_base, int *r_selmask) | |||||
| { | { | ||||
| bArmature *arm = (bArmature *)vc->obedit->data; | bArmature *arm = (bArmature *)vc->obedit->data; | ||||
| EditBone *ebone_next_act = arm->act_edbone; | EditBone *ebone_next_act = arm->act_edbone; | ||||
| EditBone *ebone; | EditBone *ebone; | ||||
| rcti rect; | rcti rect; | ||||
| unsigned int buffer[MAXPICKBUF]; | unsigned int buffer[MAXPICKBUF]; | ||||
| unsigned int hitresult, besthitresult = BONESEL_NOSEL; | unsigned int hitresult, besthitresult = BONESEL_NOSEL; | ||||
| ▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | else if (hits12 > 0) { | ||||
| if (hits5 > 0) { 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; } | else { hits = selectbuffer_ret_hits_12(buffer, hits12); goto cache_end; } | ||||
| } | } | ||||
| cache_end: | cache_end: | ||||
| view3d_opengl_select_cache_end(); | view3d_opengl_select_cache_end(); | ||||
| uint bases_len; | |||||
| Base **bases = BKE_view_layer_array_from_bases_in_mode( | |||||
| eval_ctx->view_layer, &bases_len, { | |||||
| .object_mode = OB_MODE_EDIT, | |||||
| .no_dup_data = true}); | |||||
| /* See if there are any selected bones in this group */ | /* See if there are any selected bones in this group */ | ||||
| if (hits > 0) { | if (hits > 0) { | ||||
| if (hits == 1) { | if (hits == 1) { | ||||
| if (!(buffer[3] & BONESEL_NOSEL)) | if (!(buffer[3] & BONESEL_NOSEL)) | ||||
| besthitresult = buffer[3]; | besthitresult = buffer[3]; | ||||
| } | } | ||||
| else { | else { | ||||
| for (i = 0; i < hits; i++) { | for (i = 0; i < hits; i++) { | ||||
| hitresult = buffer[3 + (i * 4)]; | hitresult = buffer[3 + (i * 4)]; | ||||
| if (!(hitresult & BONESEL_NOSEL)) { | if (!(hitresult & BONESEL_NOSEL)) { | ||||
| int dep; | Base *base = NULL; | ||||
| base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone); | |||||
| ebone = BLI_findlink(arm->edbo, hitresult & ~BONESEL_ANY); | arm = base->object->data; | ||||
| int dep; | |||||
| /* clicks on bone points get advantage */ | /* clicks on bone points get advantage */ | ||||
| if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) { | if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) { | ||||
| /* but also the unselected one */ | /* but also the unselected one */ | ||||
| if (findunsel) { | if (findunsel) { | ||||
| if ( (hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0) | if ( (hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0) | ||||
| dep = 1; | dep = 1; | ||||
| else if ( (hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0) | else if ( (hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0) | ||||
| dep = 1; | dep = 1; | ||||
| Show All 23 Lines | else { | ||||
| if (dep < mindep) { | if (dep < mindep) { | ||||
| mindep = dep; | mindep = dep; | ||||
| besthitresult = hitresult; | besthitresult = hitresult; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (!(besthitresult & BONESEL_NOSEL)) { | if (!(besthitresult & BONESEL_NOSEL)) { | ||||
| Base *base = NULL; | |||||
| ebone = BLI_findlink(arm->edbo, besthitresult & ~BONESEL_ANY); | base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone); | ||||
| arm = base->object->data; | |||||
| *r_base = base; | |||||
| *r_selmask = 0; | *r_selmask = 0; | ||||
| if (besthitresult & BONESEL_ROOT) | if (besthitresult & BONESEL_ROOT) | ||||
| *r_selmask |= BONE_ROOTSEL; | *r_selmask |= BONE_ROOTSEL; | ||||
| if (besthitresult & BONESEL_TIP) | if (besthitresult & BONESEL_TIP) | ||||
| *r_selmask |= BONE_TIPSEL; | *r_selmask |= BONE_TIPSEL; | ||||
| if (besthitresult & BONESEL_BONE) | if (besthitresult & BONESEL_BONE) | ||||
| *r_selmask |= BONE_SELECTED; | *r_selmask |= BONE_SELECTED; | ||||
| return ebone; | return ebone; | ||||
| } | } | ||||
| } | } | ||||
| *r_selmask = 0; | *r_selmask = 0; | ||||
| *r_base = NULL; | |||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| void ED_armature_edit_deselect_all(Object *obedit) | void ED_armature_edit_deselect_all(Object *obedit) | ||||
| { | { | ||||
| bArmature *arm = obedit->data; | bArmature *arm = obedit->data; | ||||
| EditBone *ebone; | EditBone *ebone; | ||||
| Show All 12 Lines | for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { | ||||
| if (EBONE_VISIBLE(arm, ebone)) { | if (EBONE_VISIBLE(arm, ebone)) { | ||||
| ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); | ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); | ||||
| } | } | ||||
| } | } | ||||
| ED_armature_edit_sync_selection(arm->edbo); | ED_armature_edit_sync_selection(arm->edbo); | ||||
| } | } | ||||
| void ED_armature_edit_deselect_all_multi(struct Object **objects, uint objects_len) | |||||
| { | |||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| Object *obedit = objects[ob_index]; | |||||
| ED_armature_edit_deselect_all(obedit); | |||||
| } | |||||
| } | |||||
| void ED_armature_edit_deselect_all_visible_multi(struct Object **objects, uint objects_len) | |||||
| { | |||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| Object *obedit = objects[ob_index]; | |||||
| ED_armature_edit_deselect_all_visible(obedit); | |||||
| } | |||||
| } | |||||
| /* accounts for connected parents */ | /* accounts for connected parents */ | ||||
| static int ebone_select_flag(EditBone *ebone) | static int ebone_select_flag(EditBone *ebone) | ||||
| { | { | ||||
| if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { | if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { | ||||
| return ((ebone->parent->flag & BONE_TIPSEL) ? BONE_ROOTSEL : 0) | (ebone->flag & (BONE_SELECTED | BONE_TIPSEL)); | return ((ebone->parent->flag & BONE_TIPSEL) ? BONE_ROOTSEL : 0) | (ebone->flag & (BONE_SELECTED | BONE_TIPSEL)); | ||||
| } | } | ||||
| else { | else { | ||||
| return ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL); | return ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL); | ||||
| } | } | ||||
| } | } | ||||
| /* context: editmode armature in view3d */ | /* 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) | ||||
| { | { | ||||
| Object *obedit = CTX_data_edit_object(C); | |||||
| EvaluationContext eval_ctx; | EvaluationContext eval_ctx; | ||||
| ViewContext vc; | ViewContext vc; | ||||
| EditBone *nearBone = NULL; | EditBone *nearBone = NULL; | ||||
| int selmask; | int selmask; | ||||
| Base *basact = NULL; | |||||
| CTX_data_eval_ctx(C, &eval_ctx); | CTX_data_eval_ctx(C, &eval_ctx); | ||||
| ED_view3d_viewcontext_init(C, &vc); | ED_view3d_viewcontext_init(C, &vc); | ||||
| vc.mval[0] = mval[0]; | vc.mval[0] = mval[0]; | ||||
| vc.mval[1] = mval[1]; | vc.mval[1] = mval[1]; | ||||
| if (BIF_sk_selectStroke(C, mval, extend)) { | if (BIF_sk_selectStroke(C, mval, extend)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| nearBone = get_nearest_editbonepoint(&eval_ctx, &vc, true, true, &selmask); | nearBone = get_nearest_editbonepoint(&eval_ctx, &vc, true, true, &basact, &selmask); | ||||
| if (nearBone) { | if (nearBone) { | ||||
| bArmature *arm = obedit->data; | ED_view3d_viewcontext_init_object(&vc, basact->object); | ||||
| bArmature *arm = vc.obedit->data; | |||||
| if (!extend && !deselect && !toggle) { | if (!extend && !deselect && !toggle) { | ||||
| ED_armature_edit_deselect_all(obedit); | uint objects_len = 0; | ||||
| Object **objects = BKE_view_layer_array_from_objects_in_mode( | |||||
| eval_ctx.view_layer, &objects_len, { | |||||
| .object_mode = OB_MODE_EDIT, | |||||
| .no_dup_data = true}); | |||||
| ED_armature_edit_deselect_all_multi(objects, objects_len); | |||||
| MEM_freeN(objects); | |||||
| } | } | ||||
| /* by definition the non-root connected bones have no root point drawn, | /* by definition the non-root connected bones have no root point drawn, | ||||
| * so a root selection needs to be delivered to the parent tip */ | * so a root selection needs to be delivered to the parent tip */ | ||||
| if (selmask & BONE_SELECTED) { | if (selmask & BONE_SELECTED) { | ||||
| if (nearBone->parent && (nearBone->flag & BONE_CONNECTED)) { | if (nearBone->parent && (nearBone->flag & BONE_CONNECTED)) { | ||||
| /* click in a chain */ | /* click in a chain */ | ||||
| ▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | if (nearBone) { | ||||
| ED_armature_edit_sync_selection(arm->edbo); | ED_armature_edit_sync_selection(arm->edbo); | ||||
| if (nearBone) { | if (nearBone) { | ||||
| /* then now check for active status */ | /* then now check for active status */ | ||||
| if (ebone_select_flag(nearBone)) { | if (ebone_select_flag(nearBone)) { | ||||
| arm->act_edbone = nearBone; | arm->act_edbone = nearBone; | ||||
| } | } | ||||
| if (eval_ctx.view_layer->basact != basact) { | |||||
| eval_ctx.view_layer->basact = basact; | |||||
| WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, vc.scene); | |||||
| } | |||||
| } | } | ||||
| WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit); | WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object); | ||||
| return true; | return true; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* **************** Selections ******************/ | /* **************** Selections ******************/ | ||||
| ▲ Show 20 Lines • Show All 696 Lines • ▼ Show 20 Lines | |||||
| static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) | static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| Object *obedit = CTX_data_edit_object(C); | Object *obedit = CTX_data_edit_object(C); | ||||
| bArmature *arm = obedit->data; | bArmature *arm = obedit->data; | ||||
| EditBone *ebone_src, *ebone_dst; | EditBone *ebone_src, *ebone_dst; | ||||
| EditBone *ebone_isect_parent = NULL; | EditBone *ebone_isect_parent = NULL; | ||||
| EditBone *ebone_isect_child[2]; | EditBone *ebone_isect_child[2]; | ||||
| bool changed; | bool changed; | ||||
| Base *base_dst = NULL; | |||||
| view3d_operator_needs_opengl(C); | view3d_operator_needs_opengl(C); | ||||
| ebone_src = arm->act_edbone; | ebone_src = arm->act_edbone; | ||||
| ebone_dst = get_nearest_bone(C, event->mval, false); | ebone_dst = get_nearest_bone(C, event->mval, false, &base_dst); | ||||
| /* fallback to object selection */ | /* fallback to object selection */ | ||||
| if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) { | if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) { | ||||
| return OPERATOR_PASS_THROUGH; | 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[0] = ebone_src; | ||||
| ebone_isect_child[1] = ebone_dst; | ebone_isect_child[1] = ebone_dst; | ||||
| /* ensure 'ebone_src' is the parent of 'ebone_dst', or set 'ebone_isect_parent' */ | /* 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)) { | if (ED_armature_ebone_is_child_recursive(ebone_src, ebone_dst)) { | ||||
| /* pass */ | /* pass */ | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 63 Lines • Show Last 20 Lines | |||||