NLA SoC: Separating out F-Modifier API
authorJoshua Leung <aligorith@gmail.com>
Thu, 2 Jul 2009 05:25:14 +0000 (05:25 +0000)
committerJoshua Leung <aligorith@gmail.com>
Thu, 2 Jul 2009 05:25:14 +0000 (05:25 +0000)
* F-Modifier API is now in its own file in blenkernel
* Renamed and refactored these so that they're no dependent on F-Curves, since all they really used was the fcu->modifiers list
* Added missing license blocks to a few files

12 files changed:
source/blender/blenkernel/BKE_fcurve.h
source/blender/blenkernel/intern/fcurve.c
source/blender/blenkernel/intern/fmodifier.c [new file with mode: 0644]
source/blender/blenkernel/intern/ipo.c
source/blender/blenkernel/intern/nla.c
source/blender/editors/animation/drivers.c
source/blender/editors/animation/fmodifier_ui.c
source/blender/editors/animation/keyframing.c
source/blender/editors/animation/keyingsets.c
source/blender/editors/space_graph/graph_draw.c
source/blender/editors/space_graph/graph_edit.c
source/blender/editors/space_graph/graph_utils.c

index 5c77e3c2ae4f8311208d0fa8bd48818458b3bdd2..cfc4e9077f65fbd1c5d7d97928cc1e245de38751 100644 (file)
@@ -104,15 +104,15 @@ FModifierTypeInfo *get_fmodifier_typeinfo(int type);
 
 /* ---------------------- */
 
-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);
+struct FModifier *add_fmodifier(ListBase *modifiers, int type);
+void copy_fmodifiers(ListBase *dst, ListBase *src);
+void remove_fmodifier(ListBase *modifiers, struct FModifier *fcm);
+void free_fmodifiers(ListBase *modifiers);
 
-struct FModifier *fcurve_find_active_modifier(struct FCurve *fcu);
-void fcurve_set_active_modifier(struct FCurve *fcu, struct FModifier *fcm);
+struct FModifier *find_active_fmodifier(ListBase *modifiers);
+void set_active_fmodifier(ListBase *modifiers, struct FModifier *fcm);
 
-short fcurve_has_suitable_modifier(struct FCurve *fcu, int mtype, short acttype);
+short list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype);
 
 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);
index e52c63d1b21db4b3c1d2f8f66714c8877b583b3b..4c2ba61fc71c4583a97c375e815209acf1715ca7 100644 (file)
@@ -56,7 +56,7 @@
 #include "RNA_types.h"
 
 #ifndef DISABLE_PYTHON
-#include "BPY_extern.h" /* for BPY_pydriver_eval() */
+#include "BPY_extern.h" 
 #endif
 
 #define SMALL -1.0e-10
@@ -84,7 +84,7 @@ void free_fcurve (FCurve *fcu)
        
        /* free extra data - i.e. modifiers, and driver */
        fcurve_free_driver(fcu);
-       fcurve_free_modifiers(fcu);
+       free_fmodifiers(&fcu->modifiers);
        
        /* free f-curve itself */
        MEM_freeN(fcu);
@@ -140,7 +140,7 @@ FCurve *copy_fcurve (FCurve *fcu)
        fcu_d->driver= fcurve_copy_driver(fcu_d->driver);
        
        /* copy modifiers */
-       fcurve_copy_modifiers(&fcu_d->modifiers, &fcu->modifiers);
+       copy_fmodifiers(&fcu_d->modifiers, &fcu->modifiers);
        
        /* return new data */
        return fcu_d;
@@ -1270,1135 +1270,6 @@ static float fcurve_eval_samples (FCurve *fcu, FPoint *fpts, float evaltime)
        return cvalue;
 }
 
