Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/src/editarmature.c')
-rw-r--r--source/blender/src/editarmature.c2574
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