diff options
-rw-r--r-- | source/blender/include/BIF_editarmature.h | 1 | ||||
-rw-r--r-- | source/blender/src/editarmature.c | 227 | ||||
-rw-r--r-- | source/blender/src/editcurve.c | 2 | ||||
-rw-r--r-- | source/blender/src/header_view3d.c | 7 | ||||
-rw-r--r-- | source/blender/src/space.c | 2 |
5 files changed, 232 insertions, 7 deletions
diff --git a/source/blender/include/BIF_editarmature.h b/source/blender/include/BIF_editarmature.h index 935b93c8626..1be3ec77723 100644 --- a/source/blender/include/BIF_editarmature.h +++ b/source/blender/include/BIF_editarmature.h @@ -93,6 +93,7 @@ void merge_armature(void); void free_editArmature(void); int join_armature(void); +void separate_armature(void); void load_editArmature(void); void make_bone_parent(void); diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c index a93d81e04af..daf26d80145 100644 --- a/source/blender/src/editarmature.c +++ b/source/blender/src/editarmature.c @@ -653,6 +653,223 @@ int join_armature(void) return 1; } +/* Helper function for armature separating - link fixing */ +static void separated_armature_fix_links(Object *origArm, Object *newArm, ListBase *edbo) +{ + Object *ob; + bPoseChannel *pchan; + bConstraint *con; + EditBone *ebo, *ebn; + + /* let's go through all objects in database */ + for (ob= G.main->object.first; ob; ob= ob->id.next) { + /* do some object-type specific things */ + if (ob->type == OB_ARMATURE) { + for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + for (con= pchan->constraints.first; con; con= con->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + /* constraint targets */ + if (cti && cti->get_constraint_targets) { + cti->get_constraint_targets(con, &targets); + + 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 + */ + if ((ct->tar == origArm) && (ct->subtarget[0] != 0)) { + for (ebo=edbo->first, ebn=edbo->last; ebo && ebn; ebo=ebo->next, ebn=ebn->prev) { + /* check if either one matches */ + if ( (strcmp(ebo->name, ct->subtarget)==0) || + (strcmp(ebn->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 (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } + } + } + } + + /* fix object-level constraints */ + if (ob != origArm) { + for (con= ob->constraints.first; con; con= con->next) { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + /* constraint targets */ + if (cti && cti->get_constraint_targets) { + cti->get_constraint_targets(con, &targets); + + 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 + */ + if ((ct->tar == origArm) && (ct->subtarget[0] != 0)) { + for (ebo=edbo->first, ebn=edbo->last; ebo && ebn; ebo=ebo->next, ebn=ebn->prev) { + /* check if either one matches */ + if ( (strcmp(ebo->name, ct->subtarget)==0) || + (strcmp(ebn->name, ct->subtarget)==0) ) + { + ct->tar= newArm; + break; + } + + /* check if both ends have met (to stop checking) */ + if (ebo == ebn) break; + } + } + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } + } + } + + /* See if an object is parented to this armature */ + if ((ob->parent) && (ob->parent == origArm)) { + /* 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) { + /* check if either one matches */ + if ( (strcmp(ebo->name, ob->parsubstr)==0) || + (strcmp(ebn->name, ob->parsubstr)==0) ) + { + ob->parent= newArm; + break; + } + + /* check if both ends have met (to stop checking) */ + if (ebo == ebn) break; + } + } + } + } +} + +void separate_armature (void) +{ + EditBone *ebo, *ebn; + Object *oldob; + Base *base, *oldbase; + 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 + // remove the following two lines to test this tool... you have been warned! + okee("Not implemented (WIP)"); + return; + + if ( G.vd==0 || (G.vd->lay & G.obedit->lay)==0 ) return; + if ( okee("Separate")==0 ) return; + + waitcursor(1); + + 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 + */ + + /* only edit-base selected */ + base= FIRSTBASE; + while(base) { + 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); + } + } + + 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(); + + BASACT->flag &= ~SELECT; + + /* 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); + + if (G.edbo.first) free_editArmature(); + + G.edbo = edbo; + + 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 */ + + G.obedit= oldob; + BASACT= oldbase; + BASACT->flag |= SELECT; + + waitcursor(0); + + countall(); + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWOOPS, 0); +} + /* **************** END tools on Editmode Armature **************** */ /* **************** PoseMode & EditMode *************************** */ @@ -1149,17 +1366,17 @@ static EditBone * get_nearest_editbonepoint (int findunsel, int *selmask) static void delete_bone(EditBone* exBone) { - EditBone *curBone; + EditBone *curBone; - /* Find any bones that refer to this bone */ - for (curBone=G.edbo.first;curBone;curBone=curBone->next){ - if (curBone->parent==exBone){ + /* Find any bones that refer to this bone */ + for (curBone=G.edbo.first;curBone;curBone=curBone->next) { + if (curBone->parent==exBone) { curBone->parent=exBone->parent; curBone->flag &= ~BONE_CONNECTED; } } - BLI_freelinkN (&G.edbo,exBone); + BLI_freelinkN(&G.edbo,exBone); } /* only editmode! */ diff --git a/source/blender/src/editcurve.c b/source/blender/src/editcurve.c index aef4d16e5e1..ae1fe22f61b 100644 --- a/source/blender/src/editcurve.c +++ b/source/blender/src/editcurve.c @@ -449,7 +449,7 @@ void separate_nurb() G.obedit= 0; /* displists behave different in edit mode */ 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 separated one */ + DAG_object_flush_update(G.scene, oldob, OB_RECALC_DATA); /* this is the original one */ G.obedit= oldob; BASACT= oldbase; diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c index f6b0239cd11..d62f69d8492 100644 --- a/source/blender/src/header_view3d.c +++ b/source/blender/src/header_view3d.c @@ -3872,6 +3872,9 @@ static void do_view3d_edit_armaturemenu(void *arg, int event) case 21: armature_autoside_names(event-19); break; + case 22: /* separate */ + separate_armature(); + break; } allqueue(REDRAWVIEW3D, 0); @@ -3961,7 +3964,7 @@ static uiBlock *view3d_edit_armaturemenu(void *arg_unused) uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extrude|E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, ""); - if(arm->flag & ARM_MIRROR_EDIT) + if (arm->flag & ARM_MIRROR_EDIT) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extrude Forked|Shift E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate|Shift D", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, ""); @@ -3969,6 +3972,8 @@ static uiBlock *view3d_edit_armaturemenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Fill Between Joints|F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete|X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Separate|Ctrl Shift P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 22, ""); + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Subdivide|W, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, ""); diff --git a/source/blender/src/space.c b/source/blender/src/space.c index 2f8e540f1c0..ab6c2b0533a 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -2377,6 +2377,8 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) clear_bone_parent(); else if((G.qual==0) && (G.obedit->type==OB_ARMATURE)) select_bone_parent(); + else if((G.qual==(LR_CTRLKEY|LR_SHIFTKEY)) && (G.obedit->type==OB_ARMATURE)) + separate_armature(); else if((G.qual==0) && G.obedit->type==OB_MESH) separatemenu(); else if ((G.qual==0) && ELEM(G.obedit->type, OB_CURVE, OB_SURF)) |