-/* ******************************** F-Curve Modifiers ********************************* */
-
-/* Template --------------------------- */
-
-/* Each modifier defines a set of functions, which will be called at the appropriate
- * times. In addition to this, each modifier should have a type-info struct, where
- * its functions are attached for use. 
- */
-/* Template for type-info data:
- *     - make a copy of this when creating new modifiers, and just change the functions
- *       pointed to as necessary
- *     - although the naming of functions doesn't matter, it would help for code
- *       readability, to follow the same naming convention as is presented here
- *     - any functions that a constraint doesn't need to define, don't define
- *       for such cases, just use NULL 
- *     - these should be defined after all the functions have been defined, so that
- *       forward-definitions/prototypes don't need to be used!
- *     - keep this copy #if-def'd so that future constraints can get based off this
- */
-#if 0
-static FModifierTypeInfo FMI_MODNAME = {
-       FMODIFIER_TYPE_MODNAME, /* type */
-       sizeof(FMod_ModName), /* size */
-       FMI_TYPE_SOME_ACTION, /* action type */
-       FMI_REQUIRES_SOME_REQUIREMENT, /* requirements */
-       "Modifier Name", /* name */
-       "FMod_ModName", /* struct name */
-       fcm_modname_free, /* free data */
-       fcm_modname_relink, /* relink data */
-       fcm_modname_copy, /* copy data */
-       fcm_modname_new_data, /* new data */
-       fcm_modname_verify, /* verify */
-       fcm_modname_time, /* evaluate time */
-       fcm_modname_evaluate /* evaluate */
-};
-#endif
-
-/* Generator F-Curve Modifier --------------------------- */
-
-/* Generators available:
- *     1) simple polynomial generator:
- *             - Exanded form - (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n])  
- *             - Factorised form - (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1]))
- */
-
-static void fcm_generator_free (FModifier *fcm)
-{
-       FMod_Generator *data= (FMod_Generator *)fcm->data;
-       
-       /* free polynomial coefficients array */
-       if (data->coefficients)
-               MEM_freeN(data->coefficients);
-}
-
-static void fcm_generator_copy (FModifier *fcm, FModifier *src)
-{
-       FMod_Generator *gen= (FMod_Generator *)fcm->data;
-       FMod_Generator *ogen= (FMod_Generator *)src->data;
-       
-       /* copy coefficients array? */
-       if (ogen->coefficients)
-               gen->coefficients= MEM_dupallocN(ogen->coefficients);
-}
-
-static void fcm_generator_new_data (void *mdata)
-{
-       FMod_Generator *data= (FMod_Generator *)mdata;
-       float *cp;
-       
-       /* set default generator to be linear 0-1 (gradient = 1, y-offset = 0) */
-       data->poly_order= 1;
-       data->arraysize= 2;
-       cp= data->coefficients= MEM_callocN(sizeof(float)*2, "FMod_Generator_Coefs");
-       cp[0] = 0; // y-offset 
-       cp[1] = 1; // gradient
-}
-
-static void fcm_generator_verify (FModifier *fcm)
-{
-       FMod_Generator *data= (FMod_Generator *)fcm->data;
-       
-       /* requirements depend on mode */
-       switch (data->mode) {
-               case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
-               {
-                       /* arraysize needs to be order+1, so resize if not */
-                       if (data->arraysize != (data->poly_order+1)) {
-                               float *nc;
-                               
-                               /* make new coefficients array, and copy over as much data as can fit */
-                               nc= MEM_callocN(sizeof(float)*(data->poly_order+1), "FMod_Generator_Coefs");
-                               
-                               if (data->coefficients) {
-                                       if (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);
-                                               
-                                       /* free the old data */
-                                       MEM_freeN(data->coefficients);
-                               }       
-                               
-                               /* set the new data */
-                               data->coefficients= nc;
-                               data->arraysize= data->poly_order+1;
-                       }
-               }
-                       break;
-               
-               case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* expanded polynomial expression */
-               {
-                       /* arraysize needs to be 2*order, so resize if not */
-                       if (data->arraysize != (data->poly_order * 2)) {
-                               float *nc;
-                               
-                               /* make new coefficients array, and copy over as much data as can fit */
-                               nc= MEM_callocN(sizeof(float)*(data->poly_order*2), "FMod_Generator_Coefs");
-                               
-                               if (data->coefficients) {
-                                       if (data->arraysize > (data->poly_order * 2))
-                                               memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order * 2));
-                                       else
-                                               memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
-                                               
-                                       /* free the old data */
-                                       MEM_freeN(data->coefficients);
-                               }       
-                               
-                               /* set the new data */
-                               data->coefficients= nc;
-                               data->arraysize= data->poly_order * 2;
-                       }
-               }
-                       break;  
-       }
-}
-
-static void fcm_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
-       FMod_Generator *data= (FMod_Generator *)fcm->data;
-       
-       /* behaviour depends on mode 
-        * NOTE: the data in its default state is fine too
-        */
-       switch (data->mode) {
-               case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
-               {
-                       /* we overwrite cvalue with the sum of the polynomial */
-                       float *powers = MEM_callocN(sizeof(float)*data->arraysize, "Poly Powers");
-                       float value= 0.0f;
-                       unsigned int i;
-                       
-                       /* for each x^n, precalculate value based on previous one first... this should be 
-                        * faster that calling pow() for each entry
-                        */
-                       for (i=0; i < data->arraysize; i++) {
-                               /* first entry is x^0 = 1, otherwise, calculate based on previous */
-                               if (i)
-                                       powers[i]= powers[i-1] * evaltime;
-                               else
-                                       powers[0]= 1;
-                       }
-                       
-                       /* for each coefficient, add to value, which we'll write to *cvalue in one go */
-                       for (i=0; i < data->arraysize; i++)
-                               value += data->coefficients[i] * powers[i];
-                       
-                       /* only if something changed, write *cvalue in one go */
-                       if (data->poly_order) {
-                               if (data->flag & FCM_GENERATOR_ADDITIVE)
-                                       *cvalue += value;
-                               else
-                                       *cvalue= value;
-                       }
-                               
-                       /* cleanup */
-                       if (powers) 
-                               MEM_freeN(powers);
-               }
-                       break;
-                       
-               case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial */
-               {
-                       float value= 1.0f, *cp=NULL;
-                       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++) 
-                               value *= (cp[0]*evaltime + cp[1]);
-                               
-                       /* only if something changed, write *cvalue in one go */
-                       if (data->poly_order) {
-                               if (data->flag & FCM_GENERATOR_ADDITIVE)
-                                       *cvalue += value;
-                               else
-                                       *cvalue= value;
-                       }
-               }
-                       break;
-       }
-}
-
-static FModifierTypeInfo FMI_GENERATOR = {
-       FMODIFIER_TYPE_GENERATOR, /* type */
-       sizeof(FMod_Generator), /* size */
-       FMI_TYPE_GENERATE_CURVE, /* action type */
-       FMI_REQUIRES_NOTHING, /* requirements */
-       "Generator", /* name */
-       "FMod_Generator", /* struct name */
-       fcm_generator_free, /* free data */
-       fcm_generator_copy, /* copy data */
-       fcm_generator_new_data, /* new data */
-       fcm_generator_verify, /* verify */
-       NULL, /* evaluate time */
-       fcm_generator_evaluate /* evaluate */
-};
-
-/* Built-In Function Generator F-Curve Modifier --------------------------- */
-
-/* This uses the general equation for equations:
- *             y = amplitude * fn(phase_multiplier*x + phase_offset) + y_offset
- *
- * where amplitude, phase_multiplier/offset, y_offset are user-defined coefficients,
- * x is the evaluation 'time', and 'y' is the resultant value
- *
- * Functions available are
- *     sin, cos, tan, sinc (normalised sin), natural log, square root 
- */
-
-static void fcm_fn_generator_new_data (void *mdata)
-{
-       FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)mdata;
-       
-       /* set amplitude and phase multiplier to 1.0f so that something is generated */
-       data->amplitude= 1.0f;
-       data->phase_multiplier= 1.0f;
-}
-
-/* Unary 'normalised sine' function
- *     y = sin(PI + x) / (PI * x),
- * except for x = 0 when y = 1.
- */
-static double sinc (double 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)
-{
-       FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)fcm->data;
-       double arg= data->phase_multiplier*evaltime + data->phase_offset;
-       double (*fn)(double v) = NULL;
-       
-       /* get function pointer to the func to use:
-        * WARNING: must perform special argument validation hereto guard against crashes  
-        */
-       switch (data->type)
-       {
-               /* simple ones */                       
-               case FCM_GENERATOR_FN_SIN: /* sine wave */
-                       fn= sin;
-                       break;
-               case FCM_GENERATOR_FN_COS: /* cosine wave */
-                       fn= cos;
-                       break;
-               case FCM_GENERATOR_FN_SINC: /* normalised sine wave */
-                       fn= sinc;
-                       break;
-                       
-               /* validation required */
-               case FCM_GENERATOR_FN_TAN: /* tangent wave */
-               {
-                       /* check that argument is not on one of the discontinuities (i.e. 90deg, 270 deg, etc) */
-                       if IS_EQ(fmod((arg - M_PI_2), M_PI), 0.0) {
-                               if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
-                                       *cvalue = 0.0f; /* no value possible here */
-                       }
-                       else
-                               fn= tan;
-               }
-                       break;
-               case FCM_GENERATOR_FN_LN: /* natural log */
-               {
-                       /* check that value is greater than 1? */
-                       if (arg > 1.0f) {
-                               fn= log;
-                       }
-                       else {
-                               if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
-                                       *cvalue = 0.0f; /* no value possible here */
-                       }
-               }
-                       break;
-               case FCM_GENERATOR_FN_SQRT: /* square root */
-               {
-                       /* no negative numbers */
-                       if (arg > 0.0f) {
-                               fn= sqrt;
-                       }
-                       else {
-                               if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
-                                       *cvalue = 0.0f; /* no value possible here */
-                       }
-               }
-                       break;
-               
-               default:
-                       printf("Invalid Function-Generator for F-Modifier - %d \n", data->type);
-       }
-       
-       /* execute function callback to set value if appropriate */
-       if (fn) {
-               float value= (float)(data->amplitude*fn(arg) + data->value_offset);
-               
-               if (data->flag & FCM_GENERATOR_ADDITIVE)
-                       *cvalue += value;
-               else
-                       *cvalue= value;
-       }
-}
-
-static FModifierTypeInfo FMI_FN_GENERATOR = {
-       FMODIFIER_TYPE_FN_GENERATOR, /* type */
-       sizeof(FMod_FunctionGenerator), /* size */
-       FMI_TYPE_GENERATE_CURVE, /* action type */
-       FMI_REQUIRES_NOTHING, /* requirements */
-       "Built-In Function", /* name */
-       "FMod_FunctionGenerator", /* struct name */
-       NULL, /* free data */
-       NULL, /* copy data */
-       fcm_fn_generator_new_data, /* new data */
-       NULL, /* verify */
-       NULL, /* evaluate time */
-       fcm_fn_generator_evaluate /* evaluate */
-};
-
-/* Envelope F-Curve Modifier --------------------------- */
-
-static void fcm_envelope_free (FModifier *fcm)
-{
-       FMod_Envelope *env= (FMod_Envelope *)fcm->data;
-       
-       /* free envelope data array */
-       if (env->data)
-               MEM_freeN(env->data);
-}
-
-static void fcm_envelope_copy (FModifier *fcm, FModifier *src)
-{
-       FMod_Envelope *env= (FMod_Envelope *)fcm->data;
-       FMod_Envelope *oenv= (FMod_Envelope *)src->data;
-       
-       /* copy envelope data array */
-       if (oenv->data)
-               env->data= MEM_dupallocN(oenv->data);
-}
-
-static void fcm_envelope_new_data (void *mdata)
-{
-       FMod_Envelope *env= (FMod_Envelope *)mdata;
-       
-       /* set default min/max ranges */
-       env->min= -1.0f;
-       env->max= 1.0f;
-}
-
-static void fcm_envelope_verify (FModifier *fcm)
-{
-       FMod_Envelope *env= (FMod_Envelope *)fcm->data;
-       
-       /* if the are points, perform bubble-sort on them, as user may have changed the order */
-       if (env->data) {
-               // XXX todo...
-       }
-}
-
-static void fcm_envelope_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
-       FMod_Envelope *env= (FMod_Envelope *)fcm->data;
-       FCM_EnvelopeData *fed, *prevfed, *lastfed;
-       float min=0.0f, max=0.0f, fac=0.0f;
-       int a;
-       
-       /* get pointers */
-       if (env->data == NULL) return;
-       prevfed= env->data;
-       fed= prevfed + 1;
-       lastfed= prevfed + (env->totvert-1);
-       
-       /* get min/max values for envelope at evaluation time (relative to mid-value) */
-       if (prevfed->time >= evaltime) {
-               /* before or on first sample, so just extend value */
-               min= prevfed->min;
-               max= prevfed->max;
-       }
-       else if (lastfed->time <= evaltime) {
-               /* after or on last sample, so just extend value */
-               min= lastfed->min;
-               max= lastfed->max;
-       }
-       else {
-               /* evaltime occurs somewhere between segments */
-               // TODO: implement binary search for this to make it faster?
-               for (a=0; prevfed && fed && (a < env->totvert-1); a++, prevfed=fed, fed++) {  
-                       /* evaltime occurs within the interval defined by these two envelope points */
-                       if ((prevfed->time <= evaltime) && (fed->time >= evaltime)) {
-                               float afac, bfac, diff;
-                               
-                               diff= fed->time - prevfed->time;
-                               afac= (evaltime - prevfed->time) / diff;
-                               bfac= (fed->time - evaltime) / diff;
-                               
-                               min= bfac*prevfed->min + afac*fed->min;
-                               max= bfac*prevfed->max + afac*fed->max;
-                               
-                               break;
-                       }
-               }
-       }
-       
-       /* adjust *cvalue 
-        *      - fac is the ratio of how the current y-value corresponds to the reference range
-        *      - thus, the new value is found by mapping the old range to the new!
-        */
-       fac= (*cvalue - (env->midval + env->min)) / (env->max - env->min);
-       *cvalue= min + fac*(max - min); 
-}
-
-static FModifierTypeInfo FMI_ENVELOPE = {
-       FMODIFIER_TYPE_ENVELOPE, /* type */
-       sizeof(FMod_Envelope), /* size */
-       FMI_TYPE_REPLACE_VALUES, /* action type */
-       0, /* requirements */
-       "Envelope", /* name */
-       "FMod_Envelope", /* struct name */
-       fcm_envelope_free, /* free data */
-       fcm_envelope_copy, /* copy data */
-       fcm_envelope_new_data, /* new data */
-       fcm_envelope_verify, /* verify */
-       NULL, /* evaluate time */
-       fcm_envelope_evaluate /* evaluate */
-};
-
-/* Cycles F-Curve Modifier  --------------------------- */
-
-/* This modifier changes evaltime to something that exists within the curve's frame-range, 
- * then re-evaluates modifier stack up to this point using the new time. This re-entrant behaviour
- * is very likely to be more time-consuming than the original approach... (which was tighly integrated into 
- * the calculation code...).
- *
- * NOTE: this needs to be at the start of the stack to be of use, as it needs to know the extents of the keyframes/sample-data
- * Possible TODO - store length of cycle information that can be initialised from the extents of the keyframes/sample-data, and adjusted
- *                             as appropriate
- */
-
-/* temp data used during evaluation */
-typedef struct tFCMED_Cycles {
-       float cycyofs;          /* y-offset to apply */
-} tFCMED_Cycles;
-static void fcm_cycles_new_data (void *mdata)
-{
-       FMod_Cycles *data= (FMod_Cycles *)mdata;
-       
-       /* turn on cycles by default */
-       data->before_mode= data->after_mode= FCM_EXTRAPOLATE_CYCLIC;
-}
-
-static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float 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;
-       
-       /* check if modifier is first in stack, otherwise disable ourself... */
-       // FIXME...
-       if (fcm->prev) {
-               fcm->flag |= FMODIFIER_FLAG_DISABLED;
-               return evaltime;
-       }
-       
-       /* calculate new evaltime due to cyclic interpolation */
-       if (fcu && fcu->bezt) {
-               BezTriple *prevbezt= fcu->bezt;
-               BezTriple *lastbezt= prevbezt + fcu->totvert-1;
-               
-               prevkey[0]= prevbezt->vec[1][0];
-               prevkey[1]= prevbezt->vec[1][1];
-               
-               lastkey[0]= lastbezt->vec[1][0];
-               lastkey[1]= lastbezt->vec[1][1];
-       }
-       else if (fcu && fcu->fpt) {
-               FPoint *prevfpt= fcu->fpt;
-               FPoint *lastfpt= prevfpt + fcu->totvert-1;
-               
-               prevkey[0]= prevfpt->vec[0];
-               prevkey[1]= prevfpt->vec[1];
-               
-               lastkey[0]= lastfpt->vec[0];
-               lastkey[1]= lastfpt->vec[1];
-       }
-       else
-               return evaltime;
-               
-       /* check if modifier will do anything
-        *      1) if in data range, definitely don't do anything
-        *      2) if before first frame or after last frame, make sure some cycling is in use
-        */
-       if (evaltime < prevkey[0]) {
-               if (data->before_mode)  {
-                       side= -1;
-                       mode= data->before_mode;
-                       cycles= data->before_cycles;
-               }
-       }
-       else if (evaltime > lastkey[0]) {
-               if (data->after_mode) {
-                       side= 1;
-                       mode= data->after_mode;
-                       cycles= data->after_cycles;
-               }
-       }
-       if ELEM(0, side, mode)
-               return evaltime;
-               
-       /* 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];
-               
-               /* calculate period and amplitude (total height) of a cycle */
-               cycdx= lastkey[0] - prevkey[0];
-               cycdy= lastkey[1] - prevkey[1];
-               
-               /* check if cycle is infinitely small, to be point of being impossible to use */
-               if (cycdx == 0)
-                       return evaltime;
-                       
-               /* calculate the 'number' of the cycle */
-               cycle= ((float)side * (evaltime - ofs) / cycdx);
-               
-               /* check that cyclic is still enabled for the specified time */
-               if (cycles == 0) {
-                       /* catch this case so that we don't exit when we have cycles=0
-                        * as this indicates infinite cycles...
-                        */
-               }
-               else if (cycle > (cycles+1)) {
-                       /* we are too far away from range to evaluate
-                        * TODO: but we should still hold last value... 
-                        */
-                       return evaltime;
-               }
-               
-               /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */
-               if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
-                       cycyofs = (float)floor((evaltime - ofs) / cycdx);
-                       cycyofs *= cycdy;
-               }
-               
-               /* calculate where in the cycle we are (overwrite evaltime to reflect this) */
-               if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle) % 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));
-                       else
-                               evaltime= (float)(lastkey[0] - fmod(evaltime-ofs, cycdx));
-               }
-               else {
-                       /* the cycle is played normally... */
-                       evaltime= (float)(fmod(evaltime-ofs, cycdx) + ofs);
-               }
-               if (evaltime < ofs) evaltime += cycdx;
-       }
-       
-       /* store temp data if needed */
-       if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
-               tFCMED_Cycles *edata;
-               
-               /* for now, this is just a float, but we could get more stuff... */
-               fcm->edata= edata= MEM_callocN(sizeof(tFCMED_Cycles), "tFCMED_Cycles");
-               edata->cycyofs= cycyofs;
-       }
-       
-       /* return the new frame to evaluate */
-       return evaltime;
-}
-static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
-       tFCMED_Cycles *edata= (tFCMED_Cycles *)fcm->edata;
-       
-       /* use temp data */
-       if (edata) {
-               /* add cyclic offset - no need to check for now, otherwise the data wouldn't exist! */
-               *cvalue += edata->cycyofs;
-               
-               /* free temp data */
-               MEM_freeN(edata);
-               fcm->edata= NULL;
-       }
-}
-
-static FModifierTypeInfo FMI_CYCLES = {
-       FMODIFIER_TYPE_CYCLES, /* type */
-       sizeof(FMod_Cycles), /* size */
-       FMI_TYPE_EXTRAPOLATION, /* action type */
-       FMI_REQUIRES_ORIGINAL_DATA, /* requirements */
-       "Cycles", /* name */
-       "FMod_Cycles", /* struct name */
-       NULL, /* free data */
-       NULL, /* copy data */
-       fcm_cycles_new_data, /* new data */
-       NULL /*fcm_cycles_verify*/, /* verify */
-       fcm_cycles_time, /* evaluate time */
-       fcm_cycles_evaluate /* evaluate */
-};
-
-/* Noise F-Curve Modifier  --------------------------- */
-
-static void fcm_noise_new_data (void *mdata)
-{
-       FMod_Noise *data= (FMod_Noise *)mdata;
-       
-       /* defaults */
-       data->size= 1.0f;
-       data->strength= 1.0f;
-       data->phase= 1.0f;
-       data->depth = 0;
-       data->modification = FCM_NOISE_MODIF_REPLACE;
-}
-static void fcm_noise_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
-       FMod_Noise *data= (FMod_Noise *)fcm->data;
-       float noise;
-       
-       noise = BLI_turbulence(data->size, evaltime, data->phase, 0.f, data->depth);
-       
-       switch (data->modification) {
-               case FCM_NOISE_MODIF_ADD:
-                       *cvalue= *cvalue + noise * data->strength;
-                       break;
-               case FCM_NOISE_MODIF_SUBTRACT:
-                       *cvalue= *cvalue - noise * data->strength;
-                       break;
-               case FCM_NOISE_MODIF_MULTIPLY:
-                       *cvalue= *cvalue * noise * data->strength;
-                       break;
-               case FCM_NOISE_MODIF_REPLACE:
-               default:
-                       *cvalue= *cvalue + (noise - 0.5f) * data->strength;
-                       break;
-       }
-}
-
-static FModifierTypeInfo FMI_NOISE = {
-       FMODIFIER_TYPE_NOISE, /* type */
-       sizeof(FMod_Noise), /* size */
-       FMI_TYPE_REPLACE_VALUES, /* action type */
-       0, /* requirements */
-       "Noise", /* name */
-       "FMod_Noise", /* struct name */
-       NULL, /* free data */
-       NULL, /* copy data */
-       fcm_noise_new_data, /* new data */
-       NULL /*fcm_noise_verify*/, /* verify */
-       NULL, /* evaluate time */
-       fcm_noise_evaluate /* evaluate */
-};
-
-/* Filter F-Curve Modifier --------------------------- */
-
-#if 0 // XXX not yet implemented 
-static FModifierTypeInfo FMI_FILTER = {
-       FMODIFIER_TYPE_FILTER, /* type */
-       sizeof(FMod_Filter), /* size */
-       FMI_TYPE_REPLACE_VALUES, /* action type */
-       0, /* requirements */
-       "Filter", /* name */
-       "FMod_Filter", /* struct name */
-       NULL, /* free data */
-       NULL, /* copy data */
-       NULL, /* new data */
-       NULL /*fcm_filter_verify*/, /* verify */
-       NULL, /* evlauate time */
-       fcm_filter_evaluate /* evaluate */
-};
-#endif // XXX not yet implemented
-
-
-/* Python F-Curve Modifier --------------------------- */
-
-static void fcm_python_free (FModifier *fcm)
-{
-       FMod_Python *data= (FMod_Python *)fcm->data;
-       
-       /* id-properties */
-       IDP_FreeProperty(data->prop);
-       MEM_freeN(data->prop);
-}
-
-static void fcm_python_new_data (void *mdata) 
-{
-       FMod_Python *data= (FMod_Python *)mdata;
-       
-       /* everything should be set correctly by calloc, except for the prop->type constant.*/
-       data->prop = MEM_callocN(sizeof(IDProperty), "PyFModifierProps");
-       data->prop->type = IDP_GROUP;
-}
-
-static void fcm_python_copy (FModifier *fcm, FModifier *src)
-{
-       FMod_Python *pymod = (FMod_Python *)fcm->data;
-       FMod_Python *opymod = (FMod_Python *)src->data;
-       
-       pymod->prop = IDP_CopyProperty(opymod->prop);
-}
-
-static void fcm_python_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
-#ifndef DISABLE_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 */
-}
-
-static FModifierTypeInfo FMI_PYTHON = {
-       FMODIFIER_TYPE_PYTHON, /* type */
-       sizeof(FMod_Python), /* size */
-       FMI_TYPE_GENERATE_CURVE, /* action type */
-       FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
-       "Python", /* name */
-       "FMod_Python", /* struct name */
-       fcm_python_free, /* free data */
-       fcm_python_copy, /* copy data */
-       fcm_python_new_data, /* new data */
-       NULL /*fcm_python_verify*/, /* verify */
-       NULL /*fcm_python_time*/, /* evaluate time */
-       fcm_python_evaluate /* evaluate */
-};
-
-
-/* Limits F-Curve Modifier --------------------------- */
-
-static float fcm_limits_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime)
-{
-       FMod_Limits *data= (FMod_Limits *)fcm->data;
-       
-       /* check for the time limits */
-       if ((data->flag & FCM_LIMIT_XMIN) && (evaltime < data->rect.xmin))
-               return data->rect.xmin;
-       if ((data->flag & FCM_LIMIT_XMAX) && (evaltime > data->rect.xmax))
-               return data->rect.xmax;
-               
-       /* modifier doesn't change time */
-       return evaltime;
-}
-
-static void fcm_limits_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
-       FMod_Limits *data= (FMod_Limits *)fcm->data;
-       
-       /* value limits now */
-       if ((data->flag & FCM_LIMIT_YMIN) && (*cvalue < data->rect.ymin))
-               *cvalue= data->rect.ymin;
-       if ((data->flag & FCM_LIMIT_YMAX) && (*cvalue > data->rect.ymax))
-               *cvalue= data->rect.ymax;
-}
-
-static FModifierTypeInfo FMI_LIMITS = {
-       FMODIFIER_TYPE_LIMITS, /* type */
-       sizeof(FMod_Limits), /* size */
-       FMI_TYPE_GENERATE_CURVE, /* action type */  /* XXX... err... */   
-       FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
-       "Limits", /* name */
-       "FMod_Limits", /* struct name */
-       NULL, /* free data */
-       NULL, /* copy data */
-       NULL, /* new data */
-       NULL, /* verify */
-       fcm_limits_time, /* evaluate time */
-       fcm_limits_evaluate /* evaluate */
-};
-
-/* F-Curve Modifier API --------------------------- */
-/* All of the F-Curve Modifier api functions use FModifierTypeInfo structs to carry out
- * and operations that involve F-Curve modifier specific code.
- */
-
-/* These globals only ever get directly accessed in this file */
-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 () 
-{
-       fmodifiersTypeInfo[0]=  NULL;                                   /* 'Null' F-Curve Modifier */
-       fmodifiersTypeInfo[1]=  &FMI_GENERATOR;                 /* Generator F-Curve Modifier */
-       fmodifiersTypeInfo[2]=  &FMI_FN_GENERATOR;              /* Built-In Function Generator F-Curve Modifier */
-       fmodifiersTypeInfo[3]=  &FMI_ENVELOPE;                  /* Envelope F-Curve Modifier */
-       fmodifiersTypeInfo[4]=  &FMI_CYCLES;                    /* Cycles F-Curve Modifier */
-       fmodifiersTypeInfo[5]=  &FMI_NOISE;                             /* Apply-Noise F-Curve Modifier */
-       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 */
-}
-
-/* This function should be used for getting the appropriate type-info when only
- * a F-Curve modifier type is known
- */
-FModifierTypeInfo *get_fmodifier_typeinfo (int type)
-{
-       /* initialise the type-info list? */
-       if (FMI_INIT) {
-               fmods_init_typeinfo();
-               FMI_INIT = 0;
-       }
-       
-       /* only return for valid types */
-       if ( (type >= FMODIFIER_TYPE_NULL) && 
-                (type <= FMODIFIER_NUM_TYPES ) ) 
-       {
-               /* there shouldn't be any segfaults here... */
-               return fmodifiersTypeInfo[type];
-       }
-       else {
-               printf("No valid F-Curve Modifier type-info data available. Type = %i \n", type);
-       }
-       
-       return NULL;
-} 
-/* This function should always be used to get the appropriate type-info, as it
- * has checks which prevent segfaults in some weird cases.
- */
-FModifierTypeInfo *fmodifier_get_typeinfo (FModifier *fcm)
-{
-       /* only return typeinfo for valid modifiers */
-       if (fcm)
-               return get_fmodifier_typeinfo(fcm->type);
-       else
-               return NULL;
-}
-
-/* API --------------------------- */
-
-/* Add a new F-Curve Modifier to the given F-Curve of a certain type */
-FModifier *fcurve_add_modifier (FCurve *fcu, int type)
-{
-       FModifierTypeInfo *fmi= get_fmodifier_typeinfo(type);
-       FModifier *fcm;
-       
-       /* sanity checks */
-       if ELEM(NULL, fcu, fmi)
-               return NULL;
-       
-       /* special checks for whether modifier can be added */
-       if ((fcu->modifiers.first) && (type == FMODIFIER_TYPE_CYCLES)) {
-               /* cycles modifier must be first in stack, so for now, don't add if it can't be */
-               // TODO: perhaps there is some better way, but for now, 
-               printf("Error: Cannot add 'Cycles' modifier to F-Curve, as 'Cycles' modifier can only be first in stack. \n");
-               return NULL;
-       }
-       
-       /* add modifier itself */
-       fcm= MEM_callocN(sizeof(FModifier), "F-Curve Modifier");
-       fcm->type = type;
-       fcm->flag = FMODIFIER_FLAG_EXPANDED;
-       BLI_addtail(&fcu->modifiers, fcm);
-       
-       /* 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);
-               
-       /* return modifier for further editing */
-       return fcm;
-}
-
-/* Duplicate all of the F-Curve Modifiers in the Modifier stacks */
-void fcurve_copy_modifiers (ListBase *dst, ListBase *src)
-{
-       FModifier *fcm, *srcfcm;
-       
-       if ELEM(NULL, dst, src)
-               return;
-       
-       dst->first= dst->last= NULL;
-       BLI_duplicatelist(dst, src);
-       
-       for (fcm=dst->first, srcfcm=src->first; fcm && srcfcm; srcfcm=srcfcm->next, fcm=fcm->next) {
-               FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-               
-               /* make a new copy of the F-Modifier's data */
-               fcm->data = MEM_dupallocN(fcm->data);
-               
-               /* only do specific constraints if required */
-               if (fmi && fmi->copy_data)
-                       fmi->copy_data(fcm, srcfcm);
-       }
-}
-
-/* Remove and free the given F-Curve Modifier from the given F-Curve's stack  */
-void fcurve_remove_modifier (FCurve *fcu, FModifier *fcm)
-{
-       FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-       
-       /* sanity check */
-       if (fcm == NULL)
-               return;
-       
-       /* free modifier's special data (stored inside fcm->data) */
-       if (fcm->data) {
-               if (fmi && fmi->free_data)
-                       fmi->free_data(fcm);
-                       
-               /* free modifier's data (fcm->data) */
-               MEM_freeN(fcm->data);
-       }
-       
-       /* remove modifier from stack */
-       if (fcu)
-               BLI_freelinkN(&fcu->modifiers, fcm);
-       else {
-               // XXX this case can probably be removed some day, as it shouldn't happen...
-               printf("fcurve_remove_modifier() - no fcurve \n");
-               MEM_freeN(fcm);
-       }
-}
-
-/* Remove all of a given F-Curve's modifiers */
-void fcurve_free_modifiers (FCurve *fcu)
-{
-       FModifier *fcm, *fmn;
-       
-       /* sanity check */
-       if (fcu == NULL)
-               return;
-       
-       /* free each modifier in order - modifier is unlinked from list and freed */
-       for (fcm= fcu->modifiers.first; fcm; fcm= fmn) {
-               fmn= fcm->next;
-               fcurve_remove_modifier(fcu, fcm);
-       }
-}
-
-/* Find the active F-Curve Modifier */
-FModifier *fcurve_find_active_modifier (FCurve *fcu)
-{
-       FModifier *fcm;
-       
-       /* sanity checks */
-       if ELEM(NULL, fcu, fcu->modifiers.first)
-               return NULL;
-       
-       /* loop over modifiers until 'active' one is found */
-       for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {
-               if (fcm->flag & FMODIFIER_FLAG_ACTIVE)
-                       return fcm;
-       }
-       
-       /* no modifier is active */
-       return NULL;
-}
-
-/* Set the active F-Curve Modifier */
-void fcurve_set_active_modifier (FCurve *fcu, FModifier *fcm)
-{
-       FModifier *fm;
-       
-       /* sanity checks */
-       if ELEM(NULL, fcu, fcu->modifiers.first)
-               return;
-       
-       /* deactivate all, and set current one active */
-       for (fm= fcu->modifiers.first; fm; fm= fm->next)
-               fm->flag &= ~FMODIFIER_FLAG_ACTIVE;
-       
-       /* make given modifier active */
-       if (fcm)
-               fcm->flag |= FMODIFIER_FLAG_ACTIVE;
-}
-
-/* Do we have any modifiers which match certain criteria 
- *     - mtype - type of modifier (if 0, doesn't matter)
- *     - acttype - type of action to perform (if -1, doesn't matter)
- */
-short fcurve_has_suitable_modifier (FCurve *fcu, int mtype, short acttype)
-{
-       FModifier *fcm;
-       
-       /* if there are no specific filtering criteria, just skip */
-       if ((mtype == 0) && (acttype == 0))
-               return (fcu && fcu->modifiers.first);
-               
-       /* sanity checks */
-       if ELEM(NULL, fcu, fcu->modifiers.first)
-               return 0;
-               
-       /* find the first mdifier fitting these criteria */
-       for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {
-               FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-               short mOk=1, aOk=1; /* by default 1, so that when only one test, won't fail */
-               
-               /* check if applicable ones are fullfilled */
-               if (mtype)
-                       mOk= (fcm->type == mtype);
-               if (acttype > -1)
-                       aOk= (fmi->acttype == acttype);
-                       
-               /* if both are ok, we've found a hit */
-               if (mOk && aOk)
-                       return 1;
-       }
-       
-       /* no matches */
-       return 0;
-}  
-
-/* 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") 
@@ -2450,7 +1321,7 @@ void calculate_fcurve (FCurve *fcu, float ctime)
         * any data which warrants this...
         */
        if ( (fcu->totvert) || (fcu->driver && !(fcu->driver->flag & DRIVER_FLAG_INVALID)) ||
-                fcurve_has_suitable_modifier(fcu, 0, FMI_TYPE_GENERATE_CURVE) )
+                list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) )
        {
                /* calculate and set curval (evaluates driver too if necessary) */
                fcu->curval= evaluate_fcurve(fcu, ctime);
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
new file mode 100644 (file)
index 0000000..aa52149
--- /dev/null
@@ -0,0 +1,1197 @@
+/**
+ * $Id: fcurve.c 21299 2009-07-02 02:12:37Z aligorith $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ *
+ * Contributor(s): Joshua Leung (full recode)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+#include <math.h>
+#include <stdio.h>
+#include <stddef.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_arithb.h"
+#include "BLI_noise.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"
+
+#ifndef DISABLE_PYTHON
+#include "BPY_extern.h" /* for BPY_pydriver_eval() */
+#endif
+
+#define SMALL -1.0e-10
+#define SELECT 1
+
+/* ******************************** F-Modifiers ********************************* */
+
+/* Info ------------------------------- */
+
+/* F-Modifiers are modifiers which operate on F-Curves. However, they can also be defined
+ * on NLA-Strips to affect all of the F-Curves referenced by the NLA-Strip. 
+ */
+
+/* Template --------------------------- */
+
+/* Each modifier defines a set of functions, which will be called at the appropriate
+ * times. In addition to this, each modifier should have a type-info struct, where
+ * its functions are attached for use. 
+ */
+/* Template for type-info data:
+ *     - make a copy of this when creating new modifiers, and just change the functions
+ *       pointed to as necessary
+ *     - although the naming of functions doesn't matter, it would help for code
+ *       readability, to follow the same naming convention as is presented here
+ *     - any functions that a constraint doesn't need to define, don't define
+ *       for such cases, just use NULL 
+ *     - these should be defined after all the functions have been defined, so that
+ *       forward-definitions/prototypes don't need to be used!
+ *     - keep this copy #if-def'd so that future constraints can get based off this
+ */
+#if 0
+static FModifierTypeInfo FMI_MODNAME = {
+       FMODIFIER_TYPE_MODNAME, /* type */
+       sizeof(FMod_ModName), /* size */
+       FMI_TYPE_SOME_ACTION, /* action type */
+       FMI_REQUIRES_SOME_REQUIREMENT, /* requirements */
+       "Modifier Name", /* name */
+       "FMod_ModName", /* struct name */
+       fcm_modname_free, /* free data */
+       fcm_modname_relink, /* relink data */
+       fcm_modname_copy, /* copy data */
+       fcm_modname_new_data, /* new data */
+       fcm_modname_verify, /* verify */
+       fcm_modname_time, /* evaluate time */
+       fcm_modname_evaluate /* evaluate */
+};
+#endif
+
+/* Generator F-Curve Modifier --------------------------- */
+
+/* Generators available:
+ *     1) simple polynomial generator:
+ *             - Exanded form - (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n])  
+ *             - Factorised form - (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1]))
+ */
+
+static void fcm_generator_free (FModifier *fcm)
+{
+       FMod_Generator *data= (FMod_Generator *)fcm->data;
+       
+       /* free polynomial coefficients array */
+       if (data->coefficients)
+               MEM_freeN(data->coefficients);
+}
+
+static void fcm_generator_copy (FModifier *fcm, FModifier *src)
+{
+       FMod_Generator *gen= (FMod_Generator *)fcm->data;
+       FMod_Generator *ogen= (FMod_Generator *)src->data;
+       
+       /* copy coefficients array? */
+       if (ogen->coefficients)
+               gen->coefficients= MEM_dupallocN(ogen->coefficients);
+}
+
+static void fcm_generator_new_data (void *mdata)
+{
+       FMod_Generator *data= (FMod_Generator *)mdata;
+       float *cp;
+       
+       /* set default generator to be linear 0-1 (gradient = 1, y-offset = 0) */
+       data->poly_order= 1;
+       data->arraysize= 2;
+       cp= data->coefficients= MEM_callocN(sizeof(float)*2, "FMod_Generator_Coefs");
+       cp[0] = 0; // y-offset 
+       cp[1] = 1; // gradient
+}
+
+static void fcm_generator_verify (FModifier *fcm)
+{
+       FMod_Generator *data= (FMod_Generator *)fcm->data;
+       
+       /* requirements depend on mode */
+       switch (data->mode) {
+               case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
+               {
+                       /* arraysize needs to be order+1, so resize if not */
+                       if (data->arraysize != (data->poly_order+1)) {
+                               float *nc;
+                               
+                               /* make new coefficients array, and copy over as much data as can fit */
+                               nc= MEM_callocN(sizeof(float)*(data->poly_order+1), "FMod_Generator_Coefs");
+                               
+                               if (data->coefficients) {
+                                       if (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);
+                                               
+                                       /* free the old data */
+                                       MEM_freeN(data->coefficients);
+                               }       
+                               
+                               /* set the new data */
+                               data->coefficients= nc;
+                               data->arraysize= data->poly_order+1;
+                       }
+               }
+                       break;
+               
+               case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* expanded polynomial expression */
+               {
+                       /* arraysize needs to be 2*order, so resize if not */
+                       if (data->arraysize != (data->poly_order * 2)) {
+                               float *nc;
+                               
+                               /* make new coefficients array, and copy over as much data as can fit */
+                               nc= MEM_callocN(sizeof(float)*(data->poly_order*2), "FMod_Generator_Coefs");
+                               
+                               if (data->coefficients) {
+                                       if (data->arraysize > (data->poly_order * 2))
+                                               memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order * 2));
+                                       else
+                                               memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
+                                               
+                                       /* free the old data */
+                                       MEM_freeN(data->coefficients);
+                               }       
+                               
+                               /* set the new data */
+                               data->coefficients= nc;
+                               data->arraysize= data->poly_order * 2;
+                       }
+               }
+                       break;  
+       }
+}
+
+static void fcm_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+{
+       FMod_Generator *data= (FMod_Generator *)fcm->data;
+       
+       /* behaviour depends on mode 
+        * NOTE: the data in its default state is fine too
+        */
+       switch (data->mode) {
+               case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
+               {
+                       /* we overwrite cvalue with the sum of the polynomial */
+                       float *powers = MEM_callocN(sizeof(float)*data->arraysize, "Poly Powers");
+                       float value= 0.0f;
+                       unsigned int i;
+                       
+                       /* for each x^n, precalculate value based on previous one first... this should be 
+                        * faster that calling pow() for each entry
+                        */
+                       for (i=0; i < data->arraysize; i++) {
+                               /* first entry is x^0 = 1, otherwise, calculate based on previous */
+                               if (i)
+                                       powers[i]= powers[i-1] * evaltime;
+                               else
+                                       powers[0]= 1;
+                       }
+                       
+                       /* for each coefficient, add to value, which we'll write to *cvalue in one go */
+                       for (i=0; i < data->arraysize; i++)
+                               value += data->coefficients[i] * powers[i];
+                       
+                       /* only if something changed, write *cvalue in one go */
+                       if (data->poly_order) {
+                               if (data->flag & FCM_GENERATOR_ADDITIVE)
+                                       *cvalue += value;
+                               else
+                                       *cvalue= value;
+                       }
+                               
+                       /* cleanup */
+                       if (powers) 
+                               MEM_freeN(powers);
+               }
+                       break;
+                       
+               case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial */
+               {
+                       float value= 1.0f, *cp=NULL;
+                       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++) 
+                               value *= (cp[0]*evaltime + cp[1]);
+                               
+                       /* only if something changed, write *cvalue in one go */
+                       if (data->poly_order) {
+                               if (data->flag & FCM_GENERATOR_ADDITIVE)
+                                       *cvalue += value;
+                               else
+                                       *cvalue= value;
+                       }
+               }
+                       break;
+       }
+}
+
+static FModifierTypeInfo FMI_GENERATOR = {
+       FMODIFIER_TYPE_GENERATOR, /* type */
+       sizeof(FMod_Generator), /* size */
+       FMI_TYPE_GENERATE_CURVE, /* action type */
+       FMI_REQUIRES_NOTHING, /* requirements */
+       "Generator", /* name */
+       "FMod_Generator", /* struct name */
+       fcm_generator_free, /* free data */
+       fcm_generator_copy, /* copy data */
+       fcm_generator_new_data, /* new data */
+       fcm_generator_verify, /* verify */
+       NULL, /* evaluate time */
+       fcm_generator_evaluate /* evaluate */
+};
+
+/* Built-In Function Generator F-Curve Modifier --------------------------- */
+
+/* This uses the general equation for equations:
+ *             y = amplitude * fn(phase_multiplier*x + phase_offset) + y_offset
+ *
+ * where amplitude, phase_multiplier/offset, y_offset are user-defined coefficients,
+ * x is the evaluation 'time', and 'y' is the resultant value
+ *
+ * Functions available are
+ *     sin, cos, tan, sinc (normalised sin), natural log, square root 
+ */
+
+static void fcm_fn_generator_new_data (void *mdata)
+{
+       FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)mdata;
+       
+       /* set amplitude and phase multiplier to 1.0f so that something is generated */
+       data->amplitude= 1.0f;
+       data->phase_multiplier= 1.0f;
+}
+
+/* Unary 'normalised sine' function
+ *     y = sin(PI + x) / (PI * x),
+ * except for x = 0 when y = 1.
+ */
+static double sinc (double 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)
+{
+       FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)fcm->data;
+       double arg= data->phase_multiplier*evaltime + data->phase_offset;
+       double (*fn)(double v) = NULL;
+       
+       /* get function pointer to the func to use:
+        * WARNING: must perform special argument validation hereto guard against crashes  
+        */
+       switch (data->type)
+       {
+               /* simple ones */                       
+               case FCM_GENERATOR_FN_SIN: /* sine wave */
+                       fn= sin;
+                       break;
+               case FCM_GENERATOR_FN_COS: /* cosine wave */
+                       fn= cos;
+                       break;
+               case FCM_GENERATOR_FN_SINC: /* normalised sine wave */
+                       fn= sinc;
+                       break;
+                       
+               /* validation required */
+               case FCM_GENERATOR_FN_TAN: /* tangent wave */
+               {
+                       /* check that argument is not on one of the discontinuities (i.e. 90deg, 270 deg, etc) */
+                       if IS_EQ(fmod((arg - M_PI_2), M_PI), 0.0) {
+                               if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
+                                       *cvalue = 0.0f; /* no value possible here */
+                       }
+                       else
+                               fn= tan;
+               }
+                       break;
+               case FCM_GENERATOR_FN_LN: /* natural log */
+               {
+                       /* check that value is greater than 1? */
+                       if (arg > 1.0f) {
+                               fn= log;
+                       }
+                       else {
+                               if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
+                                       *cvalue = 0.0f; /* no value possible here */
+                       }
+               }
+                       break;
+               case FCM_GENERATOR_FN_SQRT: /* square root */
+               {
+                       /* no negative numbers */
+                       if (arg > 0.0f) {
+                               fn= sqrt;
+                       }
+                       else {
+                               if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
+                                       *cvalue = 0.0f; /* no value possible here */
+                       }
+               }
+                       break;
+               
+               default:
+                       printf("Invalid Function-Generator for F-Modifier - %d \n", data->type);
+       }
+       
+       /* execute function callback to set value if appropriate */
+       if (fn) {
+               float value= (float)(data->amplitude*fn(arg) + data->value_offset);
+               
+               if (data->flag & FCM_GENERATOR_ADDITIVE)
+                       *cvalue += value;
+               else
+                       *cvalue= value;
+       }
+}
+
+static FModifierTypeInfo FMI_FN_GENERATOR = {
+       FMODIFIER_TYPE_FN_GENERATOR, /* type */
+       sizeof(FMod_FunctionGenerator), /* size */
+       FMI_TYPE_GENERATE_CURVE, /* action type */
+       FMI_REQUIRES_NOTHING, /* requirements */
+       "Built-In Function", /* name */
+       "FMod_FunctionGenerator", /* struct name */
+       NULL, /* free data */
+       NULL, /* copy data */
+       fcm_fn_generator_new_data, /* new data */
+       NULL, /* verify */
+       NULL, /* evaluate time */
+       fcm_fn_generator_evaluate /* evaluate */
+};
+
+/* Envelope F-Curve Modifier --------------------------- */
+
+static void fcm_envelope_free (FModifier *fcm)
+{
+       FMod_Envelope *env= (FMod_Envelope *)fcm->data;
+       
+       /* free envelope data array */
+       if (env->data)
+               MEM_freeN(env->data);
+}
+
+static void fcm_envelope_copy (FModifier *fcm, FModifier *src)
+{
+       FMod_Envelope *env= (FMod_Envelope *)fcm->data;
+       FMod_Envelope *oenv= (FMod_Envelope *)src->data;
+       
+       /* copy envelope data array */
+       if (oenv->data)
+               env->data= MEM_dupallocN(oenv->data);
+}
+
+static void fcm_envelope_new_data (void *mdata)
+{
+       FMod_Envelope *env= (FMod_Envelope *)mdata;
+       
+       /* set default min/max ranges */
+       env->min= -1.0f;
+       env->max= 1.0f;
+}
+
+static void fcm_envelope_verify (FModifier *fcm)
+{
+       FMod_Envelope *env= (FMod_Envelope *)fcm->data;
+       
+       /* if the are points, perform bubble-sort on them, as user may have changed the order */
+       if (env->data) {
+               // XXX todo...
+       }
+}
+
+static void fcm_envelope_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+{
+       FMod_Envelope *env= (FMod_Envelope *)fcm->data;
+       FCM_EnvelopeData *fed, *prevfed, *lastfed;
+       float min=0.0f, max=0.0f, fac=0.0f;
+       int a;
+       
+       /* get pointers */
+       if (env->data == NULL) return;
+       prevfed= env->data;
+       fed= prevfed + 1;
+       lastfed= prevfed + (env->totvert-1);
+       
+       /* get min/max values for envelope at evaluation time (relative to mid-value) */
+       if (prevfed->time >= evaltime) {
+               /* before or on first sample, so just extend value */
+               min= prevfed->min;
+               max= prevfed->max;
+       }
+       else if (lastfed->time <= evaltime) {
+               /* after or on last sample, so just extend value */
+               min= lastfed->min;
+               max= lastfed->max;
+       }
+       else {
+               /* evaltime occurs somewhere between segments */
+               // TODO: implement binary search for this to make it faster?
+               for (a=0; prevfed && fed && (a < env->totvert-1); a++, prevfed=fed, fed++) {  
+                       /* evaltime occurs within the interval defined by these two envelope points */
+                       if ((prevfed->time <= evaltime) && (fed->time >= evaltime)) {
+                               float afac, bfac, diff;
+                               
+                               diff= fed->time - prevfed->time;
+                               afac= (evaltime - prevfed->time) / diff;
+                               bfac= (fed->time - evaltime) / diff;
+                               
+                               min= bfac*prevfed->min + afac*fed->min;
+                               max= bfac*prevfed->max + afac*fed->max;
+                               
+                               break;
+                       }
+               }
+       }
+       
+       /* adjust *cvalue 
+        *      - fac is the ratio of how the current y-value corresponds to the reference range
+        *      - thus, the new value is found by mapping the old range to the new!
+        */
+       fac= (*cvalue - (env->midval + env->min)) / (env->max - env->min);
+       *cvalue= min + fac*(max - min); 
+}
+
+static FModifierTypeInfo FMI_ENVELOPE = {
+       FMODIFIER_TYPE_ENVELOPE, /* type */
+       sizeof(FMod_Envelope), /* size */
+       FMI_TYPE_REPLACE_VALUES, /* action type */
+       0, /* requirements */
+       "Envelope", /* name */
+       "FMod_Envelope", /* struct name */
+       fcm_envelope_free, /* free data */
+       fcm_envelope_copy, /* copy data */
+       fcm_envelope_new_data, /* new data */
+       fcm_envelope_verify, /* verify */
+       NULL, /* evaluate time */
+       fcm_envelope_evaluate /* evaluate */
+};
+
+/* Cycles F-Curve Modifier  --------------------------- */
+
+/* This modifier changes evaltime to something that exists within the curve's frame-range, 
+ * then re-evaluates modifier stack up to this point using the new time. This re-entrant behaviour
+ * is very likely to be more time-consuming than the original approach... (which was tighly integrated into 
+ * the calculation code...).
+ *
+ * NOTE: this needs to be at the start of the stack to be of use, as it needs to know the extents of the keyframes/sample-data
+ * Possible TODO - store length of cycle information that can be initialised from the extents of the keyframes/sample-data, and adjusted
+ *                             as appropriate
+ */
+
+/* temp data used during evaluation */
+typedef struct tFCMED_Cycles {
+       float cycyofs;          /* y-offset to apply */
+} tFCMED_Cycles;
+static void fcm_cycles_new_data (void *mdata)
+{
+       FMod_Cycles *data= (FMod_Cycles *)mdata;
+       
+       /* turn on cycles by default */
+       data->before_mode= data->after_mode= FCM_EXTRAPOLATE_CYCLIC;
+}
+
+static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float 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;
+       
+       /* check if modifier is first in stack, otherwise disable ourself... */
+       // FIXME...
+       if (fcm->prev) {
+               fcm->flag |= FMODIFIER_FLAG_DISABLED;
+               return evaltime;
+       }
+       
+       /* calculate new evaltime due to cyclic interpolation */
+       if (fcu && fcu->bezt) {
+               BezTriple *prevbezt= fcu->bezt;
+               BezTriple *lastbezt= prevbezt + fcu->totvert-1;
+               
+               prevkey[0]= prevbezt->vec[1][0];
+               prevkey[1]= prevbezt->vec[1][1];
+               
+               lastkey[0]= lastbezt->vec[1][0];
+               lastkey[1]= lastbezt->vec[1][1];
+       }
+       else if (fcu && fcu->fpt) {
+               FPoint *prevfpt= fcu->fpt;
+               FPoint *lastfpt= prevfpt + fcu->totvert-1;
+               
+               prevkey[0]= prevfpt->vec[0];
+               prevkey[1]= prevfpt->vec[1];
+               
+               lastkey[0]= lastfpt->vec[0];
+               lastkey[1]= lastfpt->vec[1];
+       }
+       else
+               return evaltime;
+               
+       /* check if modifier will do anything
+        *      1) if in data range, definitely don't do anything
+        *      2) if before first frame or after last frame, make sure some cycling is in use
+        */
+       if (evaltime < prevkey[0]) {
+               if (data->before_mode)  {
+                       side= -1;
+                       mode= data->before_mode;
+                       cycles= data->before_cycles;
+               }
+       }
+       else if (evaltime > lastkey[0]) {
+               if (data->after_mode) {
+                       side= 1;
+                       mode= data->after_mode;
+                       cycles= data->after_cycles;
+               }
+       }
+       if ELEM(0, side, mode)
+               return evaltime;
+               
+       /* 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];
+               
+               /* calculate period and amplitude (total height) of a cycle */
+               cycdx= lastkey[0] - prevkey[0];
+               cycdy= lastkey[1] - prevkey[1];
+               
+               /* check if cycle is infinitely small, to be point of being impossible to use */
+               if (cycdx == 0)
+                       return evaltime;
+                       
+               /* calculate the 'number' of the cycle */
+               cycle= ((float)side * (evaltime - ofs) / cycdx);
+               
+               /* check that cyclic is still enabled for the specified time */
+               if (cycles == 0) {
+                       /* catch this case so that we don't exit when we have cycles=0
+                        * as this indicates infinite cycles...
+                        */
+               }
+               else if (cycle > (cycles+1)) {
+                       /* we are too far away from range to evaluate
+                        * TODO: but we should still hold last value... 
+                        */
+                       return evaltime;
+               }
+               
+               /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */
+               if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
+                       cycyofs = (float)floor((evaltime - ofs) / cycdx);
+                       cycyofs *= cycdy;
+               }
+               
+               /* calculate where in the cycle we are (overwrite evaltime to reflect this) */
+               if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle) % 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));
+                       else
+                               evaltime= (float)(lastkey[0] - fmod(evaltime-ofs, cycdx));
+               }
+               else {
+                       /* the cycle is played normally... */
+                       evaltime= (float)(fmod(evaltime-ofs, cycdx) + ofs);
+               }
+               if (evaltime < ofs) evaltime += cycdx;
+       }
+       
+       /* store temp data if needed */
+       if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
+               tFCMED_Cycles *edata;
+               
+               /* for now, this is just a float, but we could get more stuff... */
+               fcm->edata= edata= MEM_callocN(sizeof(tFCMED_Cycles), "tFCMED_Cycles");
+               edata->cycyofs= cycyofs;
+       }
+       
+       /* return the new frame to evaluate */
+       return evaltime;
+}
+static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+{
+       tFCMED_Cycles *edata= (tFCMED_Cycles *)fcm->edata;
+       
+       /* use temp data */
+       if (edata) {
+               /* add cyclic offset - no need to check for now, otherwise the data wouldn't exist! */
+               *cvalue += edata->cycyofs;
+               
+               /* free temp data */
+               MEM_freeN(edata);
+               fcm->edata= NULL;
+       }
+}
+
+static FModifierTypeInfo FMI_CYCLES = {
+       FMODIFIER_TYPE_CYCLES, /* type */
+       sizeof(FMod_Cycles), /* size */
+       FMI_TYPE_EXTRAPOLATION, /* action type */
+       FMI_REQUIRES_ORIGINAL_DATA, /* requirements */
+       "Cycles", /* name */
+       "FMod_Cycles", /* struct name */
+       NULL, /* free data */
+       NULL, /* copy data */
+       fcm_cycles_new_data, /* new data */
+       NULL /*fcm_cycles_verify*/, /* verify */
+       fcm_cycles_time, /* evaluate time */
+       fcm_cycles_evaluate /* evaluate */
+};
+
+/* Noise F-Curve Modifier  --------------------------- */
+
+static void fcm_noise_new_data (void *mdata)
+{
+       FMod_Noise *data= (FMod_Noise *)mdata;
+       
+       /* defaults */
+       data->size= 1.0f;
+       data->strength= 1.0f;
+       data->phase= 1.0f;
+       data->depth = 0;
+       data->modification = FCM_NOISE_MODIF_REPLACE;
+}
+static void fcm_noise_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+{
+       FMod_Noise *data= (FMod_Noise *)fcm->data;
+       float noise;
+       
+       noise = BLI_turbulence(data->size, evaltime, data->phase, 0.f, data->depth);
+       
+       switch (data->modification) {
+               case FCM_NOISE_MODIF_ADD:
+                       *cvalue= *cvalue + noise * data->strength;
+                       break;
+               case FCM_NOISE_MODIF_SUBTRACT:
+                       *cvalue= *cvalue - noise * data->strength;
+                       break;
+               case FCM_NOISE_MODIF_MULTIPLY:
+                       *cvalue= *cvalue * noise * data->strength;
+                       break;
+               case FCM_NOISE_MODIF_REPLACE:
+               default:
+                       *cvalue= *cvalue + (noise - 0.5f) * data->strength;
+                       break;
+       }
+}
+
+static FModifierTypeInfo FMI_NOISE = {
+       FMODIFIER_TYPE_NOISE, /* type */
+       sizeof(FMod_Noise), /* size */
+       FMI_TYPE_REPLACE_VALUES, /* action type */
+       0, /* requirements */
+       "Noise", /* name */
+       "FMod_Noise", /* struct name */
+       NULL, /* free data */
+       NULL, /* copy data */
+       fcm_noise_new_data, /* new data */
+       NULL /*fcm_noise_verify*/, /* verify */
+       NULL, /* evaluate time */
+       fcm_noise_evaluate /* evaluate */
+};
+
+/* Filter F-Curve Modifier --------------------------- */
+
+#if 0 // XXX not yet implemented 
+static FModifierTypeInfo FMI_FILTER = {
+       FMODIFIER_TYPE_FILTER, /* type */
+       sizeof(FMod_Filter), /* size */
+       FMI_TYPE_REPLACE_VALUES, /* action type */
+       0, /* requirements */
+       "Filter", /* name */
+       "FMod_Filter", /* struct name */
+       NULL, /* free data */
+       NULL, /* copy data */
+       NULL, /* new data */
+       NULL /*fcm_filter_verify*/, /* verify */
+       NULL, /* evlauate time */
+       fcm_filter_evaluate /* evaluate */
+};
+#endif // XXX not yet implemented
+
+
+/* Python F-Curve Modifier --------------------------- */
+
+static void fcm_python_free (FModifier *fcm)
+{
+       FMod_Python *data= (FMod_Python *)fcm->data;
+       
+       /* id-properties */
+       IDP_FreeProperty(data->prop);
+       MEM_freeN(data->prop);
+}
+
+static void fcm_python_new_data (void *mdata) 
+{
+       FMod_Python *data= (FMod_Python *)mdata;
+       
+       /* everything should be set correctly by calloc, except for the prop->type constant.*/
+       data->prop = MEM_callocN(sizeof(IDProperty), "PyFModifierProps");
+       data->prop->type = IDP_GROUP;
+}
+
+static void fcm_python_copy (FModifier *fcm, FModifier *src)
+{
+       FMod_Python *pymod = (FMod_Python *)fcm->data;
+       FMod_Python *opymod = (FMod_Python *)src->data;
+       
+       pymod->prop = IDP_CopyProperty(opymod->prop);
+}
+
+static void fcm_python_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+{
+#ifndef DISABLE_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 */
+}
+
+static FModifierTypeInfo FMI_PYTHON = {
+       FMODIFIER_TYPE_PYTHON, /* type */
+       sizeof(FMod_Python), /* size */
+       FMI_TYPE_GENERATE_CURVE, /* action type */
+       FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
+       "Python", /* name */
+       "FMod_Python", /* struct name */
+       fcm_python_free, /* free data */
+       fcm_python_copy, /* copy data */
+       fcm_python_new_data, /* new data */
+       NULL /*fcm_python_verify*/, /* verify */
+       NULL /*fcm_python_time*/, /* evaluate time */
+       fcm_python_evaluate /* evaluate */
+};
+
+
+/* Limits F-Curve Modifier --------------------------- */
+
+static float fcm_limits_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime)
+{
+       FMod_Limits *data= (FMod_Limits *)fcm->data;
+       
+       /* check for the time limits */
+       if ((data->flag & FCM_LIMIT_XMIN) && (evaltime < data->rect.xmin))
+               return data->rect.xmin;
+       if ((data->flag & FCM_LIMIT_XMAX) && (evaltime > data->rect.xmax))
+               return data->rect.xmax;
+               
+       /* modifier doesn't change time */
+       return evaltime;
+}
+
+static void fcm_limits_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+{
+       FMod_Limits *data= (FMod_Limits *)fcm->data;
+       
+       /* value limits now */
+       if ((data->flag & FCM_LIMIT_YMIN) && (*cvalue < data->rect.ymin))
+               *cvalue= data->rect.ymin;
+       if ((data->flag & FCM_LIMIT_YMAX) && (*cvalue > data->rect.ymax))
+               *cvalue= data->rect.ymax;
+}
+
+static FModifierTypeInfo FMI_LIMITS = {
+       FMODIFIER_TYPE_LIMITS, /* type */
+       sizeof(FMod_Limits), /* size */
+       FMI_TYPE_GENERATE_CURVE, /* action type */  /* XXX... err... */   
+       FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
+       "Limits", /* name */
+       "FMod_Limits", /* struct name */
+       NULL, /* free data */
+       NULL, /* copy data */
+       NULL, /* new data */
+       NULL, /* verify */
+       fcm_limits_time, /* evaluate time */
+       fcm_limits_evaluate /* evaluate */
+};
+
+/* F-Curve Modifier API --------------------------- */
+/* All of the F-Curve Modifier api functions use FModifierTypeInfo structs to carry out
+ * and operations that involve F-Curve modifier specific code.
+ */
+
+/* These globals only ever get directly accessed in this file */
+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 () 
+{
+       fmodifiersTypeInfo[0]=  NULL;                                   /* 'Null' F-Curve Modifier */
+       fmodifiersTypeInfo[1]=  &FMI_GENERATOR;                 /* Generator F-Curve Modifier */
+       fmodifiersTypeInfo[2]=  &FMI_FN_GENERATOR;              /* Built-In Function Generator F-Curve Modifier */
+       fmodifiersTypeInfo[3]=  &FMI_ENVELOPE;                  /* Envelope F-Curve Modifier */
+       fmodifiersTypeInfo[4]=  &FMI_CYCLES;                    /* Cycles F-Curve Modifier */
+       fmodifiersTypeInfo[5]=  &FMI_NOISE;                             /* Apply-Noise F-Curve Modifier */
+       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 */
+}
+
+/* This function should be used for getting the appropriate type-info when only
+ * a F-Curve modifier type is known
+ */
+FModifierTypeInfo *get_fmodifier_typeinfo (int type)
+{
+       /* initialise the type-info list? */
+       if (FMI_INIT) {
+               fmods_init_typeinfo();
+               FMI_INIT = 0;
+       }
+       
+       /* only return for valid types */
+       if ( (type >= FMODIFIER_TYPE_NULL) && 
+                (type <= FMODIFIER_NUM_TYPES ) ) 
+       {
+               /* there shouldn't be any segfaults here... */
+               return fmodifiersTypeInfo[type];
+       }
+       else {
+               printf("No valid F-Curve Modifier type-info data available. Type = %i \n", type);
+       }
+       
+       return NULL;
+} 
+/* This function should always be used to get the appropriate type-info, as it
+ * has checks which prevent segfaults in some weird cases.
+ */
+FModifierTypeInfo *fmodifier_get_typeinfo (FModifier *fcm)
+{
+       /* only return typeinfo for valid modifiers */
+       if (fcm)
+               return get_fmodifier_typeinfo(fcm->type);
+       else
+               return NULL;
+}
+
+/* API --------------------------- */
+
+/* Add a new F-Curve Modifier to the given F-Curve of a certain type */
+FModifier *add_fmodifier (ListBase *modifiers, int type)
+{
+       FModifierTypeInfo *fmi= get_fmodifier_typeinfo(type);
+       FModifier *fcm;
+       
+       /* sanity checks */
+       if ELEM(NULL, modifiers, fmi)
+               return NULL;
+       
+       /* special checks for whether modifier can be added */
+       if ((modifiers->first) && (type == FMODIFIER_TYPE_CYCLES)) {
+               /* cycles modifier must be first in stack, so for now, don't add if it can't be */
+               // TODO: perhaps there is some better way, but for now, 
+               printf("Error: Cannot add 'Cycles' modifier to F-Curve, as 'Cycles' modifier can only be first in stack. \n");
+               return NULL;
+       }
+       
+       /* add modifier itself */
+       fcm= MEM_callocN(sizeof(FModifier), "F-Curve Modifier");
+       fcm->type = type;
+       fcm->flag = FMODIFIER_FLAG_EXPANDED;
+       BLI_addtail(modifiers, fcm);
+       
+       /* 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);
+               
+       /* return modifier for further editing */
+       return fcm;
+}
+
+/* Duplicate all of the F-Modifiers in the Modifier stacks */
+void copy_fmodifiers (ListBase *dst, ListBase *src)
+{
+       FModifier *fcm, *srcfcm;
+       
+       if ELEM(NULL, dst, src)
+               return;
+       
+       dst->first= dst->last= NULL;
+       BLI_duplicatelist(dst, src);
+       
+       for (fcm=dst->first, srcfcm=src->first; fcm && srcfcm; srcfcm=srcfcm->next, fcm=fcm->next) {
+               FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
+               
+               /* make a new copy of the F-Modifier's data */
+               fcm->data = MEM_dupallocN(fcm->data);
+               
+               /* only do specific constraints if required */
+               if (fmi && fmi->copy_data)
+                       fmi->copy_data(fcm, srcfcm);
+       }
+}
+
+/* Remove and free the given F-Modifier from the given stack  */
+void remove_fmodifier (ListBase *modifiers, FModifier *fcm)
+{
+       FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
+       
+       /* sanity check */
+       if (fcm == NULL)
+               return;
+       
+       /* free modifier's special data (stored inside fcm->data) */
+       if (fcm->data) {
+               if (fmi && fmi->free_data)
+                       fmi->free_data(fcm);
+                       
+               /* free modifier's data (fcm->data) */
+               MEM_freeN(fcm->data);
+       }
+       
+       /* remove modifier from stack */
+       if (modifiers)
+               BLI_freelinkN(modifiers, fcm);
+       else {
+               // XXX this case can probably be removed some day, as it shouldn't happen...
+               printf("remove_fmodifier() - no modifier stack given \n");
+               MEM_freeN(fcm);
+       }
+}
+
+/* Remove all of a given F-Curve's modifiers */
+void free_fmodifiers (ListBase *modifiers)
+{
+       FModifier *fcm, *fmn;
+       
+       /* sanity check */
+       if (modifiers == NULL)
+               return;
+       
+       /* free each modifier in order - modifier is unlinked from list and freed */
+       for (fcm= modifiers->first; fcm; fcm= fmn) {
+               fmn= fcm->next;
+               remove_fmodifier(modifiers, fcm);
+       }
+}
+
+/* Find the active F-Modifier */
+FModifier *find_active_fmodifier (ListBase *modifiers)
+{
+       FModifier *fcm;
+       
+       /* sanity checks */
+       if ELEM(NULL, modifiers, modifiers->first)
+               return NULL;
+       
+       /* loop over modifiers until 'active' one is found */
+       for (fcm= modifiers->first; fcm; fcm= fcm->next) {
+               if (fcm->flag & FMODIFIER_FLAG_ACTIVE)
+                       return fcm;
+       }
+       
+       /* no modifier is active */
+       return NULL;
+}
+
+/* Set the active F-Modifier */
+void set_active_fmodifier (ListBase *modifiers, FModifier *fcm)
+{
+       FModifier *fm;
+       
+       /* sanity checks */
+       if ELEM(NULL, modifiers, modifiers->first)
+               return;
+       
+       /* deactivate all, and set current one active */
+       for (fm= modifiers->first; fm; fm= fm->next)
+               fm->flag &= ~FMODIFIER_FLAG_ACTIVE;
+       
+       /* make given modifier active */
+       if (fcm)
+               fcm->flag |= FMODIFIER_FLAG_ACTIVE;
+}
+
+/* Do we have any modifiers which match certain criteria 
+ *     - mtype - type of modifier (if 0, doesn't matter)
+ *     - acttype - type of action to perform (if -1, doesn't matter)
+ */
+short list_has_suitable_fmodifier (ListBase *modifiers, int mtype, short acttype)
+{
+       FModifier *fcm;
+       
+       /* if there are no specific filtering criteria, just skip */
+       if ((mtype == 0) && (acttype == 0))
+               return (modifiers && modifiers->first);
+               
+       /* sanity checks */
+       if ELEM(NULL, modifiers, modifiers->first)
+               return 0;
+               
+       /* find the first mdifier fitting these criteria */
+       for (fcm= modifiers->first; fcm; fcm= fcm->next) {
+               FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
+               short mOk=1, aOk=1; /* by default 1, so that when only one test, won't fail */
+               
+               /* check if applicable ones are fullfilled */
+               if (mtype)
+                       mOk= (fcm->type == mtype);
+               if (acttype > -1)
+                       aOk= (fmi->acttype == acttype);
+                       
+               /* if both are ok, we've found a hit */
+               if (mOk && aOk)
+                       return 1;
+       }
+       
+       /* no matches */
+       return 0;
+}  
+
+/* 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->last)
+               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= 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 */
+       free_fmodifiers(&fcu->modifiers);
+       
+       /* restore driver */
+       fcu->driver= driver;
+}
index 968a0e68fb9276bbfc884c30cb110339ae85d46d..c3c5483574e38d8cdd14ff50575c62e71c036379 100644 (file)
@@ -1153,7 +1153,7 @@ static void icu_to_fcurves (ListBase *groups, ListBase *list, IpoCurve *icu, cha
                        /* Add a new FModifier (Cyclic) instead of setting extend value 
                         * as that's the new equivilant of that option. 
                         */
-                       FModifier *fcm= fcurve_add_modifier(fcu, FMODIFIER_TYPE_CYCLES);
+                       FModifier *fcm= add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES);
                        FMod_Cycles *data= (FMod_Cycles *)fcm->data;
                        
                        /* if 'offset' one is in use, set appropriate settings */
