edits ontop of Alex's patch from r41292.
[blender.git] / source / blender / blenkernel / intern / action.c
index 90a3a6ce6643b66595086480a15ee992e4b9efac..d02a1d6dd2706665def0811d1c2416b2ea81a605 100644 (file)
@@ -1,6 +1,4 @@
-/**
- * $Id$
- *
+/*
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * ***** END GPL LICENSE BLOCK *****
  */
 
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/blenkernel/intern/action.c
+ *  \ingroup bke
+ */
+
+
 #include <string.h>
 #include <math.h>
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
 #include <stdlib.h>
 #include "DNA_scene_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_animsys.h"
 #include "BKE_action.h"
 #include "BKE_anim.h"
 #include "BKE_library.h"
 #include "BKE_main.h"
 #include "BKE_object.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 "BKE_idprop.h"
 
 #include "BIK_api.h"
 
-#include "BLI_blenlib.h"
-#include "BLI_ghash.h"
-#include "BLI_math.h"
-
 #include "RNA_access.h"
 
 /* *********************** NOTE ON POSE AND ACTION **********************
 #include "RNA_access.h"
 
 /* *********************** NOTE ON POSE AND ACTION **********************
@@ -79,66 +83,79 @@ bAction *add_empty_action(const char name[])
        bAction *act;
        
        act= alloc_libblock(&G.main->action, ID_AC, 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;
 }      
 
        
        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)
 {
 // 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;
                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)
 {
        /* sanity check */
 void free_action (bAction *act)
 {
        /* sanity check */
@@ -157,6 +174,8 @@ void free_action (bAction *act)
                BLI_freelistN(&act->markers);
 }
 
                BLI_freelistN(&act->markers);
 }
 
+/* .................................. */
+
 bAction *copy_action (bAction *src)
 {
        bAction *dst = NULL;
 bAction *copy_action (bAction *src)
 {
        bAction *dst = NULL;
@@ -194,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;
 }
 
        return dst;
 }
 
@@ -249,7 +265,7 @@ bActionGroup *action_groups_add_new (bAction *act, const char name[])
        
        /* make it selected, with default name */
        agrp->flag = AGRP_SELECTED;
        
        /* make it selected, with default name */
        agrp->flag = AGRP_SELECTED;
-       strncpy(agrp->name, name[0] ? name : "Group", sizeof(agrp->name));
+       BLI_strncpy(agrp->name, name[0] ? name : "Group", sizeof(agrp->name));
        
        /* add to action, and validate */
        BLI_addtail(&act->groups, agrp);
        
        /* add to action, and validate */
        BLI_addtail(&act->groups, agrp);
@@ -376,6 +392,20 @@ bActionGroup *action_groups_find_named (bAction *act, const char name[])
        return BLI_findstring(&act->groups, name, offsetof(bActionGroup, name));
 }
 
        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;
+       
+       /* 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 *************** */
 
 /* usually used within a loop, so we got a N^2 slowdown */
 /* *************** Pose channels *************** */
 
 /* usually used within a loop, so we got a N^2 slowdown */
@@ -400,17 +430,18 @@ bPoseChannel *verify_pose_channel(bPose *pose, const char *name)
                return NULL;
        
        /* See if this channel exists */
                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");
        
        /* 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 */
        /* 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;
        chan->size[0] = chan->size[1] = chan->size[2] = 1.0f;
        
        chan->limitmin[0]= chan->limitmin[1]= chan->limitmin[2]= -180.0f;
@@ -488,7 +519,6 @@ void copy_pose (bPose **dst, bPose *src, int copycon)
                if (copycon) {
                        copy_constraints(&listb, &pchan->constraints, TRUE);  // copy_constraints NULLs listb
                        pchan->constraints= listb;
                if (copycon) {
                        copy_constraints(&listb, &pchan->constraints, TRUE);  // copy_constraints NULLs listb
                        pchan->constraints= listb;
-                       pchan->path= NULL; // XXX remove this line when the new motionpaths are ready... (depreceated code)
                        pchan->mpath= NULL; /* motion paths should not get copied yet... */
                }
                
                        pchan->mpath= NULL; /* motion paths should not get copied yet... */
                }
                
