NLA SoC: Start of 'Meta' Strips
[blender.git] / source / blender / blenkernel / intern / armature.c
index 9c764f58315a501a50da7e8d0b62644fa5e30bfe..1b930a74449b7e0353507643de2a48e7b81c87d3 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * $Id$
  *
- * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -22,7 +22,7 @@
  *
  * Contributor(s): Full recode, Ton Roosendaal, Crete 2005
  *
- * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * ***** END GPL LICENSE BLOCK *****
  */
 
 #include <ctype.h>
 #include <math.h>
 #include <string.h>
 #include <stdio.h>
+#include <float.h>
+
 #include "MEM_guardedalloc.h"
 
-#include "nla.h"
+//XXX #include "nla.h"
 
 #include "BLI_arithb.h"
 #include "BLI_blenlib.h"
@@ -65,7 +67,7 @@
 #include "BKE_object.h"
 #include "BKE_utildefines.h"
 
-#include "BIF_editdeform.h"
+//XXX #include "BIF_editdeform.h"
 
 #include "IK_solver.h"
 
 
 /*     **************** Generic Functions, data level *************** */
 
-bArmature *get_armature(Object *ob)
-{
-       if(ob==NULL) return NULL;
-       if(ob->type==OB_ARMATURE) return ob->data;
-       else return NULL;
-}
-
 bArmature *add_armature(char *name)
 {
        bArmature *arm;
@@ -92,6 +87,12 @@ bArmature *add_armature(char *name)
        return arm;
 }
 
+bArmature *get_armature(Object *ob)
+{
+       if(ob->type==OB_ARMATURE)
+               return (bArmature *)ob->data;
+       return NULL;
+}
 
 void free_boneChildren(Bone *bone)
 { 
@@ -131,6 +132,14 @@ void free_armature(bArmature *arm)
        if (arm) {
                /*              unlink_armature(arm);*/
                free_bones(arm);
+               
+               /* free editmode data */
+               if (arm->edbo) {
+                       BLI_freelistN(arm->edbo);
+                       
+                       MEM_freeN(arm->edbo);
+                       arm->edbo= NULL;
+               }
        }
 }
 
@@ -178,7 +187,7 @@ static void copy_bonechildren (Bone* newBone, Bone* oldBone)
        Bone    *curBone, *newChildBone;
        
        /*      Copy this bone's list*/
-       duplicatelist (&newBone->childbase, &oldBone->childbase);
+       BLI_duplicatelist(&newBone->childbase, &oldBone->childbase);
        
        /*      For each child in the list, update it's children*/
        newChildBone=newBone->childbase.first;
@@ -195,7 +204,7 @@ bArmature *copy_armature(bArmature *arm)
        Bone            *oldBone, *newBone;
        
        newArm= copy_libblock (arm);
-       duplicatelist(&newArm->bonebase, &arm->bonebase);
+       BLI_duplicatelist(&newArm->bonebase, &arm->bonebase);
        
        /*      Duplicate the childrens' lists*/
        newBone=newArm->bonebase.first;
@@ -354,6 +363,117 @@ void bone_flip_name (char *name, int strip_number)
        sprintf (name, "%s%s%s%s", prefix, replace, suffix, number);
 }
 
+/* Finds the best possible extension to the name on a particular axis. (For renaming, check for unique names afterwards)
+ * This assumes that bone names are at most 32 chars long!
+ *     strip_number: removes number extensions  (TODO: not used)
+ *     axis: the axis to name on
+ *     head/tail: the head/tail co-ordinate of the bone on the specified axis
+ */
+void bone_autoside_name (char *name, int strip_number, short axis, float head, float tail)
+{
+       unsigned int len;
+       char    basename[32]={""};
+       char    extension[5]={""};
+
+       len= strlen(name);
+       if (len == 0) return;
+       strcpy(basename, name);
+       
+       /* Figure out extension to append: 
+        *      - The extension to append is based upon the axis that we are working on.
+        *      - If head happens to be on 0, then we must consider the tail position as well to decide
+        *        which side the bone is on
+        *              -> If tail is 0, then it's bone is considered to be on axis, so no extension should be added
+        *              -> Otherwise, extension is added from perspective of object based on which side tail goes to
+        *      - If head is non-zero, extension is added from perspective of object based on side head is on
+        */
+       if (axis == 2) {
+               /* z-axis - vertical (top/bottom) */
+               if (IS_EQ(head, 0)) {
+                       if (tail < 0)
+                               strcpy(extension, "Bot");
+                       else if (tail > 0)
+                               strcpy(extension, "Top");
+               }
+               else {
+                       if (head < 0)
+                               strcpy(extension, "Bot");
+                       else
+                               strcpy(extension, "Top");
+               }
+       }
+       else if (axis == 1) {
+               /* y-axis - depth (front/back) */
+               if (IS_EQ(head, 0)) {
+                       if (tail < 0)
+                               strcpy(extension, "Fr");
+                       else if (tail > 0)
+                               strcpy(extension, "Bk");
+               }
+               else {
+                       if (head < 0)
+                               strcpy(extension, "Fr");
+                       else
+                               strcpy(extension, "Bk");
+               }
+       }
+       else {
+               /* x-axis - horizontal (left/right) */
+               if (IS_EQ(head, 0)) {
+                       if (tail < 0)
+                               strcpy(extension, "R");
+                       else if (tail > 0)
+                               strcpy(extension, "L");
+               }
+               else {
+                       if (head < 0)
+                               strcpy(extension, "R");
+                       else if (head > 0)
+                               strcpy(extension, "L");
+               }
+       }
+
+       /* Simple name truncation 
+        *      - truncate if there is an extension and it wouldn't be able to fit
+        *      - otherwise, just append to end
+        */
+       if (extension[0]) {
+               int change = 1;
+               
+               while (change) { /* remove extensions */
+                       change = 0;
+                       if (len > 2 && basename[len-2]=='.') {
+                               if (basename[len-1]=='L' || basename[len-1] == 'R' ) { /* L R */
+                                       basename[len-2] = '\0';
+                                       len-=2;
+                                       change= 1;
+                               }
+                       } else if (len > 3 && basename[len-3]=='.') {
+                               if (    (basename[len-2]=='F' && basename[len-1] == 'r') ||     /* Fr */
+                                               (basename[len-2]=='B' && basename[len-1] == 'k')        /* Bk */
+                               ) {
+                                       basename[len-3] = '\0';
+                                       len-=3;
+                                       change= 1;
+                               }
+                       } else if (len > 4 && basename[len-4]=='.') {
+                               if (    (basename[len-3]=='T' && basename[len-2]=='o' && basename[len-1] == 'p') ||     /* Top */
+                                               (basename[len-3]=='B' && basename[len-2]=='o' && basename[len-1] == 't')        /* Bot */
+                               ) {
+                                       basename[len-4] = '\0';
+                                       len-=4;
+                                       change= 1;
+                               }
+                       }
+               }
+               
+               if ((32 - len) < strlen(extension) + 1) { /* add 1 for the '.' */
+                       strncpy(name, basename, len-strlen(extension));
+               }
+       }
+
+       sprintf(name, "%s.%s", basename, extension);
+}
 
 /* ************* B-Bone support ******************* */
 
@@ -404,17 +524,38 @@ static void equalize_bezier(float *data, int desired)
 
 /* returns pointer to static array, filled with desired amount of bone->segments elements */
 /* this calculation is done  within unit bone space */