index 2b95584dc25d93dfef0b09836472fea513bbd7d0..14e658b3903aa4d10b5c3f356128e8a2dc72ef0a 100644 (file)
@@ -69,8 +69,6 @@
 // TODO: with things like transitions, should these get freed too? Maybe better as a UI tool
 void free_nlastrip (ListBase *strips, NlaStrip *strip)
 {
-       FModifier *fcm, *fmn;
-       
        /* sanity checks */
        if (strip == NULL)
                return;
@@ -86,13 +84,8 @@ void free_nlastrip (ListBase *strips, NlaStrip *strip)
        /* free own F-Curves */
        free_fcurves(&strip->fcurves);
        
-       /* free F-Modifiers */
-       for (fcm= strip->modifiers.first; fcm; fcm= fmn) {
-               fmn= fcm->next;
-               
-               BLI_remlink(&strip->modifiers, fcm);
-               fcurve_remove_modifier(NULL, fcm);
-       }
+       /* free own F-Modifiers */
+       free_fmodifiers(&strip->modifiers);
        
        /* free the strip itself */
        if (strips)
@@ -167,7 +160,7 @@ NlaStrip *copy_nlastrip (NlaStrip *strip)
                
        /* copy F-Curves and modifiers */
        copy_fcurves(&strip_d->fcurves, &strip->fcurves);
-       fcurve_copy_modifiers(&strip_d->modifiers, &strip->modifiers);
+       copy_fmodifiers(&strip_d->modifiers, &strip->modifiers);
        
        /* return the strip */
        return strip_d;
index 9c40128901142dc3a5ace70a4e7aad5163f1bf3d..fdce0965ce3e5c30856d497cef0aead8dacae13b 100644 (file)
@@ -1,5 +1,30 @@
-/* Testing code for 2.5 animation system 
- * Copyright 2009, Joshua Leung
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joshua Leung (full recode)
+ *
+ * ***** END GPL LICENSE BLOCK *****
  */
  
 #include <stdio.h>
@@ -94,7 +119,7 @@ FCurve *verify_driver_fcurve (ID *id, const char rna_path[], const int array_ind
                fcu->driver= MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
                
                /* add simple generator modifier for driver so that there is some visible representation */
-               fcurve_add_modifier(fcu, FMODIFIER_TYPE_GENERATOR);
+               add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR);
                
                /* just add F-Curve to end of driver list */
                BLI_addtail(&adt->drivers, fcu);
index 5968817a9a660fa8aba65b3cc370c8fc4e0a81b8..b5a998772472027d8ede1a5cdc95a4dad6bb9d22 100644 (file)
@@ -112,23 +112,23 @@ static void validate_fmodifier_cb (bContext *C, void *fcm_v, void *dummy)
 }
 
 /* callback to set the active modifier */
