Merging with trunk up to r38631.
[blender.git] / source / blender / blenkernel / intern / fmodifier.c
index fba15075bdbbd3ecce04a737294e8ee749b61e96..dcf81c194798573be58e030038684c5d137517aa 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
@@ -15,7 +15,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) 2009 Blender Foundation, Joshua Leung
  * All rights reserved.
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/blenkernel/intern/fmodifier.c
+ *  \ingroup bke
+ */
+
+
 
 #include <math.h>
 #include <stdio.h>
 #include <string.h>
 #include <float.h>
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
 #include "MEM_guardedalloc.h"
 
 #include "DNA_anim_types.h"
 
 #include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_noise.h"
+#include "BLI_math.h" /* windows needs for M_PI */
+#include "BLI_utildefines.h"
 
 #include "BKE_fcurve.h"
-#include "BKE_curve.h" 
-#include "BKE_global.h"
 #include "BKE_idprop.h"
-#include "BKE_utildefines.h"
-
-#include "RNA_access.h"
-#include "RNA_types.h"
 
-#include "AUD_C-API.h"
-
-#ifndef DISABLE_PYTHON
-#include "BPY_extern.h" /* for BPY_pydriver_eval() */
-#endif
 
 #define SMALL -1.0e-10
 #define SELECT 1
@@ -162,7 +152,7 @@ static void fcm_generator_verify (FModifier *fcm)
                                nc= MEM_callocN(sizeof(float)*(data->poly_order+1), "FMod_Generator_Coefs");
                                
                                if (data->coefficients) {
-                                       if (data->arraysize > (data->poly_order+1))
+                                       if ((int)data->arraysize > (data->poly_order+1))
                                                memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order+1));
                                        else
                                                memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
@@ -188,7 +178,7 @@ static void fcm_generator_verify (FModifier *fcm)
                                nc= MEM_callocN(sizeof(float)*(data->poly_order*2), "FMod_Generator_Coefs");
                                
                                if (data->coefficients) {
-                                       if (data->arraysize > (data->poly_order * 2))
+                                       if (data->arraysize > (unsigned int)(data->poly_order * 2))
                                                memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order * 2));
                                        else
                                                memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
@@ -206,7 +196,7 @@ static void fcm_generator_verify (FModifier *fcm)
        }
 }
 