@@ -559,17 +589,12 @@ void free_pose_channels_hash(bPose *pose)
 
 void free_pose_channel(bPoseChannel *pchan)
 {
 
 void free_pose_channel(bPoseChannel *pchan)
 {
-       // XXX this case here will need to be removed when the new motionpaths are ready
-       if (pchan->path) {
-               MEM_freeN(pchan->path);
-               pchan->path= NULL;
-       }
-       
+
        if (pchan->mpath) {
                animviz_free_motionpath(pchan->mpath);
                pchan->mpath= NULL;
        }
        if (pchan->mpath) {
                animviz_free_motionpath(pchan->mpath);
                pchan->mpath= NULL;
        }
-       
+
        free_constraints(&pchan->constraints);
        
        if (pchan->prop) {
        free_constraints(&pchan->constraints);
        
        if (pchan->prop) {
@@ -774,7 +799,7 @@ void pose_add_group (Object *ob)
                return;
        
        grp= MEM_callocN(sizeof(bActionGroup), "PoseGroup");
                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), sizeof(grp->name));
        
        BLI_addtail(&pose->agroups, grp);
        BLI_uniquename(&pose->agroups, grp, "Group", '.', offsetof(bActionGroup, name), sizeof(grp->name));
        
@@ -810,7 +835,10 @@ void pose_remove_group (Object *ob)
                
                /* now, remove it from the pose */
                BLI_freelinkN(&pose->agroups, grp);
                
                /* 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;
+               }
        }
 }
 
        }
 }
 
@@ -847,7 +875,8 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_
                                float nmin, nmax;
                                
                                /* get extents for this curve */
                                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);
                                
                                /* compare to the running tally */
                                min= MIN2(min, nmin);
@@ -953,6 +982,11 @@ short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan,
                bPtr= strstr(fcu->rna_path, basePath);
                
                if (bPtr) {
                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
                        /* 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
@@ -961,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) {
                         *      - 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) 
                                        flags |= ACT_TRANS_LOC;
                                        
                                        if (curves) 
@@ -972,8 +1006,8 @@ short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan,
                        }
                        
                        if ((curves) || (flags & ACT_TRANS_SCALE) == 0) {
                        }
                        
                        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) 
                                        flags |= ACT_TRANS_SCALE;
                                        
                                        if (curves) 
@@ -983,8 +1017,8 @@ short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan,
                        }
                        
                        if ((curves) || (flags & ACT_TRANS_ROT) == 0) {
                        }
                        
                        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) 
                                        flags |= ACT_TRANS_ROT;
                                        
                                        if (curves) 
@@ -992,6 +1026,18 @@ short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan,
                                        continue;
                                }
                        }
                                        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;
+                               }
+                       }
                }
        }
        
                }
        }
        
@@ -1027,7 +1073,6 @@ void extract_pose_from_pose(bPose *pose, const bPose *src)
 void rest_pose(bPose *pose)
 {
        bPoseChannel *pchan;
 void rest_pose(bPose *pose)
 {
        bPoseChannel *pchan;
-       int i;
        
        if (!pose)
                return;
        
        if (!pose)
                return;
@@ -1036,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) {
        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);
        }
 }
                pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE);
        }
 }
@@ -1056,7 +1097,7 @@ void copy_pose_result(bPose *to, bPose *from)
        bPoseChannel *pchanto, *pchanfrom;
        
        if(to==NULL || from==NULL) {
        bPoseChannel *pchanto, *pchanfrom;
        
        if(to==NULL || from==NULL) {
-               printf("pose result copy error to:%p from:%p\n", to, from); // debug temp
+               printf("pose result copy error to:%p from:%p\n", (void *)to, (void *)from); // debug temp
                return;
        }
 
                return;
        }
 
@@ -1091,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 
  */
 /* 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);
        
 {
        bActionGroup *agrp= action_groups_find_named(act, groupname);
        
@@ -1119,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 */
 
        
        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) {
        
        /* if we're given a group to use, it's likely to be more efficient (though a bit more dangerous) */
        if (agrp) {
@@ -1134,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 {
                animsys_evaluate_action_group(&id_ptr, act, agrp, NULL, cframe);
        }
        else {
-               AnimData adt;
+               AnimData adt= {NULL};
                
                /* init animdata, and attach to workob */
                
                /* 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) */
                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);
        }
 }
 
        }
 }