-static void activate_fmodifier_cb (bContext *C, void *fcu_v, void *fcm_v)
+static void activate_fmodifier_cb (bContext *C, void *fmods_v, void *fcm_v)
 {
-       FCurve *fcu= (FCurve *)fcu_v;
+       ListBase *modifiers = (ListBase *)fmods_v;
        FModifier *fcm= (FModifier *)fcm_v;
        
-       /* call API function to set the active modifier for active F-Curve */
-       fcurve_set_active_modifier(fcu, fcm);
+       /* call API function to set the active modifier for active modifier-stack */
+       set_active_fmodifier(modifiers, fcm);
 }
 
 /* callback to remove the given modifier  */
-static void delete_fmodifier_cb (bContext *C, void *fcu_v, void *fcm_v)
+static void delete_fmodifier_cb (bContext *C, void *fmods_v, void *fcm_v)
 {
-       FCurve *fcu= (FCurve *)fcu_v;
+       ListBase *modifiers = (ListBase *)fmods_v;
        FModifier *fcm= (FModifier *)fcm_v;
        
-       /* remove the given F-Modifier from the F-Curve */
-       fcurve_remove_modifier(fcu, fcm);
+       /* remove the given F-Modifier from the active modifier-stack */
+       remove_fmodifier(modifiers, fcm);
 }
 
 /* --------------- */