-Mat4 *b_bone_spline_setup(bPoseChannel *pchan)
+Mat4 *b_bone_spline_setup(bPoseChannel *pchan, int rest)
 {
        static Mat4 bbone_array[MAX_BBONE_SUBDIV];
+       static Mat4 bbone_rest_array[MAX_BBONE_SUBDIV];
+       Mat4 *result_array= (rest)? bbone_rest_array: bbone_array;
        bPoseChannel *next, *prev;
        Bone *bone= pchan->bone;
-       float h1[3], h2[3], length, hlength1, hlength2, roll;
-       float mat3[3][3], imat[4][4];
+       float h1[3], h2[3], scale[3], length, hlength1, hlength2, roll1=0.0f, roll2;
+       float mat3[3][3], imat[4][4], posemat[4][4], scalemat[4][4], iscalemat[4][4];
        float data[MAX_BBONE_SUBDIV+1][4], *fp;
-       int a;
-       
+       int a, doscale= 0;
+
        length= bone->length;
+
+       if(!rest) {
+               /* check if we need to take non-uniform bone scaling into account */
+               scale[0]= VecLength(pchan->pose_mat[0]);
+               scale[1]= VecLength(pchan->pose_mat[1]);
+               scale[2]= VecLength(pchan->pose_mat[2]);
+
+               if(fabs(scale[0] - scale[1]) > 1e-6f || fabs(scale[1] - scale[2]) > 1e-6f) {
+                       Mat4One(scalemat);
+                       scalemat[0][0]= scale[0];
+                       scalemat[1][1]= scale[1];
+                       scalemat[2][2]= scale[2];
+                       Mat4Invert(iscalemat, scalemat);
+
+                       length *= scale[1];
+                       doscale = 1;
+               }
+       }
+       
        hlength1= bone->ease1*length*0.390464f;         // 0.5*sqrt(2)*kappa, the handle length for near-perfect circles
        hlength2= bone->ease2*length*0.390464f;
        
@@ -430,32 +571,75 @@ Mat4 *b_bone_spline_setup(bPoseChannel *pchan)
                first point = (0,0,0)
                last point =  (0, length, 0) */
        
-       Mat4Invert(imat, pchan->pose_mat);
+       if(rest) {
+               Mat4Invert(imat, pchan->bone->arm_mat);
+       }
+       else if(doscale) {
+               Mat4CpyMat4(posemat, pchan->pose_mat);
+               Mat4Ortho(posemat);
+               Mat4Invert(imat, posemat);
+       }
+       else
+               Mat4Invert(imat, pchan->pose_mat);
        
        if(prev) {
+               float difmat[4][4], result[3][3], imat3[3][3];
+
                /* transform previous point inside this bone space */
-               VECCOPY(h1, prev->pose_head);
+               if(rest)
+                       VECCOPY(h1, prev->bone->arm_head)
+               else
+                       VECCOPY(h1, prev->pose_head)
                Mat4MulVecfl(imat, h1);
-               /* if previous bone is B-bone too, use average handle direction */
-               if(prev->bone->segments>1) h1[1]-= length;
-               Normalise(h1);
+
+               if(prev->bone->segments>1) {
+                       /* if previous bone is B-bone too, use average handle direction */
+                       h1[1]-= length;
+                       roll1= 0.0f;
+               }
+
+               Normalize(h1);
                VecMulf(h1, -hlength1);
+
+               if(prev->bone->segments==1) {
+                       /* find the previous roll to interpolate */
+                       if(rest)
+                               Mat4MulMat4(difmat, prev->bone->arm_mat, imat);
+                       else
+                               Mat4MulMat4(difmat, prev->pose_mat, imat);
+                       Mat3CpyMat4(result, difmat);                            // the desired rotation at beginning of next bone
+                       
+                       vec_roll_to_mat3(h1, 0.0f, mat3);                       // the result of vec_roll without roll
+                       
+                       Mat3Inv(imat3, mat3);
+                       Mat3MulMat3(mat3, result, imat3);                       // the matrix transforming vec_roll to desired roll
+                       
+                       roll1= (float)atan2(mat3[2][0], mat3[2][2]);
+               }
        }
        else {
                h1[0]= 0.0f; h1[1]= hlength1; h1[2]= 0.0f;
+               roll1= 0.0f;
        }
        if(next) {
                float difmat[4][4], result[3][3], imat3[3][3];
                
                /* transform next point inside this bone space */
-               VECCOPY(h2, next->pose_tail);
+               if(rest)
+                       VECCOPY(h2, next->bone->arm_tail)
+               else
+                       VECCOPY(h2, next->pose_tail)
                Mat4MulVecfl(imat, h2);
                /* if next bone is B-bone too, use average handle direction */
                if(next->bone->segments>1);
                else h2[1]-= length;
+               Normalize(h2);
                
                /* find the next roll to interpolate as well */
-               Mat4MulMat4(difmat, next->pose_mat, imat);
+               if(rest)
+                       Mat4MulMat4(difmat, next->bone->arm_mat, imat);
+               else
+                       Mat4MulMat4(difmat, next->pose_mat, imat);
                Mat3CpyMat4(result, difmat);                            // the desired rotation at beginning of next bone
                
                vec_roll_to_mat3(h2, 0.0f, mat3);                       // the result of vec_roll without roll
@@ -463,18 +647,16 @@ Mat4 *b_bone_spline_setup(bPoseChannel *pchan)
                Mat3Inv(imat3, mat3);
                Mat3MulMat3(mat3, imat3, result);                       // the matrix transforming vec_roll to desired roll
                
-               rollatan2(mat3[2][0], mat3[2][2]);
+               roll2= (float)atan2(mat3[2][0], mat3[2][2]);
                
                /* and only now negate handle */
-               Normalise(h2);
                VecMulf(h2, -hlength2);
-               
        }
        else {
                h2[0]= 0.0f; h2[1]= -hlength2; h2[2]= 0.0f;
-               roll= 0.0;
+               roll2= 0.0;
        }
-       
+
        /* make curve */
        if(bone->segments > MAX_BBONE_SUBDIV)
                bone->segments= MAX_BBONE_SUBDIV;
@@ -482,7 +664,7 @@ Mat4 *b_bone_spline_setup(bPoseChannel *pchan)
        forward_diff_bezier(0.0, h1[0],         h2[0],                  0.0,            data[0],        MAX_BBONE_SUBDIV, 4);
        forward_diff_bezier(0.0, h1[1],         length + h2[1], length,         data[0]+1,      MAX_BBONE_SUBDIV, 4);
        forward_diff_bezier(0.0, h1[2],         h2[2],                  0.0,            data[0]+2,      MAX_BBONE_SUBDIV, 4);
-       forward_diff_bezier(0.0, 0.390464f*roll, (1.0f-0.390464f)*roll, roll,   data[0]+3,      MAX_BBONE_SUBDIV, 4);
+       forward_diff_bezier(roll1, roll1 + 0.390464f*(roll2-roll1), roll2 - 0.390464f*(roll2-roll1),    roll2,  data[0]+3,      MAX_BBONE_SUBDIV, 4);
        
        equalize_bezier(data[0], bone->segments);       // note: does stride 4!
        
@@ -490,53 +672,93 @@ Mat4 *b_bone_spline_setup(bPoseChannel *pchan)
        for(a=0, fp= data[0]; a<bone->segments; a++, fp+=4) {
                VecSubf(h1, fp+4, fp);
                vec_roll_to_mat3(h1, fp[3], mat3);              // fp[3] is roll
-               Mat4CpyMat3(bbone_array[a].mat, mat3);
-               VECCOPY(bbone_array[a].mat[3], fp);
+
+               Mat4CpyMat3(result_array[a].mat, mat3);
+               VECCOPY(result_array[a].mat[3], fp);
+
+               if(doscale) {
+                       /* correct for scaling when this matrix is used in scaled space */
+                       Mat4MulSerie(result_array[a].mat, iscalemat, result_array[a].mat,
+                               scalemat, NULL, NULL, NULL, NULL, NULL);
+               }
        }
        
-       return bbone_array;
+       return result_array;
 }
 
 /* ************ Armature Deform ******************* */
 
-static void pchan_b_bone_defmats(bPoseChannel *pchan)
+static void pchan_b_bone_defmats(bPoseChannel *pchan, int use_quaternion, int rest_def)
 {
        Bone *bone= pchan->bone;
-       Mat4 *b_bone= b_bone_spline_setup(pchan);
+       Mat4 *b_bone= b_bone_spline_setup(pchan, 0);
+       Mat4 *b_bone_rest= (rest_def)? NULL: b_bone_spline_setup(pchan, 1);
        Mat4 *b_bone_mats;
+       DualQuat *b_bone_dual_quats= NULL;
+       float tmat[4][4];
        int a;
        
-       pchan->b_bone_mats=b_bone_mats= MEM_mallocN((1+bone->segments)*sizeof(Mat4), "BBone defmats");
+       /* allocate b_bone matrices and dual quats */
+       b_bone_mats= MEM_mallocN((1+bone->segments)*sizeof(Mat4), "BBone defmats");
+       pchan->b_bone_mats= b_bone_mats;
+
+       if(use_quaternion) {
+               b_bone_dual_quats= MEM_mallocN((bone->segments)*sizeof(DualQuat), "BBone dqs");
+               pchan->b_bone_dual_quats= b_bone_dual_quats;
+       }
        
-       /* first matrix is the inverse arm_mat, to bring points in local bone space */
+       /* first matrix is the inverse arm_mat, to bring points in local bone space
+          for finding out which segment it belongs to */
        Mat4Invert(b_bone_mats[0].mat, bone->arm_mat);
-       
-       /* then we multiply the bbone_mats with arm_mat */
+
+       /* then we make the b_bone_mats:
+           - first transform to local bone space
+               - translate over the curve to the bbone mat space
+               - transform with b_bone matrix
+               - transform back into global space */
+       Mat4One(tmat);
+
        for(a=0; a<bone->segments; a++) {
-               Mat4MulMat4(b_bone_mats[a+1].mat, b_bone[a].mat, bone->arm_mat);
+               if(b_bone_rest)
+                       Mat4Invert(tmat, b_bone_rest[a].mat);
+               else
+                       tmat[3][1] = -a*(bone->length/(float)bone->segments);
+
+               Mat4MulSerie(b_bone_mats[a+1].mat, pchan->chan_mat, bone->arm_mat,
+                       b_bone[a].mat, tmat, b_bone_mats[0].mat, NULL, NULL, NULL);
+
+               if(use_quaternion)
+                       Mat4ToDQuat(bone->arm_mat, b_bone_mats[a+1].mat, &b_bone_dual_quats[a]);
        }
 }
 
-static void b_bone_deform(bPoseChannel *pchan, Bone *bone, float *defpos)
+static void b_bone_deform(bPoseChannel *pchan, Bone *bone, float *co, DualQuat *dq, float defmat[][3])
 {
        Mat4 *b_bone= pchan->b_bone_mats;
-       float segment;
+       float (*mat)[4]= b_bone[0].mat;
+       float segment, y;
        int a;
        
-       /* need to transform defpos back to bonespace */
-       Mat4MulVecfl(b_bone[0].mat, defpos);
+       /* need to transform co back to bonespace, only need y */
+       y= mat[0][1]*co[0] + mat[1][1]*co[1] + mat[2][1]*co[2] + mat[3][1];
        
        /* now calculate which of the b_bones are deforming this */
        segment= bone->length/((float)bone->segments);
-       a= (int) (defpos[1]/segment);
+       a= (int)(y/segment);
        
-       /* note; by clamping it extends deform at endpoints, goes best with straight joints in restpos. */
+       /* note; by clamping it extends deform at endpoints, goes best with
+          straight joints in restpos. */
        CLAMP(a, 0, bone->segments-1);
 
-       /* since the bbone mats translate from (0.0.0) on the curve, we subtract */
-       defpos[1] -= ((float)a)*segment;
-       
-       Mat4MulVecfl(b_bone[a+1].mat, defpos);
+       if(dq) {
+               DQuatCpyDQuat(dq, &((DualQuat*)pchan->b_bone_dual_quats)[a]);
+       }
+       else {
+               Mat4MulVecfl(b_bone[a+1].mat, co);
+
+               if(defmat)
+                       Mat3CpyMat4(defmat, b_bone[a+1].mat);
+       }
 }
 
 /* using vec with dist to bone b1 - b2 */
