/* 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 = editbone_name_exists(data->lb, name); return dupli && dupli != data->bone; }
/* 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(ob); /* go through pose-channels, checking if a bone should be removed */ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchann) { pchann = pchan->next; curbone = editbone_name_exists(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); ED_armature_edit_free(ob); }
/* join armature exec is exported for use in object->join objects operator... */ int join_armature_exec(bContext *C, wmOperator *UNUSED(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]; /* 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; /* Get editbones of active armature to add editbones to */ ED_armature_to_edit(ob); /* 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); /* 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); mult_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 = editbone_name_exists(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]; float delta[3]; /* Get the premat */ sub_v3_v3v3(delta, curbone->tail, curbone->head); vec_roll_to_mat3(delta, curbone->roll, temp); unit_m4(premat); /* Mat4MulMat34 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 */ sub_v3_v3v3(delta, curbone->tail, curbone->head); vec_roll_to_mat3(delta, curbone->roll, temp); copy_m4_m3(postmat, temp); /* Find the roll */ invert_m4_m4(imat, premat); mult_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(ob); ED_armature_edit_free(ob); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; }
/* 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 = editbone_name_exists(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) { BLI_strncpy(pchan->name, newname, MAXBONENAME); if (ob->pose->chanhash) { GHash *gh = ob->pose->chanhash; /* remove the old hash entry, and replace with the new name */ BLI_ghash_remove(gh, oldname, NULL, NULL); BLI_ghash_insert(gh, pchan->name, pchan); } } } /* 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) { if (md->type == eModifierType_Hook) { HookModifierData *hmd = (HookModifierData *)md; /* uses armature, so may use the affected bone name */ if (hmd->object && (hmd->object->data == arm)) { if (!strcmp(hmd->subtarget, oldname)) BLI_strncpy(hmd->subtarget, newname, MAXBONENAME); } } } } /* 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); } } } } } } } } }