@@ -588,6 +588,7 @@ static void draw_modifier__limits(uiBlock *block, FModifier *fcm, int *yco, shor
 void ANIM_uiTemplate_fmodifier_draw (uiBlock *block, FCurve *fcu, FModifier *fcm, int *yco)
 {
        FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
+       ListBase *modifiers= &fcu->modifiers; // XXX fixme... should be arg
        uiBut *but;
        short active= (fcm->flag & FMODIFIER_FLAG_ACTIVE);
        short width= 314;
@@ -607,7 +608,7 @@ void ANIM_uiTemplate_fmodifier_draw (uiBlock *block, FCurve *fcu, FModifier *fcm
                
                /* checkbox for 'active' status (for now) */
                but= uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_ACTIVE, B_REDR, ICON_RADIOBUT_OFF, 25, *yco-1, 20, 20, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is active one.");
-               uiButSetFunc(but, activate_fmodifier_cb, fcu, fcm);
+               uiButSetFunc(but, activate_fmodifier_cb, modifiers, fcm);
                
                /* name */
                if (fmi)
@@ -620,7 +621,7 @@ void ANIM_uiTemplate_fmodifier_draw (uiBlock *block, FCurve *fcu, FModifier *fcm
                
                /* delete button */
                but= uiDefIconBut(block, BUT, B_REDR, ICON_X, 10+(width-30), *yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Delete F-Curve Modifier.");
-               uiButSetFunc(but, delete_fmodifier_cb, fcu, fcm);
+               uiButSetFunc(but, delete_fmodifier_cb, modifiers, fcm);
                
                uiBlockSetEmboss(block, UI_EMBOSS);
        }
index 908040523701afc76080d0b6cc3016af91ba810a..331e2d0894e70e86f46c03fe7017558db0608216 100644 (file)
@@ -1,5 +1,30 @@
-/* Testing code for 2.5 animation system 
- * Copyright 2009, Joshua Leung
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joshua Leung (full recode)
+ *
+ * ***** END GPL LICENSE BLOCK *****
  */
  
 #include <stdio.h>
index 1813c76d0c4053c0cdd91a11462dcd8e43a77a87..240089d26a62dd7b1d6c78772746c62e6f06b7b9 100644 (file)
@@ -1,5 +1,30 @@
-/* Testing code for 2.5 animation system 
- * Copyright 2009, Joshua Leung
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joshua Leung (full recode)
+ *
+ * ***** END GPL LICENSE BLOCK *****
  */
  
 #include <stdio.h>
index 66168f2ed8744aae6e1d48f087db6badef452bd5..0d7dafe29387c6f941e85e56546823828867fa8b 100644 (file)
@@ -795,7 +795,7 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGri
         */
        for (ale=anim_data.first; ale; ale=ale->next) {
                FCurve *fcu= (FCurve *)ale->key_data;
-               FModifier *fcm= fcurve_find_active_modifier(fcu);
+               FModifier *fcm= find_active_fmodifier(&fcu->modifiers);
                AnimData *adt= ANIM_nla_mapping_get(ac, ale);
                
                /* map keyframes for drawing if scaled F-Curve */
index ca47e69cc7588e88cc14c06a018edb5b1e398013..a82699ac1e5d0721daf4c37c5795e26ef3738ed5 100644 (file)
@@ -1769,9 +1769,9 @@ static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
        type= RNA_enum_get(op->ptr, "type");
        
        /* add F-Modifier of specified type to active F-Curve, and make it the active one */
-       fcm= fcurve_add_modifier(fcu, type);
+       fcm= add_fmodifier(&fcu->modifiers, type);
        if (fcm)
-               fcurve_set_active_modifier(fcu, fcm);
+               set_active_fmodifier(&fcu->modifiers, fcm);
        else {
                BKE_report(op->reports, RPT_ERROR, "Modifier couldn't be added. See console for details.");
                return OPERATOR_CANCELLED;
index b1ec795a08942987a2248eee4d56cbff7427e4d6..f00e7845549bb1d095efd35aef08643c313d8d5a 100644 (file)
@@ -194,7 +194,7 @@ int graphop_visible_keyframes_poll (bContext *C)
                 */
                if (fcu->bezt == NULL)
                        continue;
-               fcm= fcurve_find_active_modifier(fcu);
+               fcm= find_active_fmodifier(&fcu->modifiers);
                
                found= (fcurve_needs_draw_fmodifier_controls(fcu, fcm) == 0);
                if (found) break;
@@ -244,7 +244,7 @@ int graphop_editable_keyframes_poll (bContext *C)
                 */
                if (fcu->bezt == NULL)
                        continue;
-               fcm= fcurve_find_active_modifier(fcu);
+               fcm= find_active_fmodifier(&fcu->modifiers);
                
                found= (fcurve_needs_draw_fmodifier_controls(fcu, fcm) == 0);
                if (found) break;