@@ -548,7 +770,7 @@ float distfactor_to_bone (float vec[3], float b1[3], float b2[3], float rad1, fl
        float hsqr, a, l, rad;
        
        VecSubf (bdelta, b2, b1);
-       l = Normalise (bdelta);
+       l = Normalize (bdelta);
        
        VecSubf (pdelta, vec, b1);
        
@@ -570,7 +792,7 @@ float distfactor_to_bone (float vec[3], float b1[3], float b2[3], float rad1, fl
                
                if(l!=0.0f) {
                        rad= a/l;
-                       rad= rad*rad2 + (1.0-rad)*rad1;
+                       rad= rad*rad2 + (1.0f-rad)*rad1;
                }
                else rad= rad1;
        }
@@ -584,18 +806,31 @@ float distfactor_to_bone (float vec[3], float b1[3], float b2[3], float rad1, fl
                if(rdist==0.0f || dist >= l) 
                        return 0.0f;
                else {
-                       a= sqrt(dist)-rad;
-                       return 1.0-( a*a )/( rdist*rdist );
+                       a= (float)sqrt(dist)-rad;
+                       return 1.0f-( a*a )/( rdist*rdist );
                }
        }
 }
 
-static float dist_bone_deform(bPoseChannel *pchan, float *vec, float *co)
+static void pchan_deform_mat_add(bPoseChannel *pchan, float weight, float bbonemat[][3], float mat[][3])
+{
+       float wmat[3][3];
+
+       if(pchan->bone->segments>1)
+               Mat3CpyMat3(wmat, bbonemat);
+       else
+               Mat3CpyMat4(wmat, pchan->chan_mat);
+
+       Mat3MulFloat((float*)wmat, weight);
+       Mat3AddMat3(mat, mat, wmat);
+}
+
+static float dist_bone_deform(bPoseChannel *pchan, float *vec, DualQuat *dq, float mat[][3], float *co)
 {
        Bone *bone= pchan->bone;
-       float   fac;
-       float   cop[3];
-       float   contrib=0.0;
+       float fac, contrib=0.0;
+       float cop[3], bbonemat[3][3];
+       DualQuat bbonedq;
 
        if(bone==NULL) return 0.0f;
        
@@ -603,64 +838,98 @@ static float dist_bone_deform(bPoseChannel *pchan, float *vec, float *co)
 
        fac= distfactor_to_bone(cop, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist);
        
-       if (fac>0.0){
+       if (fac>0.0) {
                
                fac*=bone->weight;
                contrib= fac;
                if(contrib>0.0) {
+                       if(vec) {
+                               if(bone->segments>1)
+                                       // applies on cop and bbonemat
+                                       b_bone_deform(pchan, bone, cop, NULL, (mat)?bbonemat:NULL);
+                               else
+                                       Mat4MulVecfl(pchan->chan_mat, cop);
 
-                       VECCOPY (cop, co);
-                       
-                       if(bone->segments>1)
-                               b_bone_deform(pchan, bone, cop);        // applies on cop
-                       
-                       Mat4MulVecfl(pchan->chan_mat, cop);
-                       
-                       VecSubf (cop, cop, co); //      Make this a delta from the base position
-                       cop[0]*=fac; cop[1]*=fac; cop[2]*=fac;
-                       VecAddf (vec, vec, cop);
+                               //      Make this a delta from the base position
+                               VecSubf (cop, cop, co);
+                               cop[0]*=fac; cop[1]*=fac; cop[2]*=fac;
+                               VecAddf (vec, vec, cop);
+
+                               if(mat)
+                                       pchan_deform_mat_add(pchan, fac, bbonemat, mat);
+                       }
+                       else {
+                               if(bone->segments>1) {
+                                       b_bone_deform(pchan, bone, cop, &bbonedq, NULL);
+                                       DQuatAddWeighted(dq, &bbonedq, fac);
+                               }
+                               else
+                                       DQuatAddWeighted(dq, pchan->dual_quat, fac);
+                       }
                }
        }
        
        return contrib;
 }
 
-static void pchan_bone_deform(bPoseChannel *pchan, float weight, float *vec, float *co, float *contrib)
+static void pchan_bone_deform(bPoseChannel *pchan, float weight, float *vec, DualQuat *dq, float mat[][3], float *co, float *contrib)
 {
-       float   cop[3];
+       float cop[3], bbonemat[3][3];
+       DualQuat bbonedq;
 
        if (!weight)
                return;
 
-       VECCOPY (cop, co);
-       
-       if(pchan->bone->segments>1)
-               b_bone_deform(pchan, pchan->bone, cop); // applies on cop
-       
-       Mat4MulVecfl(pchan->chan_mat, cop);
-       
-       vec[0]+=(cop[0]-co[0])*weight;
-       vec[1]+=(cop[1]-co[1])*weight;
-       vec[2]+=(cop[2]-co[2])*weight;
+       VECCOPY(cop, co);
+
+       if(vec) {
+               if(pchan->bone->segments>1)
+                       // applies on cop and bbonemat
+                       b_bone_deform(pchan, pchan->bone, cop, NULL, (mat)?bbonemat:NULL);
+               else
+                       Mat4MulVecfl(pchan->chan_mat, cop);
+               
+               vec[0]+=(cop[0]-co[0])*weight;
+               vec[1]+=(cop[1]-co[1])*weight;
+               vec[2]+=(cop[2]-co[2])*weight;
+
+               if(mat)
+                       pchan_deform_mat_add(pchan, weight, bbonemat, mat);
+       }
+       else {
+               if(pchan->bone->segments>1) {
+                       b_bone_deform(pchan, pchan->bone, cop, &bbonedq, NULL);
+                       DQuatAddWeighted(dq, &bbonedq, weight);
+               }
+               else
+                       DQuatAddWeighted(dq, pchan->dual_quat, weight);
+       }
 
        (*contrib)+=weight;
 }
 
 void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
-                           float (*vertexCos)[3], int numVerts, int deformflag,
-                           const char *defgrp_name)
+                           float (*vertexCos)[3], float (*defMats)[3][3],
+                                                  int numVerts, int deformflag, 
+                                                  float (*prevCos)[3], const char *defgrp_name)
 {
+       bArmature *arm= armOb->data;
        bPoseChannel *pchan, **defnrToPC = NULL;
        MDeformVert *dverts = NULL;
        bDeformGroup *dg;
+       DualQuat *dualquats= NULL;
        float obinv[4][4], premat[4][4], postmat[4][4];
        int use_envelope = deformflag & ARM_DEF_ENVELOPE;
+       int use_quaternion = deformflag & ARM_DEF_QUATERNION;
+       int bbone_rest_def = deformflag & ARM_DEF_B_BONE_REST;
+       int invert_vgroup= deformflag & ARM_DEF_INVERT_VGROUP;
        int numGroups = 0;              /* safety for vertexgroup index overflow */
        int i, target_totvert = 0;      /* safety for vertexgroup overflow */
        int use_dverts = 0;
        int armature_def_nr = -1;
+       int totchan;
 
-       if(armOb == G.obedit) return;
+       if(arm->edbo) return;
        
        Mat4Invert(obinv, target->obmat);
        Mat4CpyMat4(premat, target->obmat);
@@ -669,11 +938,23 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
 
        /* bone defmats are already in the channels, chan_mat */
        
-       /* initialize B_bone matrices */
+       /* initialize B_bone matrices and dual quaternions */
+       if(use_quaternion) {
+               totchan= BLI_countlist(&armOb->pose->chanbase);
+               dualquats= MEM_callocN(sizeof(DualQuat)*totchan, "dualquats");
+       }
+
+       totchan= 0;
        for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) {
-               if(!(pchan->bone->flag & BONE_NO_DEFORM))
+               if(!(pchan->bone->flag & BONE_NO_DEFORM)) {
                        if(pchan->bone->segments > 1)
-                               pchan_b_bone_defmats(pchan);
+                               pchan_b_bone_defmats(pchan, use_quaternion, bbone_rest_def);
+
+                       if(use_quaternion) {
+                               pchan->dual_quat= &dualquats[totchan++];
+                               Mat4ToDQuat(pchan->bone->arm_mat, pchan->chan_mat, pchan->dual_quat);
+                       }
+               }
        }
 
        /* get the def_nr for the overall armature vertex group if present */
@@ -722,17 +1003,32 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
 
        for(i = 0; i < numVerts; i++) {
                MDeformVert *dvert;
-               float *co = vertexCos[i];
-               float vec[3];
+               DualQuat sumdq, *dq = NULL;
+               float *co, dco[3];
+               float sumvec[3], summat[3][3];
+               float *vec = NULL, (*smat)[3] = NULL;
                float contrib = 0.0f;
-               float armature_weight = 1.0f; /* default to 1 if no overall def group */
+               float armature_weight = 1.0f;   /* default to 1 if no overall def group */
+               float prevco_weight = 1.0f;             /* weight for optional cached vertexcos */
                int       j;
 
-               vec[0] = vec[1] = vec[2] = 0.0f;
+               if(use_quaternion) {
+                       memset(&sumdq, 0, sizeof(DualQuat));
+                       dq= &sumdq;
+               }
+               else {
+                       sumvec[0] = sumvec[1] = sumvec[2] = 0.0f;
+                       vec= sumvec;
+
+                       if(defMats) {
+                               Mat3Clr((float*)summat);
+                               smat = summat;
+                       }
+               }
 
                if(use_dverts || armature_def_nr >= 0) {
                        if(dm) dvert = dm->getVertData(dm, i, CD_MDEFORMVERT);
-                       else if(i < target_totvert) dvert = dverts + i;
+                       else if(dverts && i < target_totvert) dvert = dverts + i;
                        else dvert = NULL;
                } else
                        dvert = NULL;
@@ -745,11 +1041,22 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
                                        break;
                                }
                        }
+                       /* hackish: the blending factor can be used for blending with prevCos too */
+                       if(prevCos) {
+                               if(invert_vgroup)
+                                       prevco_weight= 1.0f-armature_weight;
+                               else
+                                       prevco_weight= armature_weight;
+                               armature_weight= 1.0f;
+                       }
                }
 
                /* check if there's any  point in calculating for this vert */
                if(armature_weight == 0.0f) continue;
                
