diff options
author | Joshua Leung <aligorith@gmail.com> | 2008-09-26 12:51:05 +0400 |
---|---|---|
committer | Joshua Leung <aligorith@gmail.com> | 2008-09-26 12:51:05 +0400 |
commit | 1206061ed431a37c31271364c0ed346809c3abc3 (patch) | |
tree | 2dfac9ee09f607d886d9455d660df7eb19af1bdd /source | |
parent | 06a5e9b58a0c1281609ee1ddb850fc058fe56c4f (diff) |
Patch #17346: Align bones in edit mode
Submitted by: Lorenzo Pierfederici (lento)
This patch adds the CTRL-ALT-A hotkey to align bones in armature edit mode.
It works the same way as parenting: selected bones will be aligned with active bone, if only one bone is selected it
will be aligned with its parent (if any)
Thanks!
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/include/BIF_editarmature.h | 3 | ||||
-rw-r--r-- | source/blender/src/editarmature.c | 137 | ||||
-rw-r--r-- | source/blender/src/space.c | 7 |
3 files changed, 145 insertions, 2 deletions
diff --git a/source/blender/include/BIF_editarmature.h b/source/blender/include/BIF_editarmature.h index fdd00a67465..d390b96f61f 100644 --- a/source/blender/include/BIF_editarmature.h +++ b/source/blender/include/BIF_editarmature.h @@ -139,6 +139,8 @@ void hide_selected_armature_bones(void); void hide_unselected_armature_bones(void); void show_all_armature_bones(void); +void align_selected_bones(void); + #define BONESEL_ROOT 0x10000000 #define BONESEL_TIP 0x20000000 #define BONESEL_BONE 0x40000000 @@ -157,3 +159,4 @@ void show_all_armature_bones(void); #endif + diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c index 5e50c8117cc..d5e5b5a1c4a 100644 --- a/source/blender/src/editarmature.c +++ b/source/blender/src/editarmature.c @@ -3310,6 +3310,143 @@ void switch_direction_armature (void) BIF_undo_push("Switch Direction"); } +/* editbone alignment */ + +/* helper to fix a ebone position if its parent has moved due to alignment*/ +static void fix_connected_bone(EditBone *ebone) +{ + float diff[3]; + + if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) || VecEqual(ebone->parent->tail, ebone->head)) + return; + + /* if the parent has moved we translate child's head and tail accordingly*/ + VecSubf(diff, ebone->parent->tail, ebone->head); + VecAddf(ebone->head, ebone->head, diff); + VecAddf(ebone->tail, ebone->tail, diff); + return; +} + +/* helper to recursively find chains of connected bones starting at ebone and fix their position */ +static void fix_editbone_connected_children(EditBone *ebone) +{ + EditBone *selbone; + + for (selbone = G.edbo.first; selbone; selbone=selbone->next) { + if ((selbone->parent) && (selbone->parent == ebone) && (selbone->flag & BONE_CONNECTED)) { + fix_connected_bone(selbone); + fix_editbone_connected_children(selbone); + } + } + return; +} + +static void bone_align_to_bone(EditBone *selbone, EditBone *actbone) +{ + float selboneaxis[3], actboneaxis[3], length; + + VecSubf(actboneaxis, actbone->tail, actbone->head); + Normalize(actboneaxis); + + VecSubf(selboneaxis, selbone->tail, selbone->head); + length = VecLength(selboneaxis); + + VecMulf(actboneaxis, length); + VecAddf(selbone->tail, selbone->head, actboneaxis); + selbone->roll = actbone->roll; + + /* if the bone being aligned has connected descendants they must be moved + according to their parent new position, otherwise they would be left + in an unconsistent state: connected but away from the parent*/ + fix_editbone_connected_children(selbone); + return; +} + +void align_selected_bones(void) +{ + bArmature *arm= G.obedit->data; + EditBone *actbone, *ebone, *selbone; + EditBone *flipbone, *flippar; + short allchildbones= 0, foundselbone= 0; + + /* find active bone to align to */ + for (actbone = G.edbo.first; actbone; actbone=actbone->next) { + if (arm->layer & actbone->layer) { + if (actbone->flag & BONE_ACTIVE) + break; + } + } + if (actbone == NULL) { + error("Needs an active bone"); + return; + } + + /* find selected bones */ + for (ebone = G.edbo.first; ebone; ebone=ebone->next) { + if (arm->layer & ebone->layer) { + if ((ebone->flag & BONE_SELECTED) && (ebone != actbone)) { + foundselbone++; + if (ebone->parent != actbone) allchildbones= 1; + } + } + } + /* abort if no selected bones, and active bone doesn't have a parent to work with instead */ + if (foundselbone==0 && actbone->parent==NULL) { + error("Need selected bone(s)"); + return; + } + + if (foundselbone==0 && actbone->parent) { + /* When only the active bone is selected, and it has a parent, + * align it to the parent, as that is the only possible outcome. + */ + bone_align_to_bone(actbone, actbone->parent); + + if (arm->flag & ARM_MIRROR_EDIT) { + flipbone = armature_bone_get_mirrored(actbone); + if (flipbone) + bone_align_to_bone(flipbone, flipbone->parent); + } + } + else { + /* loop through all editbones, aligning all selected bones to the active bone */ + for (selbone = G.edbo.first; selbone; selbone=selbone->next) { + if (arm->layer & selbone->layer) { + if ((selbone->flag & BONE_SELECTED) && (selbone!=actbone)) { + /* align selbone to actbone */ + bone_align_to_bone(selbone, actbone); + + if (arm->flag & ARM_MIRROR_EDIT) { + /* - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone + * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R"). + * This is useful for arm-chains, for example parenting lower arm to upper arm + * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent") + * then just use actbone. Useful when doing upper arm to spine. + */ + flipbone = armature_bone_get_mirrored(selbone); + flippar = armature_bone_get_mirrored(actbone); + + if (flipbone) { + if (flippar) + bone_align_to_bone(flipbone, flippar); + else + bone_align_to_bone(flipbone, actbone); + } + } + } + } + } + } + + countall(); /* checks selection */ + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWOOPS, 0); + BIF_undo_push("Align bones"); + + return; +} + /* ***************** Pose tools ********************* */ void clear_armature(Object *ob, char mode) diff --git a/source/blender/src/space.c b/source/blender/src/space.c index d4460e55a3e..92b5580775e 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -1864,8 +1864,11 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) break; case AKEY: - if (G.obedit == 0 && G.qual == (LR_CTRLKEY|LR_ALTKEY)) { - alignmenu(); + if(G.qual == (LR_CTRLKEY|LR_ALTKEY)) { + if(G.obedit == 0) + alignmenu(); + else if(G.obedit->type==OB_ARMATURE) + align_selected_bones(); } else if(G.qual & LR_CTRLKEY) { /* also with shift! */ apply_object(); |