-static void fcm_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+static void fcm_generator_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
 {
        FMod_Generator *data= (FMod_Generator *)fcm->data;
        
@@ -256,7 +246,7 @@ static void fcm_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue,
                        unsigned int i;
                        
                        /* for each coefficient pair, solve for that bracket before accumulating in value by multiplying */
-                       for (cp=data->coefficients, i=0; (cp) && (i < data->poly_order); cp+=2, i++) 
+                       for (cp=data->coefficients, i=0; (cp) && (i < (unsigned int)data->poly_order); cp+=2, i++) 
                                value *= (cp[0]*evaltime + cp[1]);
                                
                        /* only if something changed, write *cvalue in one go */
@@ -313,13 +303,13 @@ static void fcm_fn_generator_new_data (void *mdata)
  */
 static double sinc (double x)
 {
-    if (fabs(x) < 0.0001)
-        return 1.0;
-    else
-        return sin(M_PI * x) / (M_PI * x);
+       if (fabs(x) < 0.0001)
+               return 1.0;
+       else
+               return sin(M_PI * x) / (M_PI * x);
 }
 
-static void fcm_fn_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+static void fcm_fn_generator_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
 {
        FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)fcm->data;
        double arg= data->phase_multiplier*evaltime + data->phase_offset;
@@ -356,7 +346,7 @@ static void fcm_fn_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalu
                case FCM_GENERATOR_FN_LN: /* natural log */
                {
                        /* check that value is greater than 1? */
-                       if (arg > 1.0f) {
+                       if (arg > 1.0) {
                                fn= log;
                        }
                        else {
@@ -368,7 +358,7 @@ static void fcm_fn_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalu
                case FCM_GENERATOR_FN_SQRT: /* square root */
                {
                        /* no negative numbers */
-                       if (arg > 0.0f) {
+                       if (arg > 0.0) {
                                fn= sqrt;
                        }
                        else {
@@ -384,7 +374,7 @@ static void fcm_fn_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalu
        
        /* execute function callback to set value if appropriate */
        if (fn) {
-               float value= (float)(data->amplitude*fn(arg) + data->value_offset);
+               float value= (float)(data->amplitude*(float)fn(arg) + data->value_offset);
                
                if (data->flag & FCM_GENERATOR_ADDITIVE)
                        *cvalue += value;
@@ -448,7 +438,7 @@ static void fcm_envelope_verify (FModifier *fcm)
        }
 }
 
-static void fcm_envelope_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+static void fcm_envelope_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
 {
        FMod_Envelope *env= (FMod_Envelope *)fcm->data;
        FCM_EnvelopeData *fed, *prevfed, *lastfed;
@@ -540,12 +530,12 @@ static void fcm_cycles_new_data (void *mdata)
        data->before_mode= data->after_mode= FCM_EXTRAPOLATE_CYCLIC;
 }
 
-static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime)
+static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float UNUSED(cvalue), float evaltime)
 {
        FMod_Cycles *data= (FMod_Cycles *)fcm->data;
        float prevkey[2], lastkey[2], cycyofs=0.0f;
        short side=0, mode=0;
-       int cycles=0;
+       int cycles=0, ofs=0;
        
        /* check if modifier is first in stack, otherwise disable ourself... */
        // FIXME...
@@ -587,6 +577,7 @@ static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float e
                        side= -1;
                        mode= data->before_mode;
                        cycles= data->before_cycles;
+                       ofs= prevkey[0];
                }
        }
        else if (evaltime > lastkey[0]) {
@@ -594,6 +585,7 @@ static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float e
                        side= 1;
                        mode= data->after_mode;
                        cycles= data->after_cycles;
+                       ofs= lastkey[0];
                }
        }
        if ELEM(0, side, mode)
@@ -601,11 +593,8 @@ static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float e
                
        /* find relative place within a cycle */
        {
-               float cycdx=0, cycdy=0, ofs=0;
-               float cycle= 0;
-               
-               /* ofs is start frame of cycle */
-               ofs= prevkey[0];
+               float cycdx=0, cycdy=0;
+               float cycle= 0, cyct=0;
                
                /* calculate period and amplitude (total height) of a cycle */
                cycdx= lastkey[0] - prevkey[0];
@@ -617,6 +606,9 @@ static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float e
                        
                /* calculate the 'number' of the cycle */
                cycle= ((float)side * (evaltime - ofs) / cycdx);
+
+               /* calculate the time inside the cycle */
+               cyct= fmod(evaltime - ofs, cycdx);
                
                /* check that cyclic is still enabled for the specified time */
                if (cycles == 0) {
@@ -624,7 +616,7 @@ static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float e
                         * as this indicates infinite cycles...
                         */
                }
-               else if (cycle > (cycles+1)) {
+               else if (cycle > cycles) {
                        /* we are too far away from range to evaluate
                         * TODO: but we should still hold last value... 
                         */
@@ -633,26 +625,36 @@ static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float e
                
                /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */
                if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
-                       cycyofs = (float)floor((evaltime - ofs) / cycdx);
+                       if(side < 0)
+                               cycyofs = (float)floor((evaltime - ofs) / cycdx);
+                       else
+                               cycyofs = (float)ceil((evaltime - ofs) / cycdx);
                        cycyofs *= cycdy;
                }
-               
+
+               /* special case for cycle start/end */
+               if(cyct == 0.0f) {
+                       evaltime = (side == 1 ? lastkey[0] : prevkey[0]);
+
+                       if((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)cycle % 2))
+                               evaltime = (side == 1 ? prevkey[0] : lastkey[0]);
+               }
                /* calculate where in the cycle we are (overwrite evaltime to reflect this) */
-               if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle) % 2)) {
+               else if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle+1) % 2)) {
                        /* when 'mirror' option is used and cycle number is odd, this cycle is played in reverse 
                         *      - for 'before' extrapolation, we need to flip in a different way, otherwise values past
                         *        then end of the curve get referenced (result of fmod will be negative, and with different phase)
                         */
                        if (side < 0)
-                               evaltime= (float)(prevkey[0] - fmod(evaltime-ofs, cycdx));
+                               evaltime= prevkey[0] - cyct;
                        else
-                               evaltime= (float)(lastkey[0] - fmod(evaltime-ofs, cycdx));
+                               evaltime= lastkey[0] - cyct;
                }
                else {
                        /* the cycle is played normally... */
-                       evaltime= (float)(fmod(evaltime-ofs, cycdx) + ofs);
+                       evaltime= prevkey[0] + cyct;
                }
