edits ontop of Alex's patch from r41292.
[blender.git] / source / blender / blenkernel / intern / action.c
index fb1b2e9cf70d75b82e0805c6519ad75ed8fbbcd6..d02a1d6dd2706665def0811d1c2416b2ea81a605 100644 (file)
@@ -1,6 +1,4 @@
-/**
- * $Id$
- *
+/*
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  * All rights reserved.
  *
  * Contributor(s): Full recode, Ton Roosendaal, Crete 2005
+ *                              Full recode, Joshua Leung, 2009
  *
  * ***** END GPL LICENSE BLOCK *****
  */
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+/** \file blender/blenkernel/intern/action.c
+ *  \ingroup bke
+ */
+
 
 #include <string.h>
 #include <math.h>
-#include <stdlib.h>    /* for NULL */
+#include <stdlib.h>
+#include <stddef.h>    
 
 #include "MEM_guardedalloc.h"
 
 #include "DNA_anim_types.h"
-#include "DNA_action_types.h"
 #include "DNA_armature_types.h"
 #include "DNA_constraint_types.h"
-#include "DNA_curve_types.h"
-#include "DNA_key_types.h"
-#include "DNA_nla_types.h"
-#include "DNA_object_types.h"
 #include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
 
 #include "BKE_animsys.h"
 #include "BKE_action.h"
 #include "BKE_anim.h"
-#include "BKE_armature.h"
-#include "BKE_blender.h"
 #include "BKE_constraint.h"
-#include "BKE_displist.h"
 #include "BKE_global.h"
 #include "BKE_fcurve.h"
-#include "BKE_key.h"
-#include "BKE_lattice.h"
 #include "BKE_library.h"
 #include "BKE_main.h"
 #include "BKE_object.h"
-#include "BKE_utildefines.h"
 
-#include "BLI_arithb.h"
-#include "BLI_blenlib.h"
-#include "BLI_ghash.h"
+#include "BKE_idprop.h"
 
-#include "RNA_access.h"
-#include "RNA_types.h"
+#include "BIK_api.h"
 
-//XXX #include "nla.h"
+#include "RNA_access.h"
 
 /* *********************** NOTE ON POSE AND ACTION **********************
 
   - Pose is the local (object level) component of armature. The current
-    object pose is saved in files, and (will be) is presorted for dependency
+       object pose is saved in files, and (will be) is presorted for dependency
   - Actions have fewer (or other) channels, and write data to a Pose
   - Currently ob->pose data is controlled in where_is_pose only. The (recalc)
-    event system takes care of calling that
+       event system takes care of calling that
   - The NLA system (here too) uses Poses as interpolation format for Actions
   - Therefore we assume poses to be static, and duplicates of poses have channels in
-    same order, for quick interpolation reasons
+       same order, for quick interpolation reasons
 
   ****************************** (ton) ************************************ */
 
@@ -90,66 +83,78 @@ bAction *add_empty_action(const char name[])
        bAction *act;
        
        act= alloc_libblock(&G.main->action, ID_AC, name);
-       act->id.flag |= LIB_FAKEUSER; // XXX this is nasty for new users... maybe we don't want this anymore
-       act->id.us++;
        
        return act;
 }      
 
+/* .................................. */
+
+/* temp data for make_local_action */
+typedef struct tMakeLocalActionContext {
+       bAction *act;    /* original action */
+       bAction *actn;   /* new action */
+       
+       int lib;         /* some action users were libraries */
+       int local;       /* some action users were not libraries */
+} tMakeLocalActionContext;
+
+/* helper function for make_local_action() - local/lib init step */
+static void make_localact_init_cb(ID *id, AnimData *adt, void *mlac_ptr)
+{
+       tMakeLocalActionContext *mlac = (tMakeLocalActionContext *)mlac_ptr;
+       
+       if (adt->action == mlac->act) {
+               if (id->lib) 
+                       mlac->lib = 1;
+               else 
+                       mlac->local = 1;
+       }
+}
+
+/* helper function for make_local_action() - change references */
+static void make_localact_apply_cb(ID *id, AnimData *adt, void *mlac_ptr)
+{
+       tMakeLocalActionContext *mlac = (tMakeLocalActionContext *)mlac_ptr;
+       
+       if (adt->action == mlac->act) {
+               if (id->lib == NULL) {
+                       adt->action = mlac->actn;
+                       
+                       id_us_plus(&mlac->actn->id);
+                       id_us_min(&mlac->act->id);
+               }
+       }
+}
+
 // does copy_fcurve...
 void make_local_action(bAction *act)
 {
-       // Object *ob;
-       bAction *actn;
-       int local=0, lib=0;
-       
-       if (act->id.lib==0) return;
-       if (act->id.us==1) {
-               act->id.lib= 0;
-               act->id.flag= LIB_LOCAL;
-               //make_local_action_channels(act);
-               new_id(0, (ID *)act, 0);
+       tMakeLocalActionContext mlac = {act, NULL, 0, 0};
+       Main *bmain= G.main;
+       
+       if (act->id.lib==NULL) 
                return;
-       }
        
-#if 0  // XXX old animation system
-       ob= G.main->object.first;
-       while(ob) {
-               if(ob->action==act) {
-                       if(ob->id.lib) lib= 1;
-                       else local= 1;
-               }
-               ob= ob->id.next;
+       // XXX: double-check this; it used to be just single-user check, but that was when fake-users were still default
+       if ((act->id.flag & LIB_FAKEUSER) && (act->id.us<=1)) {
+               id_clear_lib_data(bmain, (ID *)act);
+               return;
        }
-#endif
        
-       if(local && lib==0) {
-               act->id.lib= 0;
-               act->id.flag= LIB_LOCAL;
-               //make_local_action_channels(act);
-               new_id(0, (ID *)act, 0);
+       BKE_animdata_main_cb(bmain, make_localact_init_cb, &mlac);
+       
+       if (mlac.local && mlac.lib==0) {
+               id_clear_lib_data(bmain, (ID *)act);
        }
-       else if(local && lib) {
-               actn= copy_action(act);
-               actn->id.us= 0;
+       else if (mlac.local && mlac.lib) {
+               mlac.actn= copy_action(act);
+               mlac.actn->id.us= 0;
                
-#if 0  // XXX old animation system
-               ob= G.main->object.first;
-               while(ob) {
-                       if(ob->action==act) {
-                               
-                               if(ob->id.lib==0) {
-                                       ob->action = actn;
-                                       actn->id.us++;
-                                       act->id.us--;
-                               }
-                       }
-                       ob= ob->id.next;
-               }
-#endif // XXX old animation system
+               BKE_animdata_main_cb(bmain, make_localact_apply_cb, &mlac);
        }
 }
 
+/* .................................. */
 
 void free_action (bAction *act)
 {
@@ -169,6 +174,8 @@ void free_action (bAction *act)
                BLI_freelistN(&act->markers);
 }
 
+/* .................................. */
+
 bAction *copy_action (bAction *src)
 {
        bAction *dst = NULL;
@@ -206,12 +213,10 @@ bAction *copy_action (bAction *src)
                }
        }
        
-       dst->id.flag |= LIB_FAKEUSER; // XXX this is nasty for new users... maybe we don't want this anymore
-       dst->id.us++;
-       
        return dst;
 }
 
+/* *************** Action Groups *************** */
 
 /* Get the active action-group for an Action */
 bActionGroup *get_active_actiongroup (bAction *act)
@@ -246,106 +251,97 @@ void set_active_action_group (bAction *act, bActionGroup *agrp, short select)
        }
 }
 
