/* v3d and rv3d are allowed to be NULL */ void add_primitive_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d) { Object *obedit = scene->obedit; // XXX get from context bArmature *arm = obedit->data; float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3]; EditBone *bone; /* Get inverse point for head and orientation for tail */ invert_m4_m4(obedit->imat, obedit->obmat); mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d)); if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) copy_m3_m4(obmat, rv3d->viewmat); else unit_m3(obmat); copy_m3_m4(viewmat, obedit->obmat); mul_m3_m3m3(totmat, obmat, viewmat); invert_m3_m3(imat, totmat); ED_armature_deselect_all(obedit, 0); /* Create a bone */ bone = ED_armature_edit_bone_add(arm, "Bone"); arm->act_edbone = bone; copy_v3_v3(bone->head, curs); if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1 else add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z }
static int tree_element_active_ebone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), int set) { bArmature *arm= scene->obedit->data; EditBone *ebone= te->directdata; if(set==1) { if(!(ebone->flag & BONE_HIDDEN_A)) { ED_armature_deselect_all(scene->obedit, 0); // deselect tree_element_active_ebone__sel(C, scene, arm, ebone, TRUE); return 1; } } else if (set==2) { if(!(ebone->flag & BONE_HIDDEN_A)) { if(!(ebone->flag & BONE_SELECTED)) { tree_element_active_ebone__sel(C, scene, arm, ebone, TRUE); return 1; } else { /* entirely selected, so de-select */ tree_element_active_ebone__sel(C, scene, arm, ebone, FALSE); return 0; } } } else if (ebone->flag & BONE_SELECTED) { return 1; } return 0; }
EditBone *ED_armature_edit_bone_add_primitive(Object *obedit_arm, float length, bool view_aligned) { bArmature *arm = obedit_arm->data; EditBone *bone; ED_armature_deselect_all(obedit_arm); /* Create a bone */ bone = ED_armature_edit_bone_add(arm, "Bone"); arm->act_edbone = bone; zero_v3(bone->head); zero_v3(bone->tail); bone->tail[view_aligned ? 1 : 2] = length; return bone; }
void add_primitive_bone(Object *obedit_arm, bool view_aligned) { bArmature *arm = obedit_arm->data; EditBone *bone; ED_armature_deselect_all(obedit_arm, 0); /* Create a bone */ bone = ED_armature_edit_bone_add(arm, "Bone"); arm->act_edbone = bone; zero_v3(bone->head); zero_v3(bone->tail); if (view_aligned) bone->tail[1] = 1.0f; else bone->tail[2] = 1.0f; }
static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) { RegionView3D *rv3d = CTX_wm_region_view3d(C); Object *obedit = CTX_data_edit_object(C); EditBone *bone; float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3]; char name[MAXBONENAME]; RNA_string_get(op->ptr, "name", name); copy_v3_v3(curs, ED_view3d_cursor3d_get(CTX_data_scene(C), CTX_wm_view3d(C))); /* Get inverse point for head and orientation for tail */ invert_m4_m4(obedit->imat, obedit->obmat); mul_m4_v3(obedit->imat, curs); if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) copy_m3_m4(obmat, rv3d->viewmat); else unit_m3(obmat); copy_m3_m4(viewmat, obedit->obmat); mul_m3_m3m3(totmat, obmat, viewmat); invert_m3_m3(imat, totmat); ED_armature_deselect_all(obedit); /* Create a bone */ bone = ED_armature_edit_bone_add(obedit->data, name); copy_v3_v3(bone->head, curs); if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1 else add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); return OPERATOR_FINISHED; }
static int tree_element_active_ebone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), int set, bool recursive) { bArmature *arm = scene->obedit->data; EditBone *ebone = te->directdata; int status = 0; if (set) { if (set == 1) { if (!(ebone->flag & BONE_HIDDEN_A)) { ED_armature_deselect_all(scene->obedit, 0); // deselect tree_element_active_ebone__sel(C, scene, arm, ebone, TRUE); status = 1; } } else if (set == 2) { if (!(ebone->flag & BONE_HIDDEN_A)) { if (!(ebone->flag & BONE_SELECTED)) { tree_element_active_ebone__sel(C, scene, arm, ebone, TRUE); status = 1; } else { /* entirely selected, so de-select */ tree_element_active_ebone__sel(C, scene, arm, ebone, FALSE); status = 0; } } } if (recursive) { /* Recursive select/deselect */ do_outliner_ebone_select_recursive(arm, ebone, (ebone->flag & BONE_SELECTED) != 0); } } else if (ebone->flag & BONE_SELECTED) { status = 1; } return status; }
/* 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; }
/* 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; }
/* bone adding between selected joints */ static int armature_fill_bones_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); bArmature *arm = (obedit) ? obedit->data : NULL; Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); ListBase points = {NULL, NULL}; EditBone *newbone = NULL; int count; /* sanity checks */ if (ELEM(NULL, obedit, arm)) return OPERATOR_CANCELLED; /* loop over all bones, and only consider if visible */ CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones) { if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL)) fill_add_joint(ebone, 0, &points); if (ebone->flag & BONE_TIPSEL) fill_add_joint(ebone, 1, &points); } CTX_DATA_END; /* the number of joints determines how we fill: * 1) between joint and cursor (joint=head, cursor=tail) * 2) between the two joints (order is dependent on active-bone/hierarchy) * 3+) error (a smarter method involving finding chains needs to be worked out */ count = BLI_listbase_count(&points); if (count == 0) { BKE_report(op->reports, RPT_ERROR, "No joints selected"); return OPERATOR_CANCELLED; } else if (count == 1) { EditBonePoint *ebp; float curs[3]; /* Get Points - selected joint */ ebp = points.first; /* Get points - cursor (tail) */ invert_m4_m4(obedit->imat, obedit->obmat); mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d)); /* Create a bone */ newbone = add_points_bone(obedit, ebp->vec, curs); } else if (count == 2) { EditBonePoint *ebp_a, *ebp_b; float head[3], tail[3]; short headtail = 0; /* check that the points don't belong to the same bone */ ebp_a = (EditBonePoint *)points.first; ebp_b = ebp_a->next; if (((ebp_a->head_owner == ebp_b->tail_owner) && (ebp_a->head_owner != NULL)) || ((ebp_a->tail_owner == ebp_b->head_owner) && (ebp_a->tail_owner != NULL))) { BKE_report(op->reports, RPT_ERROR, "Same bone selected..."); BLI_freelistN(&points); return OPERATOR_CANCELLED; } /* find which one should be the 'head' */ if ((ebp_a->head_owner && ebp_b->head_owner) || (ebp_a->tail_owner && ebp_b->tail_owner)) { /* use active, nice predictable */ if (arm->act_edbone && ELEM(arm->act_edbone, ebp_a->head_owner, ebp_a->tail_owner)) { headtail = 1; } else if (arm->act_edbone && ELEM(arm->act_edbone, ebp_b->head_owner, ebp_b->tail_owner)) { headtail = 2; } else { /* rule: whichever one is closer to 3d-cursor */ float curs[3]; float dist_sq_a, dist_sq_b; /* get cursor location */ invert_m4_m4(obedit->imat, obedit->obmat); mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d)); /* get distances */ dist_sq_a = len_squared_v3v3(ebp_a->vec, curs); dist_sq_b = len_squared_v3v3(ebp_b->vec, curs); /* compare distances - closer one therefore acts as direction for bone to go */ headtail = (dist_sq_a < dist_sq_b) ? 2 : 1; } } else if (ebp_a->head_owner) { headtail = 1; } else if (ebp_b->head_owner) { headtail = 2; } /* assign head/tail combinations */ if (headtail == 2) { copy_v3_v3(head, ebp_a->vec); copy_v3_v3(tail, ebp_b->vec); } else if (headtail == 1) { copy_v3_v3(head, ebp_b->vec); copy_v3_v3(tail, ebp_a->vec); } /* add new bone and parent it to the appropriate end */ if (headtail) { newbone = add_points_bone(obedit, head, tail); /* do parenting (will need to set connected flag too) */ if (headtail == 2) { /* ebp tail or head - tail gets priority */ if (ebp_a->tail_owner) newbone->parent = ebp_a->tail_owner; else newbone->parent = ebp_a->head_owner; } else { /* ebp_b tail or head - tail gets priority */ if (ebp_b->tail_owner) newbone->parent = ebp_b->tail_owner; else newbone->parent = ebp_b->head_owner; } /* don't set for bone connecting two head points of bones */ if (ebp_a->tail_owner || ebp_b->tail_owner) { newbone->flag |= BONE_CONNECTED; } } } else { /* FIXME.. figure out a method for multiple bones */ BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count); BLI_freelistN(&points); return OPERATOR_CANCELLED; } if (newbone) { ED_armature_deselect_all(obedit); arm->act_edbone = newbone; newbone->flag |= BONE_TIPSEL; } /* updates */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit); /* free points */ BLI_freelistN(&points); return OPERATOR_FINISHED; }