diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c index 99c87097bd3..14c81ef1bf5 100644 --- a/source/blender/src/editarmature.c +++ b/source/blender/src/editarmature.c @@ -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); + } }