edits ontop of Alex's patch from r41292.
[blender.git] / source / blender / blenkernel / intern / action.c
index 1e5cb364a950317c0feb27d01952d3a0b698d34a..d02a1d6dd2706665def0811d1c2416b2ea81a605 100644 (file)
@@ -1,6 +1,4 @@
-/**
- * $Id$
- *
+/*
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
@@ -15,7 +13,7 @@
  *
  * 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.
  * ***** 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 "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 "BKE_idprop.h"
 
 #include "BIK_api.h"
 
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_ghash.h"
-
 #include "RNA_access.h"
-#include "RNA_types.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) ************************************ */
 
@@ -93,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)
 {
@@ -172,6 +174,8 @@ void free_action (bAction *act)
                BLI_freelistN(&act->markers);
 }
 
+/* .................................. */
+
 bAction *copy_action (bAction *src)
 {
        bAction *dst = NULL;
@@ -209,9 +213,6 @@ 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;
 }
 
@@ -250,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 */
@@ -392,20 +384,26 @@ 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 *************** */
@@ -413,24 +411,18 @@ bActionGroup *action_groups_find_named (bAction *act, const char name[])
 /* 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 (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;
        
@@ -438,17 +430,18 @@ 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] = chan->rotAxis[1]= 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;
@@ -457,7 +450,10 @@ bPoseChannel *verify_pose_channel(bPose* pose, const char* name)
        chan->ikrotweight = chan->iklinweight = 0.0f;
        unit_m4(chan->constinv);
        
+       chan->protectflag = OB_LOCK_ROT4D;      /* lock by components by default */
+       
        BLI_addtail(&pose->chanbase, chan);
+       free_pose_channels_hash(pose);
        
        return chan;
 }
@@ -496,10 +492,10 @@ const char *get_ikparam_name(bPose *pose)
 void copy_pose (bPose **dst, bPose *src, int copycon)
 {
        bPose *outPose;
-       bPoseChannel    *pchan;
+       bPoseChannel *pchan;
        ListBase listb;
        
-       if (!src){
+       if (!src) {
                *dst=NULL;
                return;
        }
@@ -518,17 +514,22 @@ void copy_pose (bPose **dst, bPose *src, int copycon)
        outPose->ikdata = NULL;
        outPose->ikparam = MEM_dupallocN(src->ikparam);
        
-       // TODO: rename this argument...
-       if (copycon) {
-               for (pchan=outPose->chanbase.first; pchan; pchan=pchan->next) {
-                       copy_constraints(&listb, &pchan->constraints);  // copy_constraints NULLs listb
+       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... */
                }
                
-               /* for now, duplicate Bone Groups too when doing this */
-               BLI_duplicatelist(&outPose->agroups, &src->agroups);
+               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;
 }
@@ -566,14 +567,37 @@ void init_pose_ikparam(bPose *pose)
        }
 }
 
+void make_pose_channels_hash(bPose *pose) 
+{
+       if(!pose->chanhash) {
+               bPoseChannel *pchan;
+
+               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);
+       }
+}
+
+void free_pose_channels_hash(bPose *pose) 
+{
+       if(pose->chanhash) {
+               BLI_ghash_free(pose->chanhash, NULL, NULL);
+               pose->chanhash= NULL;
+       }
+}
+
+
 void free_pose_channel(bPoseChannel *pchan)
 {
-       if (pchan->path)
-               MEM_freeN(pchan->path);
 
-       free_constraints(&pchan->constraints);
+       if (pchan->mpath) {
+               animviz_free_motionpath(pchan->mpath);
+               pchan->mpath= NULL;
+       }
 
-       if(pchan->prop) {
+       free_constraints(&pchan->constraints);
+       
+       if (pchan->prop) {
                IDP_FreeProperty(pchan->prop);
                MEM_freeN(pchan->prop);
        }
@@ -586,9 +610,11 @@ void free_pose_channels(bPose *pose)
        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)
@@ -600,14 +626,14 @@ void free_pose(bPose *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);
        }
@@ -635,6 +661,48 @@ static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan
        }
 }
 
+/* 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 
  */
@@ -731,9 +799,9 @@ void pose_add_group (Object *ob)
                return;
        
        grp= MEM_callocN(sizeof(bActionGroup), "PoseGroup");
-       strcpy(grp->name, "Group");
+       BLI_strncpy(grp->name, "Group", sizeof(grp->name));
        BLI_addtail(&pose->agroups, grp);
