NLA Branch: Merge from 2.5 20116:20214
authorJoshua Leung <aligorith@gmail.com>
Fri, 15 May 2009 13:35:29 +0000 (13:35 +0000)
committerJoshua Leung <aligorith@gmail.com>
Fri, 15 May 2009 13:35:29 +0000 (13:35 +0000)
source/blender/blenkernel/BKE_fcurve.h
source/blender/blenkernel/intern/action.c
source/blender/blenkernel/intern/anim_sys.c
source/blender/blenkernel/intern/fcurve.c
source/blender/makesdna/DNA_anim_types.h

index 9b8a2990fe57dfbf5cb807bf2447dea175fae772..7058b9d236af83c2a0b33567898003a5defd1f45 100644 (file)
@@ -108,11 +108,15 @@ struct FModifier *fcurve_add_modifier(struct FCurve *fcu, int type);
 void fcurve_copy_modifiers(ListBase *dst, ListBase *src);
 void fcurve_remove_modifier(struct FCurve *fcu, struct FModifier *fcm);
 void fcurve_free_modifiers(struct FCurve *fcu);
-void fcurve_bake_modifiers(struct FCurve *fcu, int start, int end);
 
 struct FModifier *fcurve_find_active_modifier(struct FCurve *fcu);
 void fcurve_set_active_modifier(struct FCurve *fcu, struct FModifier *fcm);
 
+float evaluate_time_fmodifiers(ListBase *modifiers, struct FCurve *fcu, float cvalue, float evaltime);
+void evaluate_value_fmodifiers(ListBase *modifiers, struct FCurve *fcu, float *cvalue, float evaltime);
+
+void fcurve_bake_modifiers(struct FCurve *fcu, int start, int end);
+
 /* ************** F-Curves API ******************** */
 
 /* -------- Data Managemnt  --------  */
index d54bc749b71e8163cafc9182509178c47e53d185..f2e3583c87b5dd56e9d39a87d10f880a4bb6adfa 100644 (file)
@@ -717,45 +717,25 @@ static bActionStrip *get_active_strip(Object *ob)
        return NULL;
 }
 
-/* non clipped mapping of strip */
-static float get_actionstrip_frame(bActionStrip *strip, float cframe, int invert)
-{
-       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) */
-       
-       actlength = strip->actend-strip->actstart;
-       if (actlength == 0.0f) actlength = 1.0f;
-       length = repeat * scale * actlength;
-       
-       /* 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;
-}
-
 /* if the conditions match, it converts current time to strip time */
+// TODO: change this adt
 float get_action_frame(Object *ob, float cframe)
 {
        bActionStrip *strip= get_active_strip(ob);
        
-       if(strip)
-               return get_actionstrip_frame(strip, cframe, 0);
+       //if(strip)
+       //      return get_actionstrip_frame(strip, cframe, 0);
        return cframe;
 }
 
 /* inverted, strip time to current time */
+// TODO: change this to adt
 float get_action_frame_inv(Object *ob, float cframe)
 {
        bActionStrip *strip= get_active_strip(ob);
        
-       if(strip)
-               return get_actionstrip_frame(strip, cframe, 1);
+       //if(strip)
+       //      return get_actionstrip_frame(strip, cframe, 1);
        return cframe;
 }
 
index 30dcb383ef629410eceac9a0ec81c9827fa2f448..5a4a2d9146951afa7618523e06f8953a5b4d8930 100644 (file)
@@ -5,6 +5,8 @@
 #include <stdio.h>
 #include <string.h>
 #include <stddef.h>
+#include <float.h>
+#include <math.h>
 
 #include "MEM_guardedalloc.h"
 
@@ -544,19 +546,17 @@ typedef struct NlaEvalStrip {
        struct NlaEvalStrip *next, *prev;
        
        NlaTrack *track;                        /* track that this strip belongs to */
-       NlaStrip *strip;                /* strip that's being used */
-       NlaStrip *sblend;               /* strip that's being blended towards (if applicable) */
+       NlaStrip *strip;                        /* strip that's being used */
        
        short track_index;                      /* the index of the track within the list */
        short strip_mode;                       /* which end of the strip are we looking at */
 } NlaEvalStrip;
 
-/* bNlaEvalStrip->strip_mode */
+/* NlaEvalStrip->strip_mode */
 enum {
        NES_TIME_BEFORE = -1,
        NES_TIME_WITHIN,
        NES_TIME_AFTER,
-       NES_TIME_AFTER_BLEND
 } eNlaEvalStrip_StripMode;
 
 
