static bool armature_dissolve_ebone_cb(const char *bone_name, void *arm_p) { bArmature *arm = arm_p; EditBone *ebone; ebone = ED_armature_bone_find_name(arm->edbo, bone_name); return (ebone && (ebone->flag & BONE_DONE)); }
static bool armature_delete_ebone_cb(const char *bone_name, void *arm_p) { bArmature *arm = arm_p; EditBone *ebone; ebone = ED_armature_bone_find_name(arm->edbo, bone_name); return (ebone && (ebone->flag & BONE_SELECTED) && (arm->layer & ebone->layer)); }
/* Helper function for armature separating - remove certain bones from the given armature * sel: remove selected bones from the armature, otherwise the unselected bones are removed * (ob is not in editmode) */ static void separate_armature_bones(Object *ob, short sel) { bArmature *arm = (bArmature *)ob->data; bPoseChannel *pchan, *pchann; EditBone *curbone; /* make local set of editbones to manipulate here */ ED_armature_to_edit(arm); /* go through pose-channels, checking if a bone should be removed */ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchann) { pchann = pchan->next; curbone = ED_armature_bone_find_name(arm->edbo, pchan->name); /* check if bone needs to be removed */ if ( (sel && (curbone->flag & BONE_SELECTED)) || (!sel && !(curbone->flag & BONE_SELECTED)) ) { EditBone *ebo; bPoseChannel *pchn; /* clear the bone->parent var of any bone that had this as its parent */ for (ebo = arm->edbo->first; ebo; ebo = ebo->next) { if (ebo->parent == curbone) { ebo->parent = NULL; ebo->temp = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */ ebo->flag &= ~BONE_CONNECTED; } } /* clear the pchan->parent var of any pchan that had this as its parent */ for (pchn = ob->pose->chanbase.first; pchn; pchn = pchn->next) { if (pchn->parent == pchan) pchn->parent = NULL; } /* free any of the extra-data this pchan might have */ BKE_pose_channel_free(pchan); BKE_pose_channels_hash_free(ob->pose); /* get rid of unneeded bone */ bone_free(arm, curbone); BLI_freelinkN(&ob->pose->chanbase, pchan); } } /* exit editmode (recalculates pchans too) */ ED_armature_from_edit(ob->data); ED_armature_edit_free(ob->data); }
/** * \see #BKE_pose_channel_get_mirrored (pose-mode, matching function) */ EditBone *ED_armature_bone_get_mirrored(const ListBase *edbo, EditBone *ebo) { char name_flip[MAXBONENAME]; if (ebo == NULL) return NULL; BLI_string_flip_side_name(name_flip, ebo->name, false, sizeof(name_flip)); if (!STREQ(name_flip, ebo->name)) { return ED_armature_bone_find_name(edbo, name_flip); } return NULL; }
/* note: there's a unique_bone_name() too! */ static bool editbone_unique_check(void *arg, const char *name) { struct {ListBase *lb; void *bone; } *data = arg; EditBone *dupli = ED_armature_bone_find_name(data->lb, name); return dupli && dupli != data->bone; }
/* seems messy, but thats what you get with not using pointers but channel names :) */ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *newnamep) { Object *ob; char newname[MAXBONENAME]; char oldname[MAXBONENAME]; /* names better differ! */ if (strncmp(oldnamep, newnamep, MAXBONENAME)) { /* we alter newname string... so make copy */ BLI_strncpy(newname, newnamep, MAXBONENAME); /* we use oldname for search... so make copy */ BLI_strncpy(oldname, oldnamep, MAXBONENAME); /* now check if we're in editmode, we need to find the unique name */ if (arm->edbo) { EditBone *eBone = ED_armature_bone_find_name(arm->edbo, oldname); if (eBone) { unique_editbone_name(arm->edbo, newname, NULL); BLI_strncpy(eBone->name, newname, MAXBONENAME); } else { return; } } else { Bone *bone = BKE_armature_find_bone_name(arm, oldname); if (bone) { unique_bone_name(arm, newname); BLI_strncpy(bone->name, newname, MAXBONENAME); } else { return; } } /* do entire dbase - objects */ for (ob = G.main->object.first; ob; ob = ob->id.next) { ModifierData *md; /* we have the object using the armature */ if (arm == ob->data) { Object *cob; /* Rename the pose channel, if it exists */ if (ob->pose) { bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, oldname); if (pchan) { GHash *gh = ob->pose->chanhash; /* remove the old hash entry, and replace with the new name */ if (gh) { BLI_assert(BLI_ghash_haskey(gh, pchan->name)); BLI_ghash_remove(gh, pchan->name, NULL, NULL); } BLI_strncpy(pchan->name, newname, MAXBONENAME); if (gh) { BLI_ghash_insert(gh, pchan->name, pchan); } } BLI_assert(BKE_pose_channels_is_valid(ob->pose) == true); } /* Update any object constraints to use the new bone name */ for (cob = G.main->object.first; cob; cob = cob->id.next) { if (cob->constraints.first) constraint_bone_name_fix(ob, &cob->constraints, oldname, newname); if (cob->pose) { bPoseChannel *pchan; for (pchan = cob->pose->chanbase.first; pchan; pchan = pchan->next) { constraint_bone_name_fix(ob, &pchan->constraints, oldname, newname); } } } } /* See if an object is parented to this armature */ if (ob->parent && (ob->parent->data == arm)) { if (ob->partype == PARBONE) { /* bone name in object */ if (!strcmp(ob->parsubstr, oldname)) BLI_strncpy(ob->parsubstr, newname, MAXBONENAME); } } if (modifiers_usesArmature(ob, arm)) { bDeformGroup *dg = defgroup_find_name(ob, oldname); if (dg) { BLI_strncpy(dg->name, newname, MAXBONENAME); } } /* fix modifiers that might be using this name */ for (md = ob->modifiers.first; md; md = md->next) { switch (md->type) { case eModifierType_Hook: { HookModifierData *hmd = (HookModifierData *)md; if (hmd->object && (hmd->object->data == arm)) { if (STREQ(hmd->subtarget, oldname)) BLI_strncpy(hmd->subtarget, newname, MAXBONENAME); } break; } case eModifierType_UVWarp: { UVWarpModifierData *umd = (UVWarpModifierData *)md; if (umd->object_src && (umd->object_src->data == arm)) { if (STREQ(umd->bone_src, oldname)) BLI_strncpy(umd->bone_src, newname, MAXBONENAME); } if (umd->object_dst && (umd->object_dst->data == arm)) { if (STREQ(umd->bone_dst, oldname)) BLI_strncpy(umd->bone_dst, newname, MAXBONENAME); } break; } default: break; } } } /* Fix all animdata that may refer to this bone - we can't just do the ones attached to objects, since * other ID-blocks may have drivers referring to this bone [#29822] */ { BKE_all_animdata_fix_paths_rename(&arm->id, "pose.bones", oldname, newname); } /* correct view locking */ { bScreen *screen; for (screen = G.main->screen.first; screen; screen = screen->id.next) { ScrArea *sa; /* add regions */ for (sa = screen->areabase.first; sa; sa = sa->next) { SpaceLink *sl; for (sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype == SPACE_VIEW3D) { View3D *v3d = (View3D *)sl; if (v3d->ob_centre && v3d->ob_centre->data == arm) { if (!strcmp(v3d->ob_centre_bone, oldname)) { BLI_strncpy(v3d->ob_centre_bone, newname, MAXBONENAME); } } } } } } } } }
/** * 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; }
/* set the current pose as the restpose */ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object bArmature *arm = BKE_armature_from_object(ob); bPose *pose; bPoseChannel *pchan; EditBone *curbone; /* don't check if editmode (should be done by caller) */ if (ob->type != OB_ARMATURE) return OPERATOR_CANCELLED; if (BKE_object_obdata_is_libdata(ob)) { BKE_report(op->reports, RPT_ERROR, "Cannot apply pose to lib-linked armature"); /* error_libdata(); */ return OPERATOR_CANCELLED; } /* helpful warnings... */ /* TODO: add warnings to be careful about actions, applying deforms first, etc. */ if (ob->adt && ob->adt->action) BKE_report(op->reports, RPT_WARNING, "Actions on this armature will be destroyed by this new rest pose as the " "transforms stored are relative to the old rest pose"); /* Get editbones of active armature to alter */ ED_armature_to_edit(arm); /* get pose of active object and move it out of posemode */ pose = ob->pose; for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { curbone = ED_armature_bone_find_name(arm->edbo, pchan->name); /* simply copy the head/tail values from pchan over to curbone */ copy_v3_v3(curbone->head, pchan->pose_head); copy_v3_v3(curbone->tail, pchan->pose_tail); /* fix roll: * 1. find auto-calculated roll value for this bone now * 2. remove this from the 'visual' y-rotation */ { float premat[3][3], imat[3][3], pmat[3][3], tmat[3][3]; float delta[3], eul[3]; /* obtain new auto y-rotation */ sub_v3_v3v3(delta, curbone->tail, curbone->head); vec_roll_to_mat3(delta, 0.0f, premat); invert_m3_m3(imat, premat); /* get pchan 'visual' matrix */ copy_m3_m4(pmat, pchan->pose_mat); /* remove auto from visual and get euler rotation */ mul_m3_m3m3(tmat, imat, pmat); mat3_to_eul(eul, tmat); /* just use this euler-y as new roll value */ curbone->roll = eul[1]; } /* clear transform values for pchan */ zero_v3(pchan->loc); zero_v3(pchan->eul); unit_qt(pchan->quat); unit_axis_angle(pchan->rotAxis, &pchan->rotAngle); pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f; /* set anim lock */ curbone->flag |= BONE_UNKEYED; } /* convert editbones back to bones, and then free the edit-data */ ED_armature_from_edit(arm); ED_armature_edit_free(arm); /* flush positions of posebones */ BKE_pose_where_is(scene, ob); /* fix parenting of objects which are bone-parented */ applyarmature_fix_boneparents(scene, ob); /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); return OPERATOR_FINISHED; }
/* join armature exec is exported for use in object->join objects operator... */ int join_armature_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); bArmature *arm = (ob) ? ob->data : NULL; bPose *pose, *opose; bPoseChannel *pchan, *pchann; EditBone *curbone; float mat[4][4], oimat[4][4]; bool ok = false; /* Ensure we're not in editmode and that the active object is an armature*/ if (!ob || ob->type != OB_ARMATURE) return OPERATOR_CANCELLED; if (!arm || arm->edbo) return OPERATOR_CANCELLED; CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases) { if (base->object == ob) { ok = true; break; } } CTX_DATA_END; /* that way the active object is always selected */ if (ok == false) { BKE_report(op->reports, RPT_WARNING, "Active object is not a selected armature"); return OPERATOR_CANCELLED; } /* Get editbones of active armature to add editbones to */ ED_armature_to_edit(arm); /* get pose of active object and move it out of posemode */ pose = ob->pose; ob->mode &= ~OB_MODE_POSE; CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases) { if ((base->object->type == OB_ARMATURE) && (base->object != ob)) { bArmature *curarm = base->object->data; /* Make a list of editbones in current armature */ ED_armature_to_edit(base->object->data); /* Get Pose of current armature */ opose = base->object->pose; base->object->mode &= ~OB_MODE_POSE; //BASACT->flag &= ~OB_MODE_POSE; /* Find the difference matrix */ invert_m4_m4(oimat, ob->obmat); mul_m4_m4m4(mat, oimat, base->object->obmat); /* Copy bones and posechannels from the object to the edit armature */ for (pchan = opose->chanbase.first; pchan; pchan = pchann) { pchann = pchan->next; curbone = ED_armature_bone_find_name(curarm->edbo, pchan->name); /* Get new name */ unique_editbone_name(arm->edbo, curbone->name, NULL); /* Transform the bone */ { float premat[4][4]; float postmat[4][4]; float difmat[4][4]; float imat[4][4]; float temp[3][3]; /* Get the premat */ ED_armature_ebone_to_mat3(curbone, temp); unit_m4(premat); /* mul_m4_m3m4 only sets 3x3 part */ mul_m4_m3m4(premat, temp, mat); mul_m4_v3(mat, curbone->head); mul_m4_v3(mat, curbone->tail); /* Get the postmat */ ED_armature_ebone_to_mat3(curbone, temp); copy_m4_m3(postmat, temp); /* Find the roll */ invert_m4_m4(imat, premat); mul_m4_m4m4(difmat, imat, postmat); curbone->roll -= (float)atan2(difmat[2][0], difmat[2][2]); } /* Fix Constraints and Other Links to this Bone and Armature */ joined_armature_fix_links(ob, base->object, pchan, curbone); /* Rename pchan */ BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name)); /* Jump Ship! */ BLI_remlink(curarm->edbo, curbone); BLI_addtail(arm->edbo, curbone); BLI_remlink(&opose->chanbase, pchan); BLI_addtail(&pose->chanbase, pchan); BKE_pose_channels_hash_free(opose); BKE_pose_channels_hash_free(pose); } ED_base_object_free_and_unlink(bmain, scene, base); } } CTX_DATA_END; DAG_relations_tag_update(bmain); /* because we removed object(s) */ ED_armature_from_edit(arm); ED_armature_edit_free(arm); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; }