diff options
Diffstat (limited to 'source/blender/src/editarmature.c')
-rw-r--r-- | source/blender/src/editarmature.c | 2574 |
1 files changed, 2574 insertions, 0 deletions
diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c new file mode 100644 index 00000000000..31c9c94fa6f --- /dev/null +++ b/source/blender/src/editarmature.c @@ -0,0 +1,2574 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * editarmature.c: Interface for creating and posing armature objects + */ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#ifdef WIN32 +#include "BLI_winstuff.h" +#endif + +#include "MEM_guardedalloc.h" + +#include "BMF_Api.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_editVert.h" + +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_utildefines.h" +#include "BKE_action.h" +#include "BKE_armature.h" +#include "BKE_constraint.h" +#include "BKE_global.h" +#include "BKE_object.h" + +#include "BIF_gl.h" +#include "BIF_graphics.h" +#include "BIF_interface.h" +#include "BIF_resources.h" +#include "BIF_screen.h" +#include "BIF_space.h" +#include "BIF_toolbox.h" +#include "BIF_editarmature.h" +#include "BIF_poseobject.h" +#include "BIF_mywindow.h" + +#include "BDR_editobject.h" +#include "BDR_drawobject.h" + +#include "BSE_edit.h" +#include "BSE_view.h" +#include "BSE_trans_types.h" +#include "BSE_editaction.h" + +#include "mydevice.h" +#include "interface.h" +#include "blendef.h" +#include "nla.h" + +/* >>>>> FIXME: ARG! Colours should be defined in a header somewhere! */ +/* Note, these came from drawobject.c They really should be in a nice header file somewhere */ +#define B_YELLOW 0x77FFFF +#define B_PURPLE 0xFF70FF + +#define B_CYAN 0xFFFF00 +#define B_AQUA 0xFFBB55 /* 0xFF8833*/ + +extern int tottrans; /* Originally defined in editobject.c */ +extern struct TransOb *transmain; /* Originally defined in editobject.c */ +extern float centre[3], centroid[3]; /* Originally defined in editobject.c */ + +/* Macros */ +#define TEST_EDITARMATURE {if(G.obedit==0) return; if( (G.vd->lay & G.obedit->lay)==0 ) return;} + +/* Local Function Prototypes */ +static void editbones_to_armature (ListBase *bones, Object *ob); +static int editbone_to_parnr (EditBone *bone); + +static void validate_editbonebutton(EditBone *bone); +static void fix_bonelist_roll (ListBase *bonelist, ListBase *editbonelist); +static int select_bonechildren_by_name (struct Bone *bone, char *name, int select); +static void build_bonestring (char *string, struct EditBone *bone); +static void draw_boneverti (float x, float y, float z, float size, int flag); +static void draw_bone (int armflag, int boneflag, unsigned int id, char *name, float length); +static void draw_bonechildren (struct Bone *bone, int flag, unsigned int *index); +static void add_bone_input (struct Object *ob); +static void make_boneList(struct ListBase* list, struct ListBase *bones, struct EditBone *parent); +static void make_bone_menu_children (struct Bone *bone, char *str, int *index); +static void delete_bone(struct EditBone* exBone); +static void clear_armature_children (struct Bone *bone, struct bPose *pose, char mode); +static void parnr_to_editbone(EditBone *bone); + +static int count_bones (struct bArmature *arm, int flagmask, int allbones); + +static int count_bonechildren (struct Bone *bone, int incount, int flagmask, int allbones); +static int add_trans_bonechildren (struct Object* ob, struct Bone* bone, struct TransOb* buffer, int index, char mode); +static void deselect_bonechildren (struct Bone *bone, int mode); +static void selectconnected_posebonechildren (struct Bone *bone); + +static int editbone_name_exists (char* name); +static void unique_editbone_name (char* name); +static void *get_nearest_bone (int findunsel); +static EditBone * get_nearest_editbonepoint (int findunsel, int *selmask); + +static void attach_bone_to_parent(EditBone *bone); +static Bone *get_first_selected_bonechildren (Bone *bone); + + +/* Functions */ + + + +void apply_rot_armature (Object *ob, float mat[3][3]){ + ListBase list; + EditBone *ebone; + bArmature *arm; + + arm = get_armature(ob); + + if (!arm) + return; + + /* Put the armature into editmode */ + list.first= list.last = NULL; + make_boneList(&list, &arm->bonebase, NULL); + + /* Do the rotations */ + for (ebone = list.first; ebone; ebone=ebone->next){ + + { + + /* Fixme: This is essentially duplicated from join_armature */ + + float premat[4][4]; + float postmat[4][4]; + float difmat[4][4]; + float imat[4][4]; + float temp[4][4]; + float delta[3]; + float rmat[4][4]; + + Mat4CpyMat3 (rmat, mat); + /* Get the premat */ + VecSubf (delta, ebone->tail, ebone->head); + make_boneMatrixvr(temp, delta, ebone->roll); + Mat4MulMat4 (premat, temp, rmat); + + Mat4MulVecfl(rmat, ebone->head); + Mat4MulVecfl(rmat, ebone->tail); + + /* Get the postmat */ + VecSubf (delta, ebone->tail, ebone->head); + make_boneMatrixvr(postmat, delta, ebone->roll); + + /* Find the roll */ + Mat4Invert (imat, premat); + Mat4MulMat4 (difmat, postmat, imat); + +#if 0 + printmatrix4 ("Difmat", difmat); +#endif + ebone->roll -=atan(difmat[2][0]/difmat[2][2]); + + if (difmat[0][0]<0) + ebone->roll +=M_PI; + + } + + + } + + /* Turn the list into an armature */ + editbones_to_armature(&list, ob); + + /* Free the editbones */ + if (list.first){ + BLI_freelistN (&list); + } + +} + + + +static Bone *get_first_selected_bonechildren (Bone *bone) +{ + Bone *curbone, *result; + + if (bone->flag & BONE_SELECTED) + return bone; + + for (curbone = bone->childbase.first; curbone; curbone=curbone->next){ + result = get_first_selected_bonechildren(curbone); + if (result) + return result; + }; + + return NULL; +} + +Bone *get_first_selected_bone (void) +{ + Bone *curbone, *result; + bArmature *arm; + + arm = get_armature(OBACT); + if (!arm) + return NULL; + + for (curbone = arm->bonebase.first; curbone; curbone=curbone->next){ + result = get_first_selected_bonechildren(curbone); + if (result) + return result; + } + + return NULL; +} + +void clever_numbuts_posearmature (void) +{ + bArmature *arm; + Bone *bone; + bPoseChannel *chan; + + arm = get_armature(OBACT); + if (!arm) + return; + + bone = get_first_selected_bone(); + + if (!bone) + return; + + add_numbut(0, NUM|FLO, "Loc X:", -G.vd->far, G.vd->far, bone->loc, 0); + add_numbut(1, NUM|FLO, "Loc Y:", -G.vd->far, G.vd->far, bone->loc+1, 0); + add_numbut(2, NUM|FLO, "Loc Z:", -G.vd->far, G.vd->far, bone->loc+2, 0); + + add_numbut(3, NUM|FLO, "Quat X:", -G.vd->far, G.vd->far, bone->quat, 0); + add_numbut(4, NUM|FLO, "Quat Y:", -G.vd->far, G.vd->far, bone->quat+1, 0); + add_numbut(5, NUM|FLO, "Quat Z:", -G.vd->far, G.vd->far, bone->quat+2, 0); + add_numbut(6, NUM|FLO, "Quat W:", -G.vd->far, G.vd->far, bone->quat+3, 0); + + add_numbut(7, NUM|FLO, "Size X:", -G.vd->far, G.vd->far, bone->size, 0); + add_numbut(8, NUM|FLO, "Size Y:", -G.vd->far, G.vd->far, bone->size+1, 0); + add_numbut(9, NUM|FLO, "Size Z:", -G.vd->far, G.vd->far, bone->size+2, 0); + + do_clever_numbuts("Active Bone", 10, REDRAW); + + /* This is similar to code in special_trans_update */ + + if (!G.obpose->pose) G.obpose->pose= MEM_callocN(sizeof(bPose), "pose"); + chan = MEM_callocN (sizeof (bPoseChannel), "transPoseChannel"); + + chan->flag |= POSE_LOC|POSE_ROT|POSE_SIZE; + memcpy (chan->loc, bone->loc, sizeof (chan->loc)); + memcpy (chan->quat, bone->quat, sizeof (chan->quat)); + memcpy (chan->size, bone->size, sizeof (chan->size)); + strcpy (chan->name, bone->name); + + set_pose_channel (G.obpose->pose, chan); + +} + +void clever_numbuts_armature (void) +{ + EditBone *ebone, *child; + + ebone= G.edbo.first; + + for (ebone = G.edbo.first; ebone; ebone=ebone->next){ + if (ebone->flag & BONE_SELECTED) + break; + } + + if (!ebone) + return; + + add_numbut(0, NUM|FLO, "Root X:", -G.vd->far, G.vd->far, ebone->head, 0); + add_numbut(1, NUM|FLO, "Root Y:", -G.vd->far, G.vd->far, ebone->head+1, 0); + add_numbut(2, NUM|FLO, "Root Z:", -G.vd->far, G.vd->far, ebone->head+2, 0); + + add_numbut(3, NUM|FLO, "Tip X:", -G.vd->far, G.vd->far, ebone->tail, 0); + add_numbut(4, NUM|FLO, "Tip Y:", -G.vd->far, G.vd->far, ebone->tail+1, 0); + add_numbut(5, NUM|FLO, "Tip Z:", -G.vd->far, G.vd->far, ebone->tail+2, 0); + + /* Convert roll to degrees */ + ebone->roll *= (180.0F/M_PI); + add_numbut(6, NUM|FLO, "Roll:", -G.vd->far, G.vd->far, &ebone->roll, 0); + + do_clever_numbuts("Active Bone", 7, REDRAW); + + /* Convert roll to radians */ + ebone->roll /= (180.0F/M_PI); + + // Update our parent + if (ebone->parent && ebone->flag & BONE_IK_TOPARENT){ + VECCOPY (ebone->parent->tail, ebone->head); + } + + // Update our children if necessary + for (child = G.edbo.first; child; child=child->next){ + if (child->parent == ebone && child->flag & BONE_IK_TOPARENT){ + VECCOPY (child->head, ebone->tail); + } + } +} + +void select_bone_by_name (bArmature *arm, char *name, int select) +{ + Bone *bone; + + if (!arm) + return; + + for (bone=arm->bonebase.first; bone; bone=bone->next) + if (select_bonechildren_by_name (bone, name, select)) + break; +} + +static int select_bonechildren_by_name (Bone *bone, char *name, int select) +{ + Bone *curBone; + + if (!strcmp (bone->name, name)){ + if (select) + bone->flag |= BONE_SELECTED; + else + bone->flag &= ~BONE_SELECTED; + return 1; + } + + for (curBone=bone->childbase.first; curBone; curBone=curBone->next){ + if (select_bonechildren_by_name (curBone, name, select)) + return 1; + } + + return 0; +} +void selectconnected_armature(void) +{ + EditBone *bone, *curBone, *next; + + if (G.qual & LR_SHIFTKEY) + bone= get_nearest_bone(0); + else + bone= get_nearest_bone(1); + + if (!bone) + return; + + /* Select parents */ + for (curBone=bone; curBone; curBone=next){ + if (G.qual & LR_SHIFTKEY){ + curBone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL); + } + else{ + curBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL); + } + + if (curBone->flag & BONE_IK_TOPARENT) + next=curBone->parent; + else + next=NULL; + } + + /* Select children */ + while (bone){ + for (curBone=G.edbo.first; curBone; curBone=next){ + next = curBone->next; + if (curBone->parent == bone){ + if (curBone->flag & BONE_IK_TOPARENT){ + if (G.qual & LR_SHIFTKEY) + curBone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL); + else + curBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL); + bone=curBone; + break; + } + else{ + bone=NULL; + break; + } + } + } + if (!curBone) + bone=NULL; + + } + + countall(); + allqueue (REDRAWVIEW3D, 0); + +} + +void selectconnected_posearmature(void) +{ + Bone *bone, *curBone, *next; + + if (G.qual & LR_SHIFTKEY) + bone= get_nearest_bone(0); + else + bone = get_nearest_bone(1); + + if (!bone) + return; + + /* Select parents */ + for (curBone=bone; curBone; curBone=next){ + select_actionchannel_by_name (G.obpose->action, curBone->name, !(G.qual & LR_SHIFTKEY)); + if (G.qual & LR_SHIFTKEY) + curBone->flag &= ~BONE_SELECTED; + else + curBone->flag |= BONE_SELECTED; + + if (curBone->flag & BONE_IK_TOPARENT) + next=curBone->parent; + else + next=NULL; + } + + /* Select children */ + for (curBone=bone->childbase.first; curBone; curBone=next){ + selectconnected_posebonechildren (curBone); + } + + countall(); + allqueue (REDRAWVIEW3D, 0); + allqueue (REDRAWACTION, 0); +} + +static void selectconnected_posebonechildren (Bone *bone) +{ + Bone *curBone; + + if (!(bone->flag & BONE_IK_TOPARENT)) + return; + + select_actionchannel_by_name (G.obpose->action, bone->name, !(G.qual & LR_SHIFTKEY)); + + if (G.qual & LR_SHIFTKEY) + bone->flag &= ~BONE_SELECTED; + else + bone->flag |= BONE_SELECTED; + + for (curBone=bone->childbase.first; curBone; curBone=curBone->next){ + selectconnected_posebonechildren (curBone); + } +} + + +char *make_bone_menu (bArmature *arm) +{ + char *menustr=NULL; + Bone *curBone; + int size; + int index=0; + + + // Count the bones + size = (count_bones (arm, 0xFFFFFFFF, 1)*48) + 256; + menustr = MEM_callocN(size, "bonemenu"); + + sprintf (menustr, "Select Bone%%t"); + + for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){ + make_bone_menu_children (curBone, menustr, &index); + } + + return menustr; +} + +static void make_bone_menu_children (Bone *bone, char *str, int *index) +{ + Bone *curBone; + + sprintf (str, "%s|%s%%x%d", str, bone->name, *index); + (*index) ++; + + for (curBone=bone->childbase.first; curBone; curBone=curBone->next) + make_bone_menu_children (curBone, str, index); +} + +void free_editArmature(void) +{ + + /* Clear the editbones list */ + if (G.edbo.first){ + BLI_freelistN (&G.edbo); + } +} + +static EditBone * get_nearest_editbonepoint (int findunsel, int *selmask){ + EditBone *ebone; + GLuint buffer[MAXPICKBUF]; + short hits; + int i, takeNext=0; + int sel; + unsigned int hitresult, hitbone, firstunSel=-1; + + glInitNames(); + hits=selectprojektie(buffer, 0, 0, 0, 0); + + /* See if there are any selected bones in this group */ + if (hits){ + for (i=0; i< hits; i++){ + hitresult = buffer[3+(i*4)]; + if (!(hitresult&BONESEL_NOSEL)){ + + /* Determine which points are selected */ + hitbone = hitresult & ~(BONESEL_ROOT|BONESEL_TIP); + + /* Determine what the current bone is */ + ebone = BLI_findlink(&G.edbo, hitbone); + + /* See if it is selected */ + sel = 0; + if ((hitresult & (BONESEL_TIP|BONESEL_ROOT)) == (BONESEL_TIP|BONESEL_ROOT)) + sel = (ebone->flag & (BONE_TIPSEL| BONE_ROOTSEL)) == (BONE_TIPSEL|BONE_ROOTSEL) ? 1 : 0; + else if (hitresult & BONESEL_TIP) + sel |= ebone->flag & BONE_TIPSEL; + else if (hitresult & BONESEL_ROOT) + sel |= ebone->flag & BONE_ROOTSEL; + if (!findunsel) + sel = !sel; + + if (sel) + takeNext=1; + else{ + if (firstunSel == -1) + firstunSel = hitresult; + if (takeNext){ + *selmask =0; + if (hitresult & BONESEL_ROOT) + *selmask |= BONE_ROOTSEL; + if (hitresult & BONESEL_TIP) + *selmask |= BONE_TIPSEL; + return ebone; + } + } + } + } + + if (firstunSel != -1){ + *selmask = 0; + if (firstunSel & BONESEL_ROOT) + *selmask |= BONE_ROOTSEL; + if (firstunSel & BONESEL_TIP) + *selmask |= BONE_TIPSEL; + return BLI_findlink(&G.edbo, firstunSel & ~(BONESEL_ROOT|BONESEL_TIP)); + } +#if 1 + else{ + *selmask = 0; + if (buffer[3] & BONESEL_ROOT) + *selmask |= BONE_ROOTSEL; + if (buffer[3] & BONESEL_TIP) + *selmask |= BONE_TIPSEL; +#if 1 + return BLI_findlink(&G.edbo, buffer[3] & ~(BONESEL_ROOT|BONESEL_TIP)); +#else + return NULL; +#endif + } +#endif + } + + *selmask = 0; + return NULL; +} + +static void * get_nearest_bone (int findunsel){ + void *firstunSel=NULL, *data; + GLuint buffer[MAXPICKBUF]; + short hits; + int i, takeNext=0; + int sel; + unsigned int hitresult; + Bone *bone; + EditBone *ebone; + + glInitNames(); + hits=selectprojektie(buffer, 0, 0, 0, 0); + + + /* See if there are any selected bones in this group */ + if (hits){ + for (i=0; i< hits; i++){ + hitresult = buffer[3+(i*4)]; + if (!(hitresult&BONESEL_NOSEL)){ + + /* Determine which points are selected */ + hitresult &= ~(BONESEL_ROOT|BONESEL_TIP); + + /* Determine what the current bone is */ + if (!G.obedit){ + bone = get_indexed_bone(OBACT->data, hitresult); + if (findunsel) + sel = (bone->flag & BONE_SELECTED); + else + sel = !(bone->flag & BONE_SELECTED); + data = bone; + } + else{ + ebone = BLI_findlink(&G.edbo, hitresult); + if (findunsel) + sel = (ebone->flag & BONE_SELECTED); + else + sel = !(ebone->flag & BONE_SELECTED); + + data = ebone; + } + + if (sel) + takeNext=1; + else{ + if (!firstunSel) + firstunSel=data; + if (takeNext) + return data; + } + } + } + + if (firstunSel) + return firstunSel; +#if 1 + else{ +#if 1 + if (G.obedit) + return BLI_findlink(&G.edbo, buffer[3] & ~(BONESEL_ROOT|BONESEL_TIP)); + else + return get_indexed_bone(OBACT->data, buffer[3] & ~(BONESEL_ROOT|BONESEL_TIP)); +#else + return NULL; +#endif + } +#endif + } + + return NULL; +} + +void delete_armature(void) +{ + EditBone *curBone, *next; + + TEST_EDITARMATURE; + if(okee("Erase selected")==0) return; + + for (curBone=G.edbo.first;curBone;curBone=next){ + next=curBone->next; + if (curBone->flag&BONE_SELECTED) + delete_bone(curBone); + } + + + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWBUTSCONSTRAINT, 0); + countall(); +} + + +static void delete_bone(EditBone* exBone) +{ + EditBone *curBone; + bPoseChannel *chan; + + /* 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_IK_TOPARENT; + } + } + + /* Erase any associated pose channel */ + if (G.obedit->pose){ + for (chan=G.obedit->pose->chanbase.first; chan; chan=chan->next){ + if (!strcmp (chan->name, exBone->name)){ + free_constraints(&chan->constraints); + BLI_freelinkN (&G.obedit->pose->chanbase, chan); + break; + } + } + } + + + allqueue(REDRAWBUTSCONSTRAINT, 0); + allqueue(REDRAWBUTSEDIT, 0); + + BLI_freelinkN (&G.edbo,exBone); +} + +void remake_editArmature(void) +{ + if(okee("Reload Original data")==0) return; + + make_editArmature(); + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSHEAD, 0); + allqueue(REDRAWBUTSCONSTRAINT, 0); + allqueue(REDRAWBUTSEDIT, 0); +} + +void mouse_armature(void) +{ + EditBone* nearBone = NULL; + int selmask; + + nearBone=get_nearest_editbonepoint(1, &selmask); + + if (nearBone){ + if ((G.qual & LR_SHIFTKEY) && (nearBone->flag & selmask)) + nearBone->flag &= ~selmask; + else + nearBone->flag |= selmask; + + if (!(G.qual & LR_SHIFTKEY)){ + deselectall_armature(); + nearBone->flag |= selmask; + } + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWBUTSCONSTRAINT, 0); + }; + countall(); + rightmouse_transform(); +} + +void make_editArmature(void) +{ + bArmature *arm; + + if (G.obedit==0) + return; + + free_editArmature(); + + arm= get_armature(G.obedit); + if (!arm) + return; + + make_boneList (&G.edbo, &arm->bonebase,NULL); +} + +static void editbones_to_armature (ListBase *list, Object *ob) +{ + bArmature *arm; + EditBone *eBone; + Bone *newBone; + + arm = get_armature(ob); + if (!list) + return; + if (!arm) + return; + + free_bones(arm); + + + /* Copy the bones from the editData into the armature*/ + for (eBone=list->first;eBone;eBone=eBone->next){ + newBone=MEM_callocN (sizeof(Bone), "bone"); + eBone->temp= newBone; /* Associate the real Bones with the EditBones */ + + strcpy (newBone->name, eBone->name); + memcpy (newBone->head, eBone->head, sizeof(float)*3); + memcpy (newBone->tail, eBone->tail, sizeof(float)*3); + newBone->flag=eBone->flag &~(BONE_SELECTED|BONE_HILIGHTED); +// newBone->roll=eBone->roll; + newBone->roll = 0.0F; + + /* >>>>> FIXME: This isn't a very good system: a lot of + pointless copying involved. To be investigated + once things are working better. + */ + + newBone->weight = eBone->weight; + newBone->dist = eBone->dist; + memcpy (newBone->loc, eBone->loc, sizeof(eBone->loc)); + memcpy (newBone->dloc, eBone->dloc, sizeof(eBone->dloc)); +/* memcpy (newBone->orig, eBone->orig, sizeof(eBone->orig));*/ + memcpy (newBone->size, eBone->size, sizeof(eBone->size)); + memcpy (newBone->dsize, eBone->dsize, sizeof(eBone->dsize)); + memcpy (newBone->quat, eBone->quat, sizeof(eBone->quat)); + memcpy (newBone->dquat, eBone->dquat, sizeof(eBone->dquat)); + memcpy (newBone->obmat, eBone->obmat, sizeof(eBone->obmat)); + } + + /* Fix parenting in a separate pass to ensure ebone->bone connections + are valid at this point */ + for (eBone=list->first;eBone;eBone=eBone->next){ + newBone= (Bone*) eBone->temp; + if (eBone->parent){ + newBone->parent=(Bone*) eBone->parent->temp; + BLI_addtail (&newBone->parent->childbase,newBone); + + { + float M_boneRest[4][4]; + float M_parentRest[4][4]; + float iM_parentRest[4][4]; + float delta[3]; + + /* Get the parent's global matrix (rotation only)*/ + VecSubf (delta, eBone->parent->tail, eBone->parent->head); + make_boneMatrixvr(M_parentRest, delta, eBone->parent->roll); + + /* Get this bone's global matrix (rotation only)*/ + VecSubf (delta, eBone->tail, eBone->head); + make_boneMatrixvr(M_boneRest, delta, eBone->roll); + + /* Invert the parent matrix */ + Mat4Invert (iM_parentRest, M_parentRest); + + /* Get the new head and tail */ + VecSubf (newBone->head, eBone->head, eBone->parent->tail); + VecSubf (newBone->tail, eBone->tail, eBone->parent->tail); + + Mat4MulVecfl(iM_parentRest, newBone->head); + Mat4MulVecfl(iM_parentRest, newBone->tail); + + + } + + } + /* ...otherwise add this bone to the armature's bonebase */ + else + BLI_addtail (&arm->bonebase,newBone); + } + + /* Make a pass through the new armature to fix rolling */ + fix_bonelist_roll (&arm->bonebase, list); + /* Get rid of pose channels that may have belonged to deleted bones */ + collect_pose_garbage(ob); + /* Ensure all bones have channels */ + apply_pose_armature(arm, ob->pose, 0); + + /* Calculate and cache the inverse restposition matrices (needed for deformation)*/ + precalc_bonelist_irestmats(&arm->bonebase); +} + + +void load_editArmature(void) +{ + bArmature *arm; + + arm=get_armature(G.obedit); + if (!arm) + return; + +#if 1 + editbones_to_armature(&G.edbo, G.obedit); +#else + free_bones(arm); + + + /* Copy the bones from the editData into the armature*/ + for (eBone=G.edbo.first;eBone;eBone=eBone->next){ + newBone=MEM_callocN (sizeof(Bone), "bone"); + eBone->temp= newBone; /* Associate the real Bones with the EditBones */ + + strcpy (newBone->name, eBone->name); + memcpy (newBone->head, eBone->head, sizeof(float)*3); + memcpy (newBone->tail, eBone->tail, sizeof(float)*3); + newBone->flag=eBone->flag &~(BONE_SELECTED|BONE_HILIGHTED); + // newBone->roll=eBone->roll; + newBone->roll = 0.0F; + + /* >>>>> FIXME: This isn't a very good system: a lot of + pointless copying involved. To be investigated + once things are working better. + */ + + newBone->weight = eBone->weight; + newBone->dist = eBone->dist; + memcpy (newBone->loc, eBone->loc, sizeof(eBone->loc)); + memcpy (newBone->dloc, eBone->dloc, sizeof(eBone->dloc)); +/* memcpy (newBone->orig, eBone->orig, sizeof(eBone->orig));*/ + memcpy (newBone->size, eBone->size, sizeof(eBone->size)); + memcpy (newBone->dsize, eBone->dsize, sizeof(eBone->dsize)); + memcpy (newBone->quat, eBone->quat, sizeof(eBone->quat)); + memcpy (newBone->dquat, eBone->dquat, sizeof(eBone->dquat)); + memcpy (newBone->obmat, eBone->obmat, sizeof(eBone->obmat)); + } + + /* Fix parenting in a separate pass to ensure ebone->bone connections + are valid at this point */ + for (eBone=G.edbo.first;eBone;eBone=eBone->next){ + newBone= (Bone*) eBone->temp; + if (eBone->parent){ + newBone->parent=(Bone*) eBone->parent->temp; + BLI_addtail (&newBone->parent->childbase,newBone); + + { + float M_boneRest[4][4]; + float M_parentRest[4][4]; + float M_relativeBone[4][4]; + float iM_parentRest[4][4]; + float delta[3]; + + /* Get the parent's global matrix (rotation only)*/ + VecSubf (delta, eBone->parent->tail, eBone->parent->head); + make_boneMatrixvr(M_parentRest, delta, eBone->parent->roll); + + /* Get this bone's global matrix (rotation only)*/ + VecSubf (delta, eBone->tail, eBone->head); + make_boneMatrixvr(M_boneRest, delta, eBone->roll); + + /* Invert the parent matrix */ + Mat4Invert (iM_parentRest, M_parentRest); + + /* Get the new head and tail */ + VecSubf (newBone->head, eBone->head, eBone->parent->tail); + VecSubf (newBone->tail, eBone->tail, eBone->parent->tail); + + Mat4MulVecfl(iM_parentRest, newBone->head); + Mat4MulVecfl(iM_parentRest, newBone->tail); + + + } + + } + /* ...otherwise add this bone to the armature's bonebase */ + else + BLI_addtail (&arm->bonebase,newBone); + } + + /* Make a pass through the new armature to fix rolling */ + fix_bonelist_roll (&arm->bonebase, &G.edbo); + + /* Get rid of pose channels that may have belonged to deleted bones */ + collect_pose_garbage(G.obedit); +#endif +} + +static void fix_bonelist_roll (ListBase *bonelist, ListBase *editbonelist) +{ + Bone *curBone; + EditBone *ebone; + + for (curBone=bonelist->first; curBone; curBone=curBone->next){ + + /* Fix this bone's roll */ +#if 1 + { + float premat[4][4]; + float postmat[4][4]; + float difmat[4][4]; + float imat[4][4]; + float delta[3]; + + /* Find the associated editbone */ + for (ebone = editbonelist->first; ebone; ebone=ebone->next) + if ((Bone*)ebone->temp == curBone) + break; + + if (ebone){ + /* Get the premat */ + VecSubf (delta, ebone->tail, ebone->head); + make_boneMatrixvr(premat, delta, ebone->roll); + + /* Get the postmat */ + get_objectspace_bone_matrix(curBone, postmat, 1, 0); + postmat[3][0]=postmat[3][1]=postmat[3][2]=0.0F; +#if 1 + Mat4Invert (imat, premat); + Mat4MulMat4 (difmat, postmat, imat); +#else + Mat4Invert (imat, postmat); + Mat4MulMat4 (difmat, premat, imat); +#endif +#if 0 + printf ("Bone %s\n", curBone->name); + printmatrix4 ("premat", premat); + printmatrix4 ("postmat", postmat); + printmatrix4 ("difmat", difmat); + printf ("Roll = %f\n", (-atan(difmat[2][0]/difmat[2][2]) * (180.0/M_PI))); +#endif + curBone->roll = -atan(difmat[2][0]/difmat[2][2]); + + if (difmat[0][0]<0) + curBone->roll +=M_PI; + + } + } +#endif + + fix_bonelist_roll (&curBone->childbase, editbonelist); + } +} + +void make_bone_parent(void) +{ +/* error ("Bone Parenting not yet implemented"); */ + return; +} + +static void make_boneList(ListBase* list, ListBase *bones, EditBone *parent) +{ + EditBone *eBone; + Bone *curBone; + + for (curBone=bones->first; curBone; curBone=curBone->next){ + eBone=MEM_callocN(sizeof(EditBone),"make_editbone"); + + /* Copy relevant data from bone to eBone */ + eBone->parent=parent; + strcpy (eBone->name, curBone->name); + eBone->flag = curBone->flag & ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL); + + /* Print bone matrix before and after */ + + get_bone_root_pos(curBone, eBone->head, 0); + get_bone_tip_pos(curBone, eBone->tail, 0); +// eBone->roll=curBone->roll; + eBone->roll=0; + +#if 1 + { + float delta[3]; + float premat[4][4]; + float postmat[4][4]; + float imat[4][4]; + float difmat[4][4]; + + VecSubf (delta, eBone->tail, eBone->head); + make_boneMatrixvr(postmat, delta, eBone->roll); + + get_objectspace_bone_matrix(curBone, premat, 1, 0); + +#if 0 + Mat4Invert (imat, premat); + Mat4MulMat4 (difmat, postmat, imat); +#else + Mat4Invert (imat, postmat); + Mat4MulMat4 (difmat, premat, imat); +#endif +#if 0 + printf ("Bone %s\n", curBone->name); + printmatrix4 ("diffmat", difmat); + printf ("Roll : atan of %f / %f = %f\n", difmat[2][0], difmat[2][2], (float)atan(difmat[2][0]/difmat[2][2])*(180.0F/M_PI)); +#endif + eBone->roll = atan(difmat[2][0]/difmat[2][2]); + + if (difmat[0][0]<0) + eBone->roll +=M_PI; + } +#endif + eBone->dist= curBone->dist; + eBone->weight= curBone->weight; + memcpy (eBone->loc, curBone->loc, sizeof(curBone->loc)); + memcpy (eBone->dloc, curBone->dloc, sizeof(curBone->dloc)); + /* memcpy (eBone->orig, curBone->orig, sizeof(curBone->orig));*/ + memcpy (eBone->size, curBone->size, sizeof(curBone->size)); + memcpy (eBone->dsize, curBone->dsize, sizeof(curBone->dsize)); + memcpy (eBone->quat, curBone->quat, sizeof(curBone->quat)); + memcpy (eBone->dquat, curBone->dquat, sizeof(curBone->dquat)); + memcpy (eBone->obmat, curBone->obmat, sizeof(curBone->obmat)); + + + BLI_addtail (list, eBone); + + /* Add children if necessary */ + if (curBone->childbase.first) + make_boneList (list, &curBone->childbase, eBone); + } + + +} + +#if 0 +static EditVert* add_armatureVert (float *loc) +{ + EditVert* vert=NULL; + + vert = MEM_callocN (sizeof (EditVert), "armaturevert"); + if (vert){ + VECCOPY (vert->co, loc); + BLI_addtail (&G.edve,vert); + } + + return vert; + +} + +static EditVert* get_armatureVert (float *loc) +{ + EditVert* vert; + + for (vert=G.edve.first;vert;vert=vert->next){ + if ((vert->co[0]==loc[0])&&(vert->co[1]==loc[1])&&(vert->co[2]==loc[2])){ + return (vert); + } + } + + return add_armatureVert (loc); +} +#endif + +void draw_armature(Object *ob) +{ + bArmature *arm; + Bone *bone; + EditBone *eBone; + unsigned int index; + float delta[3],offset[3]; + float bmat[4][4]; + float length; + + if (ob==NULL) return; + + arm= ob->data; + if (arm==NULL) return; + + if (!(ob->lay & G.vd->lay)) + return; + + /* If we're in editmode, draw the Global edit data */ + if(ob==G.obedit || (G.obedit && ob->data==G.obedit->data)) { + cpack (0x000000); + + arm->flag |= ARM_EDITMODE; + for (eBone=G.edbo.first, index=0; eBone; eBone=eBone->next, index++){ + if (ob==G.obedit){ + // if ((eBone->flag&(BONE_TIPSEL | BONE_ROOTSEL))==(BONE_TIPSEL|BONE_ROOTSEL)) + // cpack (B_YELLOW); + // else + cpack (B_PURPLE); + } + else cpack (0x000000); + + glPushMatrix(); + + /* Compose the parent transforms (i.e. their translations) */ + VECCOPY (offset,eBone->head); + + glTranslatef (offset[0],offset[1],offset[2]); + + delta[0]=eBone->tail[0]-eBone->head[0]; + delta[1]=eBone->tail[1]-eBone->head[1]; + delta[2]=eBone->tail[2]-eBone->head[2]; + + length = sqrt (delta[0]*delta[0] + delta[1]*delta[1] +delta[2]*delta[2]); + + make_boneMatrixvr(bmat, delta, eBone->roll); + glMultMatrixf (bmat); + draw_bone (arm->flag, eBone->flag, index, eBone->name, length); + + glPopMatrix(); + if (eBone->parent){ + glLoadName (-1); + setlinestyle(3); + + glBegin(GL_LINES); + glVertex3fv(eBone->parent->tail); + glVertex3fv(eBone->head); + glEnd(); + + setlinestyle(0); + } + }; + arm->flag &= ~ARM_EDITMODE; + cpack (B_YELLOW); + + } + else{ + /* Draw hierarchical bone list (non-edit data) */ + + /* Ensure we're using the mose recent pose */ + if (!ob->pose) + ob->pose=MEM_callocN (sizeof(bPose), "pose"); + +#if 1 /* Activate if there are problems with action lag */ + apply_pose_armature(arm, ob->pose, 0); + where_is_armature (ob); +#endif + + if (G.obpose == ob){ + arm->flag |= ARM_POSEMODE; +#if 0 /* Depreciated interactive ik goal drawing */ + if (arm->chainbase.first){ + glPushMatrix(); + glTranslatef(((PoseChain*)arm->chainbase.first)->goal[0], + ((PoseChain*)arm->chainbase.first)->goal[1], + ((PoseChain*)arm->chainbase.first)->goal[2]); + drawaxes(1.0); + glPopMatrix(); + } +#endif + } + index = 0; + for (bone=arm->bonebase.first; bone; bone=bone->next) { + glPushMatrix(); + draw_bonechildren(bone, arm->flag, &index); + glPopMatrix(); + if (arm->flag & ARM_POSEMODE) + cpack (B_CYAN); + } + + arm->flag &= ~ARM_POSEMODE; + } +} + +static void draw_boneverti (float x, float y, float z, float size, int flag) +{ + GLUquadricObj *qobj; + + size*=0.05; + +/* + Ultimately dots should be drawn in screenspace + For now we'll just draw them any old way. +*/ + glPushMatrix(); + + glTranslatef(x, y, z); + + qobj = gluNewQuadric(); + gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); + gluPartialDisk( qobj, 0, 1.0F*size, 32, 1, 360.0, 360.0); + + glRotatef (90, 0, 1, 0); + gluPartialDisk( qobj, 0, 1.0F*size, 32, 1, 360.0, 360.0); + + glRotatef (90, 1, 0, 0); + gluPartialDisk( qobj, 0, 1.0F*size, 32, 1, 360.0, 360.0); + + gluDeleteQuadric(qobj); + + glPopMatrix(); +} + +static void draw_bonechildren (Bone *bone, int flag, unsigned int *index) +{ + Bone *cbone; + float delta[3]; + float length; + float M_objectspacemat[4][4]; + + if (bone==NULL) return; + + if (flag & ARM_POSEMODE){ + if (bone->flag & BONE_SELECTED) + cpack (B_CYAN); + else + cpack (B_AQUA); + } + + // Draw a line from our root to the parent's tip + if (bone->parent && !(bone->flag & (BONE_IK_TOPARENT|BONE_HIDDEN)) ){ + float childMat[4][4]; + float boneMat[4][4]; + float tip[3], root[3]; + get_objectspace_bone_matrix(bone->parent, boneMat, 0, 1); + get_objectspace_bone_matrix(bone, childMat, 1, 1); + + VECCOPY (tip, boneMat[3]); + VECCOPY (root, childMat[3]); + + if (flag & ARM_POSEMODE) + glLoadName (-1); + setlinestyle(3); + glBegin(GL_LINES); + glVertex3fv(tip); + glVertex3fv(root); + glEnd(); + setlinestyle(0); + } + + + /* Draw this bone in objectspace */ + delta[0]=bone->tail[0]-bone->head[0]; + delta[1]=bone->tail[1]-bone->head[1]; + delta[2]=bone->tail[2]-bone->head[2]; + length = sqrt (delta[0]*delta[0] + delta[1]*delta[1] + delta[2]*delta[2] ); + + /* Incorporates offset, rest rotation, user rotation and parent coordinates*/ + get_objectspace_bone_matrix(bone, M_objectspacemat, 1, 1); + + if (!(bone->flag & BONE_HIDDEN)){ + glPushMatrix(); + glMultMatrixf(M_objectspacemat); + + + if (flag & ARM_POSEMODE) + draw_bone(flag, (bone->parent && bone->parent->flag & BONE_HIDDEN) ? (bone->flag & ~BONE_IK_TOPARENT) : (bone->flag), *index, bone->name, length); + else + draw_bone(flag, (bone->parent && bone->parent->flag & BONE_HIDDEN) ? (bone->flag & ~BONE_IK_TOPARENT) : (bone->flag), -1, bone->name, length); + glPopMatrix(); + } + (*index)++; + + /* Draw the children */ + for (cbone= bone->childbase.first; cbone; cbone=cbone->next){ + draw_bonechildren (cbone, flag, index); + } +} + +static void draw_bone (int armflag, int boneflag, unsigned int id, char *name, float length) +{ + float vec[2]; + float bulge; + float pointsize; + /* + FIXME: This routine should probably draw the bones in screenspace using + the projected start & end points of the transformed bone + */ + + pointsize = length; + if (pointsize<0.1) + pointsize=0.1; + + /* Draw a 3d octahedral bone */ + + bulge=length*0.1; + + if (id!=-1) + glLoadName((GLuint) id ); + + glPushMatrix(); + + /* Draw root point if we have no IK parent */ + if (!(boneflag & BONE_IK_TOPARENT)){ + if (id != -1) + glLoadName (id | BONESEL_ROOT); + if (armflag & ARM_EDITMODE){ + if (boneflag & BONE_ROOTSEL) + cpack (B_YELLOW); + else + cpack (B_PURPLE); + } + draw_boneverti (0, 0, 0, pointsize, 0); + } + + /* Draw tip point (for selection only )*/ + + if (id != -1) + glLoadName (id | BONESEL_TIP); + + if (armflag & ARM_EDITMODE){ + if (boneflag & BONE_TIPSEL) + cpack (B_YELLOW); + else + cpack (B_PURPLE); + } + + draw_boneverti (0, length, 0, pointsize, 0); + + if (id != -1){ + if (armflag & ARM_POSEMODE) + glLoadName((GLuint) id); + else{ +#if 1 /* Bones not selectable in editmode */ + glLoadName((GLuint) -1); +#else + glLoadName ((GLuint) id|BONESEL_TIP|BONESEL_ROOT); +#endif + } + } + + + if (armflag & ARM_EDITMODE){ + if (boneflag & BONE_SELECTED) + cpack (B_YELLOW); + else + cpack (B_PURPLE); + } + + /* Draw additional axes */ + if (armflag & ARM_DRAWAXES){ + drawaxes(length*0.25F); + } + + /* Section 1*/ + glBegin(GL_LINE_STRIP); + vec[0]= vec[1]= 0; + glVertex2fv(vec); + + vec[0]= -bulge; vec[1]= bulge; + glVertex2fv(vec); + + vec[0]= 0; vec[1]= length; + glVertex2fv(vec); + + vec[0]= bulge; vec[1]= bulge; + glVertex2fv(vec); + + vec[0]= 0; vec[1]= 0; + glVertex2fv(vec); + glEnd(); + + /* Section 2*/ + glRotatef(90,0,1,0); + glBegin(GL_LINE_STRIP); + vec[0]= vec[1]= 0; + glVertex2fv(vec); + + vec[0]= -bulge; vec[1]= bulge; + glVertex2fv(vec); + + vec[0]= 0; vec[1]= length; + glVertex2fv(vec); + + vec[0]= bulge; vec[1]= bulge; + glVertex2fv(vec); + + vec[0]= 0; vec[1]= 0; + glVertex2fv(vec); + glEnd(); + + /* Square*/ + glTranslatef (0,bulge,0); + glRotatef(45,0,1,0); + glRotatef(90,1,0,0); + glBegin(GL_LINE_STRIP); + + vec[0]= -bulge*.707;vec[1]=-bulge*.707; + glVertex2fv(vec); + + vec[0]= bulge*.707;vec[1]= -bulge*.707; + glVertex2fv(vec); + + vec[0]= bulge*.707;vec[1]= bulge*.707; + glVertex2fv(vec); + + vec[0]= -bulge*.707;vec[1]= bulge*.707; + glVertex2fv(vec); + + vec[0]= vec[1]= -bulge*.707; + glVertex2fv(vec); + glEnd(); + + + glPopMatrix(); + + /* Draw the bone name */ + if (armflag & ARM_DRAWNAMES){ + glRasterPos3f(0, length/2.0, 0); + BMF_DrawString(G.font, " "); + BMF_DrawString(G.font, name); + } +} + + + +void add_primitiveArmature(int type) +{ + if(G.scene->id.lib) return; + + /* this function also comes from an info window */ + if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return; + if(G.vd==NULL) return; + + check_editmode(OB_ARMATURE); + + /* If we're not the "obedit", make a new object and enter editmode */ + if(G.obedit==NULL) { + add_object(OB_ARMATURE); + base_init_from_view3d(BASACT, G.vd); + G.obedit= BASACT->object; + + where_is_object(G.obedit); + + make_editArmature(); + setcursor_space(SPACE_VIEW3D, CURSOR_EDIT); + } + + switch (type){ + default: + add_bone_input (G.obedit); + break; + }; + + countall(); + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWBUTSHEAD, 0); + allqueue(REDRAWBUTSCONSTRAINT, 0); + allqueue(REDRAWNLA, 0); +} + +static void add_bone_input (Object *ob) +/* + FUNCTION: + Creates a bone chain under user input. + As the user clicks to accept each bone, + a new bone is started as the child and IK + child of the previous bone. Pressing ESC + cancels the current bone and leaves bone + adding mode. + +*/ +{ + float *cursLoc, cent[3], dx, dy; + float mat[3][3], curs[3], cmat[3][3], imat[3][3], rmat[4][4], itmat[4][4]; + short xo, yo, mval[2], afbreek=0; + short val; + float restmat[4][4], tempVec[4]; + EditBone *bone; + EditBone *parent; + unsigned short event; + float angle, scale; + float length, lengths; + float newEnd[4]; + int addbones=1; + float dvec[3], dvecp[3]; + + cursLoc= give_cursor(); + + VECCOPY (curs,cursLoc); + + while (addbones>0){ + afbreek=0; + /* Create an inverse matrix */ + Mat3CpyMat4(mat, G.obedit->obmat); + VECCOPY(cent, curs); + cent[0]-= G.obedit->obmat[3][0]; + cent[1]-= G.obedit->obmat[3][1]; + cent[2]-= G.obedit->obmat[3][2]; + + Mat3CpyMat4(imat, G.vd->viewmat); + Mat3MulVecfl(imat, cent); + + Mat3MulMat3(cmat, imat, mat); + Mat3Inv(imat,cmat); + + /* Create a temporary bone */ + bone= MEM_callocN(sizeof(EditBone), "eBone"); + + /* If we're the child of something, set that up now */ + if (addbones>1){ + parent=G.edbo.last; + bone->parent=parent; + bone->flag|=BONE_IK_TOPARENT; + } + + strcpy (bone->name,"Bone"); + unique_editbone_name (bone->name); + + BLI_addtail(&G.edbo, bone); + + bone->flag |= BONE_QUATROT; + bone->flag |= (BONE_SELECTED); + deselectall_armature(); + bone->flag |= BONE_SELECTED|BONE_HILIGHTED|BONE_TIPSEL|BONE_ROOTSEL; + + bone->weight= 1.0F; + bone->dist= 1.0F; + + /* Project cursor center to screenspace. */ + getmouseco_areawin(mval); + xo= mval[0]; + yo= mval[1]; + window_to_3d(dvecp, xo, yo); + + while (1) { + + getmouseco_areawin(mval); + window_to_3d(dvec, mval[0], mval[1]); + + scale=1000; + + dx= ((float)mval[0]-(float)xo)*scale; + dy= ((float)mval[1]-(float)yo)*scale; + + /* Calc bone length*/ + lengths= sqrt((dx*dx)+(dy*dy)); + length = sqrt(((dvec[0]-dvecp[0])*(dvec[0]-dvecp[0]))+((dvec[1]-dvecp[1])*(dvec[1]-dvecp[1]))+((dvec[2]-dvecp[2])*(dvec[2]-dvecp[2]))); + + /* Find rotation around screen normal */ + if (lengths>0.0F) { + angle= acos(dy/lengths); + if (dx<0.0F) + angle*= -1.0F; + } + else angle= 0.0F; + + /* FIXME: Is there a blender-defined way of making rot and trans matrices? */ + rmat[0][0]= cos (angle); + rmat[0][1]= -sin (angle); + rmat[0][2]= 0.0F; + rmat[0][3]= 0.0F; + rmat[1][0]= sin (angle); + rmat[1][1]= cos (angle); + rmat[1][2]= 0.0F; + rmat[1][3]= 0.0F; + rmat[2][0]= 0.0F; + rmat[2][1]= 0.0F; + rmat[2][2]= 1.0F; + rmat[2][3]= 0.0F; + rmat[3][0]= cent[0]; + rmat[3][1]= cent[1]; + rmat[3][2]= cent[2]; + rmat[3][3]= 1.0F; + + /* Rotate object's inversemat by the bone's rotation + to get the coordinate space of the bone */ + Mat4CpyMat3 (itmat, imat); + Mat4MulMat4 (restmat, rmat, itmat); + + /* Find the bone head */ + tempVec[0]=0; tempVec[1]=0.0F; tempVec[2]=0.0F; tempVec[3]=1.0F; + Mat4MulVec4fl (restmat, tempVec); + VECCOPY (bone->head, tempVec); + + /* Find the bone tail */ + tempVec[0]=0; tempVec[1]=length; tempVec[2]=0.0F; tempVec[3]=1.0F; + Mat4MulVec4fl (restmat, tempVec); + VECCOPY (bone->tail, tempVec); + + /* IF we're a child of something, add the parents' translates */ + + /* Offset of child is new cursor*/ + + VECCOPY (newEnd,bone->tail); newEnd[3]=1; + + /* Set the bone's transformations */ + Mat4One (bone->obmat); + bone->size[0]=bone->size[1]=bone->size[2]=1.0F; + + force_draw(); + while(qtest()) { + event= extern_qread(&val); + if(val) { + switch(event) { + case ESCKEY: + case RIGHTMOUSE: + BLI_freelinkN (&G.edbo,bone); + afbreek=1; + addbones=0; + break; + case LEFTMOUSE: + case MIDDLEMOUSE: + case SPACEKEY: + case RETKEY: + afbreek= 1; + + Mat4MulVec4fl (G.obedit->obmat,newEnd); + + curs[0]=newEnd[0]; + curs[1]=newEnd[1]; + curs[2]=newEnd[2]; + addbones++; + break; + } /* End of case*/ + } /* End of if (val)*/ + if(afbreek) break; + } /* Endd of Qtest loop */ + + if(afbreek) break; + }/* End of positioning loop (while)*/ + } /* End of bone adding loop*/ + + countall(); + +} + +static void validate_editbonebutton_cb(void *bonev, void *arg2_unused) +{ + EditBone *curBone= bonev; + validate_editbonebutton(curBone); +} +static void parnr_to_editbone_cb(void *bonev, void *arg2_unused) +{ + EditBone *curBone= bonev; + parnr_to_editbone(curBone); +} +static void attach_bone_to_parent_cb(void *bonev, void *arg2_unused) +{ + EditBone *curBone= bonev; + attach_bone_to_parent(curBone); +} + +void armaturebuts(void) +{ + bArmature *arm=NULL; + Object *ob=NULL; + uiBlock *block=NULL; + char str[64]; + int bx=148, by=100; + EditBone *curBone; + uiBut *but; + char *boneString=NULL; + int index; + + ob= OBACT; + if (ob==NULL) return; + + sprintf(str, "editbuttonswin %d", curarea->win); + block= uiNewBlock (&curarea->uiblocks, str, UI_EMBOSSX, UI_HELV, curarea->win); + + arm= ob->data; + if (arm==NULL) return; + + uiBlockSetCol(block, BUTGREEN); + uiDefButI(block, TOG|BIT|ARM_RESTPOSBIT,REDRAWVIEW3D, "Rest Pos", bx,by,97,20, &arm->flag, 0, 0, 0, 0, "Disable all animation for this object"); + uiDefButI(block, TOG|BIT|ARM_DRAWAXESBIT,REDRAWVIEW3D, "Draw Axes", bx,by-46,97,20, &arm->flag, 0, 0, 0, 0, "Draw bone axes"); + uiDefButI(block, TOG|BIT|ARM_DRAWNAMESBIT,REDRAWVIEW3D, "Draw Names", bx,by-69,97,20, &arm->flag, 0, 0, 0, 0, "Draw bone names"); + + uiBlockSetCol(block, BUTGREY); + + /* Draw the bone name block */ + + bx+=400; by=200; + + if (G.obedit==ob){ + uiDefBut(block, LABEL, 0, "Selected Bones", bx,by,128,18, 0, 0, 0, 0, 0, ""); + by-=20; + for (curBone=G.edbo.first, index=0; curBone; curBone=curBone->next, index++){ + if (curBone->flag & (BONE_SELECTED)){ + + /* Hide in posemode flag */ + uiBlockSetCol(block, BUTGREEN); + uiDefButI(block, TOG|BIT|BONE_HIDDENBIT, REDRAWVIEW3D, "Hide", bx-50,by,48,18, &curBone->flag, 0, 0, 0, 0, "Toggles display of this bone in posemode"); + + /* Bone naming button */ + uiBlockSetCol(block, BUTGREY); + strcpy (curBone->oldname, curBone->name); + but=uiDefBut(block, TEX, REDRAWVIEW3D, "BO:", bx,by,97,18, &curBone->name, 0, 24, 0, 0, "Change the bone name"); + uiButSetFunc(but, validate_editbonebutton_cb, curBone, NULL); + + uiDefBut(block, LABEL, 0, "child of", bx+106,by,100,18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + + boneString = malloc((BLI_countlist(&G.edbo) * 64)+64); + build_bonestring (boneString, curBone); + + curBone->parNr = editbone_to_parnr(curBone->parent); + but = uiDefButI(block, MENU,REDRAWVIEW3D, boneString, bx+164,by,97,18, &curBone->parNr, 0.0, 0.0, 0.0, 0.0, "Parent"); + uiButSetFunc(but, parnr_to_editbone_cb, curBone, NULL); + + free(boneString); + + /* IK to parent flag */ + if (curBone->parent){ + uiBlockSetCol(block, BUTGREEN); + but=uiDefButI(block, TOG|BIT|BONE_IK_TOPARENTBIT, REDRAWVIEW3D, "IK", bx+275,by,32,18, &curBone->flag, 0.0, 0.0, 0.0, 0.0, "IK link to parent"); + uiButSetFunc(but, attach_bone_to_parent_cb, curBone, NULL); + } + + /* Dist and weight buttons */ + uiBlockSetCol(block, BUTGREY); + uiDefButF(block, NUM,REDRAWVIEW3D, "Dist:", bx+320, by, 110, 18, &curBone->dist, 0.0, 1000.0, 10.0, 0.0, "Bone deformation distance"); + uiDefButF(block, NUM,REDRAWVIEW3D, "Weight:", bx+438, by, 110, 18, &curBone->weight, 0.0F, 1000.0F, 10.0F, 0.0F, "Bone deformation weight"); + + by-=19; + } + } + } + + uiDrawBlock (block); + +} + +static int editbone_to_parnr (EditBone *bone) +{ + EditBone *ebone; + int index; + + for (ebone=G.edbo.first, index=0; ebone; ebone=ebone->next, index++){ + if (ebone==bone) + return index; + } + + return -1; +} + +static void parnr_to_editbone(EditBone *bone) +{ + if (bone->parNr == -1){ + bone->parent = NULL; + bone->flag &= ~BONE_IK_TOPARENT; + } + else{ + bone->parent = BLI_findlink(&G.edbo, bone->parNr); + attach_bone_to_parent(bone); + } +} + +static void attach_bone_to_parent(EditBone *bone) +{ + EditBone *curbone; + + if (bone->flag & BONE_IK_TOPARENT) { + + /* See if there are any other bones that refer to the same parent and disconnect them */ + for (curbone = G.edbo.first; curbone; curbone=curbone->next){ + if (curbone!=bone){ + if (curbone->parent && (curbone->parent == bone->parent) && (curbone->flag & BONE_IK_TOPARENT)) + curbone->flag &= ~BONE_IK_TOPARENT; + } + } + + /* Attach this bone to its parent */ + VECCOPY(bone->head, bone->parent->tail); + } + +} + +static void build_bonestring (char *string, EditBone *bone){ + EditBone *curBone; + EditBone *pBone; + int skip=0; + int index; + + sprintf (string, "Parent%%t| %%x%d", -1); /* That space is there for a reason */ + + for (curBone = G.edbo.first, index=0; curBone; curBone=curBone->next, index++){ + /* Make sure this is a valid child */ + if (curBone != bone){ + skip=0; + for (pBone=curBone->parent; pBone; pBone=pBone->parent){ + if (pBone==bone){ + skip=1; + break; + } + } + + if (skip) + continue; + + sprintf (string, "%s|%s%%x%d", string, curBone->name, index); + } + } +} + +static void validate_editbonebutton(EditBone *eBone){ + EditBone *prev; + bAction *act; + bActionChannel *chan; + Base *base; + + /* Separate the bone from the G.edbo */ + prev=eBone->prev; + BLI_remlink (&G.edbo, eBone); + + /* Validate the name */ + unique_editbone_name (eBone->name); + + /* Re-insert the bone */ + if (prev) + BLI_insertlink(&G.edbo, prev, eBone); + else + BLI_addhead (&G.edbo, eBone); + + /* Rename channel if necessary */ + if (G.obedit) + act = G.obedit->action; + + if (act && !act->id.lib){ + // Find the appropriate channel + for (chan = act->chanbase.first; chan; chan=chan->next){ + if (!strcmp (chan->name, eBone->oldname)){ + strcpy (chan->name, eBone->name); + } + } + allqueue(REDRAWACTION, 0); + } + + /* Update the parenting info of any users */ + /* Yes, I know this is the worst thing you have ever seen. */ + + for (base = G.scene->base.first; base; base=base->next){ + Object *ob = base->object; + + /* See if an object is parented to this armature */ + if (ob->parent && ob->partype==PARBONE && (ob->parent->type==OB_ARMATURE) && (ob->parent->data == G.obedit->data)){ + if (!strcmp(ob->parsubstr, eBone->oldname)) + strcpy(ob->parsubstr, eBone->name); + } + } + + exit_editmode(0); /* To ensure new names make it to the edit armature */ + +} + +void deselectall_armature(void) +/* Actually, it toggles selection, deselecting + everything if anything is selected */ +{ + EditBone *eBone; + int sel=1; + + + /* Determine if there are any selected bones + And therefore whether we are selecting or deselecting */ + for (eBone=G.edbo.first;eBone;eBone=eBone->next){ + if (eBone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)){ + sel=0; + break; + }; + }; + + /* Set the flags */ + for (eBone=G.edbo.first;eBone;eBone=eBone->next){ + if (sel) + eBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + else + eBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + }; + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWBUTSHEAD, 0); + allqueue(REDRAWBUTSCONSTRAINT, 0); + countall(); +} + +void join_armature(void) +{ + + Object *ob; + Base *base, *nextbase; + ListBase eblist; + EditBone *curbone, *next; + float mat[4][4], imat[4][4]; + + /* Ensure we're not in editmode and that the active object is an armature*/ + if(G.obedit) return; + + ob= OBACT; + if(ob->type!=OB_ARMATURE) return; + + /* Make sure the user wants to continue*/ + if(okee("Join selected Armatures")==0) return; + + /* Put the active armature into editmode and join the bones from the other one*/ +#if 1 + enter_editmode(); +#else + baselist.first=baselist.last=0; + make_boneList(&baselist, &((bArmature*)ob->data)->bonebase, NULL); +#endif + + for (base=FIRSTBASE; base; base=nextbase) { + nextbase = base->next; + if (TESTBASE(base)){ + if ((base->object->type==OB_ARMATURE) && (base->object!=ob)){ + /* Make a list of editbones */ + eblist.first=eblist.last=0; + make_boneList (&eblist, &((bArmature*)base->object->data)->bonebase,NULL); + /* Find the difference matrix */ + Mat4Invert(imat, ob->obmat); + Mat4MulMat4(mat, base->object->obmat, imat); + + /* Copy bones from the object to the edit armature */ + for (curbone=eblist.first; curbone; curbone=next){ + next = curbone->next; + + /* Blank out tranformation data */ + curbone->loc[0]=curbone->loc[1]=curbone->loc[2]=0.0F; + curbone->size[0]=curbone->size[1]=curbone->size[2]=1.0F; + curbone->quat[0]=curbone->quat[1]=curbone->quat[2]=curbone->quat[3]=0.0F; + + unique_editbone_name (curbone->name); + + /* Transform the bone */ + { + float premat[4][4]; + float postmat[4][4]; + float difmat[4][4]; + float imat[4][4]; + float temp[4][4]; + float delta[3]; + + /* Get the premat */ + VecSubf (delta, curbone->tail, curbone->head); + make_boneMatrixvr(temp, delta, curbone->roll); + Mat4MulMat4 (premat, temp, mat); + + Mat4MulVecfl(mat, curbone->head); + Mat4MulVecfl(mat, curbone->tail); + + /* Get the postmat */ + VecSubf (delta, curbone->tail, curbone->head); + make_boneMatrixvr(postmat, delta, curbone->roll); + + /* Find the roll */ + Mat4Invert (imat, premat); + Mat4MulMat4 (difmat, postmat, imat); + + curbone->roll -=atan(difmat[2][0]/difmat[2][2]); + + if (difmat[0][0]<0) + curbone->roll +=M_PI; + + } +#if 1 + BLI_remlink(&eblist, curbone); + BLI_addtail(&G.edbo, curbone); +#else + BLI_remlink(&eblist, curbone); + BLI_addtail(&baselist, curbone); +#endif + } + + free_and_unlink_base(base); + } + } + } + +#if 1 + exit_editmode(1); +#else + editbones_to_armature(&baselist, ob); + if (baselist.first){ + BLI_freelistN (&baselist); + } +#endif + allqueue(REDRAWVIEW3D, 0); + +} + + +static int editbone_name_exists (char *name){ + EditBone *eBone; + + for (eBone=G.edbo.first; eBone; eBone=eBone->next){ + if (!strcmp (name, eBone->name)) + return 1; + } + + return 0; + +} + +static void unique_editbone_name (char *name){ + char tempname[64]; + int number; + char *dot; + + + if (editbone_name_exists(name)){ + /* Strip off the suffix */ + dot=strchr(name, '.'); + if (dot) + *dot=0; + + for (number = 1; number <=999; number++){ + sprintf (tempname, "%s.%03d", name, number); + if (!editbone_name_exists(tempname)){ + strcpy (name, tempname); + return; + } + } + } +} + +void extrude_armature(void) +{ + EditBone *newbone, *curbone, *first=NULL, *partest; + + TEST_EDITARMATURE; + + + if(okee("Extrude Bone Segments")==0) return; + + /* Duplicate the necessary bones */ + for (curbone = G.edbo.first; ((curbone) && (curbone!=first)); curbone=curbone->next){ + if (curbone->flag & (BONE_TIPSEL|BONE_SELECTED)){ + newbone = MEM_callocN(sizeof(EditBone), "extrudebone"); + + + VECCOPY (newbone->head, curbone->tail); + VECCOPY (newbone->tail, newbone->head); + newbone->parent = curbone; + newbone->flag = BONE_TIPSEL; + newbone->flag |= BONE_QUATROT; + newbone->weight= curbone->weight; + newbone->dist= curbone->dist; + Mat4One(newbone->obmat); + + /* See if there are any ik children of the parent */ + for (partest = G.edbo.first; partest; partest=partest->next){ + if ((partest->parent == curbone) && (partest->flag & BONE_IK_TOPARENT)) + break; + } + + if (!partest) + newbone->flag |= BONE_IK_TOPARENT; + + strcpy (newbone->name, curbone->name); + unique_editbone_name(newbone->name); + + /* Add the new bone to the list */ + BLI_addtail(&G.edbo, newbone); + if (!first) + first = newbone; + } + + /* Deselect the old bone */ + curbone->flag &= ~(BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL); + + } + + /* Transform the endpoints */ + countall(); + transform('g'); + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWBUTSCONSTRAINT, 0); +} + +void addvert_armature(void) +{ +/* + I haven't decided if it will be possible to add bones in this way. + For the moment, we'll use Extrude, or explicit parenting. + */ +} + + + + + +void adduplicate_armature(void) +{ + EditBone *eBone = NULL; + EditBone *curBone; + EditBone *firstDup=NULL; /* The beginning of the duplicated bones in the edbo list */ + + countall(); + + /* Find the selected bones and duplicate them as needed */ + for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next){ + if (curBone->flag & BONE_SELECTED){ + + eBone=MEM_callocN(sizeof(EditBone), "addup_editbone"); + eBone->flag |= BONE_SELECTED; + + /* Copy data from old bone to new bone */ + memcpy (eBone, curBone, sizeof(EditBone)); + + /* Blank out tranformation data */ + eBone->loc[0]=eBone->loc[1]=eBone->loc[2]=0.0F; + eBone->size[0]=eBone->size[1]=eBone->size[2]=1.0F; + eBone->quat[0]=eBone->quat[1]=eBone->quat[2]=eBone->quat[3]=0.0F; + + curBone->temp = eBone; + eBone->temp = curBone; + + unique_editbone_name (eBone->name); + BLI_addtail (&G.edbo, eBone); + if (!firstDup) + firstDup=eBone; + } + } + + if (eBone){ + /* Fix the head and tail */ + if (eBone->parent && !eBone->parent->flag & BONE_SELECTED){ + VecSubf (eBone->tail, eBone->tail, eBone->head); + VecSubf (eBone->head, eBone->head, eBone->head); + } + } + + /* Run though the list and fix the pointers */ + for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next){ + + if (curBone->flag & BONE_SELECTED){ + eBone=(EditBone*) curBone->temp; + + /* If this bone has no parent, + Set the duplicate->parent to NULL + */ + if (!curBone->parent){ + eBone->parent = NULL; + } + /* If this bone has a parent that IS selected, + Set the duplicate->parent to the curBone->parent->duplicate + */ + else if (curBone->parent->flag & BONE_SELECTED){ + eBone->parent=(EditBone*) curBone->parent->temp; + } + /* If this bone has a parent that IS not selected, + Set the duplicate->parent to the curBone->parent + */ + else { + eBone->parent=(EditBone*) curBone->parent; + eBone->flag &= ~BONE_IK_TOPARENT; + } + + } + } + + /* Deselect the old bones and select the new ones */ + + for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next){ + curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + + + transform('g'); + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWBUTSCONSTRAINT, 0); +} + +/* + * + * POSING FUNCTIONS: Maybe move these to a separate file at some point + * + * + */ + + +void clear_armature(Object *ob, char mode){ + Bone *curBone; + bArmature *arm; + + arm=get_armature(ob); + + if (!arm) + return; + + for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){ + clear_armature_children (curBone, ob->pose, mode); + } + + where_is_armature (ob); + +} + +static void clear_armature_children (Bone *bone, bPose *pose, char mode){ + Bone *curBone; + bPoseChannel *chan; + if (!bone) + return; + + verify_pose_channel (pose, bone->name); + chan=get_pose_channel (pose, bone->name); + + if (!chan) + return; + + if (bone->flag & BONE_SELECTED){ + switch (mode){ + case 'r': + chan->quat[1]=chan->quat[2]=chan->quat[3]=0.0F; chan->quat[0]=1.0F; + break; + case 'g': + chan->loc[0]=chan->loc[1]=chan->loc[2]=0.0F; + break; + case 's': + chan->size[0]=chan->size[1]=chan->size[2]=1.0F; + break; + + } + } + + for (curBone=bone->childbase.first; curBone; curBone=curBone->next){ + clear_armature_children (curBone, pose, mode); + } + +} + +void mousepose_armature(void) +/* + Handles right-clicking for selection + of bones in armature pose modes. +*/ +{ + Bone *nearBone; + + if (!G.obpose) + return; + + nearBone = get_nearest_bone(1); + + if (nearBone){ + if (!(G.qual & LR_SHIFTKEY)){ + deselectall_posearmature(0); + nearBone->flag|=BONE_SELECTED; + select_actionchannel_by_name(G.obpose->action, nearBone->name, 1); + } + else { + if (nearBone->flag & BONE_SELECTED){ + nearBone->flag &= ~BONE_SELECTED; + select_actionchannel_by_name(G.obpose->action, nearBone->name, 0); + } + else{ + nearBone->flag |= BONE_SELECTED; + select_actionchannel_by_name(G.obpose->action, nearBone->name, 1); + } + }; + } + + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWACTION, 0); + allqueue(REDRAWIPO, 0); /* To force action ipo update */ + allqueue(REDRAWBUTSCONSTRAINT, 0); + +// countall(); + rightmouse_transform(); + +} + +void make_trans_bones (char mode) +/* Used in pose mode */ +{ + bArmature *arm; + Bone *curBone; + int count=0; + + transmain=NULL; + + arm=get_armature (G.obpose); + if (!arm) + return; + + if (arm->flag & ARM_RESTPOS){ + notice ("Transformation not possible while Rest Position is enabled"); + return; + } + + + if (!(G.obpose->lay & G.vd->lay)) + return; + + + centroid[0]=centroid[1]=centroid[2]=0; + + apply_pose_armature(arm, G.obpose->pose, 0); + where_is_armature (G.obpose); + + /* Allocate memory for the transformation record */ + tottrans= count_bones (arm, BONE_SELECTED, 0); + + if (!tottrans) + return; + + transmain= MEM_callocN(tottrans*sizeof(TransOb), "bonetransmain"); + + for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){ + count = add_trans_bonechildren (G.obpose, curBone, transmain, count, mode); + } + + tottrans=count; + + if (tottrans){ + centroid[0]/=tottrans; + centroid[1]/=tottrans; + centroid[2]/=tottrans; + Mat4MulVecfl (G.obpose->obmat, centroid); + } + else{ + MEM_freeN (transmain); + } + return; + +} + +static int count_bones (bArmature *arm, int flagmask, int allbones) +{ + int count=0; + Bone *curBone; + + if (!arm) + return 0; + + for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){ + count = count_bonechildren (curBone, count, flagmask, allbones); + } + + return count; + +} + +static int count_bonechildren (Bone *bone, int incount, int flagmask, int allbones){ + + Bone *curBone; + + if (!bone) + return incount; + + if (bone->flag & flagmask || flagmask == 0xFFFFFFFF){ + incount++; + if (!allbones) + return incount; + } + + for (curBone=bone->childbase.first; curBone; curBone=curBone->next){ + incount=count_bonechildren (curBone, incount, flagmask, allbones); + } + + return incount; +} + + +static int add_trans_bonechildren (Object* ob, Bone* bone, TransOb* buffer, int index, char mode) +{ + Bone *curBone; + TransOb *curOb; + float parmat[4][4], tempmat[4][4]; + float tempobmat[4][4]; + float vec[3]; + if (!bone) + return index; + + + + /* We don't let IK children get "grabbed" */ + if (bone->flag & BONE_SELECTED){ + if (!((mode=='g' || mode=='G') && (bone->flag & BONE_IK_TOPARENT))){ + + get_bone_root_pos (bone, vec, 1); + + VecAddf (centroid, centroid, vec); + + curOb=&buffer[index]; + + curOb->ob = ob; + curOb->rot=NULL; + + curOb->quat= bone->quat; + curOb->size= bone->size; + curOb->loc = bone->loc; + + curOb->data = bone; // FIXME: Dangerous + + memcpy (curOb->oldquat, bone->quat, sizeof (bone->quat)); + memcpy (curOb->oldsize, bone->size, sizeof (bone->size)); + memcpy (curOb->oldloc, bone->loc, sizeof (bone->loc)); + +#if 0 + if (bone->parent) + get_objectspace_bone_matrix(bone->parent, tempmat, 1, 1); + else + Mat4One (tempmat); +#else + /* Get the matrix of this bone minus the usertransform */ + Mat4CpyMat4 (tempobmat, bone->obmat); + Mat4One (bone->obmat); + get_objectspace_bone_matrix(bone, tempmat, 1, 1); + Mat4CpyMat4 (bone->obmat, tempobmat); + + +#endif + +#if 1 + Mat4MulMat4 (parmat, tempmat, ob->obmat); /* Original */ + + /* Get world transform */ + get_objectspace_bone_matrix(bone, tempmat, 1, 1); + if (ob->parent){ + where_is_object(ob->parent); + Mat4MulSerie (tempobmat, ob->parent->obmat, ob->obmat, tempmat, NULL, NULL, NULL, NULL, NULL); + } + else + Mat4MulSerie (tempobmat, ob->obmat, tempmat, NULL, NULL, NULL, NULL, NULL, NULL); + Mat3CpyMat4 (curOb->axismat, tempobmat); + Mat3Ortho(curOb->axismat); + +#else + Mat4MulMat4 (parmat, ob->obmat, tempmat); +#endif + Mat3CpyMat4 (curOb->parmat, parmat); + Mat3Inv (curOb->parinv, curOb->parmat); + + Mat3CpyMat4 (curOb->obmat, bone->obmat); + Mat3Inv (curOb->obinv, curOb->obmat); + + index++; + return index; + } + + } + + /* Recursively search */ + for (curBone = bone->childbase.first; curBone; curBone=curBone->next){ + index=add_trans_bonechildren (ob, curBone, buffer, index, mode); + } + + return index; +} + +static void deselect_bonechildren (Bone *bone, int mode) +{ + Bone *curBone; + + if (!bone) + return; + + if (mode==0) + bone->flag &= ~BONE_SELECTED; + else if (!(bone->flag & BONE_HIDDEN)) + bone->flag |= BONE_SELECTED; + + select_actionchannel_by_name(G.obpose->action, bone->name, mode); + + for (curBone=bone->childbase.first; curBone; curBone=curBone->next){ + deselect_bonechildren(curBone, mode); + } +} + + +void deselectall_posearmature (int test){ + int selectmode = 0; + Bone* curBone; + + /* Determine if we're selecting or deselecting */ + if (test){ + if (!count_bones (get_armature(G.obpose), BONE_SELECTED, 0)) + selectmode = 1; + } + + /* Set the flags accordingly */ + for (curBone=get_armature(G.obpose)->bonebase.first; curBone; curBone=curBone->next) + deselect_bonechildren (curBone, selectmode); + + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWACTION, 0); + +} + +void auto_align_armature(void) +/* Sets the roll value of selected bones so that their zaxes point upwards */ +{ + EditBone *ebone; + float xaxis[3]={1.0, 0.0, 0.0}, yaxis[3], zaxis[3]={0.0, 0.0, 1.0}, ytest[3]={0.0, -1.0, 0.0}; + float targetmat[4][4], imat[4][4]; + float curmat[4][4], diffmat[4][4]; + float delta[3]; + + for (ebone = G.edbo.first; ebone; ebone=ebone->next){ + if (ebone->flag & BONE_SELECTED){ + /* Find the current bone matrix */ + VecSubf(delta, ebone->tail, ebone->head); + make_boneMatrixvr (curmat, delta, 0.0); + + /* Make new matrix based on y axis & z-up */ + VECCOPY (yaxis, curmat[1]); + + Mat4One(targetmat); + VECCOPY (targetmat[0], xaxis); + VECCOPY (targetmat[1], yaxis); + VECCOPY (targetmat[2], zaxis); + Mat4Ortho(targetmat); + + /* Find the difference between the two matrices */ + + Mat4Invert (imat, targetmat); + Mat4MulMat4(diffmat, curmat, imat); + + ebone->roll = atan(diffmat[2][0]/diffmat[2][2]); + + } + } +}
\ No newline at end of file |