@@ -565,8 +565,9 @@ enum {
 typedef struct NlaEvalChannel {
        struct NlaEvalChannel *next, *prev;
        
-       char *path;                             /* ready-to-use path (i.e. remapped already) */
-       int array_index;                /* if applicable... */
+       PointerRNA ptr;                 /* pointer to struct containing property to use */
+       PropertyRNA *prop;              /* RNA-property type to use (should be in the struct given) */
+       int index;                              /* array index (where applicable) */
        
        float value;                    /* value of this channel */
 } NlaEvalChannel;
@@ -574,24 +575,98 @@ typedef struct NlaEvalChannel {
 
 /* ---------------------- */
 
-/* evaluate the F-Curves controlling settings for the NLA-strips (currently, not relinkable) */
-static void nlastrip_evaluate_fcurves (NlaStrip *strip, float ctime)
+/* non clipped mapping for strip-time <-> global time 
+ *     invert = convert action-strip time to global time 
+ */
+static float nlastrip_get_frame (NlaStrip *strip, float cframe, short invert)
 {
-       //PointerRNA actstrip_ptr;
-       //FCurve *fcu;
+       float length, actlength, repeat, scale;
+       
+       /* get number of repeats */
+       if (strip->repeat == 0.0f) strip->repeat = 1.0f;
+       repeat = strip->repeat;
+       
+       /* scaling */
+       if (strip->scale == 0.0f) strip->scale= 1.0f;
+       scale = (float)fabs(strip->scale); /* scale must be positive - we've got a special flag for reversing */
        
-       /* create RNA-pointer needed to set values */
-       //RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &actstrip_ptr);
+       /* length of referenced action */
+       actlength = strip->actend-strip->actstart;
+       if (actlength == 0.0f) actlength = 1.0f;
        
-       /* execute these settings as per normal */
-       //animsys_evaluate_fcurves(&actstrip_ptr, &strip->fcurves, NULL, ctime);
+       /* length of strip */
+       length = repeat * scale * actlength;
+       
+       /* reversed = play strip backwards */
+       if (strip->flag & NLASTRIP_FLAG_REVERSE) {
+               // FIXME: verify these 
+               /* invert = convert action-strip time to global time */
+               if (invert)
+                       return length*(strip->actend - cframe)/(repeat*actlength) + strip->start;
+               else
+                       return strip->actend - repeat*actlength*(cframe - strip->start)/length;
+       }
+       else {
+               /* 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;
+       }
+}
+
+/* calculate influence of strip based for given frame based on blendin/out values */
+static float nlastrip_get_influence (NlaStrip *strip, float cframe)
+{
+       /* sanity checks - normalise the blendin/out values? */
+       strip->blendin= (float)fabs(strip->blendin);
+       strip->blendout= (float)fabs(strip->blendout);
+       
+       /* result depends on where frame is in respect to blendin/out values */
+       // TODO: are the fabs() tests needed here?
+       if (IS_EQ(strip->blendin, 0)==0 && (cframe <= (strip->start + strip->blendin))) {
+               /* there is some blend-in */
+               return (float)fabs(cframe - strip->start) / (strip->blendin);
+       }
+       else if (IS_EQ(strip->blendout, 0)==0 && (cframe >= (strip->end - strip->blendout))) {
+               /* there is some blend-out */
+               return (float)fabs(strip->end - cframe) / (strip->blendout);
+       }
+       else {
+               /* in the middle of the strip, we should be full strength */
+               return 1.0f;
+       }
+}
+
+/* evaluate the evaluation time and influence for the strip, storing the results in the strip */
+void nlastrip_evaluate_controls (NlaStrip *strip, float ctime)
+{
+       /* firstly, analytically generate values for influence and time (if applicable) */
+       if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0)
+               strip->strip_time= nlastrip_get_frame(strip, ctime, 1); /* last arg '1' means current time to 'strip'/action time */
+       if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0)
+               strip->influence= nlastrip_get_influence(strip, ctime);
+       
+       /* now strip's evaluate F-Curves for these settings (if applicable) */
+       if (strip->fcurves.first) {
+#if 0
+               PointerRNA strip_ptr;
+               FCurve *fcu;
+               
+               /* create RNA-pointer needed to set values */
+               RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
+               
+               /* execute these settings as per normal */
+               animsys_evaluate_fcurves(&actstrip_ptr, &strip->fcurves, NULL, ctime);
+#endif
+       }
 }
 
 
-/* gets the strip active at the current time for a track */
+/* gets the strip active at the current time for a track for evaluation purposes */
 static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index, float ctime)
 {
-       NlaStrip *strip, *astrip=NULL, *bstrip=NULL;
+       NlaStrip *strip, *estrip=NULL;
        NlaEvalStrip *nes;
        short side= 0;
        
@@ -601,84 +676,195 @@ static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index
        
        /* loop over strips, checking if they fall within the range */
        for (strip= nlt->strips.first; strip; strip= strip->next) {
-               /* only consider if:
-                *      - current time occurs within strip's extents
-                *      - current time occurs before strip (if it is the first)
-                *      - current time occurs after strip (if hold is on)
-                *      - current time occurs between strips (1st of those isn't holding) - blend!
-                */
+               /* check if current time occurs within this strip  */
                if (IN_RANGE(ctime, strip->start, strip->end)) {
-                       astrip= strip;
+                       /* this strip is active, so try to use it */
+                       estrip= strip;
                        side= NES_TIME_WITHIN;
                        break;
                }
-               else if (ctime < strip->start) {
+               
+               /* if time occurred before current strip... */
+               if (ctime < strip->start) {
                        if (strip == nlt->strips.first) {
-                               astrip= strip;
+                               /* before first strip - only try to use it if it extends backwards in time too */
+                               if (strip->extendmode == NLASTRIP_EXTEND_HOLD)
+                                       estrip= strip;
+                                       
+                               /* side is 'before' regardless of whether there's a useful strip */
                                side= NES_TIME_BEFORE;
-                               break;
                        }
                        else {
-                               astrip= strip->prev;
+                               /* before next strip - previous strip has ended, but next hasn't begun, 
+                                * so blending mode depends on whether strip is being held or not...
+                                *      - only occurs when no transition strip added, otherwise the transition would have
+                                *        been picked up above...
+                                */
+                               strip= strip->prev;
                                
-                               if (astrip->flag & NLASTRIP_HOLDLASTFRAME) {
-                                       side= NES_TIME_AFTER;
-                                       break;
-                               }
-                               else {
-                                       bstrip= strip;
-                                       side= NES_TIME_AFTER_BLEND;
-                                       break;
-                               }
+                               if (strip->extendmode != NLASTRIP_EXTEND_NOTHING)
+                                       estrip= strip;
+                               side= NES_TIME_AFTER;
                        }
+                       break;
+               }
+               
+               /* if time occurred after current strip... */
+               if (ctime > strip->end) {
+                       /* only if this is the last strip should we do anything, and only if that is being held */
+                       if (strip == nlt->strips.last) {
+                               if (strip->extendmode != NLASTRIP_EXTEND_NOTHING)
+                                       estrip= strip;
+                                       
+                               side= NES_TIME_AFTER;
+                               break;
+                       }
+                       
+                       /* otherwise, skip... as the 'before' case will catch it more elegantly! */
                }
        }
        
-       /* check if strip has been found (and whether it has data worth considering) */
-       if (ELEM(NULL, astrip, astrip->act)) 
-               return;
-       if (astrip->flag & NLASTRIP_MUTE
+       /* check if a valid strip was found
+        *      - must not be muted (i.e. will have contribution
+        */
+       if ((estrip == NULL) || (estrip->flag & NLASTRIP_FLAG_MUTED)
                return;
        
-       /* check if blending between strips */
-       if (side == NES_TIME_AFTER_BLEND) {
-               /* blending between strips... so calculate influence+act_time of both */
-               nlastrip_evaluate_fcurves(astrip, ctime);
-               nlastrip_evaluate_fcurves(bstrip, ctime);
-               
-               if ((astrip->influence <= 0.0f) && (bstrip->influence <= 0.0f))
-                       return;
-       }
-       else {
-               /* calculate/set the influence+act_time of this strip - don't consider if 0 influence */
-               nlastrip_evaluate_fcurves(astrip, ctime);
+       /* evaluate strip's evaluation controls  
+        *      - skip if no influence (i.e. same effect as muting the strip)
+        *      - negative influence is not supported yet... how would that be defined?
+        */
+       // TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on...
+       nlastrip_evaluate_controls(estrip, ctime);
+       if (estrip->influence <= 0.0f)
+               return;
                
-               if (astrip->influence <= 0.0f) 
-                       return;
+       /* check if strip has valid data to evaluate */
+       switch (estrip->type) {
+               case NLASTRIP_TYPE_CLIP: 
+                       /* clip must have some action to evaluate */
+                       if (estrip->act == NULL)
+                               return;
+                       break;
+               case NLASTRIP_TYPE_TRANSITION:
+                       /* there must be strips to transition from and to (i.e. prev and next required) */
+                       // TODO: what happens about cross-track transitions? 
+                       if (ELEM(NULL, estrip->prev, estrip->next))
+                               return;
+                       break;
        }
        
-       
-       /* allocate new eval-strip for this strip + add to stack */
+       /* add to list of strips we need to evaluate */
        nes= MEM_callocN(sizeof(NlaEvalStrip), "NlaEvalStrip");
        
        nes->track= nlt;
-       nes->strip= astrip;
-       nes->sblend= bstrip;
-       nes->track_index= index;
+       nes->strip= estrip;
        nes->strip_mode= side;
+       nes->track_index= index;
        
        BLI_addtail(list, nes);
 }
 
 /* ---------------------- */
 
+/* verify that an appropriate NlaEvalChannel for this F-Curve */
+static NlaEvalChannel *nlaevalchan_verify (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes, FCurve *fcu, short *newChan)
+{
+       NlaEvalChannel *nec= NULL;
+       NlaStrip *strip= nes->strip;
+       PropertyRNA *prop;
+       PointerRNA new_ptr;
+       char *path = NULL;
+       short free_path=0;
+       
+       /* sanity checks */
+       if (channels == NULL)
+               return NULL;
+       
+       /* get RNA pointer+property info from F-Curve for more convenient handling */
+               /* get path, remapped as appropriate to work in its new environment */
+       free_path= animsys_remap_path(strip->remap, fcu->rna_path, &path);
+       
+               /* get property to write to */
+       if (RNA_path_resolve(ptr, path, &new_ptr, &prop) == 0)
+               return NULL;
+               /* only ok if animateable */
+       else if (RNA_property_animateable(&new_ptr, prop) == 0) 
+               return NULL;
+       
+       /* loop through existing channels, checking for a channel which affects the same property */
+       for (nec= channels->first; nec; nec= nec->next) {
+               if ((nec->ptr.data == new_ptr.data) && (nec->prop == prop))
+                       return nec;
+       }
+       
+       /* allocate a new struct for this */
+       nec= MEM_callocN(sizeof(NlaEvalChannel), "NlaEvalChannel");
+       *newChan= 1;
+       BLI_addtail(channels, nec);
+       
+       nec->ptr= new_ptr; 
+       nec->prop= prop;
+       nec->index= fcu->array_index;
+       
+       return nec;
+}
+
+/* ---------------------- */
+
+/* evaluate action-clip strip */
+static void nlastrip_evaluate_actionclip (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes)
+{
+       NlaStrip *strip= nes->strip;
+       FCurve *fcu;
+       float evaltime;
+       
+       /* evaluate strip's modifiers which modify time to evaluate the base curves at */
+       evaltime= evaluate_time_fmodifiers(&strip->modifiers, NULL, 0.0f, strip->strip_time);
+       
+       /* evaluate all the F-Curves in the action, saving the relevant pointers to data that will need to be used */
+       for (fcu= strip->act->curves.first; fcu; fcu= fcu->next) {
+               NlaEvalChannel *nec;
+               float value = 0.0f;
+               short newChan = -1;
+               
+               /* check if this curve should be skipped */
+               if (fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED)) 
+                       continue;
+                       
+               /* evaluate the F-Curve's value for the time given in the strip 
+                * NOTE: we use the modified time here, since strip's F-Curve Modifiers are applied on top of this 
+                */
+               value= evaluate_fcurve(fcu, evaltime);
+               
+               /* apply strip's F-Curve Modifiers on this value 
+                * NOTE: we apply the strip's original evaluation time not the modified one (as per standard F-Curve eval)
+                */
+               evaluate_value_fmodifiers(&strip->modifiers, fcu, &value, strip->strip_time);
+               
+               
+               /* get an NLA evaluation channel to work with, and accumulate the evaluated value with the value(s)
+                * stored in this channel if it has been used already
+                */
+               nec= nlaevalchan_verify(ptr, channels, nes, fcu, &newChan);
+               //if (nec)
+               //      nlaevalchan_accumulate(ptr, nec, nes, newChan, value);
+       }
+}
+
 /* evaluates the given evaluation strip */
-// FIXME: will we need the evaluation cache table set up to blend stuff in?
 // TODO: only evaluate here, but flush in one go using the accumulated channels at end...
-static void nlastrip_ctime_evaluate (ListBase *channels, NlaEvalStrip *nes, float ctime)
+static void nlastrip_evaluate (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes)
 {
-       // 1. (in old code) was to extract 'IPO-channels' from actions
-       // 2. blend between the 'accumulated' data, and the new data
+       /* actions to take depend on the type of strip */
+       switch (nes->strip->type) {
+               case NLASTRIP_TYPE_CLIP: /* action-clip */
+                       nlastrip_evaluate_actionclip(ptr, channels, nes);
+                       break;
+               case NLASTRIP_TYPE_TRANSITION: /* transition */
+                       // XXX code this...
+                       break;
+       }
 }
 
 /* write the accumulated settings to */
@@ -713,7 +899,7 @@ static void animsys_evaluate_nla (PointerRNA *ptr, AnimData *adt, float ctime)
        
        /* 2. for each strip, evaluate then accumulate on top of existing channels, but don't set values yet */
        for (nes= estrips.first; nes; nes= nes->next) 
-               nlastrip_ctime_evaluate(&echannels, nes, ctime);
+               nlastrip_evaluate(ptr, &echannels, nes);
        
        /* 3. flush effects of accumulating channels in NLA to the actual data they affect */
        nladata_flush_channels(ptr, &echannels);
index fed5ffc2ebdb7ced01104bebe58b14870f92785b..b30eba5a631a6a6df3a6c1d8365d25ed63a7609a 100644 (file)
@@ -2170,34 +2170,6 @@ void fcurve_free_modifiers (FCurve *fcu)
        }
 }
 
-/* Bake modifiers for given F-Curve to curve sample data, in the frame range defined
- * by start and end (inclusive).
- */
-void fcurve_bake_modifiers (FCurve *fcu, int start, int end)
-{
-       ChannelDriver *driver;
-       
-       /* sanity checks */
-       // TODO: make these tests report errors using reports not printf's
-       if ELEM(NULL, fcu, fcu->modifiers.first) {
-               printf("Error: No F-Curve with F-Curve Modifiers to Bake\n");
-               return;
-       }
-       
-       /* temporarily, disable driver while we sample, so that they don't influence the outcome */
-       driver= fcu->driver;
-       fcu->driver= NULL;
-       
-       /* bake the modifiers, by sampling the curve at each frame */
-       fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
-       
-       /* free the modifiers now */
-       fcurve_free_modifiers(fcu);
-       
-       /* restore driver */
-       fcu->driver= driver;
-}
-
 /* Find the active F-Curve Modifier */
 FModifier *fcurve_find_active_modifier (FCurve *fcu)
 {
@@ -2235,6 +2207,98 @@ void fcurve_set_active_modifier (FCurve *fcu, FModifier *fcm)
                fcm->flag |= FMODIFIER_FLAG_ACTIVE;
 }
 
+/* Evaluation API --------------------------- */
+
+/* evaluate time modifications imposed by some F-Curve Modifiers
+ *     - this step acts as an optimisation to prevent the F-Curve stack being evaluated 
+ *       several times by modifiers requesting the time be modified, as the final result
+ *       would have required using the modified time
+ *     - modifiers only ever recieve the unmodified time, as subsequent modifiers should be
+ *       working on the 'global' result of the modified curve, not some localised segment,
+ *       so nevaltime gets set to whatever the last time-modifying modifier likes...
+ *     - we start from the end of the stack, as only the last one matters for now
+ */
+float evaluate_time_fmodifiers (ListBase *modifiers, FCurve *fcu, float cvalue, float evaltime)
+{
+       FModifier *fcm;
+       float m_evaltime= evaltime;
+       
+       /* sanity checks */
+       if ELEM(NULL, modifiers, modifiers->first)
+               return evaltime;
+               
+       /* find the first modifier from end of stack that modifies time, and calculate the time the modifier
+        * would calculate time at
+        */
+       for (fcm= fcu->modifiers.last; fcm; fcm= fcm->prev) {
+               FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
+               
+               /* only evaluate if there's a callback for this */
+               // TODO: implement the 'influence' control feature...
+               if (fmi && fmi->evaluate_modifier_time) {
+                       if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
+                               m_evaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
+                       break;
+               }
+       }
+       
+       /* return the modified evaltime */
+       return m_evaltime;
+}
+
+/* Evalautes the given set of F-Curve Modifiers using the given data
+ * Should only be called after evaluate_time_fmodifiers() has been called...
+ */
+void evaluate_value_fmodifiers (ListBase *modifiers, FCurve *fcu, float *cvalue, float evaltime)
+{
+       FModifier *fcm;
+       
+       /* sanity checks */
+       if ELEM(NULL, modifiers, modifiers->first)
+               return;
+       
+       /* evaluate modifiers */
+       for (fcm= modifiers->first; fcm; fcm= fcm->next) {
+               FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
+               
+               /* only evaluate if there's a callback for this */
+               // TODO: implement the 'influence' control feature...
+               if (fmi && fmi->evaluate_modifier) {
+                       if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
+                               fmi->evaluate_modifier(fcu, fcm, cvalue, evaltime);
+               }
+       }
+} 
+
+
+/* Bake modifiers for given F-Curve to curve sample data, in the frame range defined
+ * by start and end (inclusive).
+ */
+void fcurve_bake_modifiers (FCurve *fcu, int start, int end)
+{
+       ChannelDriver *driver;
+       
+       /* sanity checks */
+       // TODO: make these tests report errors using reports not printf's
+       if ELEM(NULL, fcu, fcu->modifiers.first) {
+               printf("Error: No F-Curve with F-Curve Modifiers to Bake\n");
+               return;
+       }
+       
+       /* temporarily, disable driver while we sample, so that they don't influence the outcome */
+       driver= fcu->driver;
+       fcu->driver= NULL;
+       
+       /* bake the modifiers, by sampling the curve at each frame */
+       fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
+       
+       /* free the modifiers now */
+       fcurve_free_modifiers(fcu);
+       
+       /* restore driver */
+       fcu->driver= driver;
+}
+
 /* ***************************** F-Curve - Evaluation ********************************* */
 
 /* Evaluate and return the value of the given F-Curve at the specified frame ("evaltime") 
@@ -2242,7 +2306,6 @@ void fcurve_set_active_modifier (FCurve *fcu, FModifier *fcm)
  */
 float evaluate_fcurve (FCurve *fcu, float evaltime) 
 {
-       FModifier *fcm;
        float cvalue= 0.0f;
        float devaltime;
        
@@ -2255,28 +2318,8 @@ float evaluate_fcurve (FCurve *fcu, float evaltime)
                evaltime= cvalue= evaluate_driver(fcu->driver, evaltime);
        }
        
-       /* evaluate time modifications imposed by some F-Curve Modifiers
-        *      - this step acts as an optimisation to prevent the F-Curve stack being evaluated 
-        *        several times by modifiers requesting the time be modified, as the final result
-        *        would have required using the modified time
-        *      - modifiers only ever recieve the unmodified time, as subsequent modifiers should be
-        *        working on the 'global' result of the modified curve, not some localised segment,
-        *        so nevaltime gets set to whatever the last time-modifying modifier likes...
-        *      - we start from the end of the stack, as only the last one matters for now
-        */
-       devaltime= evaltime;
-       
-       for (fcm= fcu->modifiers.last; fcm; fcm= fcm->prev) {
-               FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-               
-               /* only evaluate if there's a callback for this */
-               // TODO: implement the 'influence' control feature...
-               if (fmi && fmi->evaluate_modifier_time) {
-                       if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
-                               devaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
-                       break;
-               }
-       }
+       /* evaluate modifiers which modify time to evaluate the base curve at */
+       devaltime= evaluate_time_fmodifiers(&fcu->modifiers, fcu, cvalue, evaltime);
        
        /* evaluate curve-data 
         *      - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying 
@@ -2288,16 +2331,7 @@ float evaluate_fcurve (FCurve *fcu, float evaltime)
                cvalue= fcurve_eval_samples(fcu, fcu->fpt, devaltime);
        
        /* evaluate modifiers */
-       for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {
-               FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-               
-               /* only evaluate if there's a callback for this */
-               // TODO: implement the 'influence' control feature...
-               if (fmi && fmi->evaluate_modifier) {
-                       if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
-                               fmi->evaluate_modifier(fcu, fcm, &cvalue, evaltime);
-               }
-       }
+       evaluate_value_fmodifiers(&fcu->modifiers, fcu, &cvalue, evaltime);
        
        /* if curve can only have integral values, perform truncation (i.e. drop the decimal part)
         * here so that the curve can be sampled correctly
index f30cd63242a78c385f9bc35b8e1a0935e389f286..c0cdc1ab5894229cc474db987c7f7e590a719d1c 100644 (file)
@@ -384,26 +384,13 @@ typedef struct AnimMapper {
 
 /* ************************************************ */
 /* NLA - Non-Linear Animation */
-// TODO: the concepts here still need to be refined to solve any unresolved items
-
-/* NLA Modifiers ---------------------------------- */
-
-/* These differ from F-Curve modifiers, as although F-Curve modifiers also operate on a 
- * per-channel basis too (in general), they are part of the animation data itself, which
- * means that their effects are inherited by all of their users. In order to counteract this,
- * the modifiers here should be used to provide variation to pre-created motions only. 
- */
 
 /* NLA Strips ------------------------------------- */
 
 /* NLA Strip (strip)
  *
  * A NLA Strip is a container for the reuse of Action data, defining parameters
- * to control the remapping of the Action data to some destination. Actions being
- * referenced by NLA-Strips SHOULD-NOT be editable, unless they were created in such
- * a way that results in very little mapping distortion (i.e. for layered animation only,
- * opposed to prebuilt 'blocks' which are quickly dumped into the NLA for crappymatic machima-type
- * stuff)
+ * to control the remapping of the Action data to some destination. 
  */
 typedef struct NlaStrip {
        struct NlaStrip *next, *prev;
@@ -411,58 +398,75 @@ typedef struct NlaStrip {
        bAction *act;                           /* Action that is referenced by this strip */
        AnimMapper *remap;                      /* Remapping info this strip (for tweaking correspondance of action with context) */
        
-       ListBase modifiers;                     /* NLA Modifiers */     
-       
-       ListBase fcurves;                       /* F-Curves for controlling this strip's influence and timing */
+       ListBase fcurves;                       /* F-Curves for controlling this strip's influence and timing */        // TODO: move out?
+       ListBase modifiers;                     /* F-Curve modifiers to be applied to the entire strip's referenced F-Curves */
        float influence;                        /* Influence of strip */
-       float act_time;                         /* Current 'time' within action being used */
+       float strip_time;                       /* Current 'time' within action being used (automatically evaluated, but can be overridden) */
        
        float start, end;                       /* extents of the strip */
        float actstart, actend;         /* range of the action to use */
        
-       float   repeat;                         /* The number of times to repeat the action range (only when no F-Curves) */
-       float   scale;                          /* The amount the action range is scaled by (only when no F-Curves) */
+       float repeat;                           /* The number of times to repeat the action range (only when no F-Curves) */
+       float scale;                            /* The amount the action range is scaled by (only when no F-Curves) */
        
        float blendin, blendout;        /* strip blending length (only used when there are no F-Curves) */      
-       int blendmode;                          /* strip blending mode */       
-       
-       int flag;                                       /* settings */
-       
-               // umm... old unused cruft? 
-       int stride_axis;                        /* axis for stridebone stuff - 0=x, 1=y, 2=z */
-       int pad;
-       
-       float   actoffs;                        /* Offset within action, for cycles and striding (only set for ACT_USESTRIDE) */
-       float   stridelen;                      /* The stridelength (considered when flag & ACT_USESTRIDE) */
+       short blendmode;                        /* strip blending mode (layer-based mixing) */
+       short extendmode;                       /* strip extrapolation mode (time-based mixing) */
        
-       char    stridechannel[32];      /* Instead of stridelen, it uses an action channel */
-       char    offs_bone[32];          /* if repeat, use this bone/channel for defining offset */
+       short flag;                                     /* settings */
+       short type;                                     /* type of NLA strip */
 } NlaStrip;
 
 /* NLA Strip Blending Mode */
 enum {
-       NLASTRIPMODE_BLEND = 0,
-       NLASTRIPMODE_ADD,
-       NLASTRIPMODE_SUBTRACT,
-} eActStrip_Mode;
+       NLASTRIP_MODE_BLEND = 0,
+       NLASTRIP_MODE_ADD,
+       NLASTRIP_MODE_SUBTRACT,
+       NLASTRIP_MODE_MULTIPLY,
+} eNlaStrip_Blend_Mode;
+
+/* NLA Strip Extrpolation Mode */
+enum {
+               /* extend before first frame if no previous strips in track, and always hold+extend last frame */
+       NLASTRIP_EXTEND_HOLD    = 0,            
+               /* only hold+extend last frame */
+       NLASTRIP_EXTEND_HOLD_FORWARD,   
+               /* don't contribute at all */
+       NLASTRIP_EXTEND_NOTHING,
+} eNlaStrip_Extrapolate_Mode;
 
 /* NLA Strip Settings */
-// TODO: check on which of these are still useful...
 enum {
-       NLASTRIP_SELECT                 = (1<<0),
-       NLASTRIP_USESTRIDE              = (1<<1),
-       NLASTRIP_BLENDTONEXT    = (1<<2),       /* Not implemented. Is not used anywhere */
-       NLASTRIP_HOLDLASTFRAME  = (1<<3),
-       NLASTRIP_ACTIVE                 = (1<<4),
-       NLASTRIP_LOCK_ACTION    = (1<<5),
-       NLASTRIP_MUTE                   = (1<<6),
-       NLASTRIP_REVERSE                = (1<<7),       /* This has yet to be implemented. To indicate that a strip should be played backwards */
-       NLASTRIP_CYCLIC_USEX    = (1<<8),
-       NLASTRIP_CYCLIC_USEY    = (1<<9),
-       NLASTRIP_CYCLIC_USEZ    = (1<<10),
-       NLASTRIP_AUTO_BLENDS    = (1<<11),
-       NLASTRIP_TWEAK                  = (1<<12),      /* This strip is a tweaking strip (only set if owner track is a tweak track) */
-} eActionStrip_Flag;
+       /* UI selection flags */
+               /* NLA strip is the active one in the track (also indicates if strip is being tweaked) */
+       NLASTRIP_FLAG_ACTIVE            = (1<<0),       
+               /* NLA strip is selected for editing */
+       NLASTRIP_FLAG_SELECT            = (1<<1),
+//     NLASTRIP_FLAG_SELECT_L          = (1<<2),       // left handle selected
+//     NLASTRIP_FLAG_SELECT_R          = (1<<3),       // right handle selected
+       
+       /* controls driven by local F-Curves */
+               /* strip influence is controlled by local F-Curve */
+       NLASTRIP_FLAG_USR_INFLUENCE     = (1<<5),
+       NLASTRIP_FLAG_USR_TIME          = (1<<6),
+       
+       /* playback flags (may be overriden by F-Curves) */
+               /* NLA strip blendin/out values are set automatically based on overlaps */
+       NLASTRIP_FLAG_AUTO_BLENDS       = (1<<10),
+               /* NLA strip is played back in reverse order */
+       NLASTRIP_FLAG_REVERSE           = (1<<11),
+               /* NLA strip is muted (i.e. doesn't contribute in any way) */
+               // TODO: this overlaps a lot with the functionality in track
+       NLASTRIP_FLAG_MUTED                     = (1<<12),
+} eNlaStrip_Flag;
+
+/* NLA Strip Type */
+enum { 
+               /* 'clip' - references an Action */
+       NLASTRIP_TYPE_CLIP      = 0,
+               /* 'transition' - blends between the adjacent strips */
+       NLASTRIP_TYPE_TRANSITION,
+} eNlaStrip_Type;
 
 /* NLA Tracks ------------------------------------- */
 
@@ -481,14 +485,12 @@ typedef struct NlaTrack {
        int flag;                               /* settings for this track */
        int index;                              /* index of the track in the stack (NOTE: not really useful, but we need a pad var anyways!) */
        
-       char info[64];                  /* short user-description of this track */
+       char name[64];                  /* short user-description of this track */
 } NlaTrack;
 
 /* settings for track */
 enum {
-               /* track is the one that settings can be modified on (doesn't indicate 
-                * that it's for 'tweaking' though) 
-                */
+               /* track is the one that settings can be modified on, also indicates if track is being 'tweaked' */
        NLATRACK_ACTIVE         = (1<<0),
                /* track is selected in UI for relevant editing operations */
        NLATRACK_SELECTED       = (1<<1),
@@ -498,10 +500,6 @@ enum {
        NLATRACK_SOLO           = (1<<3),
                /* track's settings (and strips) cannot be edited (to guard against unwanted changes) */
        NLATRACK_PROTECTED      = (1<<4),
-               /* strip is the 'last' one that should be evaluated, as the active action 
-                * is being used to tweak the animation of the strips up to here 
-                */
-       NLATRACK_TWEAK          = (1<<5),
 } eNlaTrack_Flag;
 
 
@@ -674,11 +672,13 @@ enum {
        ADT_NLA_SOLO_TRACK              = (1<<0),
                /* don't use NLA */
        ADT_NLA_EVAL_OFF                = (1<<1),
-               /* don't execute drivers */
-       ADT_DRIVERS_DISABLED    = (1<<2),
+               /* NLA is being 'tweaked' (i.e. in EditMode) */
+       ADT_NLA_EDIT_ON                 = (1<<2),
        
                /* drivers expanded in UI */
        ADT_DRIVERS_COLLAPSED   = (1<<10),
+               /* don't execute drivers */
+       ADT_DRIVERS_DISABLED    = (1<<11),
 } eAnimData_Flag;
 
 /* Animation Data recalculation settings (to be set by depsgraph) */