+/* Add a new action group with the given name to the action */
+bActionGroup *action_groups_add_new (bAction *act, const char name[])
+{
+       bActionGroup *agrp;
+       
+       /* sanity check: must have action and name */
+       if (ELEM(NULL, act, name))
+               return NULL;
+       
+       /* allocate a new one */
+       agrp = MEM_callocN(sizeof(bActionGroup), "bActionGroup");
+       
+       /* make it selected, with default name */
+       agrp->flag = AGRP_SELECTED;
+       BLI_strncpy(agrp->name, name[0] ? name : "Group", sizeof(agrp->name));
+       
+       /* add to action, and validate */
+       BLI_addtail(&act->groups, agrp);
+       BLI_uniquename(&act->groups, agrp, "Group", '.', offsetof(bActionGroup, name), sizeof(agrp->name));     
+       
+       /* return the new group */
+       return agrp;
+}
+
 /* Add given channel into (active) group 
  *     - assumes that channel is not linked to anything anymore
  *     - always adds at the end of the group 
  */
 void action_groups_add_channel (bAction *act, bActionGroup *agrp, FCurve *fcurve)
-{
-       FCurve *fcu;
-       short done=0;
-       
+{      
        /* sanity checks */
        if (ELEM3(NULL, act, agrp, fcurve))
                return;
        
-       /* if no channels, just add to two lists at the same time */
+       /* if no channels anywhere, just add to two lists at the same time */
        if (act->curves.first == NULL) {
                fcurve->next = fcurve->prev = NULL;
                
                agrp->channels.first = agrp->channels.last = fcurve;
                act->curves.first = act->curves.last = fcurve;
-               
-               fcurve->grp= agrp;
-               return;
        }
        
-       /* try to find a channel to slot this in before/after */
-       for (fcu= act->curves.first; fcu; fcu= fcu->next) {
-               /* if channel has no group, then we have ungrouped channels, which should always occur after groups */
-               if (fcu->grp == NULL) {
-                       BLI_insertlinkbefore(&act->curves, fcu, fcurve);
-                       
-                       if (agrp->channels.first == NULL)
-                               agrp->channels.first= fcurve;
-                       agrp->channels.last= fcurve;
+       /* if the group already has channels, the F-Curve can simply be added to the list 
+        * (i.e. as the last channel in the group)
+        */
+       else if (agrp->channels.first) {
+               /* if the group's last F-Curve is the action's last F-Curve too, 
+                * then set the F-Curve as the last for the action first so that
+                * the lists will be in sync after linking
+                */
+               if (agrp->channels.last == act->curves.last)
+                       act->curves.last= fcurve;
                        
-                       done= 1;
-                       break;
-               }
+               /* link in the given F-Curve after the last F-Curve in the group,
+                * which means that it should be able to fit in with the rest of the
+                * list seamlessly
+                */
+               BLI_insertlinkafter(&agrp->channels, agrp->channels.last, fcurve);
+       }
+       
+       /* otherwise, need to find the nearest F-Curve in group before/after current to link with */
+       else {
+               bActionGroup *grp;
                
-               /* if channel has group after current, we can now insert (otherwise we have gone too far) */
-               else if (fcu->grp == agrp->next) {
-                       BLI_insertlinkbefore(&act->curves, fcu, fcurve);
-                       
-                       if (agrp->channels.first == NULL)
-                               agrp->channels.first= fcurve;
-                       agrp->channels.last= fcurve;
-                       
-                       done= 1;
-                       break;
-               }
+               /* firstly, link this F-Curve to the group */
+               agrp->channels.first = agrp->channels.last = fcurve;
                
-               /* if channel has group we're targeting, check whether it is the last one of these */
-               else if (fcu->grp == agrp) {
-                       if ((fcu->next) && (fcu->next->grp != agrp)) {
-                               BLI_insertlinkafter(&act->curves, fcu, fcurve);
-                               agrp->channels.last= fcurve;
-                               done= 1;
-                               break;
-                       }
-                       else if (fcu->next == NULL) {
-                               BLI_addtail(&act->curves, fcurve);
-                               agrp->channels.last= fcurve;
-                               done= 1;
+               /* step through the groups preceding this one, finding the F-Curve there to attach this one after */
+               for (grp= agrp->prev; grp; grp= grp->prev) {
+                       /* if this group has F-Curves, we want weave the given one in right after the last channel there,
+                        * but via the Action's list not this group's list
+                        *      - this is so that the F-Curve is in the right place in the Action,
+                        *        but won't be included in the previous group
+                        */
+                       if (grp->channels.last) {
+                               /* once we've added, break here since we don't need to search any further... */
+                               BLI_insertlinkafter(&act->curves, grp->channels.last, fcurve);
                                break;
                        }
                }
                
-               /* if channel has group before target, check whether the next one is something after target */
-               else if (fcu->grp == agrp->prev) {
-                       if (fcu->next) {
-                               if ((fcu->next->grp != fcu->grp) && (fcu->next->grp != agrp)) {
-                                       BLI_insertlinkafter(&act->curves, fcu, fcurve);
-                                       
-                                       agrp->channels.first= fcurve;
-                                       agrp->channels.last= fcurve;
-                                       
-                                       done= 1;
-                                       break;
-                               }
-                       }
-                       else {
-                               BLI_insertlinkafter(&act->curves, fcu, fcurve);
-                               
-                               agrp->channels.first= fcurve;
-                               agrp->channels.last= fcurve;
-                               
-                               done= 1;
-                               break;
-                       }
-               }
+               /* if grp is NULL, that means we fell through, and this F-Curve should be added as the new first
+                * since group is (effectively) the first group. Thus, the existing first F-Curve becomes the 
+                * second in the chain, etc. etc.
+                */
+               if (grp == NULL)
+                       BLI_insertlinkbefore(&act->curves, act->curves.first, fcurve);
        }
        
-       /* only if added, set channel as belonging to this group */
-       if (done) {
-               //printf("FCurve added to group \n");
-               fcurve->grp= agrp;
-       }
-       else {
-               printf("Error: FCurve '%s' couldn't be added to Group '%s' \n", fcurve->rna_path, agrp->name);
-               BLI_addtail(&act->curves, fcurve);
-       }
+       /* set the F-Curve's new group */
+       fcurve->grp= agrp;
 }      
 
 /* Remove the given channel from all groups */
@@ -388,44 +384,45 @@ void action_groups_remove_channel (bAction *act, FCurve *fcu)
 /* Find a group with the given name */
 bActionGroup *action_groups_find_named (bAction *act, const char name[])
 {
-       bActionGroup *grp;
-       
        /* sanity checks */
        if (ELEM3(NULL, act, act->groups.first, name) || (name[0] == 0))
                return NULL;
                
        /* do string comparisons */
-       for (grp= act->groups.first; grp; grp= grp->next) {
-               if (strcmp(grp->name, name) == 0)
-                       return grp;
-       }
+       return BLI_findstring(&act->groups, name, offsetof(bActionGroup, name));
+}
+
+/* Clear all 'temp' flags on all groups */
+void action_groups_clear_tempflags (bAction *act)
+{
+       bActionGroup *agrp;
        
-       /* not found */
-       return NULL;
+       /* sanity checks */
+       if (ELEM(NULL, act, act->groups.first))
+               return;
+               
+       /* flag clearing loop */
+       for (agrp = act->groups.first; agrp; agrp = agrp->next)
+               agrp->flag &= ~AGRP_TEMP;
 }
 
-/* ************************ Pose channels *************** */
+/* *************** Pose channels *************** */
 
 /* usually used within a loop, so we got a N^2 slowdown */
 bPoseChannel *get_pose_channel(const bPose *pose, const char *name)
 {
-       bPoseChannel *chan;
-
-       if (pose==NULL) return NULL;
+       if (ELEM(NULL, pose, name) || (name[0] == 0))
+               return NULL;
        
-       for (chan=pose->chanbase.first; chan; chan=chan->next) {
-               if (chan->name[0] == name[0]) {
-                       if (!strcmp (chan->name, name))
-                               return chan;
-               }
-       }
-
-       return NULL;
+       if(pose->chanhash)
+               return BLI_ghash_lookup(pose->chanhash, (void *)name);
+       
+       return BLI_findstring(&((bPose *)pose)->chanbase, name, offsetof(bPoseChannel, name));
 }
 
 /* Use with care, not on Armature poses but for temporal ones */
 /* (currently used for action constraints and in rebuild_pose) */
-bPoseChannel *verify_pose_channel(bPose* pose, const char* name)
+bPoseChannel *verify_pose_channel(bPose *pose, const char *name)
 {
        bPoseChannel *chan;
        
@@ -433,26 +430,30 @@ bPoseChannel *verify_pose_channel(bPose* pose, const char* name)
                return NULL;
        
        /* See if this channel exists */
-       for (chan=pose->chanbase.first; chan; chan=chan->next) {
-               if (!strcmp (name, chan->name))
-                       return chan;
+       chan= BLI_findstring(&pose->chanbase, name, offsetof(bPoseChannel, name));
+       if(chan) {
+               return chan;
        }
-       
+
        /* If not, create it and add it */
        chan = MEM_callocN(sizeof(bPoseChannel), "verifyPoseChannel");
        
-       strncpy(chan->name, name, 31);
+       BLI_strncpy(chan->name, name, sizeof(chan->name));
        /* init vars to prevent math errors */
-       chan->quat[0] = 1.0f;
+       unit_qt(chan->quat);
+       unit_axis_angle(chan->rotAxis, &chan->rotAngle);
        chan->size[0] = chan->size[1] = chan->size[2] = 1.0f;
        
        chan->limitmin[0]= chan->limitmin[1]= chan->limitmin[2]= -180.0f;
        chan->limitmax[0]= chan->limitmax[1]= chan->limitmax[2]= 180.0f;
        chan->stiffness[0]= chan->stiffness[1]= chan->stiffness[2]= 0.0f;
+       chan->ikrotweight = chan->iklinweight = 0.0f;
+       unit_m4(chan->constinv);
        
-       Mat4One(chan->constinv);
+       chan->protectflag = OB_LOCK_ROT4D;      /* lock by components by default */
        
        BLI_addtail(&pose->chanbase, chan);
+       free_pose_channels_hash(pose);
        
        return chan;
 }
@@ -468,22 +469,33 @@ bPoseChannel *get_active_posechannel (Object *ob)
        
        /* find active */
        for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
-               if ((pchan->bone) && (pchan->bone->flag & BONE_ACTIVE) && (pchan->bone->layer & arm->layer))
+               if ((pchan->bone) && (pchan->bone == arm->act_bone) && (pchan->bone->layer & arm->layer))
                        return pchan;
        }
        
        return NULL;
 }
 
-
+const char *get_ikparam_name(bPose *pose)
+{
+       if (pose) {
+               switch (pose->iksolver) {
+               case IKSOLVER_LEGACY:
+                       return NULL;
+               case IKSOLVER_ITASC:
+                       return "bItasc";
+               }
+       }
+       return NULL;
+}
 /* dst should be freed already, makes entire duplicate */
 void copy_pose (bPose **dst, bPose *src, int copycon)
 {
        bPose *outPose;
-       bPoseChannel    *pchan;
+       bPoseChannel *pchan;
        ListBase listb;
        
-       if (!src){
+       if (!src) {
                *dst=NULL;
                return;
        }
@@ -498,96 +510,131 @@ void copy_pose (bPose **dst, bPose *src, int copycon)
        
        BLI_duplicatelist(&outPose->chanbase, &src->chanbase);
        
-       if (copycon) {
-               for (pchan=outPose->chanbase.first; pchan; pchan=pchan->next) {
-                       copy_constraints(&listb, &pchan->constraints);  // copy_constraints NULLs listb
+       outPose->iksolver = src->iksolver;
+       outPose->ikdata = NULL;
+       outPose->ikparam = MEM_dupallocN(src->ikparam);
+       
+       for (pchan=outPose->chanbase.first; pchan; pchan=pchan->next) {
+               // TODO: rename this argument...
+               if (copycon) {
+                       copy_constraints(&listb, &pchan->constraints, TRUE);  // copy_constraints NULLs listb
                        pchan->constraints= listb;
-                       pchan->path= NULL;
+                       pchan->mpath= NULL; /* motion paths should not get copied yet... */
+               }
+               
+               if(pchan->prop) {
+                       pchan->prop= IDP_CopyProperty(pchan->prop);
                }
        }
+
+       /* for now, duplicate Bone Groups too when doing this */
+       if (copycon)
+               BLI_duplicatelist(&outPose->agroups, &src->agroups);
        
        *dst=outPose;
 }
 
-void free_pose_channels(bPose *pose) 
+void init_pose_itasc(bItasc *itasc)
 {
-       bPoseChannel *pchan;
-       
-       if (pose->chanbase.first) {
-               for (pchan = pose->chanbase.first; pchan; pchan=pchan->next){
-                       if (pchan->path)
-                               MEM_freeN(pchan->path);
-                       free_constraints(&pchan->constraints);
-               }
-               BLI_freelistN(&pose->chanbase);
+       if (itasc) {
+               itasc->iksolver = IKSOLVER_ITASC;
+               itasc->minstep = 0.01f;
+               itasc->maxstep = 0.06f;
+               itasc->numiter = 100;
+               itasc->numstep = 4;
+               itasc->precision = 0.005f;
+               itasc->flag = ITASC_AUTO_STEP|ITASC_INITIAL_REITERATION;
+               itasc->feedback = 20.f;
+               itasc->maxvel = 50.f;
+               itasc->solver = ITASC_SOLVER_SDLS;
+               itasc->dampmax = 0.5;
+               itasc->dampeps = 0.15;
        }
 }
-
-void free_pose(bPose *pose)
+void init_pose_ikparam(bPose *pose)
 {
-       if (pose) {
-               /* free pose-channels */
-               free_pose_channels(pose);
-               
-               /* free pose-groups */
-               if (pose->agroups.first)
-                       BLI_freelistN(&pose->agroups);
-               
-               /* free pose */
-               MEM_freeN(pose);
+       bItasc *itasc;
+       switch (pose->iksolver) {
+       case IKSOLVER_ITASC:
+               itasc = MEM_callocN(sizeof(bItasc), "itasc");
+               init_pose_itasc(itasc);
+               pose->ikparam = itasc;
+               break;
+       case IKSOLVER_LEGACY:
+       default:
+               pose->ikparam = NULL;
+               break;
        }
 }
 
-void game_copy_pose(bPose **dst, bPose *src)
+void make_pose_channels_hash(bPose *pose) 
 {
-       bPose *out;
-       bPoseChannel *pchan, *outpchan;
-       GHash *ghash;
-       
-       /* the game engine copies the current armature pose and then swaps
-        * the object pose pointer. this makes it possible to change poses
-        * without affecting the original blender data. */
+       if(!pose->chanhash) {
+               bPoseChannel *pchan;
 
-       if (!src) {
-               *dst=NULL;
-               return;
+               pose->chanhash= BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "make_pose_chan gh");
+               for(pchan=pose->chanbase.first; pchan; pchan=pchan->next)
+                       BLI_ghash_insert(pose->chanhash, pchan->name, pchan);
        }
-       else if (*dst==src) {
-               printf("copy_pose source and target are the same\n");
-               *dst=NULL;
-               return;
+}
+
+void free_pose_channels_hash(bPose *pose) 
+{
+       if(pose->chanhash) {
+               BLI_ghash_free(pose->chanhash, NULL, NULL);
+               pose->chanhash= NULL;
        }
-       
-       out= MEM_dupallocN(src);
-       out->agroups.first= out->agroups.last= NULL;
-       BLI_duplicatelist(&out->chanbase, &src->chanbase);
+}
 
-       /* remap pointers */
-       ghash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
 
-       pchan= src->chanbase.first;
-       outpchan= out->chanbase.first;
-       for (; pchan; pchan=pchan->next, outpchan=outpchan->next)
-               BLI_ghash_insert(ghash, pchan, outpchan);
+void free_pose_channel(bPoseChannel *pchan)
+{
 
-       for (pchan=out->chanbase.first; pchan; pchan=pchan->next) {
-               pchan->parent= BLI_ghash_lookup(ghash, pchan->parent);
-               pchan->child= BLI_ghash_lookup(ghash, pchan->child);
-               pchan->path= NULL;
+       if (pchan->mpath) {
+               animviz_free_motionpath(pchan->mpath);
+               pchan->mpath= NULL;
        }
 
-       BLI_ghash_free(ghash, NULL, NULL);
+       free_constraints(&pchan->constraints);
        
-       *dst=out;
+       if (pchan->prop) {
+               IDP_FreeProperty(pchan->prop);
+               MEM_freeN(pchan->prop);
+       }
 }
 
-void game_free_pose(bPose *pose)
+void free_pose_channels(bPose *pose) 
+{
+       bPoseChannel *pchan;
+       
+       if (pose->chanbase.first) {
+               for (pchan = pose->chanbase.first; pchan; pchan=pchan->next)
+                       free_pose_channel(pchan);
+               
+               BLI_freelistN(&pose->chanbase);
+       }
+
+       free_pose_channels_hash(pose);
+}
+
+void free_pose(bPose *pose)
 {
        if (pose) {
-               /* we don't free constraints, those are owned by the original pose */
-               if(pose->chanbase.first)
-                       BLI_freelistN(&pose->chanbase);
+               /* free pose-channels */
+               free_pose_channels(pose);
                
+               /* free pose-groups */
+               if (pose->agroups.first)
+                       BLI_freelistN(&pose->agroups);
+               
+               /* free IK solver state */
+               BIK_clear_data(pose);
+               
+               /* free IK solver param */
+               if (pose->ikparam)
+                       MEM_freeN(pose->ikparam);
+               
+               /* free pose */
                MEM_freeN(pose);
        }
 }
@@ -599,20 +646,64 @@ static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan
        VECCOPY(pchan->loc, chan->loc);
        VECCOPY(pchan->size, chan->size);
        VECCOPY(pchan->eul, chan->eul);
+       VECCOPY(pchan->rotAxis, chan->rotAxis);
+       pchan->rotAngle= chan->rotAngle;
        QUATCOPY(pchan->quat, chan->quat);
        pchan->rotmode= chan->rotmode;
-       Mat4CpyMat4(pchan->chan_mat, (float(*)[4])chan->chan_mat);
-       Mat4CpyMat4(pchan->pose_mat, (float(*)[4])chan->pose_mat);
+       copy_m4_m4(pchan->chan_mat, (float(*)[4])chan->chan_mat);
+       copy_m4_m4(pchan->pose_mat, (float(*)[4])chan->pose_mat);
        pchan->flag= chan->flag;
        
        con= chan->constraints.first;
-       for(pcon= pchan->constraints.first; pcon; pcon= pcon->next, con= con->next) {
+       for(pcon= pchan->constraints.first; pcon && con; pcon= pcon->next, con= con->next) {
                pcon->enforce= con->enforce;
                pcon->headtail= con->headtail;
        }
 }
 
-/* checks for IK constraint, and also for Follow-Path constraint.
+/* makes copies of internal data, unlike copy_pose_channel_data which only
+ * copies the pose state.
+ * hint: use when copying bones in editmode (on returned value from verify_pose_channel) */
+void duplicate_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *pchan_from)
+{
+       /* copy transform locks */
+       pchan->protectflag = pchan_from->protectflag;
+
+       /* copy rotation mode */
+       pchan->rotmode = pchan_from->rotmode;
+
+       /* copy bone group */
+       pchan->agrp_index= pchan_from->agrp_index;
+
+       /* ik (dof) settings */
+       pchan->ikflag = pchan_from->ikflag;
+       VECCOPY(pchan->limitmin, pchan_from->limitmin);
+       VECCOPY(pchan->limitmax, pchan_from->limitmax);
+       VECCOPY(pchan->stiffness, pchan_from->stiffness);
+       pchan->ikstretch= pchan_from->ikstretch;
+       pchan->ikrotweight= pchan_from->ikrotweight;
+       pchan->iklinweight= pchan_from->iklinweight;
+
+       /* constraints */
+       copy_constraints(&pchan->constraints, &pchan_from->constraints, TRUE);
+
+       /* id-properties */
+       if(pchan->prop) {
+               /* unlikely but possible it exists */
+               IDP_FreeProperty(pchan->prop);
+               MEM_freeN(pchan->prop);
+               pchan->prop= NULL;
+       }
+       if(pchan_from->prop) {
+               pchan->prop= IDP_CopyProperty(pchan_from->prop);
+       }
+
+       /* custom shape */
+       pchan->custom= pchan_from->custom;
+}
+
+
+/* checks for IK constraint, Spline IK, and also for Follow-Path constraint.
  * can do more constraints flags later 
  */
 /* pose should be entirely OK */
@@ -665,6 +756,8 @@ void update_pose_constraint_flags(bPose *pose)
                                if ((data->tar) && (data->tar->type==OB_CURVE))
                                        pose->flag |= POSE_CONSTRAINTS_TIMEDEPEND;
                        }
+                       else if (con->type == CONSTRAINT_TYPE_SPLINEIK)
+                               pchan->constflag |= PCHAN_HAS_SPLINEIK;
                        else 
                                pchan->constflag |= PCHAN_HAS_CONST;
                }
@@ -694,88 +787,96 @@ void framechange_poses_clear_unkeyed(void)
        }
 }
 
-/* ************************ END Pose channels *************** */
-
-/* ************** time ****************** */
+/* ************************** Bone Groups ************************** */
 
-static bActionStrip *get_active_strip(Object *ob)
+/* Adds a new bone-group */
+void pose_add_group (Object *ob)
 {
-#if 0  // XXX old animation system
-       bActionStrip *strip;
+       bPose *pose= (ob) ? ob->pose : NULL;
+       bActionGroup *grp;
        
-       if(ob->action==NULL)
-               return NULL;
-               
-       for (strip=ob->nlastrips.first; strip; strip=strip->next)
-               if(strip->flag & ACTSTRIP_ACTIVE)
-                       break;
+       if (ELEM(NULL, ob, ob->pose))
+               return;
        
-       if(strip && strip->act==ob->action)
-               return strip;
-#endif // XXX old animation system
-               
-       return NULL;
+       grp= MEM_callocN(sizeof(bActionGroup), "PoseGroup");
+       BLI_strncpy(grp->name, "Group", sizeof(grp->name));
+       BLI_addtail(&pose->agroups, grp);
+       BLI_uniquename(&pose->agroups, grp, "Group", '.', offsetof(bActionGroup, name), sizeof(grp->name));
+       
+       pose->active_group= BLI_countlist(&pose->agroups);
 }
 
-/* non clipped mapping of strip */
-static float get_actionstrip_frame(bActionStrip *strip, float cframe, int invert)
+/* Remove the active bone-group */
+void pose_remove_group (Object *ob)
 {
-       float length, actlength, repeat, scale;
-       
-       if (strip->repeat == 0.0f) strip->repeat = 1.0f;
-       repeat = (strip->flag & ACTSTRIP_USESTRIDE) ? (1.0f) : (strip->repeat);
-       
-       if (strip->scale == 0.0f) strip->scale= 1.0f;
-       scale = (float)fabs(strip->scale); /* scale must be positive (for now) */
+       bPose *pose= (ob) ? ob->pose : NULL;
+       bActionGroup *grp = NULL;
+       bPoseChannel *pchan;
        
-       actlength = strip->actend-strip->actstart;
-       if (actlength == 0.0f) actlength = 1.0f;
-       length = repeat * scale * actlength;
+       /* sanity checks */
+       if (ELEM(NULL, ob, pose))
+               return;
+       if (pose->active_group <= 0)
+               return;
        
-       /* invert = convert action-strip time to global time */
-       if (invert)
-               return length*(cframe - strip->actstart)/(repeat*actlength) + strip->start;
-       else
-               return repeat*actlength*(cframe - strip->start)/length + strip->actstart;
+       /* get group to remove */
+       grp= BLI_findlink(&pose->agroups, pose->active_group-1);
+       if (grp) {
+               /* adjust group references (the trouble of using indices!):
+                *      - firstly, make sure nothing references it 
+                *      - also, make sure that those after this item get corrected
+                */
+               for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
+                       if (pchan->agrp_index == pose->active_group)
+                               pchan->agrp_index= 0;
+                       else if (pchan->agrp_index > pose->active_group)
+                               pchan->agrp_index--;
+               }
+               
+               /* now, remove it from the pose */
+               BLI_freelinkN(&pose->agroups, grp);
+               pose->active_group--;
+               if(pose->active_group < 0 || pose->agroups.first == NULL) {
+                       pose->active_group= 0;
+               }
+       }
 }
 
-/* if the conditions match, it converts current time to strip time */
-float get_action_frame(Object *ob, float cframe)
-{
-       bActionStrip *strip= get_active_strip(ob);
-       
-       if(strip)
-               return get_actionstrip_frame(strip, cframe, 0);
-       return cframe;
-}
+/* ************** F-Curve Utilities for Actions ****************** */
 
-/* inverted, strip time to current time */
-float get_action_frame_inv(Object *ob, float cframe)
+/* Check if the given action has any keyframes */
+short action_has_motion(const bAction *act)
 {
-       bActionStrip *strip= get_active_strip(ob);
+       FCurve *fcu;
        
-       if(strip)
-               return get_actionstrip_frame(strip, cframe, 1);
-       return cframe;
+       /* return on the first F-Curve that has some keyframes/samples defined */
+       if (act) {
+               for (fcu= act->curves.first; fcu; fcu= fcu->next) {
+                       if (fcu->totvert)
+                               return 1;
+               }
+       }
+       
+       /* nothing found */
+       return 0;
 }
 
-
-
-
 /* Calculate the extents of given action */
-void calc_action_range(const bAction *act, float *start, float *end, int incl_hidden)
+void calc_action_range(const bAction *act, float *start, float *end, short incl_modifiers)
 {
        FCurve *fcu;
        float min=999999999.0f, max=-999999999.0f;
-       short foundvert=0;
+       short foundvert=0, foundmod=0;
 
        if (act) {
                for (fcu= act->curves.first; fcu; fcu= fcu->next) {
+                       /* if curve has keyframes, consider them first */
                        if (fcu->totvert) {
                                float nmin, nmax;
                                
                                /* get extents for this curve */
-                               calc_fcurve_range(fcu, &nmin, &nmax);
+                               // TODO: allow enabling/disabling this?
+                               calc_fcurve_range(fcu, &nmin, &nmax, FALSE, TRUE);
                                
                                /* compare to the running tally */
                                min= MIN2(min, nmin);
@@ -783,10 +884,53 @@ void calc_action_range(const bAction *act, float *start, float *end, int incl_hi
                                
                                foundvert= 1;
                        }
+                       
+                       /* if incl_modifiers is enabled, need to consider modifiers too
+                        *      - only really care about the last modifier
+                        */
+                       if ((incl_modifiers) && (fcu->modifiers.last)) {
+                               FModifier *fcm= fcu->modifiers.last;
+                               
+                               /* only use the maximum sensible limits of the modifiers if they are more extreme */
+                               switch (fcm->type) {
+                                       case FMODIFIER_TYPE_LIMITS: /* Limits F-Modifier */
+                                       {
+                                               FMod_Limits *fmd= (FMod_Limits *)fcm->data;
+                                               
+                                               if (fmd->flag & FCM_LIMIT_XMIN) {
+                                                       min= MIN2(min, fmd->rect.xmin);
+                                               }
+                                               if (fmd->flag & FCM_LIMIT_XMAX) {
+                                                       max= MAX2(max, fmd->rect.xmax);
+                                               }
+                                       }
+                                               break;
+                                               
+                                       case FMODIFIER_TYPE_CYCLES: /* Cycles F-Modifier */
+                                       {
+                                               FMod_Cycles *fmd= (FMod_Cycles *)fcm->data;
+                                               
+                                               if (fmd->before_mode != FCM_EXTRAPOLATE_NONE)
+                                                       min= MINAFRAMEF;
+                                               if (fmd->after_mode != FCM_EXTRAPOLATE_NONE)
+                                                       max= MAXFRAMEF;
+                                       }
+                                               break;
+                                               
+                                       // TODO: function modifier may need some special limits
+                                               
+                                       default: /* all other standard modifiers are on the infinite range... */
+                                               min= MINAFRAMEF;
+                                               max= MAXFRAMEF;
+                                               break;
+                               }
+                               
+                               foundmod= 1;
+                       }
                }
        }       
        
-       if (foundvert) {
+       if (foundvert || foundmod) {
                if(min==max) max+= 1.0f;
                *start= min;
                *end= max;
@@ -797,6 +941,115 @@ void calc_action_range(const bAction *act, float *start, float *end, int incl_hi
        }
 }
 
+/* Return flags indicating which transforms the given object/posechannel has 
+ *     - if 'curves' is provided, a list of links to these curves are also returned
+ */
+short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan, ListBase *curves)
+{
+       PointerRNA ptr;
+       FCurve *fcu;
+       char *basePath=NULL;
+       short flags=0;
+       
+       /* build PointerRNA from provided data to obtain the paths to use */
+       if (pchan)
+               RNA_pointer_create((ID *)ob, &RNA_PoseBone, pchan, &ptr);
+       else if (ob)
+               RNA_id_pointer_create((ID *)ob, &ptr);
+       else    
+               return 0;
+               
+       /* get the basic path to the properties of interest */
+       basePath= RNA_path_from_ID_to_struct(&ptr);
+       if (basePath == NULL)
+               return 0;
+               
+       /* search F-Curves for the given properties 
+        *      - we cannot use the groups, since they may not be grouped in that way...
+        */
+       for (fcu= act->curves.first; fcu; fcu= fcu->next) {
+               char *bPtr=NULL, *pPtr=NULL;
+               
+               /* if enough flags have been found, we can stop checking unless we're also getting the curves */
+               if ((flags == ACT_TRANS_ALL) && (curves == NULL))
+                       break;
+                       
+               /* just in case... */
+               if (fcu->rna_path == NULL)
+                       continue;
+               
+               /* step 1: check for matching base path */
+               bPtr= strstr(fcu->rna_path, basePath);
+               
+               if (bPtr) {
+                       /* we must add len(basePath) bytes to the match so that we are at the end of the 
+                        * base path so that we don't get false positives with these strings in the names
+                        */
+                       bPtr += strlen(basePath);
+                       
+                       /* step 2: check for some property with transforms 
+                        *      - to speed things up, only check for the ones not yet found 
+                        *        unless we're getting the curves too
+                        *      - if we're getting the curves, the BLI_genericNodeN() creates a LinkData
+                        *        node wrapping the F-Curve, which then gets added to the list
+                        *      - once a match has been found, the curve cannot possibly be any other one
+                        */
+                       if ((curves) || (flags & ACT_TRANS_LOC) == 0) {
+                               pPtr= strstr(bPtr, "location");
+                               if (pPtr) {
+                                       flags |= ACT_TRANS_LOC;
+                                       
+                                       if (curves) 
+                                               BLI_addtail(curves, BLI_genericNodeN(fcu));
+                                       continue;
+                               }
+                       }
+                       
+                       if ((curves) || (flags & ACT_TRANS_SCALE) == 0) {
+                               pPtr= strstr(bPtr, "scale");
+                               if (pPtr) {
+                                       flags |= ACT_TRANS_SCALE;
+                                       
+                                       if (curves) 
+                                               BLI_addtail(curves, BLI_genericNodeN(fcu));
+                                       continue;
+                               }
+                       }
+                       
+                       if ((curves) || (flags & ACT_TRANS_ROT) == 0) {
+                               pPtr= strstr(bPtr, "rotation");
+                               if (pPtr) {
+                                       flags |= ACT_TRANS_ROT;
+                                       
+                                       if (curves) 
+                                               BLI_addtail(curves, BLI_genericNodeN(fcu));
+                                       continue;
+                               }
+                       }
+                       
+                       if ((curves) || (flags & ACT_TRANS_PROP) == 0) {
+                               /* custom properties only */
+                               pPtr= strstr(bPtr, "[\""); /* extra '"' comment here to keep my texteditor functionlist working :) */  
+                               if (pPtr) {
+                                       flags |= ACT_TRANS_PROP;
+                                       
+                                       if (curves)
+                                               BLI_addtail(curves, BLI_genericNodeN(fcu));
+                                       continue;
+                               }
+                       }
+               }
+       }
+       
+       /* free basePath */
+       MEM_freeN(basePath);
+       
+       /* return flags found */
+       return flags;
+}
+
+/* ************** Pose Management Tools ****************** */
+
 /* Copy the data from the action-pose (src) into the pose */
 /* both args are assumed to be valid */
 /* exported to game engine */
@@ -820,7 +1073,6 @@ void extract_pose_from_pose(bPose *pose, const bPose *src)
 void rest_pose(bPose *pose)
 {
        bPoseChannel *pchan;
-       int i;
        
        if (!pose)
                return;
@@ -828,15 +1080,13 @@ void rest_pose(bPose *pose)
        memset(pose->stride_offset, 0, sizeof(pose->stride_offset));
        memset(pose->cyclic_offset, 0, sizeof(pose->cyclic_offset));
        
-       for (pchan=pose->chanbase.first; pchan; pchan= pchan->next){
-               for (i=0; i<3; i++) {
-                       pchan->loc[i]= 0.0f;
-                       pchan->quat[i+1]= 0.0f;
-                       pchan->eul[i]= 0.0f;
-                       pchan->size[i]= 1.0f;
-               }
-               pchan->quat[0]= 1.0f;
-               
+       for (pchan=pose->chanbase.first; pchan; pchan= pchan->next) {
+               zero_v3(pchan->loc);
+               zero_v3(pchan->eul);
+               unit_qt(pchan->quat);
+               unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
+               pchan->size[0]= pchan->size[1]= pchan->size[2]= 1.0f;
+
                pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE);
        }
 }
@@ -847,7 +1097,7 @@ void copy_pose_result(bPose *to, bPose *from)
        bPoseChannel *pchanto, *pchanfrom;
        
        if(to==NULL || from==NULL) {
-               printf("pose result copy error\n"); // debug temp
+               printf("pose result copy error to:%p from:%p\n", (void *)to, (void *)from); // debug temp
                return;
        }
 
@@ -860,8 +1110,8 @@ void copy_pose_result(bPose *to, bPose *from)
        for(pchanfrom= from->chanbase.first; pchanfrom; pchanfrom= pchanfrom->next) {
                pchanto= get_pose_channel(to, pchanfrom->name);
                if(pchanto) {
-                       Mat4CpyMat4(pchanto->pose_mat, pchanfrom->pose_mat);
-                       Mat4CpyMat4(pchanto->chan_mat, pchanfrom->chan_mat);
+                       copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat);
+                       copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat);
                        
                        /* used for local constraints */
                        VECCOPY(pchanto->loc, pchanfrom->loc);
@@ -871,7 +1121,10 @@ void copy_pose_result(bPose *to, bPose *from)
                        
                        VECCOPY(pchanto->pose_head, pchanfrom->pose_head);
                        VECCOPY(pchanto->pose_tail, pchanfrom->pose_tail);
+                       
+                       pchanto->rotmode= pchanfrom->rotmode;
                        pchanto->flag= pchanfrom->flag;
+                       pchanto->protectflag= pchanfrom->protectflag;
                }
        }
 }
@@ -879,7 +1132,7 @@ void copy_pose_result(bPose *to, bPose *from)
 /* For the calculation of the effects of an Action at the given frame on an object 
  * This is currently only used for the Action Constraint 
  */
-void what_does_obaction (Scene *scene, Object *ob, Object *workob, bPose *pose, bAction *act, char groupname[], float cframe)
+void what_does_obaction (Object *ob, Object *workob, bPose *pose, bAction *act, char groupname[], float cframe)
 {
        bActionGroup *agrp= action_groups_find_named(act, groupname);
        
@@ -887,12 +1140,13 @@ void what_does_obaction (Scene *scene, Object *ob, Object *workob, bPose *pose,
        clear_workob(workob);
        
        /* init workob */
-       Mat4CpyMat4(workob->obmat, ob->obmat);
-       Mat4CpyMat4(workob->parentinv, ob->parentinv);
-       Mat4CpyMat4(workob->constinv, ob->constinv);
+       copy_m4_m4(workob->obmat, ob->obmat);
+       copy_m4_m4(workob->parentinv, ob->parentinv);
+       copy_m4_m4(workob->constinv, ob->constinv);
        workob->parent= ob->parent;
-       workob->track= ob->track;
-
+       
+       workob->rotmode= ob->rotmode;
+       
        workob->trackflag= ob->trackflag;
        workob->upflag= ob->upflag;
        
@@ -906,8 +1160,8 @@ void what_does_obaction (Scene *scene, Object *ob, Object *workob, bPose *pose,
        
        workob->pose= pose;     /* need to set pose too, since this is used for both types of Action Constraint */
 
-       strcpy(workob->parsubstr, ob->parsubstr);
-       strcpy(workob->id.name, "OB<ConstrWorkOb>"); /* we don't use real object name, otherwise RNA screws with the real thing */
+       BLI_strncpy(workob->parsubstr, ob->parsubstr, sizeof(workob->parsubstr));
+       BLI_strncpy(workob->id.name, "OB<ConstrWorkOb>", sizeof(workob->id.name)); /* we don't use real object name, otherwise RNA screws with the real thing */
        
        /* if we're given a group to use, it's likely to be more efficient (though a bit more dangerous) */
        if (agrp) {
@@ -921,17 +1175,16 @@ void what_does_obaction (Scene *scene, Object *ob, Object *workob, bPose *pose,
                animsys_evaluate_action_group(&id_ptr, act, agrp, NULL, cframe);
        }
        else {
-               AnimData adt;
+               AnimData adt= {NULL};
                
                /* init animdata, and attach to workob */
-               memset(&adt, 0, sizeof(AnimData));
                workob->adt= &adt;
                
                adt.recalc= ADT_RECALC_ANIM;
                adt.action= act;
                
                /* execute effects of Action on to workob (or it's PoseChannels) */
-               BKE_animsys_evaluate_animdata(&workob->id, &adt, cframe, ADT_RECALC_ANIM);
+               BKE_animsys_evaluate_animdata(NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM);
        }
 }
 
@@ -956,7 +1209,7 @@ static void blend_pose_strides(bPose *dst, bPose *src, float srcweight, short mo
                        dstweight = 1.0F;
        }
        
-       VecLerpf(dst->stride_offset, dst->stride_offset, src->stride_offset, srcweight);
+       interp_v3_v3v3(dst->stride_offset, dst->stride_offset, src->stride_offset, srcweight);
 }
 
 
@@ -964,17 +1217,17 @@ static void blend_pose_strides(bPose *dst, bPose *src, float srcweight, short mo
 
 bone matching diagram, strips A and B
 
-                 .------------------------.
-                 |         A              |
-                 '------------------------'
+                                .------------------------.
+                                |         A              |
+                                '------------------------'
                                 .          .             b2
-                 .          .-------------v----------.
-                 .             |         B   .          |
-                 .          '------------------------'
-                 .          .             .
-                 .          .             .
+                                .          .-------------v----------.
+                                .              |         B   .          |
+                                .          '------------------------'
+                                .          .             .
+                                .          .             .
 offset:          .    0     .    A-B      .  A-b2+B     
-                 .          .             .
+                                .          .             .
 
 */
 
@@ -1016,228 +1269,27 @@ static void blend_pose_offset_bone(bActionStrip *strip, bPose *dst, bPose *src,
                                                execute_action_ipo(achan, &pchan);
                                                
                                                /* store offset that moves src to location of pchan */
-                                               VecSubf(vec, dpchan->loc, pchan.loc);
+                                               sub_v3_v3v3(vec, dpchan->loc, pchan.loc);
                                                
-                                               Mat4Mul3Vecfl(dpchan->bone->arm_mat, vec);
+                                               mul_mat3_m4_v3(dpchan->bone->arm_mat, vec);
                                        }
                                }
                                else {
                                        /* store offset that moves src to location of dst */
                                        
-                                       VecSubf(vec, dpchan->loc, spchan->loc);
-                                       Mat4Mul3Vecfl(dpchan->bone->arm_mat, vec);
+                                       sub_v3_v3v3(vec, dpchan->loc, spchan->loc);
+                                       mul_mat3_m4_v3(dpchan->bone->arm_mat, vec);
                                }
                                
                                /* if blending, we only add with factor scrweight */
-                               VecMulf(vec, srcweight);
-                               
-                               VecAddf(dst->cyclic_offset, dst->cyclic_offset, vec);
-                       }
-               }
-       }
-       
-       VecAddf(dst->cyclic_offset, dst->cyclic_offset, src->cyclic_offset);
-}
-
-
-/* Only allowed for Poses with identical channels */
-void blend_poses(bPose *dst, bPose *src, float srcweight, short mode)
-{
-       bPoseChannel *dchan;
-       const bPoseChannel *schan;
-       bConstraint *dcon, *scon;
-       float dstweight;
-       int i;
-       
-       switch (mode){
-       case ACTSTRIPMODE_BLEND:
-               dstweight = 1.0F - srcweight;
-               break;
-       case ACTSTRIPMODE_ADD:
-               dstweight = 1.0F;
-               break;
-       default :
-               dstweight = 1.0F;
-       }
-       
-       schan= src->chanbase.first;
-       for (dchan = dst->chanbase.first; dchan; dchan=dchan->next, schan= schan->next){
-               if (schan->flag & (POSE_ROT|POSE_LOC|POSE_SIZE)) {
-                       /* replaced quat->matrix->quat conversion with decent quaternion interpol (ton) */
-                       
-                       /* Do the transformation blend */
-                       if (schan->flag & POSE_ROT) {
-                               /* quat interpolation done separate */
-                               if (schan->rotmode == PCHAN_ROT_QUAT) {
-                                       float dquat[4], squat[4];
-                                       
-                                       QUATCOPY(dquat, dchan->quat);
-                                       QUATCOPY(squat, schan->quat);
-                                       if (mode==ACTSTRIPMODE_BLEND)
-                                               QuatInterpol(dchan->quat, dquat, squat, srcweight);
-                                       else {
-                                               QuatMulFac(squat, srcweight);
-                                               QuatMul(dchan->quat, dquat, squat);
-                                       }
-                                       
-                                       NormalQuat(dchan->quat);
-                               }
-                       }
-
-                       for (i=0; i<3; i++) {
-                               /* blending for loc and scale are pretty self-explanatory... */
-                               if (schan->flag & POSE_LOC)
-                                       dchan->loc[i] = (dchan->loc[i]*dstweight) + (schan->loc[i]*srcweight);
-                               if (schan->flag & POSE_SIZE)
-                                       dchan->size[i] = 1.0f + ((dchan->size[i]-1.0f)*dstweight) + ((schan->size[i]-1.0f)*srcweight);
+                               mul_v3_fl(vec, srcweight);
                                
-                               /* euler-rotation interpolation done here instead... */
-                               // FIXME: are these results decent?
-                               if ((schan->flag & POSE_ROT) && (schan->rotmode))
-                                       dchan->eul[i] = (dchan->eul[i]*dstweight) + (schan->eul[i]*srcweight);
-                       }
-                       dchan->flag |= schan->flag;
-               }
-               for(dcon= dchan->constraints.first, scon= schan->constraints.first; dcon && scon; dcon= dcon->next, scon= scon->next) {
-                       /* no 'add' option for constraint blending */
-                       dcon->enforce= dcon->enforce*(1.0f-srcweight) + scon->enforce*srcweight;
-               }
-       }
-       
-       /* this pose is now in src time */
-       dst->ctime= src->ctime;
-}
-
-typedef struct NlaIpoChannel {
-       struct NlaIpoChannel *next, *prev;
-       float val;
-       void *poin;
-       int type;
-} NlaIpoChannel;
-
-void extract_ipochannels_from_action(ListBase *lb, ID *id, bAction *act, const char *name, float ctime)
-{
-       bActionChannel *achan= get_action_channel(act, name);
-       IpoCurve *icu;
-       NlaIpoChannel *nic;
-       
-       if(achan==NULL) return;
-       
-       if(achan->ipo) {
-               calc_ipo(achan->ipo, ctime);
-               
-               for(icu= achan->ipo->curve.first; icu; icu= icu->next) {
-                       /* skip IPO_BITS, is for layers and cannot be blended */
-                       if(icu->vartype != IPO_BITS) {
-                               nic= MEM_callocN(sizeof(NlaIpoChannel), "NlaIpoChannel");
-                               BLI_addtail(lb, nic);
-                               nic->val= icu->curval;
-                               nic->poin= get_ipo_poin(id, icu, &nic->type);
+                               add_v3_v3(dst->cyclic_offset, vec);
                        }
                }
        }
        
-       /* constraint channels only for objects */
-       if(GS(id->name)==ID_OB) {
-               Object *ob= (Object *)id;
-               bConstraint *con;
-               bConstraintChannel *conchan;
-               
-               for (con=ob->constraints.first; con; con=con->next) {
-                       conchan = get_constraint_channel(&achan->constraintChannels, con->name);
-                       
-                       if(conchan && conchan->ipo) {
-                               calc_ipo(conchan->ipo, ctime);
-                               
-                               icu= conchan->ipo->curve.first; // only one ipo now
-                               if(icu) {
-                                       nic= MEM_callocN(sizeof(NlaIpoChannel), "NlaIpoChannel constr");
-                                       BLI_addtail(lb, nic);
-                                       nic->val= icu->curval;
-                                       nic->poin= &con->enforce;
-                                       nic->type= IPO_FLOAT;
-                               }
-                       }
-               }
-       }
-}
-
-static NlaIpoChannel *find_nla_ipochannel(ListBase *lb, void *poin)
-{
-       NlaIpoChannel *nic;
-       
-       if(poin) {
-               for(nic= lb->first; nic; nic= nic->next) {
-                       if(nic->poin==poin)
-                               return nic;
-               }
-       }
-       return NULL;
-}
-
-
-static void blend_ipochannels(ListBase *dst, ListBase *src, float srcweight, int mode)
-{
-       NlaIpoChannel *snic, *dnic, *next;
-       float dstweight;
-       
-       switch (mode){
-               case ACTSTRIPMODE_BLEND:
-                       dstweight = 1.0F - srcweight;
-                       break;
-               case ACTSTRIPMODE_ADD:
-                       dstweight = 1.0F;
-                       break;
-               default :
-                       dstweight = 1.0F;
-       }
-       
-       for(snic= src->first; snic; snic= next) {
-               next= snic->next;
-               
-               dnic= find_nla_ipochannel(dst, snic->poin);
-               if(dnic==NULL) {
-                       /* remove from src list, and insert in dest */
-                       BLI_remlink(src, snic);
-                       BLI_addtail(dst, snic);
-               }
-               else {
-                       /* we do the blend */
-                       dnic->val= dstweight*dnic->val + srcweight*snic->val;
-               }
-       }
-}
-
-int execute_ipochannels(ListBase *lb)
-{
-       NlaIpoChannel *nic;
-       int count = 0;
-       
-       for(nic= lb->first; nic; nic= nic->next) {
-               if(nic->poin) {
-                       write_ipo_poin(nic->poin, nic->type, nic->val);
-                       count++;
-               }
-       }
-       return count;
-}
-
-/* nla timing */
-
-/* this now only used for repeating cycles, to enable fields and blur. */
-/* the whole time control in blender needs serious thinking... */
-static float nla_time(Scene *scene, float cfra, float unit)
-{
-       extern float bluroffs;  // bad construct, borrowed from object.c for now
-       extern float fieldoffs;
-       
-       /* motion blur & fields */
-       cfra+= unit*(bluroffs+fieldoffs);
-       
-       /* global time */
-       cfra*= scene->r.framelen;       
-       
-       return cfra;
+       add_v3_v3(dst->cyclic_offset, src->cyclic_offset);
 }
 
 /* added "sizecorr" here, to allow armatures to be scaled and still have striding.
@@ -1297,14 +1349,14 @@ static float stridechannel_frame(Object *ob, float sizecorr, bActionStrip *strip
                        if (pdistNewNormalized <= 1) {
                                // search for correction in positive path-direction
                                where_on_path(ob, pdistNewNormalized, vec2, dir);       /* vec needs size 4 */
-                               VecSubf(stride_offset, vec2, vec1);
+                               sub_v3_v3v3(stride_offset, vec2, vec1);
                        }
                        else {
                                // we reached the end of the path, search backwards instead
                                where_on_path(ob, (pathdist-pdist)/path->totdist, vec2, dir);   /* vec needs size 4 */
-                               VecSubf(stride_offset, vec1, vec2);
+                               sub_v3_v3v3(stride_offset, vec1, vec2);
                        }
