replace VECCOPY and QUATCOPY with inline funcs.
[blender.git] / source / blender / blenkernel / intern / armature.c
index 2e760f5..9fba18d 100644 (file)
@@ -1,6 +1,4 @@
-/**
- * $Id$
- *
+/*
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/blenkernel/intern/armature.c
+ *  \ingroup bke
+ */
+
+
 #include <ctype.h>
 #include <stdlib.h>
 #include <math.h>
 
 #include "MEM_guardedalloc.h"
 
+#include "BLI_bpath.h"
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
 
 #include "DNA_anim_types.h"
 #include "DNA_armature_types.h"
 #include "BKE_lattice.h"
 #include "BKE_main.h"
 #include "BKE_object.h"
-#include "BKE_utildefines.h"
+
 #include "BIK_api.h"
 #include "BKE_sketch.h"
 
 /*     **************** Generic Functions, data level *************** */
 
-bArmature *add_armature(char *name)
+bArmature *add_armature(const char *name)
 {
        bArmature *arm;
        
@@ -131,39 +136,42 @@ void free_armature(bArmature *arm)
 
 void make_local_armature(bArmature *arm)
 {
-       int local=0, lib=0;
+       Main *bmain= G.main;
+       int is_local= FALSE, is_lib= FALSE;
        Object *ob;
-       bArmature *newArm;
-       
-       if (arm->id.lib==0)
-               return;
+
+       if (arm->id.lib==NULL) return;
        if (arm->id.us==1) {
-               arm->id.lib= 0;
-               arm->id.flag= LIB_LOCAL;
-               new_id(0, (ID*)arm, 0);
+               id_clear_lib_data(bmain, &arm->id);
                return;
        }
-       
-       if(local && lib==0) {
-               arm->id.lib= 0;
-               arm->id.flag= LIB_LOCAL;
-               new_id(0, (ID *)arm, 0);
+
+       for(ob= bmain->object.first; ob && ELEM(0, is_lib, is_local); ob= ob->id.next) {
+               if(ob->data == arm) {
+                       if(ob->id.lib) is_lib= TRUE;
+                       else is_local= TRUE;
+               }
        }
-       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++;
+
+       if(is_local && is_lib == FALSE) {
+               id_clear_lib_data(bmain, &arm->id);
+       }
+       else if(is_local && is_lib) {
+               char *bpath_user_data[2]= {bmain->name, arm->id.lib->filepath};
+               bArmature *armn= copy_armature(arm);
+               armn->id.us= 0;
+
+               /* Remap paths of new ID using old library as base. */
+               bpath_traverse_id(bmain, &armn->id, bpath_relocate_visitor, 0, bpath_user_data);
+
+               for(ob= bmain->object.first; ob; ob= ob->id.next) {
+                       if(ob->data == arm) {
+                               if(ob->id.lib==NULL) {
+                                       ob->data= armn;
+                                       armn->id.us++;
                                        arm->id.us--;
                                }
                        }
-                       ob= ob->id.next;
                }
        }
 }
@@ -208,6 +216,11 @@ bArmature *copy_armature(bArmature *arm)
        };
        
        newArm->act_bone= newActBone;
+
+       newArm->edbo= NULL;
+       newArm->act_edbone= NULL;
+       newArm->sketch= NULL;
+
        return newArm;
 }
 
@@ -247,20 +260,19 @@ Bone *get_named_bone (bArmature *arm, const char *name)
 }
 
 /* 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
  */
-int bone_autoside_name (char *name, int strip_number, short axis, float head, float tail)
+int bone_autoside_name (char name[MAXBONENAME], int UNUSED(strip_number), short axis, float head, float tail)
 {
        unsigned int len;
-       char    basename[32]={""};
-       char    extension[5]={""};
+       char    basename[MAXBONENAME]= "";
+       char    extension[5]= "";
 
        len= strlen(name);
        if (len == 0) return 0;
-       strcpy(basename, name);
+       BLI_strncpy(basename, name, sizeof(basename));
        
        /* Figure out extension to append: 
         *      - The extension to append is based upon the axis that we are working on.
@@ -349,13 +361,13 @@ int bone_autoside_name (char *name, int strip_number, short axis, float head, fl
                                }
                        }
                }
-               
-               if ((32 - len) < strlen(extension) + 1) { /* add 1 for the '.' */
+
+               if ((MAXBONENAME - len) < strlen(extension) + 1) { /* add 1 for the '.' */
                        strncpy(name, basename, len-strlen(extension));
                }
-               
-               sprintf(name, "%s.%s", basename, extension);
-               
+
+               BLI_snprintf(name, MAXBONENAME, "%s.%s", basename, extension);
+
                return 1;
        }
 
@@ -378,11 +390,11 @@ static void equalize_bezier(float *data, int desired)
        
        pdist[0]= 0.0f;
        for(a=0, fp= data; a<MAX_BBONE_SUBDIV; a++, fp+=4) {
-               QUATCOPY(temp[a], fp);
+               copy_qt_qt(temp[a], fp);
                pdist[a+1]= pdist[a]+len_v3v3(fp, fp+4);
        }
        /* do last point */
-       QUATCOPY(temp[a], fp);
+       copy_qt_qt(temp[a], fp);
        totdist= pdist[a];
        
        /* go over distances and calculate new points */
@@ -408,7 +420,7 @@ static void equalize_bezier(float *data, int desired)
                fp[3]= fac1*temp[nr-1][3]+ fac2*temp[nr][3];
        }
        /* set last point, needed for orientation calculus */
-       QUATCOPY(fp, temp[MAX_BBONE_SUBDIV]);
+       copy_qt_qt(fp, temp[MAX_BBONE_SUBDIV]);
 }
 
 /* returns pointer to static array, filled with desired amount of bone->segments elements */
@@ -433,7 +445,7 @@ Mat4 *b_bone_spline_setup(bPoseChannel *pchan, int rest)
                scale[1]= len_v3(pchan->pose_mat[1]);
                scale[2]= len_v3(pchan->pose_mat[2]);
 