+               /* get the coord we work on */
+               co= prevCos?prevCos[i]:vertexCos[i];
+               
                /* Apply the object's matrix */
                Mat4MulVecfl(premat, co);
                
@@ -772,7 +1079,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
                                                                             bone->rad_tail,
                                                                             bone->dist);
                                        }
-                                       pchan_bone_deform(pchan, weight, vec, co, &contrib);
+                                       pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib);
                                }
                        }
                        /* if there are vertexgroups but not groups with bones
@@ -782,7 +1089,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
                                for(pchan = armOb->pose->chanbase.first; pchan;
                                    pchan = pchan->next) {
                                        if(!(pchan->bone->flag & BONE_NO_DEFORM))
-                                               contrib += dist_bone_deform(pchan, vec, co);
+                                               contrib += dist_bone_deform(pchan, vec, dq, smat, co);
                                }
                        }
                }
@@ -790,19 +1097,61 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
                        for(pchan = armOb->pose->chanbase.first; pchan;
                            pchan = pchan->next) {
                                if(!(pchan->bone->flag & BONE_NO_DEFORM))
-                                       contrib += dist_bone_deform(pchan, vec, co);
+                                       contrib += dist_bone_deform(pchan, vec, dq, smat, co);
                        }
                }
 
                /* actually should be EPSILON? weight values and contrib can be like 10e-39 small */
                if(contrib > 0.0001f) {
-                       VecMulf(vec, armature_weight / contrib);
-                       VecAddf(co, vec, co);
+                       if(use_quaternion) {
+                               DQuatNormalize(dq, contrib);
+
+                               if(armature_weight != 1.0f) {
+                                       VECCOPY(dco, co);
+                                       DQuatMulVecfl(dq, dco, (defMats)? summat: NULL);
+                                       VecSubf(dco, dco, co);
+                                       VecMulf(dco, armature_weight);
+                                       VecAddf(co, co, dco);
+                               }
+                               else
+                                       DQuatMulVecfl(dq, co, (defMats)? summat: NULL);
+
+                               smat = summat;
+                       }
+                       else {
+                               VecMulf(vec, armature_weight/contrib);
+                               VecAddf(co, vec, co);
+                       }
+
+                       if(defMats) {
+                               float pre[3][3], post[3][3], tmpmat[3][3];
+
+                               Mat3CpyMat4(pre, premat);
+                               Mat3CpyMat4(post, postmat);
+                               Mat3CpyMat3(tmpmat, defMats[i]);
+
+                               if(!use_quaternion) /* quaternion already is scale corrected */
+                                       Mat3MulFloat((float*)smat, armature_weight/contrib);
+
+                               Mat3MulSerie(defMats[i], tmpmat, pre, smat, post,
+                                       NULL, NULL, NULL, NULL);
+                       }
                }
+               
                /* always, check above code */
                Mat4MulVecfl(postmat, co);
+               
+               
+               /* interpolate with previous modifier position using weight group */
+               if(prevCos) {
+                       float mw= 1.0f - prevco_weight;
+                       vertexCos[i][0]= prevco_weight*vertexCos[i][0] + mw*co[0];
+                       vertexCos[i][1]= prevco_weight*vertexCos[i][1] + mw*co[1];
+                       vertexCos[i][2]= prevco_weight*vertexCos[i][2] + mw*co[2];
+               }
        }
 
+       if(dualquats) MEM_freeN(dualquats);
        if(defnrToPC) MEM_freeN(defnrToPC);
        
        /* free B_bone matrices */
@@ -811,6 +1160,12 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
                        MEM_freeN(pchan->b_bone_mats);
                        pchan->b_bone_mats = NULL;
                }
+               if(pchan->b_bone_dual_quats) {
+                       MEM_freeN(pchan->b_bone_dual_quats);
+                       pchan->b_bone_dual_quats = NULL;
+               }
+
+               pchan->dual_quat = NULL;
        }
 }
 