-               if (evaltime < ofs) evaltime += cycdx;
+               if (evaltime < prevkey[0]) evaltime += cycdx;
        }
        
        /* store temp data if needed */
@@ -668,7 +670,7 @@ static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float e
        return evaltime;
 }
  
-static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+static void fcm_cycles_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float UNUSED(evaltime))
 {
        tFCMED_Cycles *edata= (tFCMED_Cycles *)fcm->edata;
        
@@ -712,7 +714,7 @@ static void fcm_noise_new_data (void *mdata)
        data->modification = FCM_NOISE_MODIF_REPLACE;
 }
  
-static void fcm_noise_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+static void fcm_noise_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
 {
        FMod_Noise *data= (FMod_Noise *)fcm->data;
        float noise;
@@ -804,15 +806,15 @@ static void fcm_python_copy (FModifier *fcm, FModifier *src)
        pymod->prop = IDP_CopyProperty(opymod->prop);
 }
 
-static void fcm_python_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+static void fcm_python_evaluate (FCurve *UNUSED(fcu), FModifier *UNUSED(fcm), float *UNUSED(cvalue), float UNUSED(evaltime))
 {
-#ifndef DISABLE_PYTHON
+#ifdef WITH_PYTHON
        //FMod_Python *data= (FMod_Python *)fcm->data;
        
        /* FIXME... need to implement this modifier...
         *      It will need it execute a script using the custom properties 
         */
-#endif /* DISABLE_PYTHON */
+#endif /* WITH_PYTHON */
 }
 
 static FModifierTypeInfo FMI_PYTHON = {
@@ -833,7 +835,7 @@ static FModifierTypeInfo FMI_PYTHON = {
 
 /* Limits F-Curve Modifier --------------------------- */
 
-static float fcm_limits_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime)
+static float fcm_limits_time (FCurve *UNUSED(fcu), FModifier *fcm, float UNUSED(cvalue), float evaltime)
 {
        FMod_Limits *data= (FMod_Limits *)fcm->data;
        
@@ -847,7 +849,7 @@ static float fcm_limits_time (FCurve *fcu, FModifier *fcm, float cvalue, float e
        return evaltime;
 }
 
-static void fcm_limits_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+static void fcm_limits_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float UNUSED(evaltime))
 {
        FMod_Limits *data= (FMod_Limits *)fcm->data;
        
@@ -873,89 +875,57 @@ static FModifierTypeInfo FMI_LIMITS = {
        fcm_limits_evaluate /* evaluate */
 };
 
-/* Sound F-Curve Modifier  --------------------------- */
+/* Stepped F-Curve Modifier --------------------------- */
 
-static void fcm_sound_new_data (void *mdata)
+static void fcm_stepped_new_data (void *mdata) 
 {
-       FMod_Sound *data= (FMod_Sound *)mdata;
-
-       /* defaults */
-       data->strength= 1.0f;
-       data->delay = 0.0f;
-       data->modification = FCM_SOUND_MODIF_REPLACE;
-       data->sound = NULL;
+       FMod_Stepped *data= (FMod_Stepped *)mdata;
+       
+       /* just need to set the step-size to 2-frames by default */
+       // XXX: or would 5 be more normal?
+       data->step_size = 2.0f;
 }
 
-static void fcm_sound_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+static float fcm_stepped_time (FCurve *UNUSED(fcu), FModifier *fcm, float UNUSED(cvalue), float evaltime)
 {
-       FMod_Sound *data= (FMod_Sound *)fcm->data;
-       float amplitude;
-
-       AUD_Device* device;
-       SoundHandle* handle;
-       AUD_Sound* limiter;
-       AUD_SoundInfo info;
-
-//     evaltime = FRA2TIME(evaltime);
-       evaltime -= data->delay;
-
-       if(evaltime < 0.0f || data->sound == NULL || data->sound->cache == NULL)
-               return;
-
-       info = AUD_getInfo(data->sound->cache);
-       info.specs.channels = 1;
-       info.specs.format = AUD_FORMAT_FLOAT32;
-       device = AUD_openReadDevice(info.specs);
-       limiter = AUD_limitSound(data->sound->cache, evaltime, evaltime + 1);
-       AUD_playDevice(device, limiter);
-       AUD_unload(limiter);
-       AUD_readDevice(device, &amplitude, 1);
-       AUD_closeReadDevice(device);
-
-       /* combine the amplitude with existing motion data */
-       switch (data->modification) {
-               case FCM_SOUND_MODIF_ADD:
-                       *cvalue= *cvalue + amplitude * data->strength;
-                       break;
-               case FCM_SOUND_MODIF_SUBTRACT:
-                       *cvalue= *cvalue - amplitude * data->strength;
-                       break;
-               case FCM_SOUND_MODIF_MULTIPLY:
-                       *cvalue= *cvalue * amplitude * data->strength;
-                       break;
-               case FCM_SOUND_MODIF_REPLACE:
-               default:
-                       *cvalue= *cvalue + amplitude * data->strength;
-                       break;
+       FMod_Stepped *data= (FMod_Stepped *)fcm->data;
+       int snapblock;
+       
+       /* check range clamping to see if we should alter the timing to achieve the desired results */
+       if (data->flag & FCM_STEPPED_NO_BEFORE) {
+               if (evaltime < data->start_frame)
+                       return evaltime;
        }
+       if (data->flag & FCM_STEPPED_NO_AFTER) {
+               if (evaltime > data->end_frame)
+                       return evaltime;
+       }
+       
+       /* we snap to the start of the previous closest block of 'step_size' frames 
+        * after the start offset has been discarded 
+        *      - i.e. round down
+        */
+       snapblock = (int)((evaltime - data->offset) / data->step_size);
+       
+       /* reapply the offset, and multiple the snapblock by the size of the steps to get 
+        * the new time to evaluate at 
+        */
+       return ((float)snapblock * data->step_size) + data->offset;
 }
 
-static float fcm_sound_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime)
-{
-       FMod_Sound *data= (FMod_Sound *)fcm->data;
-
-       /* check for the time delay */
-//     evaltime = FRA2TIME(evaltime);
-       if(evaltime < data->delay)
-               return data->delay;
-
-       /* modifier doesn't change time */
-       return evaltime;
-}
-
-static FModifierTypeInfo FMI_SOUND = {
-       FMODIFIER_TYPE_SOUND, /* type */
-       sizeof(FMod_Sound), /* size */
-       FMI_TYPE_REPLACE_VALUES, /* action type */
-       0, /* requirements */
-       "Sound", /* name */
-       "FMod_Sound", /* struct name */
+static FModifierTypeInfo FMI_STEPPED = {
+       FMODIFIER_TYPE_STEPPED, /* type */
+       sizeof(FMod_Limits), /* size */
+       FMI_TYPE_GENERATE_CURVE, /* action type */  /* XXX... err... */   
+       FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
+       "Stepped", /* name */
+       "FMod_Stepped", /* struct name */
        NULL, /* free data */
        NULL, /* copy data */
-       fcm_sound_new_data, /* new data */
+       fcm_stepped_new_data, /* new data */
        NULL, /* verify */
-       fcm_sound_time, /* evaluate time */
-       fcm_sound_evaluate /* evaluate */
+       fcm_stepped_time, /* evaluate time */
+       NULL /* evaluate */
 };
 
 /* F-Curve Modifier API --------------------------- */
@@ -968,7 +938,7 @@ static FModifierTypeInfo *fmodifiersTypeInfo[FMODIFIER_NUM_TYPES];
 static short FMI_INIT= 1; /* when non-zero, the list needs to be updated */
 
 /* This function only gets called when FMI_INIT is non-zero */
-static void fmods_init_typeinfo () 
+static void fmods_init_typeinfo (void
 {
        fmodifiersTypeInfo[0]=  NULL;                                   /* 'Null' F-Curve Modifier */
        fmodifiersTypeInfo[1]=  &FMI_GENERATOR;                 /* Generator F-Curve Modifier */
@@ -979,7 +949,7 @@ static void fmods_init_typeinfo ()
        fmodifiersTypeInfo[6]=  NULL/*&FMI_FILTER*/;                    /* Filter F-Curve Modifier */  // XXX unimplemented
        fmodifiersTypeInfo[7]=  &FMI_PYTHON;                    /* Custom Python F-Curve Modifier */
        fmodifiersTypeInfo[8]=  &FMI_LIMITS;                    /* Limits F-Curve Modifier */
-       fmodifiersTypeInfo[9]=  &FMI_SOUND;                             /* Sound F-Curve Modifier */
+       fmodifiersTypeInfo[9]=  &FMI_STEPPED;                   /* Stepped F-Curve Modifier */
 }
 
 /* This function should be used for getting the appropriate type-info when only
@@ -1043,11 +1013,16 @@ FModifier *add_fmodifier (ListBase *modifiers, int type)
        fcm= MEM_callocN(sizeof(FModifier), "F-Curve Modifier");
        fcm->type = type;
        fcm->flag = FMODIFIER_FLAG_EXPANDED;
+       fcm->influence = 1.0f;
        BLI_addtail(modifiers, fcm);
        
+       /* tag modifier as "active" if no other modifiers exist in the stack yet */
+       if (modifiers->first == modifiers->last)
+               fcm->flag |= FMODIFIER_FLAG_ACTIVE;
+       
        /* add modifier's data */
        fcm->data= MEM_callocN(fmi->size, fmi->structName);
-               
+       
        /* init custom settings if necessary */
        if (fmi->new_data)      
                fmi->new_data(fcm->data);
@@ -1056,6 +1031,31 @@ FModifier *add_fmodifier (ListBase *modifiers, int type)
        return fcm;
 }
 
+/* Make a copy of the specified F-Modifier */
+FModifier *copy_fmodifier (FModifier *src)
+{
+       FModifierTypeInfo *fmi= fmodifier_get_typeinfo(src);
+       FModifier *dst;
+       
+       /* sanity check */
+       if (src == NULL)
+               return NULL;
+               
+       /* copy the base data, clearing the links */
+       dst = MEM_dupallocN(src);
+       dst->next = dst->prev = NULL;
+       
+       /* make a new copy of the F-Modifier's data */
+       dst->data = MEM_dupallocN(src->data);
+       
+       /* only do specific constraints if required */
+       if (fmi && fmi->copy_data)
+               fmi->copy_data(dst, src);
+               
+       /* return the new modifier */
+       return dst;
+}
+
 /* Duplicate all of the F-Modifiers in the Modifier stacks */
 void copy_fmodifiers (ListBase *dst, ListBase *src)
 {
@@ -1110,13 +1110,6 @@ int remove_fmodifier (ListBase *modifiers, FModifier *fcm)
        }
 }
 
-/* Remove and free the nth F-Modifier from the given stack */
-int remove_fmodifier_index (ListBase *modifiers, int index)
-{
-       FModifier *fcm= BLI_findlink(modifiers, index);
-       return remove_fmodifier(modifiers, fcm);
-}
-
 /* Remove all of a given F-Curve's modifiers */
 void free_fmodifiers (ListBase *modifiers)
 {
@@ -1208,11 +1201,52 @@ short list_has_suitable_fmodifier (ListBase *modifiers, int mtype, short acttype
 
 /* Evaluation API --------------------------- */
 
+/* helper function - calculate influence of FModifier */
+static float eval_fmodifier_influence (FModifier *fcm, float evaltime)
+{
+       float influence;
+       
+       /* sanity check */
+       if (fcm == NULL) 
+               return 0.0f;
+       
+       /* should we use influence stored in modifier or not 
+        * NOTE: this is really just a hack so that we don't need to version patch old files ;)
+        */
+       if (fcm->flag & FMODIFIER_FLAG_USEINFLUENCE)
+               influence = fcm->influence;
+       else
+               influence = 1.0f;
+               
+       /* restricted range or full range? */
+       if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) {
+               if ((evaltime <= fcm->sfra) || (evaltime >= fcm->efra)) {
+                       /* out of range */
+                       return 0.0f;
+               }
+               else if ((evaltime > fcm->sfra) && (evaltime < fcm->sfra + fcm->blendin)) {
+                       /* blend in range */
+                       float a = fcm->sfra;
+                       float b = fcm->sfra + fcm->blendin;
+                       return influence * (evaltime - a) / (b - a);
+               }
+               else if ((evaltime < fcm->efra) && (evaltime > fcm->efra - fcm->blendout)) {
+                       /* blend out range */
+                       float a = fcm->efra;
+                       float b = fcm->efra - fcm->blendout;
+                       return influence * (evaltime - a) / (b - a);
+               }
+       }
+       
+       /* just return the influence of the modifier */
+       return influence;
+}
+
 /* 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
+ *     - modifiers only ever receive 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
@@ -1220,29 +1254,47 @@ short list_has_suitable_fmodifier (ListBase *modifiers, int mtype, short acttype
 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->last)
                return evaltime;
                
-       /* find the first modifier from end of stack that modifies time, and calculate the time the modifier
-        * would calculate time at
+       /* Starting from the end of the stack, calculate the time effects of various stacked modifiers 
+        * on the time the F-Curve should be evaluated at. 
+        *
+        * This is done in reverse order to standard evaluation, as when this is done in standard
+        * order, each modifier would cause jumps to other points in the curve, forcing all
+        * previous ones to be evaluated again for them to be correct. However, if we did in the 
+        * reverse order as we have here, we can consider them a macro to micro type of waterfall
+        * effect, which should get us the desired effects when using layered time manipulations
+        * (such as multiple 'stepped' modifiers in sequence, causing different stepping rates)
         */
        for (fcm= 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;
+               if (fmi == NULL) 
+                       continue;
+               
+               /* if modifier cannot be applied on this frame (whatever scale it is on, it won't affect the results)
+                * hence we shouldn't bother seeing what it would do given the chance
+                */
+               if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT)==0 || 
+                       ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime)) )
+               {
+                       /* only evaluate if there's a callback for this */
+                       if (fmi->evaluate_modifier_time) {
+                               if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) {
+                                       float influence = eval_fmodifier_influence(fcm, evaltime);
+                                       float nval = fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
+                                       
+                                       evaltime = interpf(nval, evaltime, influence);
+                               }
+                       }
                }
        }
        
        /* return the modified evaltime */
-       return m_evaltime;
+       return evaltime;
 }
 
 /* Evalautes the given set of F-Curve Modifiers using the given data
@@ -1260,11 +1312,22 @@ void evaluate_value_fmodifiers (ListBase *modifiers, FCurve *fcu, float *cvalue,
        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);
+               if (fmi == NULL) 
+                       continue;
+               
+               /* only evaluate if there's a callback for this, and if F-Modifier can be evaluated on this frame */
+               if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT)==0 || 
+                       ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime)) )
+               {
+                       if (fmi->evaluate_modifier) {
+                               if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) {
+                                       float influence = eval_fmodifier_influence(fcm, evaltime);
+                                       float nval = *cvalue;
+                                       
+                                       fmi->evaluate_modifier(fcu, fcm, &nval, evaltime);
+                                       *cvalue = interpf(nval, *cvalue, influence);
+                               }
+                       }
                }
        }
 }