-               if(fabs(scale[0] - scale[1]) > 1e-6f || fabs(scale[1] - scale[2]) > 1e-6f) {
+               if(fabsf(scale[0] - scale[1]) > 1e-6f || fabsf(scale[1] - scale[2]) > 1e-6f) {
                        unit_m4(scalemat);
                        scalemat[0][0]= scale[0];
                        scalemat[1][1]= scale[1];
@@ -476,9 +488,9 @@ Mat4 *b_bone_spline_setup(bPoseChannel *pchan, int rest)
 
                /* transform previous point inside this bone space */
                if(rest)
-                       VECCOPY(h1, prev->bone->arm_head)
+                       copy_v3_v3(h1, prev->bone->arm_head);
                else
-                       VECCOPY(h1, prev->pose_head)
+                       copy_v3_v3(h1, prev->pose_head);
                mul_m4_v3(imat, h1);
 
                if(prev->bone->segments>1) {
@@ -515,9 +527,9 @@ Mat4 *b_bone_spline_setup(bPoseChannel *pchan, int rest)
                
                /* transform next point inside this bone space */
                if(rest)
-                       VECCOPY(h2, next->bone->arm_tail)
+                       copy_v3_v3(h2, next->bone->arm_tail);
                else
-                       VECCOPY(h2, next->pose_tail)
+                       copy_v3_v3(h2, next->pose_tail);
                mul_m4_v3(imat, h2);
                /* if next bone is B-bone too, use average handle direction */
                if(next->bone->segments>1);
@@ -563,7 +575,7 @@ Mat4 *b_bone_spline_setup(bPoseChannel *pchan, int rest)
                vec_roll_to_mat3(h1, fp[3], mat3);              // fp[3] is roll
 
                copy_m4_m3(result_array[a].mat, mat3);
-               VECCOPY(result_array[a].mat[3], fp);
+               copy_v3_v3(result_array[a].mat[3], fp);
 
                if(doscale) {
                        /* correct for scaling when this matrix is used in scaled space */
@@ -577,23 +589,29 @@ Mat4 *b_bone_spline_setup(bPoseChannel *pchan, int rest)
 
 /* ************ Armature Deform ******************* */
 
-static void pchan_b_bone_defmats(bPoseChannel *pchan, int use_quaternion)
+typedef struct bPoseChanDeform {
+       Mat4            *b_bone_mats;   
+       DualQuat        *dual_quat;
+       DualQuat        *b_bone_dual_quats;
+} bPoseChanDeform;
+
+static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info, int use_quaternion)
 {
        Bone *bone= pchan->bone;
        Mat4 *b_bone= b_bone_spline_setup(pchan, 0);
        Mat4 *b_bone_rest= b_bone_spline_setup(pchan, 1);
        Mat4 *b_bone_mats;
        DualQuat *b_bone_dual_quats= NULL;
-       float tmat[4][4];
+       float tmat[4][4]= MAT4_UNITY;
        int a;
        
        /* 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;
+       pdef_info->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;
+               pdef_info->b_bone_dual_quats= b_bone_dual_quats;
        }
        
        /* first matrix is the inverse arm_mat, to bring points in local bone space
@@ -605,7 +623,6 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan, int use_quaternion)
                - translate over the curve to the bbone mat space
                - transform with b_bone matrix
                - transform back into global space */
-       unit_m4(tmat);
 
        for(a=0; a<bone->segments; a++) {
                invert_m4_m4(tmat, b_bone_rest[a].mat);
@@ -618,9 +635,9 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan, int use_quaternion)
        }
 }
 
-static void b_bone_deform(bPoseChannel *pchan, Bone *bone, float *co, DualQuat *dq, float defmat[][3])
+static void b_bone_deform(bPoseChanDeform *pdef_info, Bone *bone, float *co, DualQuat *dq, float defmat[][3])
 {
-       Mat4 *b_bone= pchan->b_bone_mats;
+       Mat4 *b_bone= pdef_info->b_bone_mats;
        float (*mat)[4]= b_bone[0].mat;
        float segment, y;
        int a;
@@ -637,7 +654,7 @@ static void b_bone_deform(bPoseChannel *pchan, Bone *bone, float *co, DualQuat *
        CLAMP(a, 0, bone->segments-1);
 
        if(dq) {
-               copy_dq_dq(dq, &((DualQuat*)pchan->b_bone_dual_quats)[a]);
+               copy_dq_dq(dq, &(pdef_info->b_bone_dual_quats)[a]);
        }
        else {
                mul_m4_v3(b_bone[a+1].mat, co);
@@ -711,7 +728,7 @@ static void pchan_deform_mat_add(bPoseChannel *pchan, float weight, float bbonem
        add_m3_m3m3(mat, mat, wmat);
 }
 
-static float dist_bone_deform(bPoseChannel *pchan, float *vec, DualQuat *dq, float mat[][3], float *co)
+static float dist_bone_deform(bPoseChannel *pchan, bPoseChanDeform *pdef_info, float *vec, DualQuat *dq, float mat[][3], float *co)
 {
        Bone *bone= pchan->bone;
        float fac, contrib=0.0;
@@ -720,19 +737,19 @@ static float dist_bone_deform(bPoseChannel *pchan, float *vec, DualQuat *dq, flo
 
        if(bone==NULL) return 0.0f;
        
-       VECCOPY (cop, co);
+       copy_v3_v3(cop, 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.0f) {
                
                fac*=bone->weight;
                contrib= fac;
-               if(contrib>0.0) {
+               if(contrib > 0.0f) {
                        if(vec) {
                                if(bone->segments>1)
                                        // applies on cop and bbonemat
-                                       b_bone_deform(pchan, bone, cop, NULL, (mat)?bbonemat:NULL);
+                                       b_bone_deform(pdef_info, bone, cop, NULL, (mat)?bbonemat:NULL);
                                else
                                        mul_m4_v3(pchan->chan_mat, cop);
 
@@ -745,11 +762,11 @@ static float dist_bone_deform(bPoseChannel *pchan, float *vec, DualQuat *dq, flo
                        }
                        else {
                                if(bone->segments>1) {
-                                       b_bone_deform(pchan, bone, cop, &bbonedq, NULL);
+                                       b_bone_deform(pdef_info, bone, cop, &bbonedq, NULL);
                                        add_weighted_dq_dq(dq, &bbonedq, fac);
                                }
                                else
-                                       add_weighted_dq_dq(dq, pchan->dual_quat, fac);
+                                       add_weighted_dq_dq(dq, pdef_info->dual_quat, fac);
                        }
                }
        }
@@ -757,7 +774,7 @@ static float dist_bone_deform(bPoseChannel *pchan, float *vec, DualQuat *dq, flo
        return contrib;
 }
 
-static void pchan_bone_deform(bPoseChannel *pchan, float weight, float *vec, DualQuat *dq, float mat[][3], float *co, float *contrib)
+static void pchan_bone_deform(bPoseChannel *pchan, bPoseChanDeform *pdef_info, float weight, float *vec, DualQuat *dq, float mat[][3], float *co, float *contrib)
 {
        float cop[3], bbonemat[3][3];
        DualQuat bbonedq;
@@ -765,12 +782,12 @@ static void pchan_bone_deform(bPoseChannel *pchan, float weight, float *vec, Dua
        if (!weight)
                return;
 
-       VECCOPY(cop, co);
+       copy_v3_v3(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);
+                       b_bone_deform(pdef_info, pchan->bone, cop, NULL, (mat)?bbonemat:NULL);
                else
                        mul_m4_v3(pchan->chan_mat, cop);
                
@@ -783,11 +800,11 @@ static void pchan_bone_deform(bPoseChannel *pchan, float weight, float *vec, Dua
        }
        else {
                if(pchan->bone->segments>1) {
-                       b_bone_deform(pchan, pchan->bone, cop, &bbonedq, NULL);
+                       b_bone_deform(pdef_info, pchan->bone, cop, &bbonedq, NULL);
                        add_weighted_dq_dq(dq, &bbonedq, weight);
                }
                else
-                       add_weighted_dq_dq(dq, pchan->dual_quat, weight);
+                       add_weighted_dq_dq(dq, pdef_info->dual_quat, weight);
        }
 
        (*contrib)+=weight;
@@ -798,15 +815,18 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
                                                   int numVerts, int deformflag, 
                                                   float (*prevCos)[3], const char *defgrp_name)
 {
+       bPoseChanDeform *pdef_info_array;
+       bPoseChanDeform *pdef_info= NULL;
        bArmature *arm= armOb->data;
        bPoseChannel *pchan, **defnrToPC = NULL;
+       int *defnrToPCIndex= 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 invert_vgroup= deformflag & ARM_DEF_INVERT_VGROUP;
+       const short use_envelope = deformflag & ARM_DEF_ENVELOPE;
+       const short use_quaternion = deformflag & ARM_DEF_QUATERNION;
+       const short 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;
@@ -823,20 +843,24 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
        /* bone defmats are already in the channels, chan_mat */
        
        /* initialize B_bone matrices and dual quaternions */
+       totchan= BLI_countlist(&armOb->pose->chanbase);
+
        if(use_quaternion) {
-               totchan= BLI_countlist(&armOb->pose->chanbase);
                dualquats= MEM_callocN(sizeof(DualQuat)*totchan, "dualquats");
        }
+       
+       pdef_info_array= MEM_callocN(sizeof(bPoseChanDeform)*totchan, "bPoseChanDeform");
 
        totchan= 0;
-       for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) {
+       pdef_info= pdef_info_array;
+       for(pchan= armOb->pose->chanbase.first; pchan; pchan= pchan->next, pdef_info++) {
                if(!(pchan->bone->flag & BONE_NO_DEFORM)) {
                        if(pchan->bone->segments > 1)
-                               pchan_b_bone_defmats(pchan, use_quaternion);
+                               pchan_b_bone_defmats(pchan, pdef_info, use_quaternion);
 
                        if(use_quaternion) {
-                               pchan->dual_quat= &dualquats[totchan++];
-                               mat4_to_dquat( pchan->dual_quat,pchan->bone->arm_mat, pchan->chan_mat);
+                               pdef_info->dual_quat= &dualquats[totchan++];
+                               mat4_to_dquat( pdef_info->dual_quat,pchan->bone->arm_mat, pchan->chan_mat);
                        }
                }
        }
@@ -872,15 +896,19 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
                        else if(dverts) use_dverts = 1;
 
                        if(use_dverts) {
-                               defnrToPC = MEM_callocN(sizeof(*defnrToPC) * numGroups,
-                                                                               "defnrToBone");
+                               defnrToPC = MEM_callocN(sizeof(*defnrToPC) * numGroups, "defnrToBone");
+                               defnrToPCIndex = MEM_callocN(sizeof(*defnrToPCIndex) * numGroups, "defnrToIndex");
                                for(i = 0, dg = target->defbase.first; dg;
                                        i++, dg = dg->next) {
                                        defnrToPC[i] = get_pose_channel(armOb->pose, dg->name);
                                        /* exclude non-deforming bones */
                                        if(defnrToPC[i]) {
-                                               if(defnrToPC[i]->bone->flag & BONE_NO_DEFORM)
+                                               if(defnrToPC[i]->bone->flag & BONE_NO_DEFORM) {
                                                        defnrToPC[i]= NULL;
+                                               }
+                                               else {
+                                                       defnrToPCIndex[i]= BLI_findindex(&armOb->pose->chanbase, defnrToPC[i]);
+                                               }
                                        }
                                }
                        }
@@ -920,19 +948,15 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
                        dvert = NULL;
 
                if(armature_def_nr >= 0 && dvert) {
-                       armature_weight = 0.0f; /* a def group was given, so default to 0 */
-                       for(j = 0; j < dvert->totweight; j++) {
-                               if(dvert->dw[j].def_nr == armature_def_nr) {
-                                       armature_weight = dvert->dw[j].weight;
-                                       break;
-                               }
+                       armature_weight= defvert_find_weight(dvert, armature_def_nr);
+
+                       if(invert_vgroup) {
+                               armature_weight= 1.0f-armature_weight;
                        }
+
                        /* 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;
+                               prevco_weight= armature_weight;
                                armature_weight= 1.0f;
                        }
                }
@@ -951,10 +975,10 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
                        
                        for(j = 0; j < dvert->totweight; j++){
                                int index = dvert->dw[j].def_nr;
-                               pchan = index < numGroups?defnrToPC[index]:NULL;
-                               if(pchan) {
+                               if(index < numGroups && (pchan= defnrToPC[index])) {
                                        float weight = dvert->dw[j].weight;
-                                       Bone *bone = pchan->bone;
+                                       Bone *bone= pchan->bone;
+                                       pdef_info= pdef_info_array + defnrToPCIndex[index];
 
                                        deformed = 1;
                                        
@@ -965,25 +989,27 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
                                                                                                         bone->rad_tail,
                                                                                                         bone->dist);
                                        }
-                                       pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib);
+                                       pchan_bone_deform(pchan, pdef_info, weight, vec, dq, smat, co, &contrib);
                                }
                        }
                        /* if there are vertexgroups but not groups with bones
                         * (like for softbody groups)
                         */
                        if(deformed == 0 && use_envelope) {
-                               for(pchan = armOb->pose->chanbase.first; pchan;
-                                       pchan = pchan->next) {
+                               pdef_info= pdef_info_array;
+                               for(pchan= armOb->pose->chanbase.first; pchan;
+                                       pchan= pchan->next, pdef_info++) {
                                        if(!(pchan->bone->flag & BONE_NO_DEFORM))
-                                               contrib += dist_bone_deform(pchan, vec, dq, smat, co);
+                                               contrib += dist_bone_deform(pchan, pdef_info, vec, dq, smat, co);
                                }
                        }
                }
                else if(use_envelope) {
+                       pdef_info= pdef_info_array;
                        for(pchan = armOb->pose->chanbase.first; pchan;
-                               pchan = pchan->next) {
+                               pchan = pchan->next, pdef_info++) {
                                if(!(pchan->bone->flag & BONE_NO_DEFORM))
-                                       contrib += dist_bone_deform(pchan, vec, dq, smat, co);
+                                       contrib += dist_bone_deform(pchan, pdef_info, vec, dq, smat, co);
                        }
                }
 
@@ -993,7 +1019,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
                                normalize_dq(dq, contrib);
 
                                if(armature_weight != 1.0f) {
-                                       VECCOPY(dco, co);
+                                       copy_v3_v3(dco, co);
                                        mul_v3m3_dq( dco, (defMats)? summat: NULL,dq);
                                        sub_v3_v3(dco, co);
                                        mul_v3_fl(dco, armature_weight);
@@ -1039,25 +1065,25 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
 
        if(dualquats) MEM_freeN(dualquats);
        if(defnrToPC) MEM_freeN(defnrToPC);
-       
+       if(defnrToPCIndex) MEM_freeN(defnrToPCIndex);
+
        /* free B_bone matrices */
-       for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) {
-               if(pchan->b_bone_mats) {
-                       MEM_freeN(pchan->b_bone_mats);
-                       pchan->b_bone_mats = NULL;
+       pdef_info= pdef_info_array;
+       for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next, pdef_info++) {
+               if(pdef_info->b_bone_mats) {
+                       MEM_freeN(pdef_info->b_bone_mats);
                }
-               if(pchan->b_bone_dual_quats) {
-                       MEM_freeN(pchan->b_bone_dual_quats);
-                       pchan->b_bone_dual_quats = NULL;
+               if(pdef_info->b_bone_dual_quats) {
+                       MEM_freeN(pdef_info->b_bone_dual_quats);
                }
-
-               pchan->dual_quat = NULL;
        }
+
+       MEM_freeN(pdef_info_array);
 }
 
 /* ************ END Armature Deform ******************* */
 
-void get_objectspace_bone_matrix (struct Bone* bone, float M_accumulatedMatrix[][4], int root, int posed)
+void get_objectspace_bone_matrix (struct Bone* bone, float M_accumulatedMatrix[][4], int UNUSED(root), int UNUSED(posed))
 {
        copy_m4_m4(M_accumulatedMatrix, bone->arm_mat);
 }
@@ -1085,16 +1111,15 @@ void armature_mat_world_to_pose(Object *ob, float inmat[][4], float outmat[][4])
  */
 void armature_loc_world_to_pose(Object *ob, float *inloc, float *outloc) 
 {
-       float xLocMat[4][4];
+       float xLocMat[4][4]= MAT4_UNITY;
        float nLocMat[4][4];
        
        /* build matrix for location */
-       unit_m4(xLocMat);
-       VECCOPY(xLocMat[3], inloc);
+       copy_v3_v3(xLocMat[3], inloc);
 
        /* get bone-space cursor matrix and extract location */
        armature_mat_world_to_pose(ob, xLocMat, nLocMat);
-       VECCOPY(outloc, nLocMat[3]);
+       copy_v3_v3(outloc, nLocMat[3]);
 }
 
 /* Convert Pose-Space Matrix to Bone-Space Matrix 
@@ -1105,22 +1130,50 @@ void armature_mat_pose_to_bone(bPoseChannel *pchan, float inmat[][4], float outm
 {
        float pc_trans[4][4], inv_trans[4][4];
        float pc_posemat[4][4], inv_posemat[4][4];
-       
+       float pose_mat[4][4];
+
        /* paranoia: prevent crashes with no pose-channel supplied */
        if (pchan==NULL) return;
-       
-       /* get the inverse matrix of the pchan's transforms */
-       if (pchan->rotmode)
-               loc_eul_size_to_mat4(pc_trans, pchan->loc, pchan->eul, pchan->size);
-       else
-               loc_quat_size_to_mat4(pc_trans, pchan->loc, pchan->quat, pchan->size);
+
+       /* default flag */
+       if((pchan->bone->flag & BONE_NO_LOCAL_LOCATION)==0) {
+               /* get the inverse matrix of the pchan's transforms */
+               switch(pchan->rotmode) {
+               case ROT_MODE_QUAT:
+                       loc_quat_size_to_mat4(pc_trans, pchan->loc, pchan->quat, pchan->size);
+                       break;
+               case ROT_MODE_AXISANGLE:
+                       loc_axisangle_size_to_mat4(pc_trans, pchan->loc, pchan->rotAxis, pchan->rotAngle, pchan->size);
+                       break;
+               default: /* euler */
+                       loc_eul_size_to_mat4(pc_trans, pchan->loc, pchan->eul, pchan->size);
+               }
+
+               copy_m4_m4(pose_mat, pchan->pose_mat);
+       }
+       else {
+               /* local location, this is not default, different calculation
+                * note: only tested for location with pose bone snapping.
+                * If this is not useful in other cases the BONE_NO_LOCAL_LOCATION
+                * case may have to be split into its own function. */
+               unit_m4(pc_trans);
+               copy_v3_v3(pc_trans[3], pchan->loc);
+
+               /* use parents rotation/scale space + own absolute position */
+               if(pchan->parent)       copy_m4_m4(pose_mat, pchan->parent->pose_mat);
+               else                            unit_m4(pose_mat);
+
+               copy_v3_v3(pose_mat[3], pchan->pose_mat[3]);
+       }
+
+
        invert_m4_m4(inv_trans, pc_trans);
        
        /* Remove the pchan's transforms from it's pose_mat.
         * This should leave behind the effects of restpose + 
         * parenting + constraints
         */
-       mul_m4_m4m4(pc_posemat, inv_trans, pchan->pose_mat);
+       mul_m4_m4m4(pc_posemat, inv_trans, pose_mat);
        
        /* get the inverse of the leftovers so that we can remove 
         * that component from the supplied matrix
@@ -1137,44 +1190,41 @@ void armature_mat_pose_to_bone(bPoseChannel *pchan, float inmat[][4], float outm
  */
 void armature_loc_pose_to_bone(bPoseChannel *pchan, float *inloc, float *outloc) 
 {
-       float xLocMat[4][4];
+       float xLocMat[4][4]= MAT4_UNITY;
        float nLocMat[4][4];
        
        /* build matrix for location */
-       unit_m4(xLocMat);
-       VECCOPY(xLocMat[3], inloc);
+       copy_v3_v3(xLocMat[3], inloc);
 
        /* get bone-space cursor matrix and extract location */
        armature_mat_pose_to_bone(pchan, xLocMat, nLocMat);
-       VECCOPY(outloc, nLocMat[3]);
+       copy_v3_v3(outloc, nLocMat[3]);
 }
 
+/* same as object_mat3_to_rot() */
+void pchan_mat3_to_rot(bPoseChannel *pchan, float mat[][3], short use_compat)
+{
+       switch(pchan->rotmode) {
+       case ROT_MODE_QUAT:
+               mat3_to_quat(pchan->quat, mat);
+               break;
+       case ROT_MODE_AXISANGLE:
+               mat3_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, mat);
+               break;
+       default: /* euler */
+               if(use_compat)  mat3_to_compatible_eulO(pchan->eul, pchan->eul, pchan->rotmode, mat);
+               else                    mat3_to_eulO(pchan->eul, pchan->rotmode, mat);
+       }
+}
 
 /* Apply a 4x4 matrix to the pose bone,
  * similar to object_apply_mat4()
  */
-void pchan_apply_mat4(bPoseChannel *pchan, float mat[][4])
+void pchan_apply_mat4(bPoseChannel *pchan, float mat[][4], short use_compat)
 {
-       /* location */
-       copy_v3_v3(pchan->loc, mat[3]);
-
-       /* scale */
-       mat4_to_size(pchan->size, mat);
-
-       /* rotation */
-       if (pchan->rotmode == ROT_MODE_AXISANGLE) {
-               float tmp_quat[4];
-
-               /* need to convert to quat first (in temp var)... */
-               mat4_to_quat(tmp_quat, mat);
-               quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, tmp_quat);
-       }
-       else if (pchan->rotmode == ROT_MODE_QUAT) {
-               mat4_to_quat(pchan->quat, mat);
-       }
-       else {
-               mat4_to_eulO(pchan->eul, pchan->rotmode, mat);
-       }
+       float rot[3][3];
+       mat4_to_loc_rot_size(pchan->loc, rot, pchan->size, mat);
+       pchan_mat3_to_rot(pchan, rot, use_compat);
 }
 
 /* Remove rest-position effects from pose-transform for obtaining
@@ -1183,10 +1233,10 @@ void pchan_apply_mat4(bPoseChannel *pchan, float mat[][4])
  */
 void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float arm_mat[][4])
 {
-        float imat[4][4];
-        invert_m4_m4(imat, arm_mat);
-        mul_m4_m4m4(delta_mat, pose_mat, imat);
+       float imat[4][4];
+       
+       invert_m4_m4(imat, arm_mat);
+       mul_m4_m4m4(delta_mat, pose_mat, imat);
 }
 
 /* **************** Rotation Mode Conversions ****************************** */
@@ -1206,6 +1256,7 @@ void BKE_rotMode_change_values (float quat[4], float eul[3], float axis[3], floa
                }
                else if (oldMode == ROT_MODE_QUAT) {
                        /* quat to euler */
+                       normalize_qt(quat);
                        quat_to_eulO( eul, newMode,quat);
                }
                /* else { no conversion needed } */
@@ -1228,11 +1279,12 @@ void BKE_rotMode_change_values (float quat[4], float eul[3], float axis[3], floa
                }
                else if (oldMode == ROT_MODE_QUAT) {
                        /* quat to axis angle */
+                       normalize_qt(quat);
                        quat_to_axis_angle( axis, angle,quat);
                }
                
                /* when converting to axis-angle, we need a special exception for the case when there is no axis */
-               if (IS_EQ(axis[0], axis[1]) && IS_EQ(axis[1], axis[2])) {
+               if (IS_EQF(axis[0], axis[1]) && IS_EQF(axis[1], axis[2])) {
                        /* for now, rotate around y-axis then (so that it simply becomes the roll) */
                        axis[1]= 1.0f;
                }
@@ -1290,8 +1342,12 @@ void vec_roll_to_mat3(float *vec, float roll, float mat[][3])
        cross_v3_v3v3(axis,target,nor);
 
        /* was 0.0000000000001, caused bug [#23954], smaller values give unstable
-        * roll when toggling editmode */
-       if (dot_v3v3(axis,axis) > 0.00001) {
+        * roll when toggling editmode.
+        *
+        * was 0.00001, causes bug [#27675], with 0.00000495,
+        * so a value inbetween these is needed.
+        */
+       if (dot_v3v3(axis,axis) > 0.000001f) {
                /* if nor is *not* a multiple of target ... */
                normalize_v3(axis);
                
@@ -1334,7 +1390,7 @@ void where_is_armature_bone(Bone *bone, Bone *prevbone)
        bone->length= len_v3v3(bone->head, bone->tail);
        
        /* this is called on old file reading too... */
-       if(bone->xwidth==0.0) {
+       if(bone->xwidth==0.0f) {
                bone->xwidth= 0.1f;
                bone->zwidth= 0.1f;
                bone->segments= 1;
@@ -1347,7 +1403,7 @@ void where_is_armature_bone(Bone *bone, Bone *prevbone)
                copy_m4_m3(offs_bone, bone->bone_mat);
                                
                /* The bone's root offset (is in the parent's coordinate system) */
-               VECCOPY(offs_bone[3], bone->head);
+               copy_v3_v3(offs_bone[3], bone->head);
 
                /* Get the length translation of parent (length along y axis) */
                offs_bone[3][1]+= prevbone->length;
@@ -1357,16 +1413,9 @@ void where_is_armature_bone(Bone *bone, Bone *prevbone)
        }
        else {
                copy_m4_m3(bone->arm_mat, bone->bone_mat);
-               VECCOPY(bone->arm_mat[3], bone->head);
+               copy_v3_v3(bone->arm_mat[3], bone->head);
        }
        
-       /* head */
-       VECCOPY(bone->arm_head, bone->arm_mat[3]);
-       /* tail is in current local coord system */
-       VECCOPY(vec, bone->arm_mat[1]);
-       mul_v3_fl(vec, bone->length);
-       add_v3_v3v3(bone->arm_tail, bone->arm_head, vec);
-       
        /* and the kiddies */
        prevbone= bone;
        for(bone= bone->childbase.first; bone; bone= bone->next) {
@@ -1411,10 +1460,6 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
        if(error)
                return;
        
-       /* exception, armature local layer should be proxied too */
-       if (pose->proxy_layer)
-               ((bArmature *)ob->data)->layer= pose->proxy_layer;
-       
        /* clear all transformation values from library */
        rest_pose(frompose);
        
@@ -1439,7 +1484,6 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
                        pchanw.next= pchan->next;
                        pchanw.parent= pchan->parent;
                        pchanw.child= pchan->child;
-                       pchanw.path= NULL;
                        
                        /* this is freed so copy a copy, else undo crashes */
                        if(pchanw.prop) {
@@ -1460,7 +1504,7 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
                         */
                        extract_proxylocal_constraints(&proxylocal_constraints, &pchan->constraints);
                        copy_constraints(&pchanw.constraints, &pchanp->constraints, FALSE);
-                       addlisttolist(&pchanw.constraints, &proxylocal_constraints);
+                       BLI_movelisttolist(&pchanw.constraints, &proxylocal_constraints);
                        
                        /* constraints - set target ob pointer to own object */
                        for (con= pchanw.constraints.first; con; con= con->next) {
@@ -1616,7 +1660,7 @@ typedef struct tSplineIK_Tree {
 /* ----------- */
 
 /* Tag the bones in the chain formed by the given bone for IK */
-static void splineik_init_tree_from_pchan(Scene *scene, Object *ob, bPoseChannel *pchan_tip)
+static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPoseChannel *pchan_tip)
 {
        bPoseChannel *pchan, *pchanRoot=NULL;
        bPoseChannel *pchanChain[255];
@@ -1689,28 +1733,25 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *ob, bPoseChannel
                ikData->numpoints= ikData->chainlen+1; 
                ikData->points= MEM_callocN(sizeof(float)*ikData->numpoints, "Spline IK Binding");
                
+               /* bind 'tip' of chain (i.e. first joint = tip of bone with the Spline IK Constraint) */
+               ikData->points[0] = 1.0f;
+               
                /* perform binding of the joints to parametric positions along the curve based 
                 * proportion of the total length that each bone occupies
                 */
                for (i = 0; i < segcount; i++) {
-                       if (i != 0) {
-                               /* 'head' joints 
-                                *      - 2 methods; the one chosen depends on whether we've got usable lengths
-                                */
-                               if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) {
-                                       /* 1) equi-spaced joints */
-                                       ikData->points[i]= ikData->points[i-1] - segmentLen;
-                               }
-                               else {
-                                        /*     2) to find this point on the curve, we take a step from the previous joint
-                                         *       a distance given by the proportion that this bone takes
-                                         */
-                                       ikData->points[i]= ikData->points[i-1] - (boneLengths[i] / totLength);
-                               }
+                       /* 'head' joints, travelling towards the root of the chain
+                        *      - 2 methods; the one chosen depends on whether we've got usable lengths
+                        */
+                       if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) {
+                               /* 1) equi-spaced joints */
+                               ikData->points[i+1]= ikData->points[i] - segmentLen;
                        }
                        else {
-                               /* 'tip' of chain, special exception for the first joint */
-                               ikData->points[0]= 1.0f;
+                               /*      2) to find this point on the curve, we take a step from the previous joint
+                                *        a distance given by the proportion that this bone takes
+                                */
+                               ikData->points[i+1]= ikData->points[i] - (boneLengths[i] / totLength);
                        }
                }
                
@@ -1785,7 +1826,7 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *ob, bPoseChannel
 }
 
 /* Tag which bones are members of Spline IK chains */
-static void splineik_init_tree(Scene *scene, Object *ob, float ctime)
+static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime))
 {
        bPoseChannel *pchan;
        
@@ -1808,8 +1849,8 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o
        /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */
        where_is_pose_bone(scene, ob, pchan, ctime, 1);
        
-       VECCOPY(poseHead, pchan->pose_head);
-       VECCOPY(poseTail, pchan->pose_tail);
+       copy_v3_v3(poseHead, pchan->pose_head);
+       copy_v3_v3(poseTail, pchan->pose_tail);
        
        /* step 1: determine the positions for the endpoints of the bone */
        {
@@ -1853,7 +1894,7 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o
                        
                        /* store the position, and convert it to pose space */
                        mul_m4_v3(ob->imat, vec);
-                       VECCOPY(poseHead, vec);
+                       copy_v3_v3(poseHead, vec);
                        
                        /* set the new radius (it should be the average value) */
                        radius = (radius+rad) / 2;
@@ -1877,9 +1918,9 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o
                /* compute the raw rotation matrix from the bone's current matrix by extracting only the
                 * orientation-relevant axes, and normalising them
                 */
-               VECCOPY(rmat[0], pchan->pose_mat[0]);
-               VECCOPY(rmat[1], pchan->pose_mat[1]);
-               VECCOPY(rmat[2], pchan->pose_mat[2]);
+               copy_v3_v3(rmat[0], pchan->pose_mat[0]);
+               copy_v3_v3(rmat[1], pchan->pose_mat[1]);
+               copy_v3_v3(rmat[2], pchan->pose_mat[2]);
                normalize_m3(rmat);
                
                /* also, normalise the orientation imposed by the bone, now that we've extracted the scale factor */
@@ -1939,12 +1980,12 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o
                                /* calculate volume preservation factor which is 
                                 * basically the inverse of the y-scaling factor 
                                 */
-                               if (fabs(scaleFac) != 0.0f) {
-                                       scale= 1.0 / fabs(scaleFac);
+                               if (fabsf(scaleFac) != 0.0f) {
+                                       scale= 1.0f / fabsf(scaleFac);
                                        
                                        /* we need to clamp this within sensible values */
                                        // NOTE: these should be fine for now, but should get sanitised in future
-                                       scale= MIN2(MAX2(scale, 0.0001) , 100000);
+                                       CLAMP(scale, 0.0001f, 100000.0f);
                                }
                                else
                                        scale= 1.0f;
@@ -1970,7 +2011,7 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o
                /* when the 'no-root' option is affected, the chain can retain
                 * the shape but be moved elsewhere
                 */
-               VECCOPY(poseHead, pchan->pose_head);
+               copy_v3_v3(poseHead, pchan->pose_head);
        }
        else if (tree->con->enforce < 1.0f) {
                /* when the influence is too low
@@ -1978,19 +2019,21 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o
                 *      - stick to the parent for any other
                 */
                if (pchan->parent) {
-                       VECCOPY(poseHead, pchan->pose_head);
+                       copy_v3_v3(poseHead, pchan->pose_head);
                }
                else {
                        // FIXME: this introduces popping artifacts when we reach 0.0
                        interp_v3_v3v3(poseHead, pchan->pose_head, poseHead, tree->con->enforce);
                }
        }
-       VECCOPY(poseMat[3], poseHead);
+       copy_v3_v3(poseMat[3], poseHead);
        
        /* finally, store the new transform */
        copy_m4_m4(pchan->pose_mat, poseMat);
-       VECCOPY(pchan->pose_head, poseHead);
-       VECCOPY(pchan->pose_tail, poseTail);
+       copy_v3_v3(pchan->pose_head, poseHead);
+       
+       /* recalculate tail, as it's now outdated after the head gets adjusted above! */
+       where_is_pose_bone_tail(pchan);
        
        /* done! */
        pchan->flag |= POSE_DONE;
@@ -2055,8 +2098,7 @@ void pchan_to_mat4(bPoseChannel *pchan, float chan_mat[4][4])
                 * but if this proves to be too problematic, switch back to the old system of operating directly on 
                 * the stored copy
                 */
-               QUATCOPY(quat, pchan->quat);
-               normalize_qt(quat);
+               normalize_qt_qt(quat, pchan->quat);
                quat_to_mat3(rmat, quat);
        }
        
@@ -2067,13 +2109,13 @@ void pchan_to_mat4(bPoseChannel *pchan, float chan_mat[4][4])
        /* prevent action channels breaking chains */
        /* need to check for bone here, CONSTRAINT_TYPE_ACTION uses this call */
        if ((pchan->bone==NULL) || !(pchan->bone->flag & BONE_CONNECTED)) {
-               VECCOPY(chan_mat[3], pchan->loc);
+               copy_v3_v3(chan_mat[3], pchan->loc);
        }
 }
 
 /* loc/rot/size to mat4 */
 /* used in constraint.c too */
-void chan_calc_mat(bPoseChannel *pchan)
+void pchan_calc_mat(bPoseChannel *pchan)
 {
        /* this is just a wrapper around the copy of this function which calculates the matrix 
         * and stores the result in any given channel
@@ -2153,11 +2195,11 @@ static void do_strip_modifiers(Scene *scene, Object *armob, Bone *bone, bPoseCha
                                                ofs = amod->turbul / 200.0f;
                                                
                                                /* make a copy of starting conditions */
-                                               VECCOPY(loc, pchan->pose_mat[3]);
+                                               copy_v3_v3(loc, pchan->pose_mat[3]);
                                                mat4_to_eul( eul,pchan->pose_mat);
                                                mat4_to_size( size,pchan->pose_mat);
-                                               VECCOPY(eulo, eul);
-                                               VECCOPY(sizeo, size);
+                                               copy_v3_v3(eulo, eul);
+                                               copy_v3_v3(sizeo, size);
                                                
                                                /* apply noise to each set of channels */
                                                if (amod->channels & 4) {
@@ -2203,6 +2245,15 @@ static void do_strip_modifiers(Scene *scene, Object *armob, Bone *bone, bPoseCha
        }
 }
 
+/* calculate tail of posechannel */
+void where_is_pose_bone_tail(bPoseChannel *pchan)
+{
+       float vec[3];
+       
+       copy_v3_v3(vec, pchan->pose_mat[1]);
+       mul_v3_fl(vec, pchan->bone->length);
+       add_v3_v3v3(pchan->pose_tail, pchan->pose_head, vec);
+}
 
 /* The main armature solver, does all constraints excluding IK */
 /* pchan is validated, as having bone and parent pointer
@@ -2220,7 +2271,7 @@ void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float cti
        parchan= pchan->parent;
        
        /* this gives a chan_mat with actions (ipos) results */
-       if(do_extra)    chan_calc_mat(pchan);
+       if(do_extra)    pchan_calc_mat(pchan);
        else                    unit_m4(pchan->chan_mat);
 
        /* construct the posemat based on PoseChannels, that we do before applying constraints */
@@ -2233,19 +2284,34 @@ void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float cti
                copy_m4_m3(offs_bone, bone->bone_mat);
                
                /* The bone's root offset (is in the parent's coordinate system) */
-               VECCOPY(offs_bone[3], bone->head);
+               copy_v3_v3(offs_bone[3], bone->head);
                
                /* Get the length translation of parent (length along y axis) */
                offs_bone[3][1]+= parbone->length;
                
                /* Compose the matrix for this bone  */
-               if(bone->flag & BONE_HINGE) {   // uses restposition rotation, but actual position
+               if((bone->flag & BONE_HINGE) && (bone->flag & BONE_NO_SCALE)) { // uses restposition rotation, but actual position
                        float tmat[4][4];
-                       
                        /* the rotation of the parent restposition */
                        copy_m4_m4(tmat, parbone->arm_mat);
                        mul_serie_m4(pchan->pose_mat, tmat, offs_bone, pchan->chan_mat, NULL, NULL, NULL, NULL, NULL);
                }
+               else if(bone->flag & BONE_HINGE) {      // same as above but apply parent scale
+                       float tmat[4][4];
+
+                       /* apply the parent matrix scale */
+                       float tsmat[4][4], tscale[3];
+
+                       /* the rotation of the parent restposition */
+                       copy_m4_m4(tmat, parbone->arm_mat);
+
+                       /* extract the scale of the parent matrix */
+                       mat4_to_size(tscale, parchan->pose_mat);
+                       size_to_mat4(tsmat, tscale);
+                       mul_m4_m4m4(tmat, tmat, tsmat);
+
+                       mul_serie_m4(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];
                        
@@ -2296,7 +2362,7 @@ void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float cti
                        bConstraintOb *cob;
 
                        /* make a copy of location of PoseChannel for later */
-                       VECCOPY(vec, pchan->pose_mat[3]);
+                       copy_v3_v3(vec, pchan->pose_mat[3]);
 
                        /* prepare PoseChannel for Constraint solving
                         * - makes a copy of matrix, and creates temporary struct to use
@@ -2313,17 +2379,15 @@ void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float cti
 
                        /* prevent constraints breaking a chain */
                        if(pchan->bone->flag & BONE_CONNECTED) {
-                               VECCOPY(pchan->pose_mat[3], vec);
+                               copy_v3_v3(pchan->pose_mat[3], vec);
                        }
                }
        }
        
        /* calculate head */
-       VECCOPY(pchan->pose_head, pchan->pose_mat[3]);
+       copy_v3_v3(pchan->pose_head, pchan->pose_mat[3]);
        /* calculate tail */
-       VECCOPY(vec, pchan->pose_mat[1]);
-       mul_v3_fl(vec, bone->length);
-       add_v3_v3v3(pchan->pose_tail, pchan->pose_head, vec);
+       where_is_pose_bone_tail(pchan);
 }
 
 /* This only reads anim data from channels, and writes to channels */
@@ -2341,7 +2405,7 @@ void where_is_pose (Scene *scene, Object *ob)
        
        if(ELEM(NULL, arm, scene)) return;
        if((ob->pose==NULL) || (ob->pose->flag & POSE_RECALC)) 
-          armature_rebuild_pose(ob, arm);
+               armature_rebuild_pose(ob, arm);
           
        ctime= bsystem_time(scene, ob, (float)scene->r.cfra, 0.0);      /* not accurate... */
        
@@ -2352,8 +2416,8 @@ void where_is_pose (Scene *scene, Object *ob)
                        bone= pchan->bone;
                        if(bone) {
                                copy_m4_m4(pchan->pose_mat, bone->arm_mat);
-                               VECCOPY(pchan->pose_head, bone->arm_head);
-                               VECCOPY(pchan->pose_tail, bone->arm_tail);
+                               copy_v3_v3(pchan->pose_head, bone->arm_head);
+                               copy_v3_v3(pchan->pose_tail, bone->arm_tail);
                        }
                }
        }
@@ -2401,3 +2465,33 @@ void where_is_pose (Scene *scene, Object *ob)
                }
        }
 }
+
+
+/* Returns total selected vgroups,
+ * wpi.defbase_sel is assumed malloc'd, all values are set */
+int get_selected_defgroups(Object *ob, char *dg_selection, int defbase_len)
+{
+       bDeformGroup *defgroup;
+       unsigned int i;
+       Object *armob= object_pose_armature_get(ob);
+       int dg_flags_sel_tot= 0;
+
+       if(armob) {
+               bPose *pose= armob->pose;
+               for (i= 0, defgroup= ob->defbase.first; i < defbase_len && defgroup; defgroup = defgroup->next, i++) {
+                       bPoseChannel *pchan= get_pose_channel(pose, defgroup->name);
+                       if(pchan && (pchan->bone->flag & BONE_SELECTED)) {
+                               dg_selection[i]= TRUE;
+                               dg_flags_sel_tot++;
+                       }
+                       else {
+                               dg_selection[i]= FALSE;
+                       }
+               }
+       }
+       else {
+               memset(dg_selection, FALSE, sizeof(char) * defbase_len);
+       }
+
+       return dg_flags_sel_tot;
+}