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/blenkernel/intern/armature.c')
-rw-r--r--source/blender/blenkernel/intern/armature.c1451
1 files changed, 1451 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
new file mode 100644
index 00000000000..86ce2faa07c
--- /dev/null
+++ b/source/blender/blenkernel/intern/armature.c
@@ -0,0 +1,1451 @@
+/**
+ * $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 *****
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+#include "MEM_guardedalloc.h"
+
+#include "nla.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_action_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_constraint_types.h"
+
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_library.h"
+#include "BKE_blender.h"
+#include "BKE_armature.h"
+#include "BKE_action.h"
+#include "BKE_constraint.h"
+#include "BKE_object.h"
+#include "BKE_object.h"
+#include "BKE_deform.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editdeform.h"
+
+#include "IK_solver.h"
+
+/* Function prototypes */
+
+static void apply_pose_bonechildren (Bone* bone, bPose* pose, int doit);
+static float dist_to_bone (float vec[3], float b1[3], float b2[3]);
+static Bone *get_named_bone_bonechildren (Bone *bone, const char *name);
+static Bone *get_indexed_bone_bonechildren (Bone *bone, int *index);
+/*void make_bone_parent_matrix (Bone* bone);*/
+static void copy_bonechildren (Bone* newBone, Bone* oldBone);
+static void calc_armature_deform_bonechildren (Bone *bone, float *vec, float *co, float *contrib, float obmat[][4]);
+static int verify_boneptr_children (Bone *cBone, Bone *tBone);
+static void where_is_bonelist_time (Object *ob, ListBase *base, float ctime);
+static Bone *get_last_ik_bone (Bone *bone);
+static void precalc_bonelist_posemats(ListBase *bonelist, float parlen);
+
+/* Globals */
+static float g_premat[4][4];
+static float g_postmat[4][4];
+static MDeformVert *g_dverts;
+static ListBase *g_defbase;
+static bArmature *g_defarm;
+
+/* Functions */
+
+float get_bone_length (Bone *bone)
+{
+ float result[3];
+
+ VecSubf (result, bone->tail, bone->head);
+ return (float)sqrt(result[0]*result[0] + result[1]*result[1] + result[2]*result[2]);
+
+}
+
+void apply_bonemat(Bone *bone)
+{
+ float mat[3][3], imat[3][3], tmat[3][3];
+
+ if(!bone)
+ return;
+
+ Mat3CpyMat4(mat, bone->obmat);
+
+ VECCOPY(bone->loc, bone->obmat[3]);
+
+ Mat3ToQuat(mat, bone->quat);
+ QuatToMat3(bone->quat, tmat);
+
+ Mat3Inv(imat, tmat);
+
+ Mat3MulMat3(tmat, imat, mat);
+
+ bone->size[0]= tmat[0][0];
+ bone->size[1]= tmat[1][1];
+ bone->size[2]= tmat[2][2];
+
+}
+
+void GB_build_mats (float parmat[][4], float obmat[][4], float premat[][4], float postmat[][4])
+{
+ float obinv[4][4];
+#if 0
+ Mat4Invert(obinv, obmat);
+ Mat4CpyMat4(premat, obmat);
+ Mat4MulMat4(postmat, parmat, obinv);
+
+ Mat4Invert (postmat, premat);
+#else
+ Mat4Invert(obinv, obmat);
+ Mat4CpyMat4(premat, obmat);
+ Mat4MulMat4(postmat, parmat, obinv);
+
+ Mat4Invert (premat, postmat);
+#endif
+}
+
+void GB_init_armature_deform(ListBase *defbase, float premat[][4], float postmat[][4])
+{
+ g_defbase = defbase;
+ Mat4CpyMat4 (g_premat, premat);
+ Mat4CpyMat4 (g_postmat, postmat);
+
+}
+
+void GB_validate_defgroups (Mesh *mesh, ListBase *defbase)
+{
+ /* Should only be called when the mesh or armature changes */
+ int j, i;
+ MDeformVert *dvert;
+
+ for (j=0; j<mesh->totvert; j++){
+ dvert = mesh->dvert+j;
+ for (i=0; i<dvert->totweight; i++)
+ dvert->dw[i].data = ((bDeformGroup*)BLI_findlink (defbase, dvert->dw[i].def_nr))->data;
+ }
+}
+
+void GB_calc_armature_deform (float *co, MDeformVert *dvert)
+{
+ float vec[3]={0, 0, 0};
+ float contrib = 0;
+ int i;
+ Bone *bone;
+
+ Mat4MulVecfl(g_premat, co);
+
+ for (i=0; i<dvert->totweight; i++){
+ bone = dvert->dw[i].data;
+ if (bone) calc_bone_deform (bone, dvert->dw[i].weight, vec, co, &contrib);
+ }
+
+ if (contrib){
+ vec[0]/=contrib;
+ vec[1]/=contrib;
+ vec[2]/=contrib;
+ }
+
+ VecAddf (co, vec, co);
+ Mat4MulVecfl(g_postmat, co);
+}
+
+static Bone *get_last_ik_bone (Bone *bone)
+{
+ Bone *curBone;
+
+ for (curBone = bone->childbase.first; curBone; curBone=curBone->next){
+ if (curBone->flag & BONE_IK_TOPARENT){
+ return get_last_ik_bone (curBone);
+ }
+ }
+
+ return bone;
+}
+
+#if 0
+static Bone *get_first_ik_bone (Bone *bone)
+{
+ Bone *curBone;
+
+ for (curBone = bone; curBone; curBone=curBone->parent){
+ if (!bone->parent)
+ return curBone;
+ if (!bone->flag & BONE_IK_TOPARENT)
+ return curBone;
+ }
+
+ return bone;
+/* for (curBone = bone->childbase.first; curBone; curBone=curBone->next){
+ if (curBone->flag & BONE_IK_TOPARENT){
+ return get_last_ik_bone (curBone);
+ }
+ }
+*/
+ return bone;
+
+}
+#endif
+
+void where_is_bone(Object *ob, Bone *bone)
+{
+ where_is_bone_time (ob, bone, G.scene->r.cfra);
+}
+
+void where_is_bone_time (Object *ob, Bone *bone, float ctime)
+{
+ where_is_bone1_time (ob, get_last_ik_bone(bone), ctime);
+}
+
+void rebuild_bone_parent_matrix (Bone *bone)
+{
+ if (!bone)
+ return;
+
+ if (bone->parent)
+ rebuild_bone_parent_matrix(bone->parent);
+
+ /* Get the parent inverse */
+ if (bone->parent)
+ Mat4MulMat4(bone->parmat, bone->parent->obmat, bone->parent->parmat);
+ else
+ Mat4One (bone->parmat);
+
+}
+void where_is_bone1_time (Object *ob, Bone *bone, float ctime)
+/* Assumes the pose has already been retrieved from the action */
+/* Also assumes where_is_object has been called for owner */
+{
+ bPose *pose;
+ bPoseChannel *chan;
+ bArmature *arm;
+ float imat[4][4];
+ float totmat[4][4];
+ Object conOb;
+
+ pose = ob->pose;
+ if (!pose)
+ return;
+
+ arm = get_armature(ob);
+
+ /* Ensure there is achannel for this bone*/
+ verify_pose_channel (pose, bone->name);
+
+ /* Search the pose for a channel with the same name, and copy the
+ transformations from the channel into the bone */
+ for (chan=pose->chanbase.first; chan; chan=chan->next){
+ if (!strcmp (chan->name, bone->name)){
+
+#if 1 /* If 1 attempt to use pose caching features */
+ /* Bail out if we've been recalced recently */
+ if (chan->flag & PCHAN_DONE){
+ Mat4CpyMat4 (bone->obmat, chan->obmat);
+ if (bone->parent){
+ if ((bone->flag & BONE_IK_TOPARENT))
+ where_is_bone1_time (ob, bone->parent, ctime);
+ else
+ where_is_bone_time (ob, bone->parent, ctime);
+ }
+ return;
+ }
+ else
+ chan->flag |= PCHAN_DONE;
+#endif
+ break;
+ }
+ }
+
+#if 1
+ /* Ensure parents have been evaluated */
+ if (bone->parent){
+ if ((bone->flag & BONE_IK_TOPARENT))
+ where_is_bone1_time (ob, bone->parent, ctime);
+ else
+ where_is_bone_time (ob, bone->parent, ctime);
+ }
+
+ /* Build the parent matrix : Depreciated */
+// if (bone->parent)
+// Mat4MulMat4(bone->parmat, bone->parent->obmat, bone->parent->parmat);
+// else
+// Mat4One (bone->parmat);
+#endif
+
+ if (arm){
+ if ((arm->flag & ARM_RESTPOS) || ((G.obedit && (ob->data == G.obedit->data)))){
+ Mat4One (bone->obmat);
+ Mat4One (chan->obmat);
+ return;
+ }
+ }
+
+ if (bone->flag & BONE_IK_TOPARENT){
+ bone->loc[0]=bone->loc[1]=bone->loc[2]=0.0F;
+ }
+ bone_to_mat4(bone, bone->obmat);
+
+ /* Do constraints */
+ // clear_workob();
+
+ memset(&conOb, 0, sizeof(Object));
+ conOb.size[0]= conOb.size[1]= conOb.size[2]= 1.0;
+
+ /* Collect the constraints from the pose */
+ conOb.constraints.first = chan->constraints.first;
+ conOb.constraints.last = chan->constraints.last;
+
+ /* Totmat takes bone's obmat to worldspace */
+
+ {
+ float parmat[4][4];
+ float temp[4][4];
+
+ Mat4CpyMat4 (temp, bone->obmat);
+ Mat4One (bone->obmat);
+ get_objectspace_bone_matrix(bone, parmat, 1, 1);
+ Mat4CpyMat4 (bone->obmat, temp);
+ Mat4MulMat4 (totmat, parmat, ob->obmat);
+ }
+
+ /* Build a workob to pass the bone to the constraint solver */
+ conOb.data = ob->data;
+ conOb.type = ob->type;
+ conOb.parent = ob;
+ conOb.trackflag = ob->trackflag;
+ conOb.upflag = ob->upflag;
+
+ VECCOPY(conOb.size, bone->size);
+
+ Mat4MulMat4 (conOb.obmat, bone->obmat, totmat);
+
+ /* Solve */
+ solve_constraints (&conOb, TARGET_BONE, (void*)bone, ctime);
+
+ {
+ float parmat[4][4];
+ float temp[4][4];
+
+ Mat4CpyMat4 (temp, bone->obmat);
+ Mat4One (bone->obmat);
+ get_objectspace_bone_matrix(bone, parmat, 1, 1);
+ Mat4CpyMat4 (bone->obmat, temp);
+ Mat4MulMat4 (totmat, parmat, ob->obmat);
+ }
+
+ VECCOPY(bone->size, conOb.size);
+
+ /* Take out of worldspace */
+ Mat4Invert (imat, totmat);
+ Mat4MulMat4 (bone->obmat, conOb.obmat, imat);
+ Mat4CpyMat4 (chan->obmat, bone->obmat);
+
+}
+
+
+bArmature *get_armature(Object *ob)
+{
+ if(ob==NULL) return NULL;
+ if(ob->type==OB_ARMATURE) return ob->data;
+ else return NULL;
+}
+
+void init_armature_deform(Object *parent, Object *ob)
+{
+ bArmature *arm;
+ bDeformGroup *dg;
+ Bone *curBone;
+ MDeformVert *dvert;
+ int totverts;
+ float obinv[4][4];
+ int i, j;
+
+ arm = get_armature(parent);
+ if (!arm)
+ return;
+
+ if (ob)
+ where_is_object (ob);
+
+#if 1
+ apply_pose_armature (arm, parent->pose, 1); /* Hopefully doit parameter can be set to 0 in future */
+ where_is_armature (parent);
+#else
+ apply_pose_armature (arm, parent->pose, 0);
+#endif
+
+ g_defbase = &ob->defbase;
+ g_defarm = arm;
+
+ Mat4Invert(obinv, ob->obmat);
+ Mat4CpyMat4(g_premat, ob->obmat);
+ Mat4MulMat4(g_postmat, parent->obmat, obinv);
+
+ Mat4Invert (g_premat, g_postmat);
+
+ /* Store the deformation verts */
+ if (ob->type==OB_MESH){
+ g_dverts = ((Mesh*)ob->data)->dvert;
+ totverts = ((Mesh*)ob->data)->totvert;
+ }
+ else{
+ g_dverts=NULL;
+ totverts=0;
+ }
+
+ /* Precalc bone defmats */
+ precalc_armature_posemats (arm);
+
+ for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){
+ precalc_bone_defmat(curBone);
+ }
+
+ /* Validate bone data in bDeformGroups */
+
+ for (dg=g_defbase->first; dg; dg=dg->next)
+ dg->data = (void*)get_named_bone(arm, dg->name);
+
+ if (g_dverts){
+ for (j=0; j<totverts; j++){
+ dvert = g_dverts+j;
+ for (i=0; i<dvert->totweight; i++){
+ bDeformGroup *fg;
+ fg = BLI_findlink (g_defbase, dvert->dw[i].def_nr);
+
+ if (fg)
+ dvert->dw[i].data = fg->data;
+ else
+ dvert->dw[i].data = NULL;
+ }
+ }
+ }
+}
+
+void get_bone_root_pos (Bone* bone, float vec[3], int posed)
+{
+ Bone *curBone;
+ float mat[4][4];
+
+ get_objectspace_bone_matrix(bone, mat, 1, posed);
+ VECCOPY (vec, mat[3]);
+ return;
+
+ rebuild_bone_parent_matrix(bone);
+ if (posed){
+
+ get_objectspace_bone_matrix(bone, mat, 1, posed);
+ VECCOPY (vec, mat[3]);
+ }
+ else {
+ vec[0]=vec[1]=vec[2]=0.0F;
+ for (curBone=bone; curBone; curBone=curBone->parent){
+ if (curBone==bone)
+ VecAddf (vec, vec, curBone->head);
+ else
+ VecAddf (vec, vec, curBone->tail);
+ }
+ }
+}
+
+void get_bone_tip_pos (Bone* bone, float vec[3], int posed)
+{
+ Bone *curBone;
+ float mat[4][4], tmat[4][4], rmat[4][4], bmat[4][4], fmat[4][4];
+
+ get_objectspace_bone_matrix(bone, mat, 0, posed);
+ VECCOPY (vec, mat[3]);
+ return;
+
+ rebuild_bone_parent_matrix(bone);
+ if (posed){
+
+ Mat4One (mat);
+
+ for (curBone = bone; curBone; curBone=curBone->parent){
+ Mat4One (bmat);
+ /* [BMAT] This bone's offset */
+ VECCOPY (bmat[3], curBone->head);
+ if (curBone==bone){
+ Mat4One (tmat);
+ VecSubf (tmat[3], curBone->tail, curBone->head);
+ Mat4MulMat4 (bmat, tmat, curBone->obmat);
+ VecAddf (bmat[3], bmat[3], curBone->head);
+ }
+ else
+ VecAddf (bmat[3], bmat[3], curBone->obmat[3]); // Test
+
+ /* [RMAT] Parent's bone length = parent rotmat * bone length */
+ if (curBone->parent){
+ Mat4One (tmat);
+ VecSubf (tmat[3], curBone->parent->tail, curBone->parent->head);
+ Mat4MulMat4 (rmat, tmat, curBone->parent->obmat);
+ VecSubf (rmat[3], rmat[3], curBone->parent->obmat[3]);
+ }
+ else
+ Mat4One (rmat);
+
+ Mat4MulSerie (fmat, rmat, bmat, mat, 0, 0, 0, 0, 0);
+ Mat4CpyMat4 (mat, fmat);
+ }
+
+ VECCOPY (vec, mat[3]);
+ }
+ else{
+ vec[0]=vec[1]=vec[2]=0.0F;
+ for (curBone=bone; curBone; curBone=curBone->parent){
+ VecAddf (vec, vec, curBone->tail);
+ }
+ }
+}
+
+int verify_boneptr (bArmature *arm, Bone *bone)
+{
+ /* Ensures that a given bone exists in an armature */
+ Bone *curBone;
+
+ if (!arm)
+ return 0;
+
+ for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){
+ if (verify_boneptr_children (curBone, bone))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int verify_boneptr_children (Bone *cBone, Bone *tBone)
+{
+ Bone *curBone;
+
+ if (cBone == tBone)
+ return 1;
+
+ for (curBone=cBone->childbase.first; curBone; curBone=curBone->next){
+ if (verify_boneptr_children (curBone, tBone))
+ return 1;
+ }
+ return 0;
+}
+
+
+static float dist_to_bone (float vec[3], float b1[3], float b2[3])
+{
+/* float dist=0; */
+ float bdelta[3];
+ float pdelta[3];
+ float hsqr, a, l;
+
+ VecSubf (bdelta, b2, b1);
+ l = Normalise (bdelta);
+
+ VecSubf (pdelta, vec, b1);
+
+ a = bdelta[0]*pdelta[0] + bdelta[1]*pdelta[1] + bdelta[2]*pdelta[2];
+ hsqr = ((pdelta[0]*pdelta[0]) + (pdelta[1]*pdelta[1]) + (pdelta[2]*pdelta[2]));
+
+ if (a < 0.0F){
+ //return 100000;
+ /* If we're past the end of the bone, do some weird field attenuation thing */
+ return ((b1[0]-vec[0])*(b1[0]-vec[0]) +(b1[1]-vec[1])*(b1[1]-vec[1]) +(b1[2]-vec[2])*(b1[2]-vec[2])) ;
+ }
+ else if (a > l){
+ //return 100000;
+ /* If we're past the end of the bone, do some weird field attenuation thing */
+ return ((b2[0]-vec[0])*(b2[0]-vec[0]) +(b2[1]-vec[1])*(b2[1]-vec[1]) +(b2[2]-vec[2])*(b2[2]-vec[2])) ;
+ }
+ else {
+ return (hsqr - (a*a));
+ }
+
+
+}
+
+static void calc_armature_deform_bonechildren (Bone *bone, float *vec, float *co, float *contrib, float obmat[][4])
+{
+ Bone *curBone;
+ float root[3];
+ float tip[3];
+ float dist, fac, ifac;
+ float cop[3];
+ float bdsqr;
+
+
+ get_bone_root_pos (bone, root, 0);
+ get_bone_tip_pos (bone, tip, 0);
+
+ bdsqr = bone->dist*bone->dist;
+ VECCOPY (cop, co);
+
+ dist = dist_to_bone(cop, root, tip);
+
+ if ((dist) <= bdsqr){
+ fac = (dist)/bdsqr;
+ ifac = 1.0F-fac;
+
+ ifac*=bone->weight;
+
+ if (!vec)
+ (*contrib) +=ifac;
+ else{
+ ifac*=(1.0F/(*contrib));
+
+ VECCOPY (cop, co);
+
+ Mat4MulVecfl(bone->defmat, cop);
+
+ VecSubf (cop, cop, co); // Make this a delta from the base position
+ cop[0]*=ifac; cop[1]*=ifac; cop[2]*=ifac;
+ VecAddf (vec, vec, cop);
+
+ }
+ }
+
+// calc_bone_deform (bone, bone->weight, vec, co, contrib, obmat);
+ for (curBone = bone->childbase.first; curBone; curBone=curBone->next)
+ calc_armature_deform_bonechildren (curBone, vec, co, contrib, obmat);
+}
+
+void precalc_bone_irestmat (Bone *bone)
+{
+ float restmat[4][4];
+
+ get_objectspace_bone_matrix(bone, restmat, 1, 0);
+ Mat4Invert (bone->irestmat, restmat);
+}
+
+static void precalc_bonelist_posemats(ListBase *bonelist, float parlen)
+{
+ Bone *curBone;
+ float length;
+ float T_parlen[4][4];
+ float T_root[4][4];
+ float M_obmat[4][4];
+ float R_bmat[4][4];
+ float M_accumulatedMatrix[4][4];
+ float delta[3];
+
+ for (curBone = bonelist->first; curBone; curBone=curBone->next){
+
+ /* Get the length translation (length along y axis) */
+ length = get_bone_length(curBone);
+
+ /* Get the bone's root offset (in the parent's coordinate system) */
+ Mat4One (T_root);
+ VECCOPY (T_root[3], curBone->head);
+
+ /* Compose the restmat */
+ VecSubf(delta, curBone->tail, curBone->head);
+ make_boneMatrixvr(R_bmat, delta, curBone->roll);
+
+ /* Retrieve the obmat (user transformation) */
+ Mat4CpyMat4 (M_obmat, curBone->obmat);
+
+ /* Compose the accumulated matrix (i.e. parent matrix * parent translation ) */
+ if (curBone->parent){
+ Mat4One (T_parlen);
+ T_parlen[3][1] = parlen;
+ Mat4MulMat4 (M_accumulatedMatrix, T_parlen, curBone->parent->posemat);
+ }
+ else
+ Mat4One (M_accumulatedMatrix);
+
+ /* Compose the matrix for this bone */
+ Mat4MulSerie (curBone->posemat, M_accumulatedMatrix, T_root, R_bmat, M_obmat, NULL, NULL, NULL, NULL);
+
+ precalc_bonelist_posemats(&curBone->childbase, length);
+ }
+}
+
+void precalc_armature_posemats (bArmature *arm)
+{
+ precalc_bonelist_posemats(&arm->bonebase, 0.0);
+}
+
+void precalc_bone_defmat (Bone *bone)
+{
+ Bone *curBone;
+#if 0
+ float restmat[4][4];
+ float posemat[4][4];
+ float imat[4][4];
+
+ /* Store restmat and restmat inverse - Calculate once when leaving editmode */
+ /* Store all bones' posemats - Do when applied */
+
+ /* EXPENSIVE! Don't do this! */
+ get_objectspace_bone_matrix(bone, restmat, 1, 0);
+ get_objectspace_bone_matrix(bone, posemat, 1, 1);
+ Mat4Invert (imat, restmat);
+ Mat4MulMat4 (bone->defmat, imat, posemat);
+ /* /EXPENSIVE */
+#else
+ Mat4MulMat4 (bone->defmat, bone->irestmat, bone->posemat);
+#endif
+ for (curBone = bone->childbase.first; curBone; curBone=curBone->next){
+ precalc_bone_defmat(curBone);
+ }
+}
+
+void calc_bone_deform (Bone *bone, float weight, float *vec, float *co, float *contrib)
+{
+ float cop[3];
+
+ if (!weight)
+ return;
+
+ VECCOPY (cop, co);
+
+ Mat4MulVecfl(bone->defmat, cop);
+
+ vec[0]+=(cop[0]-co[0])*weight;
+ vec[1]+=(cop[1]-co[1])*weight;
+ vec[2]+=(cop[2]-co[2])*weight;
+
+ (*contrib)+=weight;
+}
+
+void calc_armature_deform (Object *ob, float *co, int index)
+{
+ bArmature *arm;
+ Bone *bone;
+ Bone *curBone;
+ float vec[3];
+ float contrib=0;
+ int i;
+ MDeformVert *dvert = g_dverts+index;
+
+ arm=g_defarm;
+ vec[0]=vec[1]=vec[2]=0;
+
+ /* Apply the object's matrix */
+ Mat4MulVecfl(g_premat, co);
+
+ if (g_dverts){
+ for (i=0; i<dvert->totweight; i++){
+ bone = dvert->dw[i].data;
+ if (bone) calc_bone_deform (bone, dvert->dw[i].weight, vec, co, &contrib);
+ }
+
+ if (contrib){
+ vec[0]/=contrib;
+ vec[1]/=contrib;
+ vec[2]/=contrib;
+ }
+ VecAddf (co, vec, co);
+ Mat4MulVecfl(g_postmat, co);
+ return;
+ }
+
+
+ // Count the number of interested bones
+ for (curBone = arm->bonebase.first; curBone; curBone=curBone->next)
+ calc_armature_deform_bonechildren (curBone, NULL, co, &contrib, ob->obmat);
+
+ // Do the deformation
+ for (curBone = arm->bonebase.first; curBone; curBone=curBone->next)
+ calc_armature_deform_bonechildren (curBone, vec, co, &contrib, ob->obmat);
+
+ VecAddf (co, vec, co);
+ Mat4MulVecfl(g_postmat, co);
+}
+
+void apply_pose_armature (bArmature* arm, bPose* pose, int doit)
+{
+ Bone *curBone;
+ for (curBone = arm->bonebase.first; curBone; curBone=curBone->next){
+ apply_pose_bonechildren (curBone, pose, doit);
+ }
+}
+
+void where_is_armature (Object *ob)
+{
+ where_is_object (ob);
+ where_is_armature_time(ob, (float)G.scene->r.cfra);
+}
+
+void where_is_armature_time (Object *ob, float ctime)
+{
+ bArmature *arm;
+
+ arm = get_armature(ob);
+ if (!arm)
+ return;
+
+ where_is_bonelist_time (ob, &arm->bonebase, ctime);
+
+}
+
+static void where_is_bonelist_time (Object *ob, ListBase *base, float ctime)
+{
+ Bone *curBone;
+
+ for (curBone=base->first; curBone; curBone=curBone->next){
+ if (!curBone->childbase.first)
+ where_is_bone1_time (ob, curBone, ctime);
+
+ where_is_bonelist_time(ob, &curBone->childbase, ctime);
+ }
+}
+static void apply_pose_bonechildren (Bone* bone, bPose* pose, int doit)
+{
+ Bone *curBone;
+ bPoseChannel *chan;
+
+ if (!pose){
+
+ bone->dsize[0]=bone->dsize[1]=bone->dsize[2]=1.0F;
+ bone->size[0]=bone->size[1]=bone->size[2]=1.0F;
+
+ bone->dquat[0]=bone->dquat[1]=bone->dquat[2]=bone->dquat[3]=0;
+ bone->quat[0]=bone->quat[1]=bone->quat[2]=bone->quat[3]=0.0F;
+
+ bone->dloc[0]=bone->dloc[1]=bone->dloc[2]=0.0F;
+ bone->loc[0]=bone->loc[1]=bone->loc[2]=0.0F;
+ }
+
+ // Ensure there is achannel for this bone
+ verify_pose_channel (pose, bone->name);
+
+ // Search the pose for a channel with the same name
+ if (pose){
+ for (chan=pose->chanbase.first; chan; chan=chan->next){
+ if (!strcmp (chan->name, bone->name)){
+ if (chan->flag & POSE_LOC)
+ memcpy (bone->loc, chan->loc, sizeof (bone->loc));
+ if (chan->flag & POSE_SIZE)
+ memcpy (bone->size, chan->size, sizeof (bone->size));
+ if (chan->flag & POSE_ROT)
+ memcpy (bone->quat, chan->quat, sizeof (bone->quat));
+
+ if (doit){
+ bone_to_mat4(bone, bone->obmat);
+ }
+ else{
+ Mat4CpyMat4 (bone->obmat, chan->obmat);
+ }
+
+
+ break;
+ }
+ }
+ }
+
+ for (curBone = bone->childbase.first; curBone; curBone=curBone->next){
+ apply_pose_bonechildren (curBone, pose, doit);
+ }
+}
+
+void make_boneMatrixvr (float outmatrix[][4],float delta[3], float roll)
+/* Calculates the rest matrix of a bone based
+ On its vector and a roll around that vector */
+{
+ float nor[3],axis[3],target[3]={0,1,0};
+ float theta;
+ float rMatrix[3][3], bMatrix[3][3], fMatrix[3][3];
+
+ VECCOPY (nor,delta);
+ Normalise (nor);
+
+ /* Find Axis & Amount for bone matrix*/
+ Crossf (axis,target,nor);
+ Normalise (axis);
+ theta=(float) acos (Inpf (target,nor));
+
+ /* Make Bone matrix*/
+ VecRotToMat3(axis, theta, bMatrix);
+
+ /* Make Roll matrix*/
+ VecRotToMat3(nor, roll, rMatrix);
+
+ /* Combine and output result*/
+ Mat3MulMat3 (fMatrix,rMatrix,bMatrix);
+ Mat4CpyMat3 (outmatrix,fMatrix);
+}
+
+void make_boneMatrix (float outmatrix[][4], Bone *bone)
+/* Calculates the rest matrix of a bone based
+ On its vector and a roll around that vector */
+{
+ float delta[3];
+ float parmat[4][4], imat[4][4], obmat[4][4];
+
+ if (bone->parent){
+ VecSubf (delta, bone->parent->tail, bone->parent->head);
+ make_boneMatrixvr(parmat, delta, bone->parent->roll);
+ }
+ else{
+ Mat4One (parmat);
+ }
+
+ Mat4Invert (imat, parmat);
+
+ VecSubf (delta, bone->tail, bone->head);
+ make_boneMatrixvr(obmat, delta, bone->roll);
+
+ Mat4MulMat4(outmatrix, obmat, imat);
+
+}
+
+
+bArmature *add_armature()
+{
+ bArmature *arm;
+
+ arm= alloc_libblock (&G.main->armature, ID_AR, "Armature");
+
+ if(arm) {
+
+
+ }
+ return arm;
+}
+
+
+void free_boneChildren(Bone *bone)
+{
+ Bone *child;
+
+ if (bone) {
+
+ child=bone->childbase.first;
+ if (child){
+ while (child){
+ free_boneChildren (child);
+ child=child->next;
+ }
+ BLI_freelistN (&bone->childbase);
+ }
+ }
+}
+
+void free_bones (bArmature *arm)
+{
+ Bone *bone;
+ /* Free children (if any) */
+ bone= arm->bonebase.first;
+ if (bone) {
+ while (bone){
+ free_boneChildren (bone);
+ bone=bone->next;
+ }
+ }
+
+
+ BLI_freelistN(&arm->bonebase);
+}
+
+void free_armature(bArmature *arm)
+{
+ if (arm) {
+/* unlink_armature(arm);*/
+ free_bones(arm);
+ }
+}
+
+void make_local_armature(bArmature *arm)
+{
+ int local=0, lib=0;
+ Object *ob;
+ bArmature *newArm;
+
+ if (arm->id.lib==0)
+ return;
+ if (arm->id.us==1) {
+ arm->id.lib= 0;
+ arm->id.flag= LIB_LOCAL;
+ new_id(0, (ID*)arm, 0);
+ return;
+ }
+
+ if(local && lib==0) {
+ arm->id.lib= 0;
+ arm->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)arm, 0);
+ }
+ else if(local && lib) {
+ newArm= copy_armature(arm);
+ newArm->id.us= 0;
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->data==arm) {
+
+ if(ob->id.lib==0) {
+ ob->data= newArm;
+ newArm->id.us++;
+ arm->id.us--;
+ }
+ }
+ ob= ob->id.next;
+ }
+ }
+}
+
+static void copy_bonechildren (Bone* newBone, Bone* oldBone)
+{
+ Bone *curBone, *newChildBone;
+
+ /* Copy this bone's list*/
+ duplicatelist (&newBone->childbase, &oldBone->childbase);
+
+ /* For each child in the list, update it's children*/
+ newChildBone=newBone->childbase.first;
+ for (curBone=oldBone->childbase.first;curBone;curBone=curBone->next){
+ newChildBone->parent=newBone;
+ copy_bonechildren(newChildBone,curBone);
+ newChildBone=newChildBone->next;
+ }
+}
+
+bArmature *copy_armature(bArmature *arm)
+{
+ bArmature *newArm;
+ Bone *oldBone, *newBone;
+
+ newArm= copy_libblock (arm);
+ duplicatelist(&newArm->bonebase, &arm->bonebase);
+
+ /* Duplicate the childrens' lists*/
+ newBone=newArm->bonebase.first;
+ for (oldBone=arm->bonebase.first;oldBone;oldBone=oldBone->next){
+ newBone->parent=NULL;
+ copy_bonechildren (newBone, oldBone);
+ newBone=newBone->next;
+ };
+
+ return newArm;
+}
+
+
+void bone_to_mat3(Bone *bone, float mat[][3]) /* no parent */
+{
+ float smat[3][3];
+ float rmat[3][3];
+/* float q1[4], vec[3];*/
+
+ /* size */
+/* if(bone->ipo) {
+ vec[0]= bone->size[0]+bone->dsize[0];
+ vec[1]= bone->size[1]+bone->dsize[1];
+ vec[2]= bone->size[2]+bone->dsize[2];
+ SizeToMat3(vec, smat);
+ }
+ else
+*/ {
+ SizeToMat3(bone->size, smat);
+ }
+
+ /* rot */
+ /*if(bone->flag & BONE_QUATROT) {
+ if(bone->ipo) {
+ QuatMul(q1, bone->quat, bone->dquat);
+ QuatToMat3(q1, rmat);
+ }
+ else
+ */ {
+ NormalQuat(bone->quat);
+ QuatToMat3(bone->quat, rmat);
+ }
+/* }
+*/
+ Mat3MulMat3(mat, rmat, smat);
+}
+
+void bone_to_mat4(Bone *bone, float mat[][4])
+{
+ float tmat[3][3];
+
+ bone_to_mat3(bone, tmat);
+
+ Mat4CpyMat3(mat, tmat);
+
+ VECCOPY(mat[3], bone->loc);
+// VecAddf(mat[3], mat[3], bone->loc);
+/* if(bone->ipo) {
+ mat[3][0]+= bone->dloc[0];
+ mat[3][1]+= bone->dloc[1];
+ mat[3][2]+= bone->dloc[2];
+ }
+*/
+}
+
+Bone *get_indexed_bone (bArmature *arm, int index)
+/*
+ Walk the list until the index is reached
+*/
+{
+ Bone *bone=NULL, *curBone;
+ int ref=index;
+
+ if (!arm)
+ return NULL;
+
+ for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){
+ bone = get_indexed_bone_bonechildren (curBone, &ref);
+ if (bone)
+ return bone;
+ }
+
+ return bone;
+}
+
+Bone *get_named_bone (bArmature *arm, const char *name)
+/*
+ Walk the list until the bone is found
+*/
+{
+ Bone *bone=NULL, *curBone;
+
+ if (!arm) return NULL;
+
+ for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){
+ bone = get_named_bone_bonechildren (curBone, name);
+ if (bone)
+ return bone;
+ }
+
+ return bone;
+}
+
+static Bone *get_indexed_bone_bonechildren (Bone *bone, int *index)
+{
+ Bone *curBone, *rbone;
+
+ if (!*index)
+ return bone;
+
+ (*index)--;
+
+ for (curBone=bone->childbase.first; curBone; curBone=curBone->next){
+ rbone=get_indexed_bone_bonechildren (curBone, index);
+ if (rbone)
+ return rbone;
+ }
+
+ return NULL;
+}
+
+static Bone *get_named_bone_bonechildren (Bone *bone, const char *name)
+{
+ Bone *curBone, *rbone;
+
+ if (!strcmp (bone->name, name))
+ return bone;
+
+ for (curBone=bone->childbase.first; curBone; curBone=curBone->next){
+ rbone=get_named_bone_bonechildren (curBone, name);
+ if (rbone)
+ return rbone;
+ }
+
+ return NULL;
+}
+
+void make_displists_by_armature (Object *ob)
+{
+ Base *base;
+
+ if (ob){
+ for (base= G.scene->base.first; base; base= base->next){
+ if ((ob==base->object->parent) && (base->lay & G.scene->lay))
+ if (base->object->partype==PARSKEL )
+ makeDispList(base->object);
+ }
+ }
+}
+
+void get_objectspace_bone_matrix (struct Bone* bone, float M_accumulatedMatrix[][4], int root, int posed)
+/* Gets matrix that transforms the bone to object space */
+/* This function is also used to compute the orientation of the bone for display */
+{
+ Bone *curBone;
+
+ Bone *bonelist[256];
+ int bonecount=0, i;
+
+ Mat4One (M_accumulatedMatrix);
+
+ /* Build a list of bones from tip to root */
+ for (curBone=bone; curBone; curBone=curBone->parent){
+ bonelist[bonecount] = curBone;
+ bonecount++;
+ }
+
+ /* Count through the inverted list (i.e. iterate from root to tip)*/
+ for (i=0; i<bonecount; i++){
+ float T_root[4][4];
+ float T_len[4][4];
+ float R_bmat[4][4];
+ float M_obmat[4][4];
+ float M_boneMatrix[4][4];
+ float delta[3];
+
+ curBone = bonelist[bonecount-i-1];
+
+ /* Get the length translation (length along y axis) */
+ Mat4One (T_len);
+ T_len[3][1] = get_bone_length(curBone);
+
+ if ((curBone == bone) && (root))
+ Mat4One (T_len);
+
+ /* Get the bone's root offset (in the parent's coordinate system) */
+ Mat4One (T_root);
+ VECCOPY (T_root[3], curBone->head);
+
+ /* Compose the restmat */
+ VecSubf(delta, curBone->tail, curBone->head);
+ make_boneMatrixvr(R_bmat, delta, curBone->roll);
+
+
+ /* Retrieve the obmat (user transformation) */
+ if (posed)
+ Mat4CpyMat4 (M_obmat, curBone->obmat);
+ else
+ Mat4One (M_obmat);
+
+ /* Compose the matrix for this bone */
+#if 0
+ Mat4MulSerie (M_boneMatrix, M_accumulatedMatrix, T_root, M_obmat, R_bmat, T_len, NULL, NULL, NULL);
+#else
+ Mat4MulSerie (M_boneMatrix, M_accumulatedMatrix, T_root, R_bmat, M_obmat, T_len, NULL, NULL, NULL);
+#endif
+ Mat4CpyMat4 (M_accumulatedMatrix, M_boneMatrix);
+ }
+
+
+}
+
+void solve_posechain (PoseChain *chain)
+{
+ float goal[3];
+ int i;
+ Bone *curBone;
+ float M_obmat[4][4];
+ float M_basischange[4][4];
+ bPoseChannel *chan;
+
+ if (!chain->solver) return;
+
+ /**
+ * Transform the goal from worldspace
+ * to the coordinate system of the root
+ * of the chain. The matrix for this
+ * was computed when the chain was built
+ * in ik_chain_to_posechain
+ */
+
+ VECCOPY (goal, chain->goal);
+ Mat4MulVecfl (chain->goalinv, goal);
+
+ /* Solve the chain */
+
+ IK_SolveChain(chain->solver,
+ goal,
+ chain->tolerance,
+ chain->iterations,
+ 0.1f,
+ chain->solver->segments);
+
+ /* Copy the results back into the bones */
+ for (i = chain->solver->num_segments-1, curBone=chain->target->parent; i>=0; i--, curBone=curBone->parent){
+
+ /* Retrieve the delta rotation from the solver */
+ Mat4One(M_basischange);
+ Mat4CpyMat3(M_basischange, chain->solver->segments[i].basis_change);
+
+
+ /**
+ * Multiply the bone's usertransform by the
+ * basis change to get the new usertransform
+ */
+
+ Mat4CpyMat4 (M_obmat, curBone->obmat);
+ Mat4MulMat4 (curBone->obmat, M_basischange, M_obmat);
+
+ /* Store the solve results on the childrens' channels */
+ for (chan = chain->pose->chanbase.first; chan; chan=chan->next){
+ if (!strcmp (chan->name, curBone->name)){
+ Mat4CpyMat4 (chan->obmat, curBone->obmat);
+ break;
+ }
+ }
+
+ }
+}
+
+void free_posechain (PoseChain *chain)
+{
+ if (chain->solver) {
+ MEM_freeN (chain->solver->segments);
+ chain->solver->segments = NULL;
+ IK_FreeChain(chain->solver);
+ }
+ MEM_freeN (chain);
+}
+
+PoseChain *ik_chain_to_posechain (Object *ob, Bone *bone)
+{
+ IK_Segment_Extern *segs;
+ PoseChain *chain = NULL;
+ Bone *curBone, *rootBone;
+ int segcount, curseg, icurseg;
+ float imat[4][4];
+ Bone *bonelist[256];
+ float rootmat[4][4];
+ float bonespace[4][4];
+
+ /**
+ * Some interesting variables in this function:
+ *
+ * Bone->obmat Bone's user transformation;
+ * It is initialized in where_is_bone1_time
+ *
+ * rootmat Bone's coordinate system, computed by
+ * get_objectspace_bone_matrix. Takes all
+ * parents transformations into account.
+ */
+
+
+
+ /* Ensure that all of the bone parent matrices are correct */
+
+ /* Find the chain's root & count the segments needed */
+ segcount = 0;
+ for (curBone = bone; curBone; curBone=curBone->parent){
+ rootBone = curBone;
+ if (curBone!=bone){
+ bonelist[segcount]=curBone;
+ segcount++;
+ }
+ if (!curBone->parent)
+ break;
+ else if (!(curBone->flag & BONE_IK_TOPARENT))
+ break;
+ }
+
+ if (!segcount)
+ return NULL;
+
+
+ /**
+ * Initialize a record to store information about the original bones
+ * This will be the return value for this function.
+ */
+
+ chain = MEM_callocN(sizeof(PoseChain), "posechain");
+ chain->solver = IK_CreateChain();
+ chain->target = bone;
+ chain->root = rootBone;
+ chain->pose = ob->pose;
+
+ /* Allocate some IK segments */
+ segs = MEM_callocN (sizeof(IK_Segment_Extern)*segcount, "iksegments");
+
+
+ /**
+ * Remove the offset from the first bone in the chain and take the target to chainspace
+ */
+
+
+ get_objectspace_bone_matrix(rootBone, bonespace, 1, 1);
+ Mat4One (rootmat);
+ VECCOPY (rootmat[3], bonespace[3]);
+
+ /* Take the target to bonespace */
+ Mat4MulMat4 (imat, rootmat, ob->obmat);
+ Mat4Invert (chain->goalinv, imat);
+
+
+ /**
+ * Build matrices from the root to the tip
+ * We count backwards through the bone list (which is sorted tip to root)
+ * and forwards through the ik_segment list
+ */
+
+ for (curseg = segcount-1; curseg>=0; curseg--){
+ float M_basismat[4][4];
+ float R_parmat[4][4];
+ float iR_parmat[4][4];
+ float R_bonemat[4][4];
+
+ /* Retrieve the corresponding bone for this segment */
+ icurseg=segcount-curseg-1;
+ curBone = bonelist[curseg];
+
+ /* Get the basis matrix */
+ Mat4One (R_parmat);
+ get_objectspace_bone_matrix(curBone, R_bonemat, 1, 1);
+ R_bonemat[3][0]=R_bonemat[3][1]=R_bonemat[3][2]=0.0F;
+
+ if (curBone->parent && (curBone->flag & BONE_IK_TOPARENT)){
+ get_objectspace_bone_matrix(curBone->parent, R_parmat, 1, 1);
+ R_parmat[3][0]=R_parmat[3][1]=R_parmat[3][2]=0.0F;
+ }
+
+ Mat4Invert(iR_parmat, R_parmat);
+ Mat4MulMat4(M_basismat, R_bonemat, iR_parmat);
+
+ /* Copy the matrix into the basis and transpose */
+ Mat3CpyMat4(segs[icurseg].basis, M_basismat);
+ Mat3Transp(segs[icurseg].basis);
+
+ /* Fill out the IK segment */
+ segs[icurseg].length = get_bone_length(curBone);
+
+ };
+
+ IK_LoadChain(chain->solver, segs, segcount);
+ return chain;
+}
+
+
+
+void precalc_bonelist_irestmats (ListBase* bonelist)
+{
+ Bone *curbone;
+
+ if (!bonelist)
+ return;
+
+ for (curbone = bonelist->first; curbone; curbone=curbone->next){
+ precalc_bone_irestmat(curbone);
+ precalc_bonelist_irestmats(&curbone->childbase);
+ }
+}