static int armature_select_hierarchy_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); Object *ob; bArmature *arm; EditBone *curbone, *pabone, *chbone; int direction = RNA_enum_get(op->ptr, "direction"); int add_to_sel = RNA_boolean_get(op->ptr, "extend"); ob = obedit; arm = (bArmature *)ob->data; for (curbone = arm->edbo->first; curbone; curbone = curbone->next) { /* only work on bone if it is visible and its selection can change */ if (EBONE_SELECTABLE(arm, curbone)) { if (curbone == arm->act_edbone) { if (direction == BONE_SELECT_PARENT) { if (curbone->parent == NULL) continue; else pabone = curbone->parent; if (EBONE_VISIBLE(arm, pabone)) { pabone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); arm->act_edbone = pabone; if (pabone->parent) pabone->parent->flag |= BONE_TIPSEL; if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); break; } } else { // BONE_SELECT_CHILD chbone = editbone_get_child(arm, curbone, 1); if (chbone == NULL) continue; if (EBONE_SELECTABLE(arm, chbone)) { chbone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); arm->act_edbone = chbone; if (!add_to_sel) { curbone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL); if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL; } break; } } } } } ED_armature_sync_selection(arm->edbo); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); return OPERATOR_FINISHED; }
void ED_armature_deselect_all_visible(Object *obedit) { bArmature *arm = obedit->data; EditBone *ebone; for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { /* first and foremost, bone must be visible and selected */ if (EBONE_VISIBLE(arm, ebone)) { ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); } } ED_armature_sync_selection(arm->edbo); }
/* toggle==0: deselect * toggle==1: swap (based on test) * toggle==2: swap (no test), CURRENTLY UNUSED */ void ED_armature_deselect_all(Object *obedit, int toggle) { bArmature *arm = obedit->data; EditBone *eBone; int sel = 1; if (toggle == 1) { /* Determine if there are any selected bones * and therefore whether we are selecting or deselecting */ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { // if (arm->layer & eBone->layer) { if (eBone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) { sel = 0; break; } // } } } else { sel = toggle; } /* Set the flags */ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { if (sel == 2) { /* invert selection of bone */ if (EBONE_VISIBLE(arm, eBone)) { eBone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); if (arm->act_edbone == eBone) arm->act_edbone = NULL; } } else if (sel == 1) { /* select bone */ if (EBONE_VISIBLE(arm, eBone)) { eBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); if (eBone->parent) eBone->parent->flag |= (BONE_TIPSEL); } } else { /* deselect bone */ eBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); if (arm->act_edbone == eBone) arm->act_edbone = NULL; } } ED_armature_sync_selection(arm->edbo); }
/* only editmode! */ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op)) { bArmature *arm; EditBone *curBone, *ebone_next; Object *obedit = CTX_data_edit_object(C); // XXX get from context bool changed = false; arm = obedit->data; /* cancel if nothing selected */ if (CTX_DATA_COUNT(C, selected_bones) == 0) return OPERATOR_CANCELLED; armature_select_mirrored(arm); BKE_pose_channels_remove(obedit, armature_delete_ebone_cb, arm); for (curBone = arm->edbo->first; curBone; curBone = ebone_next) { ebone_next = curBone->next; if (arm->layer & curBone->layer) { if (curBone->flag & BONE_SELECTED) { if (curBone == arm->act_edbone) arm->act_edbone = NULL; ED_armature_edit_bone_remove(arm, curBone); changed = true; } } } if (!changed) return OPERATOR_CANCELLED; ED_armature_sync_selection(arm->edbo); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); return OPERATOR_FINISHED; }
/* if forked && mirror-edit: makes two bones with flipped names */ static int armature_extrude_exec(bContext *C, wmOperator *op) { Object *obedit; bArmature *arm; EditBone *newbone, *ebone, *flipbone, *first = NULL; int a, totbone = 0, do_extrude; bool forked = RNA_boolean_get(op->ptr, "forked"); obedit = CTX_data_edit_object(C); arm = obedit->data; /* since we allow root extrude too, we have to make sure selection is OK */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_VISIBLE(arm, ebone)) { if (ebone->flag & BONE_ROOTSEL) { if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { if (ebone->parent->flag & BONE_TIPSEL) ebone->flag &= ~BONE_ROOTSEL; } } } } /* Duplicate the necessary bones */ for (ebone = arm->edbo->first; ((ebone) && (ebone != first)); ebone = ebone->next) { if (EBONE_VISIBLE(arm, ebone)) { /* we extrude per definition the tip */ do_extrude = false; if (ebone->flag & (BONE_TIPSEL | BONE_SELECTED)) { do_extrude = true; } else if (ebone->flag & BONE_ROOTSEL) { /* but, a bone with parent deselected we do the root... */ if (ebone->parent && (ebone->parent->flag & BONE_TIPSEL)) { /* pass */ } else { do_extrude = 2; } } if (do_extrude) { /* we re-use code for mirror editing... */ flipbone = NULL; if (arm->flag & ARM_MIRROR_EDIT) { flipbone = ED_armature_bone_get_mirrored(arm->edbo, ebone); if (flipbone) { forked = 0; // we extrude 2 different bones if (flipbone->flag & (BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED)) /* don't want this bone to be selected... */ flipbone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); } if ((flipbone == NULL) && (forked)) flipbone = ebone; } for (a = 0; a < 2; a++) { if (a == 1) { if (flipbone == NULL) break; else { SWAP(EditBone *, flipbone, ebone); } } totbone++; newbone = MEM_callocN(sizeof(EditBone), "extrudebone"); if (do_extrude == true) { copy_v3_v3(newbone->head, ebone->tail); copy_v3_v3(newbone->tail, newbone->head); newbone->parent = ebone; newbone->flag = ebone->flag & (BONE_TIPSEL | BONE_RELATIVE_PARENTING); // copies it, in case mirrored bone if (newbone->parent) newbone->flag |= BONE_CONNECTED; } else { copy_v3_v3(newbone->head, ebone->head); copy_v3_v3(newbone->tail, ebone->head); newbone->parent = ebone->parent; newbone->flag = BONE_TIPSEL; if (newbone->parent && (ebone->flag & BONE_CONNECTED)) { newbone->flag |= BONE_CONNECTED; } } newbone->weight = ebone->weight; newbone->dist = ebone->dist; newbone->xwidth = ebone->xwidth; newbone->zwidth = ebone->zwidth; newbone->ease1 = ebone->ease1; newbone->ease2 = ebone->ease2; newbone->rad_head = ebone->rad_tail; // don't copy entire bone... newbone->rad_tail = ebone->rad_tail; newbone->segments = 1; newbone->layer = ebone->layer; newbone->roll1 = ebone->roll1; newbone->roll2 = ebone->roll2; newbone->curveInX = ebone->curveInX; newbone->curveInY = ebone->curveInY; newbone->curveOutX = ebone->curveOutX; newbone->curveOutY = ebone->curveOutY; newbone->scaleIn = ebone->scaleIn; newbone->scaleOut = ebone->scaleOut; BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name)); if (flipbone && forked) { // only set if mirror edit if (strlen(newbone->name) < (MAXBONENAME - 2)) { if (a == 0) strcat(newbone->name, "_L"); else strcat(newbone->name, "_R"); } } unique_editbone_name(arm->edbo, newbone->name, NULL); /* Add the new bone to the list */ BLI_addtail(arm->edbo, newbone); if (!first) first = newbone; /* restore ebone if we were flipping */ if (a == 1 && flipbone) SWAP(EditBone *, flipbone, ebone); } } /* Deselect the old bone */ ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); } } /* if only one bone, make this one active */ if (totbone == 1 && first) arm->act_edbone = first; if (totbone == 0) return OPERATOR_CANCELLED; /* Transform the endpoints */ ED_armature_sync_selection(arm->edbo); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); return OPERATOR_FINISHED; }
/** * near duplicate of #armature_duplicate_selected_exec, * except for parenting part (keep in sync) */ static int armature_symmetrize_exec(bContext *C, wmOperator *op) { bArmature *arm; EditBone *ebone_iter; EditBone *ebone_first_dupe = NULL; /* The beginning of the duplicated mirrored bones in the edbo list */ Object *obedit = CTX_data_edit_object(C); const int direction = RNA_enum_get(op->ptr, "direction"); const int axis = 0; arm = obedit->data; /* cancel if nothing selected */ if (CTX_DATA_COUNT(C, selected_bones) == 0) return OPERATOR_CANCELLED; ED_armature_sync_selection(arm->edbo); // XXX why is this needed? preEditBoneDuplicate(arm->edbo); /* Select mirrored bones */ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED)) { char name_flip[MAX_VGROUP_NAME]; BKE_deform_flip_side_name(name_flip, ebone_iter->name, false); if (STREQ(name_flip, ebone_iter->name)) { /* if the name matches, we don't have the potential to be mirrored, just skip */ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); } else { EditBone *ebone = ED_armature_bone_find_name(arm->edbo, name_flip); if (ebone) { if ((ebone->flag & BONE_SELECTED) == 0) { /* simple case, we're selected, the other bone isn't! */ ebone_iter->temp.ebone = ebone; } else { /* complicated - choose which direction to copy */ float axis_delta; axis_delta = ebone->head[axis] - ebone_iter->head[axis]; if (axis_delta == 0.0f) { axis_delta = ebone->tail[axis] - ebone_iter->tail[axis]; } if (axis_delta == 0.0f) { /* both mirrored bones exist and point to eachother and overlap exactly. * * in this case theres no well defined solution, so de-select both and skip. */ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); } else { EditBone *ebone_src, *ebone_dst; if (((axis_delta < 0.0f) ? -1 : 1) == direction) { ebone_src = ebone; ebone_dst = ebone_iter; } else { ebone_src = ebone_iter; ebone_dst = ebone; } ebone_src->temp.ebone = ebone_dst; ebone_dst->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); } } } } } } /* Find the selected bones and duplicate them as needed, with mirrored name */ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED) && /* will be set if the mirror bone already exists (no need to make a new one) */ (ebone_iter->temp.ebone == NULL)) { char name_flip[MAX_VGROUP_NAME]; BKE_deform_flip_side_name(name_flip, ebone_iter->name, false); /* bones must have a side-suffix */ if (!STREQ(name_flip, ebone_iter->name)) { EditBone *ebone; ebone = duplicateEditBone(ebone_iter, name_flip, arm->edbo, obedit); if (!ebone_first_dupe) { ebone_first_dupe = ebone; } } } } /* Run through the list and fix the pointers */ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { if (ebone_iter->temp.ebone) { /* copy all flags except for ... */ const int flag_copy = ((int)~0) & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL); EditBone *ebone = ebone_iter->temp.ebone; /* copy flags incase bone is pre-existing data */ ebone->flag = (ebone->flag & ~flag_copy) | (ebone_iter->flag & flag_copy); if (ebone_iter->parent == NULL) { /* If this bone has no parent, * Set the duplicate->parent to NULL */ ebone->parent = NULL; ebone->flag &= ~BONE_CONNECTED; } else { /* the parent may have been duplicated, if not lookup the mirror parent */ EditBone *ebone_parent = (ebone_iter->parent->temp.ebone ? ebone_iter->parent->temp.ebone : ED_armature_bone_get_mirrored(arm->edbo, ebone_iter->parent)); if (ebone_parent == NULL) { /* If the mirror lookup failed, (but the current bone has a parent) * then we can assume the parent has no L/R but is a center bone. * So just use the same parent for both. */ ebone_parent = ebone_iter->parent; ebone->flag &= ~BONE_CONNECTED; } ebone->parent = ebone_parent; } /* Lets try to fix any constraint subtargets that might * have been duplicated */ updateDuplicateSubtarget(ebone, arm->edbo, obedit); } } transform_armature_mirror_update(obedit); /* Selected bones now have their 'temp' pointer set, * so we don't need this anymore */ /* Deselect the old bones and select the new ones */ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { if (EBONE_VISIBLE(arm, ebone_iter)) { ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); } } /* New bones will be selected, but some of the bones may already exist */ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { EditBone *ebone = ebone_iter->temp.ebone; if (ebone && EBONE_SELECTABLE(arm, ebone)) { ED_armature_ebone_select_set(ebone, true); } } /* correct the active bone */ if (arm->act_edbone && arm->act_edbone->temp.ebone) { arm->act_edbone = arm->act_edbone->temp.ebone; } postEditBoneDuplicate(arm->edbo, obedit); ED_armature_validate_active(arm); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); return OPERATOR_FINISHED; }
static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op)) { bArmature *arm; EditBone *ebone_iter; EditBone *ebone_first_dupe = NULL; /* The beginning of the duplicated bones in the edbo list */ Object *obedit = CTX_data_edit_object(C); arm = obedit->data; /* cancel if nothing selected */ if (CTX_DATA_COUNT(C, selected_bones) == 0) return OPERATOR_CANCELLED; ED_armature_sync_selection(arm->edbo); // XXX why is this needed? preEditBoneDuplicate(arm->edbo); /* Select mirrored bones */ if (arm->flag & ARM_MIRROR_EDIT) { for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED)) { EditBone *ebone; ebone = ED_armature_bone_get_mirrored(arm->edbo, ebone_iter); if (ebone) { ebone->flag |= BONE_SELECTED; } } } } /* Find the selected bones and duplicate them as needed */ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED)) { EditBone *ebone; ebone = duplicateEditBone(ebone_iter, ebone_iter->name, arm->edbo, obedit); if (!ebone_first_dupe) { ebone_first_dupe = ebone; } } } /* Run though the list and fix the pointers */ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED)) { EditBone *ebone = ebone_iter->temp.ebone; if (!ebone_iter->parent) { /* If this bone has no parent, * Set the duplicate->parent to NULL */ ebone->parent = NULL; } else if (ebone_iter->parent->temp.ebone) { /* If this bone has a parent that was duplicated, * Set the duplicate->parent to the curBone->parent->temp */ ebone->parent = ebone_iter->parent->temp.ebone; } else { /* If this bone has a parent that IS not selected, * Set the duplicate->parent to the curBone->parent */ ebone->parent = (EditBone *) ebone_iter->parent; ebone->flag &= ~BONE_CONNECTED; } /* Lets try to fix any constraint subtargets that might * have been duplicated */ updateDuplicateSubtarget(ebone, arm->edbo, obedit); } } /* correct the active bone */ if (arm->act_edbone && arm->act_edbone->temp.ebone) { arm->act_edbone = arm->act_edbone->temp.ebone; } /* Deselect the old bones and select the new ones */ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { if (EBONE_VISIBLE(arm, ebone_iter)) { ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); } } postEditBoneDuplicate(arm->edbo, obedit); ED_armature_validate_active(arm); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); return OPERATOR_FINISHED; }
/* the ctrl-click method */ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op)) { View3D *v3d; bArmature *arm; EditBone *ebone, *newbone, *flipbone; float mat[3][3], imat[3][3]; const float *curs; int a, to_root = 0; Object *obedit; Scene *scene; scene = CTX_data_scene(C); v3d = CTX_wm_view3d(C); obedit = CTX_data_edit_object(C); arm = obedit->data; /* find the active or selected bone */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_VISIBLE(arm, ebone)) { if (ebone->flag & BONE_TIPSEL || arm->act_edbone == ebone) break; } } if (ebone == NULL) { for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_VISIBLE(arm, ebone)) { if (ebone->flag & BONE_ROOTSEL || arm->act_edbone == ebone) break; } } if (ebone == NULL) return OPERATOR_CANCELLED; to_root = 1; } ED_armature_deselect_all(obedit); /* we re-use code for mirror editing... */ flipbone = NULL; if (arm->flag & ARM_MIRROR_EDIT) flipbone = ED_armature_bone_get_mirrored(arm->edbo, ebone); for (a = 0; a < 2; a++) { if (a == 1) { if (flipbone == NULL) break; else { SWAP(EditBone *, flipbone, ebone); } } newbone = ED_armature_edit_bone_add(arm, ebone->name); arm->act_edbone = newbone; if (to_root) { copy_v3_v3(newbone->head, ebone->head); newbone->rad_head = ebone->rad_tail; newbone->parent = ebone->parent; } else { copy_v3_v3(newbone->head, ebone->tail); newbone->rad_head = ebone->rad_tail; newbone->parent = ebone; newbone->flag |= BONE_CONNECTED; } curs = ED_view3d_cursor3d_get(scene, v3d); copy_v3_v3(newbone->tail, curs); sub_v3_v3v3(newbone->tail, newbone->tail, obedit->obmat[3]); if (a == 1) newbone->tail[0] = -newbone->tail[0]; copy_m3_m4(mat, obedit->obmat); invert_m3_m3(imat, mat); mul_m3_v3(imat, newbone->tail); newbone->length = len_v3v3(newbone->head, newbone->tail); newbone->rad_tail = newbone->length * 0.05f; newbone->dist = newbone->length * 0.25f; } ED_armature_sync_selection(arm->edbo); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); return OPERATOR_FINISHED; }
static int armature_merge_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); bArmature *arm = (obedit) ? obedit->data : NULL; short type = RNA_enum_get(op->ptr, "type"); /* sanity checks */ if (ELEM(NULL, obedit, arm)) return OPERATOR_CANCELLED; /* for now, there's only really one type of merging that's performed... */ if (type == 1) { /* go down chains, merging bones */ ListBase chains = {NULL, NULL}; LinkData *chain, *nchain; EditBone *ebo; armature_tag_select_mirrored(arm); /* get chains (ends on chains) */ chains_find_tips(arm->edbo, &chains); if (chains.first == NULL) return OPERATOR_CANCELLED; /* each 'chain' is the last bone in the chain (with no children) */ for (chain = chains.first; chain; chain = nchain) { EditBone *bstart = NULL, *bend = NULL; EditBone *bchild = NULL, *child = NULL; /* temporarily remove chain from list of chains */ nchain = chain->next; BLI_remlink(&chains, chain); /* only consider bones that are visible and selected */ for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) { /* check if visible + selected */ if (EBONE_VISIBLE(arm, ebo) && ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) && (ebo->flag & BONE_SELECTED) ) { /* set either end or start (end gets priority, unless it is already set) */ if (bend == NULL) { bend = ebo; bchild = child; } else bstart = ebo; } else { /* chain is broken... merge any continous segments then clear */ if (bstart && bend) bones_merge(obedit, bstart, bend, bchild, &chains); bstart = NULL; bend = NULL; bchild = NULL; } } /* merge from bstart to bend if something not merged */ if (bstart && bend) bones_merge(obedit, bstart, bend, bchild, &chains); /* put back link */ BLI_insertlinkbefore(&chains, nchain, chain); } armature_tag_unselect(arm); BLI_freelistN(&chains); } /* updates */ ED_armature_sync_selection(arm->edbo); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit); return OPERATOR_FINISHED; }
/* this function merges between two bones, removes them and those in-between, * and adjusts the parent relationships for those in-between */ static void bones_merge(Object *obedit, EditBone *start, EditBone *end, EditBone *endchild, ListBase *chains) { bArmature *arm = obedit->data; EditBone *ebo, *ebone, *newbone; LinkData *chain; float head[3], tail[3]; /* check if same bone */ if (start == end) { if (G.debug & G_DEBUG) { printf("Error: same bone!\n"); printf("\tstart = %s, end = %s\n", start->name, end->name); } } /* step 1: add a new bone * - head = head/tail of start (default head) * - tail = head/tail of end (default tail) * - parent = parent of start */ if ((start->flag & BONE_TIPSEL) && (start->flag & BONE_SELECTED) == 0) { copy_v3_v3(head, start->tail); } else { copy_v3_v3(head, start->head); } if ((end->flag & BONE_ROOTSEL) && (end->flag & BONE_SELECTED) == 0) { copy_v3_v3(tail, end->head); } else { copy_v3_v3(tail, end->tail); } newbone = add_points_bone(obedit, head, tail); newbone->parent = start->parent; /* TODO, copy more things to the new bone */ newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_SCALE | BONE_NO_CYCLICOFFSET | BONE_NO_LOCAL_LOCATION | BONE_DONE); /* step 2a: reparent any side chains which may be parented to any bone in the chain of bones to merge * - potentially several tips for side chains leading to some tree exist... */ for (chain = chains->first; chain; chain = chain->next) { /* traverse down chain until we hit the bottom or if we run into the tip of the chain of bones we're * merging (need to stop in this case to avoid corrupting this chain too!) */ for (ebone = chain->data; (ebone) && (ebone != end); ebone = ebone->parent) { short found = 0; /* check if this bone is parented to one in the merging chain * ! WATCHIT: must only go check until end of checking chain */ for (ebo = end; (ebo) && (ebo != start->parent); ebo = ebo->parent) { /* side-chain found? --> remap parent to new bone, then we're done with this chain :) */ if (ebone->parent == ebo) { ebone->parent = newbone; found = 1; break; } } /* carry on to the next tip now */ if (found) break; } } /* step 2b: parent child of end to newbone (child from this chain) */ if (endchild) endchild->parent = newbone; /* step 3: delete all bones between and including start and end */ for (ebo = end; ebo; ebo = ebone) { ebone = (ebo == start) ? (NULL) : (ebo->parent); bone_free(arm, ebo); } newbone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED); ED_armature_sync_selection(arm->edbo); }
/* context: editmode armature in view3d */ bool mouse_armature(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) { Object *obedit = CTX_data_edit_object(C); bArmature *arm = obedit->data; ViewContext vc; EditBone *nearBone = NULL; int selmask; view3d_set_viewcontext(C, &vc); BIF_sk_selectStroke(C, mval, extend); nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, 1, &selmask); if (nearBone) { if (!extend && !deselect && !toggle) ED_armature_deselect_all(obedit, 0); /* 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_sync_selection(arm->edbo); if (nearBone) { /* then now check for active status */ if (ebone_select_flag(nearBone)) { arm->act_edbone = nearBone; } } WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit); return true; } return false; }
/* previously "selectconnected_armature" */ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bArmature *arm; EditBone *bone, *curBone, *next; const bool extend = RNA_boolean_get(op->ptr, "extend"); Object *obedit = CTX_data_edit_object(C); arm = obedit->data; view3d_operator_needs_opengl(C); if (extend) bone = get_nearest_bone(C, 0, event->mval[0], event->mval[1]); else bone = get_nearest_bone(C, 1, event->mval[0], event->mval[1]); if (!bone) return OPERATOR_CANCELLED; /* Select parents */ for (curBone = bone; curBone; curBone = next) { if ((curBone->flag & BONE_UNSELECTABLE) == 0) { if (extend) { 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 (extend) 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_sync_selection(arm->edbo); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); return OPERATOR_FINISHED; }