-                       Mat4Mul3Vecfl(ob->obmat, stride_offset);
+                       mul_mat3_m4_v3(ob->obmat, stride_offset);
                        return striptime;
                }
        }
@@ -1343,10 +1395,10 @@ static void cyclic_offs_bone(Object *ob, bPose *pose, bActionStrip *strip, float
                        }
                        if(foundvert) {
                                /* bring it into armature space */
-                               VecSubf(min, max, min);
+                               sub_v3_v3v3(min, max, min);
                                bone= get_named_bone(ob->data, strip->offs_bone);       /* weak */
                                if(bone) {
-                                       Mat4Mul3Vecfl(bone->arm_mat, min);
+                                       mul_mat3_m4_v3(bone->arm_mat, min);
                                        
                                        /* dominant motion, cyclic_offset was cleared in rest_pose */
                                        if (strip->flag & (ACTSTRIP_CYCLIC_USEX | ACTSTRIP_CYCLIC_USEY | ACTSTRIP_CYCLIC_USEZ)) {
@@ -1399,7 +1451,7 @@ static void do_nla(Scene *scene, Object *ob, int blocktype)
        bActionStrip *strip, *striplast=NULL, *stripfirst=NULL;
        float striptime, frametime, length, actlength;
        float blendfac, stripframe;
-       float scene_cfra= frame_to_float(scene, scene->r.cfra); 
+       float scene_cfra= BKE_curframe(scene);
        int     doit, dostride;
        
        if(blocktype==ID_AR) {
@@ -1597,7 +1649,7 @@ static void do_nla(Scene *scene, Object *ob, int blocktype)
        }
        else if(blocktype==ID_AR) {
                /* apply stride offset to object */
-               VecAddf(ob->obmat[3], ob->obmat[3], ob->pose->stride_offset);
+               add_v3_v3(ob->obmat[3], ob->pose->stride_offset);
        }
        
        /* free */