diff options
author | Joshua Leung <aligorith@gmail.com> | 2007-12-13 13:55:10 +0300 |
---|---|---|
committer | Joshua Leung <aligorith@gmail.com> | 2007-12-13 13:55:10 +0300 |
commit | 8e81daa8bc09b5c2ef7c9d26b6c9bc8628d38f02 (patch) | |
tree | 8067e1465416d11c9b5a0db3d77c5dbec650da69 /source/blender/src | |
parent | ac09c432e0000cba5114c29fb11ba0d7f198f62c (diff) |
== 2 New Rigging Tools ==
This commit introduces two (currently only one is actually functional) new features for working with armatures.
* Bone Merging (Alt-M)
It is now possible to select a bunch of linked bones and "merge" them together. Currently, there's only one option to merge bones that are selected and linked to each other in a chain.
* Add Bone Between Joints (FKEY)
This allows you to select a few joints, and have a bone created between them. Currently, this is not yet functional (but the code is there)
Diffstat (limited to 'source/blender/src')
-rw-r--r-- | source/blender/src/editarmature.c | 285 | ||||
-rw-r--r-- | source/blender/src/header_view3d.c | 12 | ||||
-rw-r--r-- | source/blender/src/space.c | 8 |
3 files changed, 293 insertions, 12 deletions
diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c index 7c25afc94c2..51acac45b3f 100644 --- a/source/blender/src/editarmature.c +++ b/source/blender/src/editarmature.c @@ -1488,7 +1488,7 @@ static EditBone *add_editbone(char *name) EditBone *bone= MEM_callocN(sizeof(EditBone), "eBone"); - BLI_strncpy (bone->name, name, 32); + BLI_strncpy(bone->name, name, 32); unique_editbone_name(&G.edbo, bone->name); BLI_addtail(&G.edbo, bone); @@ -1663,6 +1663,19 @@ void addvert_armature(void) while(get_mbut()&R_MOUSE); } +/* adds an EditBone between the nominated locations (should be in the right space) */ +static EditBone *add_points_bone (float head[], float tail[]) +{ + EditBone *ebo; + + ebo= add_editbone("Bone"); + + VECCOPY(ebo->head, head); + VECCOPY(ebo->tail, tail); + + return ebo; +} + static EditBone *get_named_editbone(char *name) { @@ -1858,6 +1871,276 @@ void adduplicate_armature(void) /* *************** END Adding stuff in editmode *************** */ +/* ************** Add/Remove stuff in editmode **************** */ + +/* temporary data-structure for merge/fill bones */ +typedef struct EditBonePoint { + struct EditBonePoint *next, *prev; + + EditBone *head_owner; /* EditBone which uses this point as a 'head' point */ + EditBone *tail_owner; /* EditBone which uses this point as a 'tail' point */ + + float vec[3]; /* the actual location of the point in local/EditMode space */ +} EditBonePoint; + +/* find chain-tips (i.e. bones without children) */ +static void chains_find_tips (ListBase *list) +{ + EditBone *curBone, *ebo; + LinkData *ld; + + /* note: this is potentially very slow ... there's got to be a better way */ + for (curBone= G.edbo.first; curBone; curBone= curBone->next) { + short stop= 0; + + /* is this bone contained within any existing chain? (skip if so) */ + for (ld= list->first; ld; ld= ld->next) { + for (ebo= ld->data; ebo; ebo= ebo->parent) { + if (ebo == curBone) { + stop= 1; + break; + } + } + + if (stop) break; + } + /* skip current bone if it is part of an existing chain */ + if (stop) continue; + + /* is any existing chain part of the chain formed by this bone? */ + stop= 0; + for (ebo= curBone->parent; ebo; ebo= ebo->parent) { + for (ld= list->first; ld; ld= ld->next) { + if (ld->data == ebo) { + ld->data= curBone; + stop= 1; + break; + } + } + + if (stop) break; + } + /* current bone has already been added to a chain? */ + if (stop) continue; + + /* add current bone to a new chain */ + ld= MEM_callocN(sizeof(LinkData), "BoneChain"); + ld->data= curBone; + BLI_addtail(list, ld); + } +} + +/* bone adding between selected joints */ +void fill_bones_armature(void) +{ + bArmature *arm= G.obedit->data; + + ListBase chains = {NULL, NULL}; + LinkData *chain; + + ListBase points = {NULL, NULL}; + EditBonePoint *ebp; + int count; + + EditBone *ebo, *newbone=NULL; + + + // temp... warning about this not being coded (will be fixed) + error("This tool hasn't been coded!"); + return; + + /* get chains */ + chains_find_tips(&chains); + if (chains.first == NULL) return; + + /* traverse chains to find selected joints */ + for (chain= chains.first; chain; chain= chain->next) { + for (ebo= chain->data; ebo; ebo= ebo->parent) { + if (ebo->flag & (BONE_SELECTED|BONE_ACTIVE)) { + + } + else if (ebo->flag & BONE_ROOTSEL) { + + } + else if (ebo->flag & BONE_TIPSEL) { + + } + } + } + + /* the number of joints determines how we fill: + * 1) between joint and cursor (joint=head, cursor=tail) + * 2) between the two joints (order is dependent on active-bone/hierachy) + * 3+) error (a smarter method involving finding chains needs to be worked out + */ + count= BLI_countlist(&points); + + if (count == 1) { + float curs[3]; + + /* Get Points - selected joint */ + ebp= (EditBonePoint *)points.first; + + /* Get points - cursor (tail) */ + VECCOPY (curs, give_cursor()); + + Mat4Invert(G.obedit->imat, G.obedit->obmat); + Mat4MulVecfl(G.obedit->imat, curs); + + /* Create a bone */ + newbone= add_points_bone(ebp->vec, curs); + } + else if (count == 2) { + + } + else { + error("Too many points selected"); // FIXME.. + } + + /* free chains */ + BLI_freelistN(&chains); + + /* undo + updates */ + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSEDIT, 0); + BIF_undo_push("Merge Bones"); +} + +/* this function merges between two bones, removes them and those in-between, + * and adjusts the parent relationships for those in-between + */ +static void bones_merge(EditBone *start, EditBone *end, ListBase *chains) +{ + EditBone *ebo, *ebone, *newbone; + LinkData *chain; + float head[3], tail[3]; + + /* check if same bone */ + if (start == end) { + printf("Error: same bone! \n"); + printf("\tstart = %s, end = %s \n", start->name, end->name); + } + + /* step 1: add a new bone + * - head = head/tail of start (default head) + * - tail = head/tail of end (default tail) + * - parent = parent of start + */ + if ((start->flag & BONE_TIPSEL) && !(start->flag & (BONE_SELECTED|BONE_ACTIVE))) { + VECCOPY(head, start->tail); + } + else { + VECCOPY(head, start->head); + } + if ((end->flag & BONE_ROOTSEL) && !(end->flag & (BONE_SELECTED|BONE_ACTIVE))) { + VECCOPY(tail, end->head); + } + else { + VECCOPY(tail, end->tail); + } + newbone= add_points_bone(head, tail); + newbone->parent = start->parent; + + /* step 2: parent children of in-between bones to newbone */ + for (chain= chains->first; chain; chain= chain->next) { + /* ick: we need to check if parent of each bone in chain is */ + for (ebo= chain->data; ebo; ebo= ebo->parent) { + short found= 0; + + /* try to find which bone from the list to be removed, is the parent */ + for (ebone= end; ebone; ebone= ebone->parent) { + if (ebo->parent == ebone) { + found= 1; + break; + } + } + + /* adjust this bone's parent to newbone then */ + if (found) { + ebo->parent= newbone; + break; + } + } + } + + /* step 3: delete all bones between and including start and end */ + for (ebo= end; ebo; ebo= ebone) { + ebone= (ebo == start) ? (NULL) : (ebo->parent); + BLI_freelinkN(&G.edbo, ebo); + } +} + +/* bone merging - has a menu! */ +void merge_armature(void) +{ + bArmature *arm= G.obedit->data; + short val= 0; + + /* process a menu to determine how to merge */ + // TODO: there's room for more modes of merging stuff... + val= pupmenu("Merge Selected Bones%t|Within Chains%x1"); + if (val <= 0) return; + + if (val == 1) { + /* go down chains, merging bones */ + ListBase chains = {NULL, NULL}; + LinkData *chain, *nchain; + EditBone *ebo; + + /* get chains (ends on chains) */ + chains_find_tips(&chains); + if (chains.first == NULL) return; + + /* each 'chain' is the last bone in the chain (with no children) */ + for (chain= chains.first; chain; chain= nchain) { + EditBone *bstart= NULL, *bend= NULL; + + /* temporarily remove chain from list of chains */ + nchain= chain->next; + BLI_remlink(&chains, chain); + + /* only consider bones that are visible and selected */ + for (ebo= chain->data; ebo; ebo= ebo->parent) { + /* check if visible + selected */ + if ( (arm->layer & ebo->layer) && !(ebo->flag & BONE_HIDDEN_A) && + ((ebo->flag & BONE_CONNECTED) || (ebo->parent==NULL)) && + (ebo->flag & (BONE_SELECTED|BONE_ACTIVE)) ) + { + /* set either end or start (end gets priority, unless it is already set) */ + if (bend == NULL) + bend= ebo; + else + bstart= ebo; + } + else { + /* chain is broken... merge any continous segments then clear */ + if (bstart && bend) + bones_merge(bstart, bend, &chains); + + bstart = NULL; + bend = NULL; + } + } + + /* merge from bstart to bend if something not merged */ + if (bstart && bend) + bones_merge(bstart, bend, &chains); + + /* put back link */ + BLI_insertlinkbefore(&chains, nchain, chain); + } + + BLI_freelistN(&chains); + } + + /* undo + updates */ + countall(); + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSEDIT, 0); + BIF_undo_push("Merge Bones"); +} + +/* ************** END Add/Remove stuff in editmode ************ */ /* *************** Tools in editmode *********** */ diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c index 1085b8598a1..3a86a55a0aa 100644 --- a/source/blender/src/header_view3d.c +++ b/source/blender/src/header_view3d.c @@ -3765,8 +3765,8 @@ static void do_view3d_edit_armaturemenu(void *arg, int event) case 17: /* move to layer */ pose_movetolayer(); break; - case 18: - uv_autocalc_tface(); + case 18: /* merge bones */ + merge_armature(); break; } @@ -3838,6 +3838,8 @@ static uiBlock *view3d_edit_armaturemenu(void *arg_unused) 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, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Merge|Alt M", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, ""); + 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, ""); uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); @@ -3850,11 +3852,7 @@ static uiBlock *view3d_edit_armaturemenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Switch Armature Layers|Shift M", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Move Bone To Layer|M", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, ""); - - uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); - - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "UV Unwrap|U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, ""); - + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefIconTextBlockBut(block, view3d_edit_armature_parentmenu, NULL, ICON_RIGHTARROW_THIN, "Parent", 0, yco-=20, 120, 19, ""); diff --git a/source/blender/src/space.c b/source/blender/src/space.c index 984c1e65feb..2e560b05228 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -1897,7 +1897,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) addsegment_nurb(); } else if(G.obedit->type == OB_ARMATURE) { - //fill_bones_armature(); + fill_bones_armature(); } } else if(G.qual==LR_CTRLKEY) @@ -2161,12 +2161,12 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) pose_movetolayer(); } else if (G.qual==LR_ALTKEY) { - if(G.obedit->type==OB_MESH) { + if (G.obedit->type == OB_MESH) { mergemenu(); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); } - else if (G.obedit == OB_ARMATURE) { - //merge_armature(); + else if (G.obedit->type == OB_ARMATURE) { + merge_armature(); } } else if ((G.qual==0) || (G.qual==LR_CTRLKEY)) { |