@@ -869,7 +1224,10 @@ void armature_mat_pose_to_bone(bPoseChannel *pchan, float inmat[][4], float outm
        if (pchan==NULL) return;
        
        /* get the inverse matrix of the pchan's transforms */
-       LocQuatSizeToMat4(pc_trans, pchan->loc, pchan->quat, pchan->size);
+       if (pchan->rotmode)
+               LocEulSizeToMat4(pc_trans, pchan->loc, pchan->eul, pchan->size);
+       else
+               LocQuatSizeToMat4(pc_trans, pchan->loc, pchan->quat, pchan->size);
        Mat4Invert(inv_trans, pc_trans);
        
        /* Remove the pchan's transforms from it's pose_mat.
@@ -941,18 +1299,18 @@ void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float
      contain only a rotation, and no scaling. */ 
 void mat3_to_vec_roll(float mat[][3], float *vec, float *roll) 
 {
-     if (vec)
-         VecCopyf(vec, mat[1]);
+    if (vec)
+        VecCopyf(vec, mat[1]);
 
-     if (roll) {
-         float vecmat[3][3], vecmatinv[3][3], rollmat[3][3];
+    if (roll) {
+        float vecmat[3][3], vecmatinv[3][3], rollmat[3][3];
 
-         vec_roll_to_mat3(mat[1], 0.0f, vecmat);
-         Mat3Inv(vecmatinv, vecmat);
-         Mat3MulMat3(rollmat, vecmatinv, mat);
+        vec_roll_to_mat3(mat[1], 0.0f, vecmat);
+        Mat3Inv(vecmatinv, vecmat);
+        Mat3MulMat3(rollmat, vecmatinv, mat);
 
-         *roll= atan2(rollmat[2][0], rollmat[2][2]);
-     }
+        *roll= (float)atan2(rollmat[2][0], rollmat[2][2]);
+    }
 }
 
 /*     Calculates the rest matrix of a bone based
@@ -964,14 +1322,14 @@ void vec_roll_to_mat3(float *vec, float roll, float mat[][3])
        float   rMatrix[3][3], bMatrix[3][3];
        
        VECCOPY (nor, vec);
-       Normalise (nor);
+       Normalize (nor);
        
        /*      Find Axis & Amount for bone matrix*/
        Crossf (axis,target,nor);
 
        if (Inpf(axis,axis) > 0.0000000000001) {
                /* if nor is *not* a multiple of target ... */
-               Normalise (axis);
+               Normalize (axis);
                
                theta= NormalizedVecAngle2(target, nor);
                
@@ -983,7 +1341,7 @@ void vec_roll_to_mat3(float *vec, float roll, float mat[][3])
                float updown;
                
                /* point same direction, or opposite? */
-               updown = ( Inpf (target,nor) > 0 ) ? 1.0 : -1.0;
+               updown = ( Inpf (target,nor) > 0 ) ? 1.0f : -1.0f;
                
                /* I think this should work ... */
                bMatrix[0][0]=updown; bMatrix[0][1]=0.0;    bMatrix[0][2]=0.0;
@@ -1070,20 +1428,28 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
        bPose *pose= ob->pose, *frompose= from->pose;
        bPoseChannel *pchan, *pchanp, pchanw;
        bConstraint *con;
-       char *str;
        
-       if(frompose==NULL) return;
+       if (frompose==NULL) return;
        
        /* exception, armature local layer should be proxied too */
-       if(pose->proxy_layer)
+       if (pose->proxy_layer)
                ((bArmature *)ob->data)->layer= pose->proxy_layer;
        
        /* clear all transformation values from library */
        rest_pose(frompose);
        
-       pchan= pose->chanbase.first;
-       for(; pchan; pchan= pchan->next) {
-               if(pchan->bone->layer & layer_protected) {
+       /* copy over all of the proxy's bone groups */
+               /* TODO for later - implement 'local' bone groups as for constraints
+                *      Note: this isn't trivial, as bones reference groups by index not by pointer, 
+                *               so syncing things correctly needs careful attention
+                */
+       BLI_freelistN(&pose->agroups);
+       BLI_duplicatelist(&pose->agroups, &frompose->agroups);
+       pose->active_group= frompose->active_group;
+       
+       for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
+               if (pchan->bone->layer & layer_protected) {
+                       ListBase proxylocal_constraints = {NULL, NULL};
                        pchanp= get_pose_channel(frompose, pchan->name);
                        
                        /* copy posechannel to temp, but restore important pointers */
@@ -1094,16 +1460,36 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
                        pchanw.child= pchan->child;
                        pchanw.path= NULL;
                        
-                       /* constraints, set target ob pointer to own object */
+                       /* constraints - proxy constraints are flushed... local ones are added after 
+                        *      1. extract constraints not from proxy (CONSTRAINT_PROXY_LOCAL) from pchan's constraints
+                        *      2. copy proxy-pchan's constraints on-to new
+                        *      3. add extracted local constraints back on top 
+                        */
+                       extract_proxylocal_constraints(&proxylocal_constraints, &pchan->constraints);
                        copy_constraints(&pchanw.constraints, &pchanp->constraints);
-
-                       for(con= pchanw.constraints.first; con; con= con->next) {
-                               if(from==get_constraint_target(con, &str))
-                                       set_constraint_target(con, ob, NULL);
+                       addlisttolist(&pchanw.constraints, &proxylocal_constraints);
+                       
+                       /* constraints - set target ob pointer to own object */
+                       for (con= pchanw.constraints.first; con; con= con->next) {
+                               bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+                               ListBase targets = {NULL, NULL};
+                               bConstraintTarget *ct;
+                               
+                               if (cti && cti->get_constraint_targets) {
+                                       cti->get_constraint_targets(con, &targets);
+                                       
+                                       for (ct= targets.first; ct; ct= ct->next) {
+                                               if (ct->tar == from)
+                                                       ct->tar = ob;
+                                       }
+                                       
+                                       if (cti->flush_constraint_targets)
+                                               cti->flush_constraint_targets(con, &targets, 0);
+                               }
                        }
                        
                        /* free stuff from current channel */
-                       if(pchan->path) MEM_freeN(pchan->path);
+                       if (pchan->path) MEM_freeN(pchan->path);
                        free_constraints(&pchan->constraints);
                        
                        /* the final copy */
@@ -1193,26 +1579,21 @@ static void initialize_posetree(struct Object *ob, bPoseChannel *pchan_tip)
        PoseTree *tree;
        PoseTarget *target;
        bConstraint *con;
-       bKinematicConstraint *data;
+       bKinematicConstraint *data= NULL;
        int a, segcount= 0, size, newsize, *oldparent, parent;
        
        /* find IK constraint, and validate it */
        for(con= pchan_tip->constraints.first; con; con= con->next) {
-               if(con->type==CONSTRAINT_TYPE_KINEMATIC) break;
+               if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
+                       data=(bKinematicConstraint*)con->data;
+                       if (data->flag & CONSTRAINT_IK_AUTO) break;
+                       if (data->tar==NULL) continue;
+                       if (data->tar->type==OB_ARMATURE && data->subtarget[0]==0) continue;
+                       if ((con->flag & CONSTRAINT_DISABLE)==0 && (con->enforce!=0.0)) break;
+               }
        }
        if(con==NULL) return;
        
-       data=(bKinematicConstraint*)con->data;
-       
-       /* two types of targets */
-       if(data->flag & CONSTRAINT_IK_AUTO);
-       else {
-               if(con->flag & CONSTRAINT_DISABLE) return;      /* checked in editconstraint.c */
-               if(con->enforce == 0.0f) return;
-               if(data->tar==NULL) return;
-               if(data->tar->type==OB_ARMATURE && data->subtarget[0]==0) return;
-       }
-       
        /* exclude tip from chain? */
        if(!(data->flag & CONSTRAINT_IK_TIP))
                pchan_tip= pchan_tip->parent;
@@ -1315,66 +1696,67 @@ static void initialize_posetree(struct Object *ob, bPoseChannel *pchan_tip)
 were executed & assigned. Now as last we do an IK pass */
 static void execute_posetree(Object *ob, PoseTree *tree)
 {
-       float R_parmat[3][3];
+       float R_parmat[3][3], identity[3][3];
        float iR_parmat[3][3];
        float R_bonemat[3][3];
        float goalrot[3][3], goalpos[3];
        float rootmat[4][4], imat[4][4];
        float goal[4][4], goalinv[4][4];
-       float size[3], irest_basis[3][3], full_basis[3][3];
+       float irest_basis[3][3], full_basis[3][3];
        float end_pose[4][4], world_pose[4][4];
        float length, basis[3][3], rest_basis[3][3], start[3], *ikstretch=NULL;
-       int a, flag, hasstretch=0;
+       float resultinf=0.0f;
+       int a, flag, hasstretch=0, resultblend=0;
        bPoseChannel *pchan;
        IK_Segment *seg, *parent, **iktree, *iktarget;
        IK_Solver *solver;
        PoseTarget *target;
-       bKinematicConstraint *data;
+       bKinematicConstraint *data, *poleangledata=NULL;
        Bone *bone;
 
        if (tree->totchannel == 0)
                return;
-
+       
        iktree= MEM_mallocN(sizeof(void*)*tree->totchannel, "ik tree");
 
        for(a=0; a<tree->totchannel; a++) {
                pchan= tree->pchan[a];
                bone= pchan->bone;
-
+               
                /* set DoF flag */
                flag= 0;
-               if((pchan->ikflag & BONE_IK_NO_XDOF) == 0)
+               if(!(pchan->ikflag & BONE_IK_NO_XDOF) && !(pchan->ikflag & BONE_IK_NO_XDOF_TEMP))
                        flag |= IK_XDOF;
-               if((pchan->ikflag & BONE_IK_NO_YDOF) == 0)
+               if(!(pchan->ikflag & BONE_IK_NO_YDOF) && !(pchan->ikflag & BONE_IK_NO_YDOF_TEMP))
                        flag |= IK_YDOF;
-               if((pchan->ikflag & BONE_IK_NO_ZDOF) == 0)
+               if(!(pchan->ikflag & BONE_IK_NO_ZDOF) && !(pchan->ikflag & BONE_IK_NO_ZDOF_TEMP))
                        flag |= IK_ZDOF;
-
+               
                if(tree->stretch && (pchan->ikstretch > 0.0)) {
                        flag |= IK_TRANS_YDOF;
                        hasstretch = 1;
                }
-
+               
                seg= iktree[a]= IK_CreateSegment(flag);
-
+               
                /* find parent */
                if(a == 0)
                        parent= NULL;
                else
                        parent= iktree[tree->parent[a]];
-
+                       
                IK_SetParent(seg, parent);
-       
+                       
                /* get the matrix that transforms from prevbone into this bone */
                Mat3CpyMat4(R_bonemat, pchan->pose_mat);
-
+               
                /* gather transformations for this IK segment */
-
+               
                if (pchan->parent)
                        Mat3CpyMat4(R_parmat, pchan->parent->pose_mat);
                else
                        Mat3One(R_parmat);
-
+               
                /* bone offset */
                if (pchan->parent && (a > 0))
                        VecSubf(start, pchan->pose_head, pchan->parent->pose_tail);
@@ -1384,41 +1766,41 @@ static void execute_posetree(Object *ob, PoseTree *tree)
                
                /* change length based on bone size */
                length= bone->length*VecLength(R_bonemat[1]);
-
+               
                /* compute rest basis and its inverse */
                Mat3CpyMat3(rest_basis, bone->bone_mat);
                Mat3CpyMat3(irest_basis, bone->bone_mat);
                Mat3Transp(irest_basis);
-
+               
                /* compute basis with rest_basis removed */
                Mat3Inv(iR_parmat, R_parmat);
                Mat3MulMat3(full_basis, iR_parmat, R_bonemat);
                Mat3MulMat3(basis, irest_basis, full_basis);
-
+               
                /* basis must be pure rotation */
                Mat3Ortho(basis);
-
+               
                /* transform offset into local bone space */
                Mat3Ortho(iR_parmat);
                Mat3MulVecfl(iR_parmat, start);
-
+               
                IK_SetTransform(seg, start, rest_basis, basis, length);
-
+               
                if (pchan->ikflag & BONE_IK_XLIMIT)
                        IK_SetLimit(seg, IK_X, pchan->limitmin[0], pchan->limitmax[0]);
                if (pchan->ikflag & BONE_IK_YLIMIT)
                        IK_SetLimit(seg, IK_Y, pchan->limitmin[1], pchan->limitmax[1]);
                if (pchan->ikflag & BONE_IK_ZLIMIT)
                        IK_SetLimit(seg, IK_Z, pchan->limitmin[2], pchan->limitmax[2]);
-
+               
                IK_SetStiffness(seg, IK_X, pchan->stiffness[0]);
                IK_SetStiffness(seg, IK_Y, pchan->stiffness[1]);
                IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]);
-
-               if(tree->stretch && (pchan->ikstretch > 0.0)) {
+               
+               if(tree->stretch && (pchan->ikstretch > 0.0f)) {
                        float ikstretch = pchan->ikstretch*pchan->ikstretch;
-                       IK_SetStiffness(seg, IK_TRANS_Y, MIN2(1.0-ikstretch, 0.99));
-                       IK_SetLimit(seg, IK_TRANS_Y, 0.001, 1e10);
+                       IK_SetStiffness(seg, IK_TRANS_Y, MIN2(1.0f-ikstretch, 0.99f));
+                       IK_SetLimit(seg, IK_TRANS_Y, 0.001f, 1e10);
                }
        }
 
@@ -1440,89 +1822,135 @@ static void execute_posetree(Object *ob, PoseTree *tree)
        Mat4MulMat4 (imat, rootmat, ob->obmat);
        Mat4Invert (goalinv, imat);
        
-       for(target=tree->targets.first; target; target=target->next) {
+       for (target=tree->targets.first; target; target=target->next) {
+               float polepos[3];
+               int poleconstrain= 0;
+               
                data= (bKinematicConstraint*)target->con->data;
-
-               /* 1.0=ctime, we pass on object for auto-ik */
-               get_constraint_target_matrix(target->con, TARGET_BONE, ob, rootmat, size, 1.0);
-
+               
+               /* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though
+                * strictly speaking, it is a posechannel)
+                */
+               get_constraint_target_matrix(target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
+               
                /* and set and transform goal */
                Mat4MulMat4(goal, rootmat, goalinv);
-
+               
                VECCOPY(goalpos, goal[3]);
                Mat3CpyMat4(goalrot, goal);
+               
+               /* same for pole vector target */
+               if(data->poletar) {
+                       get_constraint_target_matrix(target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
+                       
+                       if(data->flag & CONSTRAINT_IK_SETANGLE) {
+                               /* don't solve IK when we are setting the pole angle */
+                               break;
+                       }
+                       else {
+                               Mat4MulMat4(goal, rootmat, goalinv);
+                               VECCOPY(polepos, goal[3]);
+                               poleconstrain= 1;
+
+                               /* for pole targets, we blend the result of the ik solver
+                                * instead of the target position, otherwise we can't get
+                                * a smooth transition */
+                               resultblend= 1;
+                               resultinf= target->con->enforce;
+                               
+                               if(data->flag & CONSTRAINT_IK_GETANGLE) {
+                                       poleangledata= data;
+                                       data->flag &= ~CONSTRAINT_IK_GETANGLE;
+                               }
+                       }
+               }
 
                /* do we need blending? */
-               if(target->con->enforce!=1.0) {
+               if (!resultblend && target->con->enforce!=1.0f) {
                        float q1[4], q2[4], q[4];
                        float fac= target->con->enforce;
-                       float mfac= 1.0-fac;
+                       float mfac= 1.0f-fac;
                        
                        pchan= tree->pchan[target->tip];
-
+                       
                        /* end effector in world space */
                        Mat4CpyMat4(end_pose, pchan->pose_mat);
                        VECCOPY(end_pose[3], pchan->pose_tail);
                        Mat4MulSerie(world_pose, goalinv, ob->obmat, end_pose, 0, 0, 0, 0, 0);
-
+                       
                        /* blend position */
                        goalpos[0]= fac*goalpos[0] + mfac*world_pose[3][0];
                        goalpos[1]= fac*goalpos[1] + mfac*world_pose[3][1];
                        goalpos[2]= fac*goalpos[2] + mfac*world_pose[3][2];
-
+                       
                        /* blend rotation */
                        Mat3ToQuat(goalrot, q1);
                        Mat4ToQuat(world_pose, q2);
                        QuatInterpol(q, q1, q2, mfac);
                        QuatToMat3(q, goalrot);
                }
-
+               
                iktarget= iktree[target->tip];
-
-               if(data->weight != 0.0)
+               
+               if(data->weight != 0.0f) {
+                       if(poleconstrain)
+                               IK_SolverSetPoleVectorConstraint(solver, iktarget, goalpos,
+                                       polepos, data->poleangle*(float)M_PI/180.0f, (poleangledata == data));
                        IK_SolverAddGoal(solver, iktarget, goalpos, data->weight);
-               if((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0) && (data->flag & CONSTRAINT_IK_AUTO)==0)
-                       IK_SolverAddGoalOrientation(solver, iktarget, goalrot, data->orientweight);
+               }
+               if((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0f))
+                       if((data->flag & CONSTRAINT_IK_AUTO)==0)
+                               IK_SolverAddGoalOrientation(solver, iktarget, goalrot,
+                                       data->orientweight);
        }
 
        /* solve */
        IK_Solve(solver, 0.0f, tree->iterations);
+
+       if(poleangledata)
+               poleangledata->poleangle= IK_SolverGetPoleAngle(solver)*180.0f/(float)M_PI;
+
        IK_FreeSolver(solver);
 
        /* gather basis changes */
        tree->basis_change= MEM_mallocN(sizeof(float[3][3])*tree->totchannel, "ik basis change");
        if(hasstretch)
                ikstretch= MEM_mallocN(sizeof(float)*tree->totchannel, "ik stretch");
-
+       
        for(a=0; a<tree->totchannel; a++) {
                IK_GetBasisChange(iktree[a], tree->basis_change[a]);
-
+               
                if(hasstretch) {
                        /* have to compensate for scaling received from parent */
                        float parentstretch, stretch;
-
+                       
                        pchan= tree->pchan[a];
-                       parentstretch= (tree->parent[a] >= 0)? ikstretch[tree->parent[a]]: 1.0;
-
-                       if(tree->stretch && (pchan->ikstretch > 0.0)) {
+                       parentstretch= (tree->parent[a] >= 0)? ikstretch[tree->parent[a]]: 1.0f;
+                       
+                       if(tree->stretch && (pchan->ikstretch > 0.0f)) {
                                float trans[3], length;
-
+                               
                                IK_GetTranslationChange(iktree[a], trans);
                                length= pchan->bone->length*VecLength(pchan->pose_mat[1]);
-
-                               ikstretch[a]= (length == 0.0)? 1.0: (trans[1]+length)/length;
+                               
+                               ikstretch[a]= (length == 0.0f)? 1.0f: (trans[1]+length)/length;
                        }
                        else
-                               ikstretch[a] = 1.0;
-
-                       stretch= (parentstretch == 0.0)? 1.0: ikstretch[a]/parentstretch;
-
+                               ikstretch[a] = 1.0f;
+                       
+                       stretch= (parentstretch == 0.0f)? 1.0f: ikstretch[a]/parentstretch;
+                       
                        VecMulf(tree->basis_change[a][0], stretch);
                        VecMulf(tree->basis_change[a][1], stretch);
                        VecMulf(tree->basis_change[a][2], stretch);
-
                }
 
+               if(resultblend && resultinf!=1.0f) {
+                       Mat3One(identity);
+                       Mat3BlendMat3(tree->basis_change[a], identity,
+                               tree->basis_change[a], resultinf);
+               }
+               
                IK_FreeSegment(iktree[a]);
        }
        
@@ -1550,22 +1978,29 @@ void chan_calc_mat(bPoseChannel *chan)
        float rmat[3][3];
        float tmat[3][3];
        
+       /* get scaling matrix */
        SizeToMat3(chan->size, smat);
        
-       NormalQuat(chan->quat);
-
-       QuatToMat3(chan->quat, rmat);
+       /* rotations may either be quats or eulers (no rotation modes for now...) */
+       if (chan->rotmode) {
+               /* euler rotations (will cause gimble lock... no rotation order to solve that yet) */
+               EulToMat3(chan->eul, rmat);
+       }
+       else {
+               /* quats are normalised before use to eliminate scaling issues */
+               NormalQuat(chan->quat);
+               QuatToMat3(chan->quat, rmat);
+       }
        
+       /* calculate matrix of bone (as 3x3 matrix, but then copy the 4x4) */
        Mat3MulMat3(tmat, rmat, smat);
-       
        Mat4CpyMat3(chan->chan_mat, tmat);
        
        /* prevent action channels breaking chains */
        /* need to check for bone here, CONSTRAINT_TYPE_ACTION uses this call */
-       if (chan->bone==NULL || !(chan->bone->flag & BONE_CONNECTED)) {
+       if ((chan->bone==NULL) || !(chan->bone->flag & BONE_CONNECTED)) {
                VECCOPY(chan->chan_mat[3], chan->loc);
        }
-
 }
 
 /* transform from bone(b) to bone(b+1), store in chan_mat */
@@ -1603,217 +2038,123 @@ static void where_is_ik_bone(bPoseChannel *pchan, float ik_mat[][3])   // nr = t
        pchan->flag |= POSE_DONE;
 }
 
-static void do_local_constraint(bPoseChannel *pchan, bConstraint *con)
+/* NLA strip modifiers */
+static void do_strip_modifiers(Scene *scene, Object *armob, Bone *bone, bPoseChannel *pchan)
 {
-       switch(con->type) {
-               case CONSTRAINT_TYPE_LOCLIKE:
-               {
-                       bLocateLikeConstraint *data= con->data;
-                       float fac= con->enforce;
+       bActionModifier *amod;
+       bActionStrip *strip, *strip2;
+       float scene_cfra= (float)scene->r.cfra;
+       int do_modif;
+
+       for (strip=armob->nlastrips.first; strip; strip=strip->next) {
+               do_modif=0;
+               
+               if (scene_cfra>=strip->start && scene_cfra<=strip->end)
+                       do_modif=1;
+               
+               if ((scene_cfra > strip->end) && (strip->flag & ACTSTRIP_HOLDLASTFRAME)) {
+                       do_modif=1;
                        
-                       if(data->tar && data->subtarget[0]) {
-                               bPoseChannel *pchant= get_pose_channel(data->tar->pose, data->subtarget);
-                               if(pchant) {
-                                       if (data->flag & LOCLIKE_X)
-                                               pchan->loc[0]= FloatLerpf(pchant->loc[0], pchan->loc[0], fac);
-                                       if (data->flag & LOCLIKE_Y)
-                                               pchan->loc[1]= FloatLerpf(pchant->loc[1], pchan->loc[1], fac);
-                                       if (data->flag & LOCLIKE_Z)
-                                               pchan->loc[2]= FloatLerpf(pchant->loc[2], pchan->loc[2], fac);
-                                       if (data->flag & LOCLIKE_X_INVERT)
-                                               pchan->loc[0]= FloatLerpf(pchant->loc[0], pchan->loc[0], -fac);
-                                       if (data->flag & LOCLIKE_Y_INVERT)
-                                               pchan->loc[1]= FloatLerpf(pchant->loc[1], pchan->loc[1], -fac);
-                                       if (data->flag & LOCLIKE_Z_INVERT)
-                                               pchan->loc[2]= FloatLerpf(pchant->loc[2], pchan->loc[2], -fac);
-                               }
-                       }
-               }
-                       break;
-               case CONSTRAINT_TYPE_ROTLIKE:
-               {
-                       bRotateLikeConstraint *data= con->data;
-                       if(data->tar && data->subtarget[0]) {
-                               bPoseChannel *pchant= get_pose_channel(data->tar->pose, data->subtarget);
-                               if(pchant) {
-                                       if(data->flag != (ROTLIKE_X|ROTLIKE_Y|ROTLIKE_Z)) {
-                                               float eul[3], eult[3], euln[3], fac= con->enforce;
-                                               
-                                               QuatToEul(pchan->quat, eul);
-                                               QuatToEul(pchant->quat, eult);
-                                               VECCOPY(euln, eul);
-                                               if(data->flag & ROTLIKE_X) euln[0]= FloatLerpf(eult[0], eul[0], fac); 
-                                               if(data->flag & ROTLIKE_Y) euln[1]= FloatLerpf(eult[1], eul[1], fac);
-                                               if(data->flag & ROTLIKE_Z) euln[2]= FloatLerpf(eult[2], eul[2], fac);
-                                               if(data->flag & ROTLIKE_X_INVERT) euln[0]= FloatLerpf(eult[0], eul[0], -fac); 
-                                               if(data->flag & ROTLIKE_Y_INVERT) euln[1]= FloatLerpf(eult[1], eul[1], -fac);
-                                               if(data->flag & ROTLIKE_Z_INVERT) euln[2]= FloatLerpf(eult[2], eul[2], -fac);
-                                               compatible_eul(eul, euln);
-                                               EulToQuat(euln, pchan->quat);
-                                       }
-                                       else {
-                                               QuatInterpol(pchan->quat, pchan->quat, pchant->quat, con->enforce);
-                                       }
+                       /* if there are any other strips active, ignore modifiers for this strip - 
+                        * 'hold' option should only hold action modifiers if there are 
+                        * no other active strips */
+                       for (strip2=strip->next; strip2; strip2=strip2->next) {
+                               if (strip2 == strip) continue;
+                               
+                               if (scene_cfra>=strip2->start && scene_cfra<=strip2->end) {
+                                       if (!(strip2->flag & ACTSTRIP_MUTE))
+                                               do_modif=0;
                                }
                        }
-               }
-                       break;
-               case CONSTRAINT_TYPE_SIZELIKE:
-               {
-                       bSizeLikeConstraint *data= con->data;
-                       float fac= con->enforce;
                        
-                       if(data->tar && data->subtarget[0]) {
-                               bPoseChannel *pchant= get_pose_channel(data->tar->pose, data->subtarget);
-                               if(pchant) {
-                                       if (data->flag & SIZELIKE_X)
-                                               pchan->size[0]= FloatLerpf(pchant->size[0], pchan->size[0], fac);
-                                       if (data->flag & SIZELIKE_Y)
-                                               pchan->size[1]= FloatLerpf(pchant->size[1], pchan->size[1], fac);
-                                       if (data->flag & SIZELIKE_Z)
-                                               pchan->size[2]= FloatLerpf(pchant->size[2], pchan->size[2], fac);
+                       /* if there are any later, activated, strips with 'hold' set, they take precedence, 
+                        * so ignore modifiers for this strip */
+                       for (strip2=strip->next; strip2; strip2=strip2->next) {
+                               if (scene_cfra < strip2->start) continue;
+                               if ((strip2->flag & ACTSTRIP_HOLDLASTFRAME) && !(strip2->flag & ACTSTRIP_MUTE)) {
+                                       do_modif=0;
                                }
                        }
                }
-                       break;
-               case CONSTRAINT_TYPE_LOCLIMIT:
-               {
-                       bLocLimitConstraint *data= con->data;
-                       float fac= con->enforce;
-                       
-                       if (data->flag & LIMIT_XMIN) {
-                               if(pchan->loc[0] < data->xmin)
-                                       pchan->loc[0] = FloatLerpf(data->xmin, pchan->loc[0], fac);
-                       }
-                       if (data->flag & LIMIT_XMAX) {
-                               if (pchan->loc[0] > data->xmax)
-                                       pchan->loc[0] = FloatLerpf(data->xmax, pchan->loc[0], fac);
-                       }
-                       if (data->flag & LIMIT_YMIN) {
-                               if(pchan->loc[1] < data->ymin)
-                                       pchan->loc[1] = FloatLerpf(data->ymin, pchan->loc[1], fac);
-                       }
-                       if (data->flag & LIMIT_YMAX) {
-                               if (pchan->loc[1] > data->ymax)
-                                       pchan->loc[1] = FloatLerpf(data->ymax, pchan->loc[1], fac);
-                       }
-                       if (data->flag & LIMIT_ZMIN) {
-                               if(pchan->loc[2] < data->zmin)
-                                       pchan->loc[2] = FloatLerpf(data->zmin, pchan->loc[2], fac);
-                       }
-                       if (data->flag & LIMIT_ZMAX) {
-                               if (pchan->loc[2] > data->zmax)
-                                       pchan->loc[2] = FloatLerpf(data->zmax, pchan->loc[2], fac);
-                       }
-               }       
-                       break;
-               case CONSTRAINT_TYPE_ROTLIMIT:
-               {
-                       bRotLimitConstraint *data = con->data;
-                       float eul[3];
-                       float fac= con->enforce;
-                       
-                       QuatToEul(pchan->quat, eul);
-                       
-                       /* eulers: radians to degrees! */
-                       eul[0] = (eul[0] / (2*M_PI) * 360);
-                       eul[1] = (eul[1] / (2*M_PI) * 360);
-                       eul[2] = (eul[2] / (2*M_PI) * 360);
-                       
-                       /* limiting of euler values... */
-                       if (data->flag & LIMIT_XROT) {
-                               if (eul[0] < data->xmin) 
-                                       eul[0] = FloatLerpf(data->xmin, eul[0], fac);
-                                       
-                               if (eul[0] > data->xmax)
-                                       eul[0] = FloatLerpf(data->xmax, eul[0], fac);
-                       }
-                       if (data->flag & LIMIT_YROT) {
-                               if (eul[1] < data->ymin)
-                                       eul[1] = FloatLerpf(data->ymin, eul[1], fac);
-                                       
-                               if (eul[1] > data->ymax)
-                                       eul[1] = FloatLerpf(data->ymax, eul[1], fac);
-                       }
-                       if (data->flag & LIMIT_ZROT) {
-                               if (eul[2] < data->zmin)
-                                       eul[2] = FloatLerpf(data->zmin, eul[2], fac);
-                                       
-                               if (eul[2] > data->zmax)
-                                       eul[2] = FloatLerpf(data->zmax, eul[2], fac);
-                       }
-                               
-                       /* eulers: degrees to radians ! */
-                       eul[0] = (eul[0] / 360 * (2*M_PI)); 
-                       eul[1] = (eul[1] / 360 * (2*M_PI));
-                       eul[2] = (eul[2] / 360 * (2*M_PI));
-                       
-                       /* convert back */
-                       EulToQuat(eul, pchan->quat);
-               }
-                       break;
-               case CONSTRAINT_TYPE_SIZELIMIT:
-               {
-                       bSizeLimitConstraint *data= con->data;
-                       float fac= con->enforce;
-                       
-                       if (data->flag & LIMIT_XMIN) {
-                               if(pchan->size[0] < data->xmin)
-                                       pchan->size[0] = FloatLerpf(data->xmin, pchan->size[0], fac);
-                       }
-                       if (data->flag & LIMIT_XMAX) {
-                               if (pchan->size[0] > data->xmax)
-                                       pchan->size[0] = FloatLerpf(data->xmax, pchan->size[0], fac);
-                       }
-                       if (data->flag & LIMIT_YMIN) {
-                               if(pchan->size[1] < data->ymin)
-                                       pchan->size[1] = FloatLerpf(data->ymin, pchan->size[1], fac);
-                       }
-                       if (data->flag & LIMIT_YMAX) {
-                               if (pchan->size[1] > data->ymax)
-                                       pchan->size[1] = FloatLerpf(data->ymax, pchan->size[1], fac);
-                       }
-                       if (data->flag & LIMIT_ZMIN) {
-                               if(pchan->size[2] < data->zmin)
-                                       pchan->size[2] = FloatLerpf(data->zmin, pchan->size[2], fac);
-                       }
-                       if (data->flag & LIMIT_ZMAX) {
-                               if (pchan->size[2] > data->zmax)
-                                       pchan->size[2] = FloatLerpf(data->zmax, pchan->size[2], fac);
-                       }
-               }
-                       break;
-       }
-}
-
-static void do_strip_modifiers(Object *armob, Bone *bone, bPoseChannel *pchan)
-{
-       bActionModifier *amod;
-       bActionStrip *strip;
-       float scene_cfra= G.scene->r.cfra;
-
-       for (strip=armob->nlastrips.first; strip; strip=strip->next) {
-               if(scene_cfra>=strip->start && scene_cfra<=strip->end) {
-                       
+               
+               if (do_modif) {
                        /* temporal solution to prevent 2 strips accumulating */
                        if(scene_cfra==strip->end && strip->next && strip->next->start==scene_cfra)
                                continue;
                        
                        for(amod= strip->modifiers.first; amod; amod= amod->next) {
-                               if(amod->type==ACTSTRIP_MOD_DEFORM) {
+                               switch (amod->type) {
+                               case ACTSTRIP_MOD_DEFORM:
+                               {
                                        /* validate first */
                                        if(amod->ob && amod->ob->type==OB_CURVE && amod->channel[0]) {
                                                
                                                if( strcmp(pchan->name, amod->channel)==0 ) {
                                                        float mat4[4][4], mat3[3][3];
                                                        
-                                                       curve_deform_vector(amod->ob, armob, bone->arm_mat[3], pchan->pose_mat[3], mat3, amod->no_rot_axis);
+                                                       curve_deform_vector(scene, amod->ob, armob, bone->arm_mat[3], pchan->pose_mat[3], mat3, amod->no_rot_axis);
                                                        Mat4CpyMat4(mat4, pchan->pose_mat);
                                                        Mat4MulMat34(pchan->pose_mat, mat3, mat4);
                                                        
                                                }
                                        }
                                }
+                                       break;
+                               case ACTSTRIP_MOD_NOISE:        
+                               {
+                                       if( strcmp(pchan->name, amod->channel)==0 ) {
+                                               float nor[3], loc[3], ofs;
+                                               float eul[3], size[3], eulo[3], sizeo[3];
+                                               
+                                               /* calculate turbulance */
+                                               ofs = amod->turbul / 200.0f;
+                                               
+                                               /* make a copy of starting conditions */
+                                               VECCOPY(loc, pchan->pose_mat[3]);
+                                               Mat4ToEul(pchan->pose_mat, eul);
+                                               Mat4ToSize(pchan->pose_mat, size);
+                                               VECCOPY(eulo, eul);
+                                               VECCOPY(sizeo, size);
+                                               
+                                               /* apply noise to each set of channels */
+                                               if (amod->channels & 4) {
+                                                       /* for scaling */
+                                                       nor[0] = BLI_gNoise(amod->noisesize, size[0]+ofs, size[1], size[2], 0, 0) - ofs;
+                                                       nor[1] = BLI_gNoise(amod->noisesize, size[0], size[1]+ofs, size[2], 0, 0) - ofs;        
+                                                       nor[2] = BLI_gNoise(amod->noisesize, size[0], size[1], size[2]+ofs, 0, 0) - ofs;
+                                                       VecAddf(size, size, nor);
+                                                       
+                                                       if (sizeo[0] != 0)
+                                                               VecMulf(pchan->pose_mat[0], size[0] / sizeo[0]);
+                                                       if (sizeo[1] != 0)
+                                                               VecMulf(pchan->pose_mat[1], size[1] / sizeo[1]);
+                                                       if (sizeo[2] != 0)
+                                                               VecMulf(pchan->pose_mat[2], size[2] / sizeo[2]);
+                                               }
+                                               if (amod->channels & 2) {
+                                                       /* for rotation */
+                                                       nor[0] = BLI_gNoise(amod->noisesize, eul[0]+ofs, eul[1], eul[2], 0, 0) - ofs;
+                                                       nor[1] = BLI_gNoise(amod->noisesize, eul[0], eul[1]+ofs, eul[2], 0, 0) - ofs;   
+                                                       nor[2] = BLI_gNoise(amod->noisesize, eul[0], eul[1], eul[2]+ofs, 0, 0) - ofs;
+                                                       
+                                                       compatible_eul(nor, eulo);
+                                                       VecAddf(eul, eul, nor);
+                                                       compatible_eul(eul, eulo);
+                                                       
+                                                       LocEulSizeToMat4(pchan->pose_mat, loc, eul, size);
+                                               }
+                                               if (amod->channels & 1) {
+                                                       /* for location */
+                                                       nor[0] = BLI_gNoise(amod->noisesize, loc[0]+ofs, loc[1], loc[2], 0, 0) - ofs;
+                                                       nor[1] = BLI_gNoise(amod->noisesize, loc[0], loc[1]+ofs, loc[2], 0, 0) - ofs;   
+                                                       nor[2] = BLI_gNoise(amod->noisesize, loc[0], loc[1], loc[2]+ofs, 0, 0) - ofs;
+                                                       
+                                                       VecAddf(pchan->pose_mat[3], loc, nor);
+                                               }
+                                       }
+                               }
+                                       break;
+                               }
                        }
                }
        }
@@ -1822,36 +2163,20 @@ static void do_strip_modifiers(Object *armob, Bone *bone, bPoseChannel *pchan)
 
 /* The main armature solver, does all constraints excluding IK */
 /* pchan is validated, as having bone and parent pointer */
-static void where_is_pose_bone(Object *ob, bPoseChannel *pchan, float ctime)
+static void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float ctime)
 {
        Bone *bone, *parbone;
        bPoseChannel *parchan;
-       float vec[3], quat[4];
-       int did_local= 0;       /* copying quaternion should be limited, chan_calc_mat() normalizes quat */
+       float vec[3];
        
        /* set up variables for quicker access below */
        bone= pchan->bone;
        parbone= bone->parent;
        parchan= pchan->parent;
-               
-       /* Do local constraints, these only work on the channel data (loc rot size) */
-       QUATCOPY(quat, pchan->quat);
-       if(pchan->constraints.first) {
-               bConstraint *con;
-               for(con=pchan->constraints.first; con; con= con->next) {
-                       if(con->flag & CONSTRAINT_LOCAL) {
-                               do_local_constraint(pchan, con);
-                               did_local= 1;
-                       }
-               }
-       }
        
        /* this gives a chan_mat with actions (ipos) results */
        chan_calc_mat(pchan);
        
-       if(did_local) 
-               QUATCOPY(pchan->quat, quat);    /* local constraint hack. bad! */
-       
        /* construct the posemat based on PoseChannels, that we do before applying constraints */
        /* pose_mat(b)= pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b) */
        
@@ -1881,53 +2206,59 @@ static void where_is_pose_bone(Object *ob, bPoseChannel *pchan, float ctime)
                        
                        Mat4MulSerie(pchan->pose_mat, tmat, offs_bone, pchan->chan_mat, NULL, NULL, NULL, NULL, NULL);
                }
+               else if(bone->flag & BONE_NO_SCALE) {
+                       float orthmat[4][4], vec[3];
+                       
+                       /* get the official transform, but we only use the vector from it (optimize...) */
+                       Mat4MulSerie(pchan->pose_mat, parchan->pose_mat, offs_bone, pchan->chan_mat, NULL, NULL, NULL, NULL, NULL);
+                       VECCOPY(vec, pchan->pose_mat[3]);
+                       
+                       /* do this again, but with an ortho-parent matrix */
+                       Mat4CpyMat4(orthmat, parchan->pose_mat);
+                       Mat4Ortho(orthmat);
+                       Mat4MulSerie(pchan->pose_mat, orthmat, offs_bone, pchan->chan_mat, NULL, NULL, NULL, NULL, NULL);
+                       
+                       /* copy correct transform */
+                       VECCOPY(pchan->pose_mat[3], vec);
+               }
                else 
                        Mat4MulSerie(pchan->pose_mat, parchan->pose_mat, offs_bone, pchan->chan_mat, NULL, NULL, NULL, NULL, NULL);
        }
        else {
                Mat4MulMat4(pchan->pose_mat, pchan->chan_mat, bone->arm_mat);
-               /* only rootbones get the cyclic offset */
-               VecAddf(pchan->pose_mat[3], pchan->pose_mat[3], ob->pose->cyclic_offset);
+               
+               /* only rootbones get the cyclic offset (unless user doesn't want that) */
+               if ((bone->flag & BONE_NO_CYCLICOFFSET) == 0)
+                       VecAddf(pchan->pose_mat[3], pchan->pose_mat[3], ob->pose->cyclic_offset);
        }
        
-       do_strip_modifiers(ob, bone, pchan);
+       /* do NLA strip modifiers - i.e. curve follow */
+       do_strip_modifiers(scene, ob, bone, pchan);
        
        /* Do constraints */
-       if(pchan->constraints.first) {
-               static Object conOb;
-               static int initialized= 0;
+       if (pchan->constraints.first) {
+               bConstraintOb *cob;
                
+               /* make a copy of location of PoseChannel for later */
                VECCOPY(vec, pchan->pose_mat[3]);
                
-               /* Build a workob to pass the bone to the constraint solver */
-               if(initialized==0) {
-                       memset(&conOb, 0, sizeof(Object));
-                       initialized= 1;
-               }
-               conOb.size[0]= conOb.size[1]= conOb.size[2]= 1.0;
-               conOb.data = ob->data;
-               conOb.type = ob->type;
-               conOb.parent = ob;      // ik solver retrieves the armature that way !?!?!?!
-               conOb.pose= ob->pose;                           // needed for retrieving pchan
-               conOb.trackflag = ob->trackflag;
-               conOb.upflag = ob->upflag;
-               
-               /* Collect the constraints from the pose (listbase copy) */
-               conOb.constraints = pchan->constraints;
-               
-               /* conOb.obmat takes bone to worldspace */
-               Mat4MulMat4 (conOb.obmat, pchan->pose_mat, ob->obmat);
+               /* prepare PoseChannel for Constraint solving 
+                * - makes a copy of matrix, and creates temporary struct to use 
+                */
+               cob= constraints_make_evalob(scene, ob, pchan, CONSTRAINT_OBTYPE_BONE);
                
-               /* Solve */
-               solve_constraints (&conOb, TARGET_BONE, (void*)pchan, ctime);   // ctime doesnt alter objects
+               /* Solve PoseChannel's Constraints */
+               solve_constraints(&pchan->constraints, cob, ctime);     // ctime doesnt alter objects
                
-               /* Take out of worldspace */
-               Mat4MulMat4 (pchan->pose_mat, conOb.obmat, ob->imat);
+               /* cleanup after Constraint Solving 
+                * - applies matrix back to pchan, and frees temporary struct used
+                */
+               constraints_clear_evalob(cob);
                
                /* prevent constraints breaking a chain */
-               if(pchan->bone->flag & BONE_CONNECTED)
+               if(pchan->bone->flag & BONE_CONNECTED) {
                        VECCOPY(pchan->pose_mat[3], vec);
-
+               }
        }
        
        /* calculate head */
@@ -1936,27 +2267,29 @@ static void where_is_pose_bone(Object *ob, bPoseChannel *pchan, float ctime)
        VECCOPY(vec, pchan->pose_mat[1]);
        VecMulf(vec, bone->length);
        VecAddf(pchan->pose_tail, pchan->pose_head, vec);
-       
 }
 
 /* This only reads anim data from channels, and writes to channels */
 /* This is the only function adding poses */
-void where_is_pose (Object *ob)
+void where_is_pose (Scene *scene, Object *ob)
 {
        bArmature *arm;
        Bone *bone;
        bPoseChannel *pchan;
        float imat[4][4];
-       float ctime= bsystem_time(ob, NULL, (float)G.scene->r.cfra, 0.0);       /* not accurate... */
+       float ctime;
        
-       arm = get_armature(ob);
+       if(ob->type!=OB_ARMATURE) return;
+       arm = ob->data;
        
-       if(arm==NULL) return;
-       if(ob->pose==NULL || (ob->pose->flag & POSE_RECALC)) 
+       if(ELEM(NULL, arm, scene)) return;
+       if((ob->pose==NULL) || (ob->pose->flag & POSE_RECALC)) 
           armature_rebuild_pose(ob, arm);
+          
+       ctime= bsystem_time(scene, ob, (float)scene->r.cfra, 0.0);      /* not accurate... */
        
-       /* In restposition we read the data from the bones */
-       if(ob==G.obedit || (arm->flag & ARM_RESTPOS)) {
+       /* In editmode or restposition we read the data from the bones */
+       if(arm->edbo || (arm->flag & ARM_RESTPOS)) {
                
                for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
                        bone= pchan->bone;
@@ -1989,7 +2322,7 @@ void where_is_pose (Object *ob)
                                        /* 4. walk over the tree for regular solving */
                                        for(a=0; a<tree->totchannel; a++) {
                                                if(!(tree->pchan[a]->flag & POSE_DONE)) // successive trees can set the flag
-                                                       where_is_pose_bone(ob, tree->pchan[a], ctime);
+                                                       where_is_pose_bone(scene, ob, tree->pchan[a], ctime);
                                        }
                                        /* 5. execute the IK solver */
                                        execute_posetree(ob, tree);
@@ -2009,7 +2342,7 @@ void where_is_pose (Object *ob)
                                }
                        }
                        else if(!(pchan->flag & POSE_DONE)) {
-                               where_is_pose_bone(ob, pchan, ctime);
+                               where_is_pose_bone(scene, ob, pchan, ctime);
                        }
                }
        }