Separating armatures should now be more stable than it was, but is still too unstable to enable for release. So for now, the old warning stands.

This commit is contained in:
Joshua Leung
2008-05-11 11:53:12 +00:00
parent a2528b4123
commit 1decc569dd

View File

@@ -180,7 +180,7 @@ void make_boneList(ListBase *list, ListBase *bones, EditBone *parent)
/* Add children if necessary */
if (curBone->childbase.first)
make_boneList (list, &curBone->childbase, eBone);
make_boneList(list, &curBone->childbase, eBone);
}
}
@@ -600,25 +600,24 @@ int join_armature(void)
float delta[3];
/* Get the premat */
VecSubf (delta, curbone->tail, curbone->head);
VecSubf(delta, curbone->tail, curbone->head);
vec_roll_to_mat3(delta, curbone->roll, temp);
Mat4MulMat34 (premat, temp, mat);
Mat4MulMat34(premat, temp, mat);
Mat4MulVecfl(mat, curbone->head);
Mat4MulVecfl(mat, curbone->tail);
/* Get the postmat */
VecSubf (delta, curbone->tail, curbone->head);
VecSubf(delta, curbone->tail, curbone->head);
vec_roll_to_mat3(delta, curbone->roll, temp);
Mat4CpyMat3(postmat, temp);
/* Find the roll */
Mat4Invert (imat, premat);
Mat4MulMat4 (difmat, postmat, imat);
Mat4Invert(imat, premat);
Mat4MulMat4(difmat, postmat, imat);
curbone->roll -= atan2(difmat[2][0], difmat[2][2]);
}
/* Fix Constraints and Other Links to this Bone and Armature */
@@ -651,12 +650,15 @@ int join_armature(void)
}
/* Helper function for armature separating - link fixing */
static void separated_armature_fix_links(Object *origArm, Object *newArm, ListBase *edbo)
static void separated_armature_fix_links(Object *origArm, Object *newArm)
{
Object *ob;
bPoseChannel *pchan;
bPoseChannel *pchan, *pcha, *pchb;
bConstraint *con;
EditBone *ebo, *ebn;
ListBase *npchans;
/* get reference to list of bones in new armature */
npchans= &newArm->pose->chanbase;
/* let's go through all objects in database */
for (ob= G.main->object.first; ob; ob= ob->id.next) {
@@ -675,27 +677,21 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm, ListBa
for (ct= targets.first; ct; ct= ct->next) {
/* any targets which point to original armature are redirected to the new one only if:
* - the target isn't the original armature itself
* - the target is one of the bones which were moved into newArm
* - the target is one that can be found in newArm
*/
if ((ct->tar == origArm) && (ct->subtarget[0] != 0)) {
for (ebo=edbo->first, ebn=edbo->last; ebo && ebn; ebo=ebo->next, ebn=ebn->prev) {
for (pcha=npchans->first, pchb=npchans->last; pcha && pchb; pcha=pcha->next, pchb=pchb->prev) {
/* check if either one matches */
if ( (strcmp(ebo->name, ct->subtarget)==0) ||
(strcmp(ebn->name, ct->subtarget)==0) )
if ( (strcmp(pcha->name, ct->subtarget)==0) ||
(strcmp(pchb->name, ct->subtarget)==0) )
{
ct->tar= newArm;
printf("arm = '%s' pchan = '%s', ebo = '%s', YES \n", ob->id.name+2, pchan->name, ebo->name);
printf("arm = '%s' pchan = '%s', ebn = '%s', YES \n", ob->id.name+2, pchan->name, ebn->name);
break;
}
else {
printf("arm = '%s' pchan = '%s', ebo = '%s', NOT\n", ob->id.name+2, pchan->name, ebo->name);
printf("arm = '%s' pchan = '%s', ebn = '%s', NOT \n", ob->id.name+2, pchan->name, ebn->name);
}
/* check if both ends have met (to stop checking) */
if (ebo == ebn) break;
}
if (pcha == pchb) break;
}
}
}
@@ -723,17 +719,17 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm, ListBa
* - the target is one of the bones which were moved into newArm
*/
if ((ct->tar == origArm) && (ct->subtarget[0] != 0)) {
for (ebo=edbo->first, ebn=edbo->last; ebo && ebn; ebo=ebo->next, ebn=ebn->prev) {
for (pcha=npchans->first, pchb=npchans->last; pcha && pchb; pcha=pcha->next, pchb=pchb->prev) {
/* check if either one matches */
if ( (strcmp(ebo->name, ct->subtarget)==0) ||
(strcmp(ebn->name, ct->subtarget)==0) )
if ( (strcmp(pcha->name, ct->subtarget)==0) ||
(strcmp(pchb->name, ct->subtarget)==0) )
{
ct->tar= newArm;
break;
}
/* check if both ends have met (to stop checking) */
if (ebo == ebn) break;
if (pcha == pchb) break;
}
}
}
@@ -749,34 +745,86 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm, ListBa
/* Is object parented to a bone of this src armature? */
if (ob->partype==PARBONE) {
/* bone name in object */
for (ebo=edbo->first, ebn=edbo->last; ebo && ebn; ebo=ebo->next, ebn=ebn->prev) {
for (pcha=npchans->first, pchb=npchans->last; pcha && pchb; pcha=pcha->next, pchb=pchb->prev) {
/* check if either one matches */
if ( (strcmp(ebo->name, ob->parsubstr)==0) ||
(strcmp(ebn->name, ob->parsubstr)==0) )
if ( (strcmp(pcha->name, ob->parsubstr)==0) ||
(strcmp(pchb->name, ob->parsubstr)==0) )
{
ob->parent= newArm;
break;
}
/* check if both ends have met (to stop checking) */
if (ebo == ebn) break;
if (pcha == pchb) break;
}
}
}
}
}
/* 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
*/
static void separate_armature_bones (Object *ob, short sel)
{
ListBase edbo = {NULL, NULL};
bArmature *arm= (bArmature *)ob->data;
bPoseChannel *pchan, *pchann;
EditBone *curbone;
/* make local set of editbones to manipulate here */
make_boneList(&edbo, &arm->bonebase, NULL);
/* 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(&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= 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 editbones_to_armature */
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 */
if (pchan->path) MEM_freeN(pchan->path);
free_constraints(&pchan->constraints);
/* get rid of unneeded bone */
BLI_freelinkN(&edbo, curbone);
BLI_freelinkN(&ob->pose->chanbase, pchan);
}
}
/* exit editmode (recalculates pchans too) */
editbones_to_armature(&edbo, ob);
BLI_freelistN(&edbo);
}
void separate_armature (void)
{
EditBone *ebo, *ebn;
Object *oldob;
Base *base, *oldbase;
Object *oldob, *newob;
Base *base, *oldbase, *newbase;
bArmature *arm;
ListBase edbo = {NULL, NULL};
// 31Mar08 - Aligorith:
// this tool is currently not ready for production use, as it will still
// crash in some cases, and also constraint relinking isn't working yet
// 31 Mar 08 \ 11 May 08 - Aligorith:
// currently, this is still too unstable to be enabled for general consumption.
// remove the following two lines to test this tool... you have been warned!
okee("Not implemented (WIP)");
return;
@@ -788,77 +836,58 @@ void separate_armature (void)
arm= G.obedit->data;
/* we are going to trick everything as follows:
* 1. duplicate base: this is the new one, remember old pointer
* 2. set aside all NOT selected bones
* 3. load_editArmature(): this will be the new base
* 4. freelist and restore old armature
/* we are going to do this as follows (unlike every other instance of separate):
* 1. exit editmode for active armature/base. Take note of what this is.
* 2. duplicate base - BASACT is the new one now
* 3. for each of the two armatures, enter editmode -> remove appropriate bones -> exit editmode + recalc
* 4. fix constraint links
* 5. make original armature active and enter editmode
*/
/* only edit-base selected */
/* 1) only edit-base selected */
base= FIRSTBASE;
while(base) {
if(base->lay & G.vd->lay) {
if(base->object==G.obedit) base->flag |= 1;
for (base= FIRSTBASE; base; base= base->next) {
if (base->lay & G.vd->lay) {
if (base->object==G.obedit) base->flag |= 1;
else base->flag &= ~1;
}
base= base->next;
}
/* set aside: everything that is not selected */
for (ebo= G.edbo.first; ebo; ebo= ebn) {
ebn= ebo->next;
/* remove from original, and move to duplicate if not-selected */
if ((ebo->flag & BONE_SELECTED)==0) {
EditBone *curbone;
/* need to make sure children don't still refer to this only if they are selected
* - potentially slow O(n*n) situation here...
*/
for (curbone= G.edbo.first; curbone; curbone=curbone->next) {
if ((curbone->parent == ebo) && (curbone->flag & BONE_SELECTED)) {
curbone->parent= ebo->parent;
curbone->flag &= ~BONE_CONNECTED;
}
}
BLI_remlink(&G.edbo, ebo);
BLI_addtail(&edbo, ebo);
}
}
/* 1) store starting settings and exit editmode */
oldob= G.obedit;
oldbase= BASACT;
adduplicate(1, 0); /* no transform and zero so do get a linked dupli */
G.obedit= BASACT->object; /* basact is set in adduplicate() */
G.obedit->data= copy_armature(arm);
/* because new armature is a copy: reduce user count */
arm->id.us--;
load_editArmature();
free_editArmature();
BASACT->flag &= ~SELECT;
/* 2) duplicate base */
adduplicate(1, USER_DUP_ARM); /* no transform and zero so do get a linked dupli */
/* fix links before depsgraph flushes */ // err... or after?
printf("oldob = %p, obact = %p \n", oldob, G.obedit);
separated_armature_fix_links(oldob, G.obedit, &G.edbo);
newbase= BASACT; /* basact is set in adduplicate() */
newob= newbase->object;
newbase->flag &= ~SELECT;
if (G.edbo.first) free_editArmature();
G.edbo = edbo;
/* 3) remove bones that shouldn't still be around on both armatures */
separate_armature_bones(oldob, 1);
separate_armature_bones(newob, 0);
/* 4) fix links before depsgraph flushes */ // err... or after?
separated_armature_fix_links(oldob, newob);
G.obedit= 0; /* displists behave different in edit mode */ // needed?
DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA); /* this is the separated one */
DAG_object_flush_update(G.scene, oldob, OB_RECALC_DATA); /* this is the original one */
DAG_object_flush_update(G.scene, newob, OB_RECALC_DATA); /* this is the separated one */
/* 5) restore original conditions */
G.obedit= oldob;
BASACT= oldbase;
BASACT->flag |= SELECT;
make_editArmature();
/* recalc/redraw + cleanup */
waitcursor(0);
countall();
@@ -1442,9 +1471,10 @@ void delete_armature(void)
for (curBone=G.edbo.first;curBone;curBone=next) {
next=curBone->next;
if (arm->layer & curBone->layer)
if (arm->layer & curBone->layer) {
if (curBone->flag & BONE_SELECTED)
delete_bone(curBone);
}
}