-       BLI_uniquename(&pose->agroups, grp, "Group", '.', offsetof(bActionGroup, name), 32);
+       BLI_uniquename(&pose->agroups, grp, "Group", '.', offsetof(bActionGroup, name), sizeof(grp->name));
        
        pose->active_group= BLI_countlist(&pose->agroups);
 }
@@ -767,7 +835,10 @@ void pose_remove_group (Object *ob)
                
                /* now, remove it from the pose */
                BLI_freelinkN(&pose->agroups, grp);
-               pose->active_group= 0;
+               pose->active_group--;
+               if(pose->active_group < 0 || pose->agroups.first == NULL) {
+                       pose->active_group= 0;
+               }
        }
 }
 
@@ -804,7 +875,8 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_
                                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);
@@ -910,6 +982,11 @@ short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan,
                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
@@ -918,8 +995,8 @@ short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan,
                         *      - once a match has been found, the curve cannot possibly be any other one
                         */
                        if ((curves) || (flags & ACT_TRANS_LOC) == 0) {
-                               pPtr= strstr(fcu->rna_path, "location");
-                               if ((pPtr) && (pPtr >= bPtr)) {
+                               pPtr= strstr(bPtr, "location");
+                               if (pPtr) {
                                        flags |= ACT_TRANS_LOC;
                                        
                                        if (curves) 
@@ -929,8 +1006,8 @@ short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan,
                        }
                        
                        if ((curves) || (flags & ACT_TRANS_SCALE) == 0) {
-                               pPtr= strstr(fcu->rna_path, "scale");
-                               if ((pPtr) && (pPtr >= bPtr)) {
+                               pPtr= strstr(bPtr, "scale");
+                               if (pPtr) {
                                        flags |= ACT_TRANS_SCALE;
                                        
                                        if (curves) 
@@ -940,8 +1017,8 @@ short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan,
                        }
                        
                        if ((curves) || (flags & ACT_TRANS_ROT) == 0) {
-                               pPtr= strstr(fcu->rna_path, "rotation");
-                               if ((pPtr) && (pPtr >= bPtr)) {
+                               pPtr= strstr(bPtr, "rotation");
+                               if (pPtr) {
                                        flags |= ACT_TRANS_ROT;
                                        
                                        if (curves) 
@@ -949,6 +1026,18 @@ short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan,
                                        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;
+                               }
+                       }
                }
        }
        
@@ -984,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;
@@ -993,16 +1081,12 @@ void rest_pose(bPose *pose)
        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->rotAxis[i]= 0.0f;
-               }
-               pchan->quat[0]= pchan->rotAxis[1]= 1.0f;
-               pchan->rotAngle= 0.0f;
-               
+               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);
        }
 }
@@ -1013,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;
        }
 
@@ -1037,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;
                }
        }
 }
@@ -1045,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);
        
@@ -1057,7 +1144,6 @@ void what_does_obaction (Scene *scene, Object *ob, Object *workob, bPose *pose,
        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;
        
@@ -1074,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) {
@@ -1089,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);
        }
 }
 
@@ -1132,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     
-                 .          .             .
+                                .          .             .
 
 */
 
@@ -1199,12 +1284,12 @@ static void blend_pose_offset_bone(bActionStrip *strip, bPose *dst, bPose *src,
                                /* if blending, we only add with factor scrweight */
                                mul_v3_fl(vec, srcweight);
                                
-                               add_v3_v3v3(dst->cyclic_offset, dst->cyclic_offset, vec);
+                               add_v3_v3(dst->cyclic_offset, vec);
                        }
                }
        }
        
-       add_v3_v3v3(dst->cyclic_offset, dst->cyclic_offset, src->cyclic_offset);
+       add_v3_v3(dst->cyclic_offset, src->cyclic_offset);
 }
 
 /* added "sizecorr" here, to allow armatures to be scaled and still have striding.
@@ -1366,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) {
@@ -1564,7 +1649,7 @@ static void do_nla(Scene *scene, Object *ob, int blocktype)
        }
        else if(blocktype==ID_AR) {
                /* apply stride offset to object */
-               add_v3_v3v3(ob->obmat[3], ob->obmat[3], ob->pose->stride_offset);
+               add_v3_v3(ob->obmat[3], ob->pose->stride_offset);
        }
        
        /* free */