Blender V2.61 - r43446

fmodifier.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
00019  * All rights reserved.
00020  *
00021  * Contributor(s): Joshua Leung (full recode)
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  */
00025 
00032 #include <math.h>
00033 #include <stdio.h>
00034 #include <stddef.h>
00035 #include <string.h>
00036 #include <float.h>
00037 
00038 #include "MEM_guardedalloc.h"
00039 
00040 #include "DNA_anim_types.h"
00041 
00042 #include "BLI_blenlib.h"
00043 #include "BLI_math.h" /* windows needs for M_PI */
00044 #include "BLI_utildefines.h"
00045 
00046 #include "BKE_fcurve.h"
00047 #include "BKE_idprop.h"
00048 
00049 
00050 #define SMALL -1.0e-10
00051 #define SELECT 1
00052 
00053 /* ******************************** F-Modifiers ********************************* */
00054 
00055 /* Info ------------------------------- */
00056 
00057 /* F-Modifiers are modifiers which operate on F-Curves. However, they can also be defined
00058  * on NLA-Strips to affect all of the F-Curves referenced by the NLA-Strip. 
00059  */
00060 
00061 /* Template --------------------------- */
00062 
00063 /* Each modifier defines a set of functions, which will be called at the appropriate
00064  * times. In addition to this, each modifier should have a type-info struct, where
00065  * its functions are attached for use. 
00066  */
00067  
00068 /* Template for type-info data:
00069  *  - make a copy of this when creating new modifiers, and just change the functions
00070  *    pointed to as necessary
00071  *  - although the naming of functions doesn't matter, it would help for code
00072  *    readability, to follow the same naming convention as is presented here
00073  *  - any functions that a constraint doesn't need to define, don't define
00074  *    for such cases, just use NULL 
00075  *  - these should be defined after all the functions have been defined, so that
00076  *    forward-definitions/prototypes don't need to be used!
00077  *  - keep this copy #if-def'd so that future constraints can get based off this
00078  */
00079 #if 0
00080 static FModifierTypeInfo FMI_MODNAME = {
00081     FMODIFIER_TYPE_MODNAME, /* type */
00082     sizeof(FMod_ModName), /* size */
00083     FMI_TYPE_SOME_ACTION, /* action type */
00084     FMI_REQUIRES_SOME_REQUIREMENT, /* requirements */
00085     "Modifier Name", /* name */
00086     "FMod_ModName", /* struct name */
00087     fcm_modname_free, /* free data */
00088     fcm_modname_relink, /* relink data */
00089     fcm_modname_copy, /* copy data */
00090     fcm_modname_new_data, /* new data */
00091     fcm_modname_verify, /* verify */
00092     fcm_modname_time, /* evaluate time */
00093     fcm_modname_evaluate /* evaluate */
00094 };
00095 #endif
00096 
00097 /* Generator F-Curve Modifier --------------------------- */
00098 
00099 /* Generators available:
00100  *  1) simple polynomial generator:
00101  *      - Exanded form - (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n])  
00102  *      - Factorised form - (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1]))
00103  */
00104 
00105 static void fcm_generator_free (FModifier *fcm)
00106 {
00107     FMod_Generator *data= (FMod_Generator *)fcm->data;
00108     
00109     /* free polynomial coefficients array */
00110     if (data->coefficients)
00111         MEM_freeN(data->coefficients);
00112 }
00113 
00114 static void fcm_generator_copy (FModifier *fcm, FModifier *src)
00115 {
00116     FMod_Generator *gen= (FMod_Generator *)fcm->data;
00117     FMod_Generator *ogen= (FMod_Generator *)src->data;
00118     
00119     /* copy coefficients array? */
00120     if (ogen->coefficients)
00121         gen->coefficients= MEM_dupallocN(ogen->coefficients);
00122 }
00123 
00124 static void fcm_generator_new_data (void *mdata)
00125 {
00126     FMod_Generator *data= (FMod_Generator *)mdata;
00127     float *cp;
00128     
00129     /* set default generator to be linear 0-1 (gradient = 1, y-offset = 0) */
00130     data->poly_order= 1;
00131     data->arraysize= 2;
00132     cp= data->coefficients= MEM_callocN(sizeof(float)*2, "FMod_Generator_Coefs");
00133     cp[0] = 0; // y-offset 
00134     cp[1] = 1; // gradient
00135 }
00136 
00137 static void fcm_generator_verify (FModifier *fcm)
00138 {
00139     FMod_Generator *data= (FMod_Generator *)fcm->data;
00140     
00141     /* requirements depend on mode */
00142     switch (data->mode) {
00143         case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
00144         {
00145             /* arraysize needs to be order+1, so resize if not */
00146             if (data->arraysize != (data->poly_order+1)) {
00147                 float *nc;
00148                 
00149                 /* make new coefficients array, and copy over as much data as can fit */
00150                 nc= MEM_callocN(sizeof(float)*(data->poly_order+1), "FMod_Generator_Coefs");
00151                 
00152                 if (data->coefficients) {
00153                     if ((int)data->arraysize > (data->poly_order+1))
00154                         memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order+1));
00155                     else
00156                         memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
00157                         
00158                     /* free the old data */
00159                     MEM_freeN(data->coefficients);
00160                 }   
00161                 
00162                 /* set the new data */
00163                 data->coefficients= nc;
00164                 data->arraysize= data->poly_order+1;
00165             }
00166         }
00167             break;
00168         
00169         case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* expanded polynomial expression */
00170         {
00171             /* arraysize needs to be 2*order, so resize if not */
00172             if (data->arraysize != (data->poly_order * 2)) {
00173                 float *nc;
00174                 
00175                 /* make new coefficients array, and copy over as much data as can fit */
00176                 nc= MEM_callocN(sizeof(float)*(data->poly_order*2), "FMod_Generator_Coefs");
00177                 
00178                 if (data->coefficients) {
00179                     if (data->arraysize > (unsigned int)(data->poly_order * 2))
00180                         memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order * 2));
00181                     else
00182                         memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
00183                         
00184                     /* free the old data */
00185                     MEM_freeN(data->coefficients);
00186                 }   
00187                 
00188                 /* set the new data */
00189                 data->coefficients= nc;
00190                 data->arraysize= data->poly_order * 2;
00191             }
00192         }
00193             break;  
00194     }
00195 }
00196 
00197 static void fcm_generator_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
00198 {
00199     FMod_Generator *data= (FMod_Generator *)fcm->data;
00200     
00201     /* behaviour depends on mode 
00202      * NOTE: the data in its default state is fine too
00203      */
00204     switch (data->mode) {
00205         case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
00206         {
00207             /* we overwrite cvalue with the sum of the polynomial */
00208             float *powers = MEM_callocN(sizeof(float)*data->arraysize, "Poly Powers");
00209             float value= 0.0f;
00210             unsigned int i;
00211             
00212             /* for each x^n, precalculate value based on previous one first... this should be 
00213              * faster that calling pow() for each entry
00214              */
00215             for (i=0; i < data->arraysize; i++) {
00216                 /* first entry is x^0 = 1, otherwise, calculate based on previous */
00217                 if (i)
00218                     powers[i]= powers[i-1] * evaltime;
00219                 else
00220                     powers[0]= 1;
00221             }
00222             
00223             /* for each coefficient, add to value, which we'll write to *cvalue in one go */
00224             for (i=0; i < data->arraysize; i++)
00225                 value += data->coefficients[i] * powers[i];
00226             
00227             /* only if something changed, write *cvalue in one go */
00228             if (data->poly_order) {
00229                 if (data->flag & FCM_GENERATOR_ADDITIVE)
00230                     *cvalue += value;
00231                 else
00232                     *cvalue= value;
00233             }
00234                 
00235             /* cleanup */
00236             if (powers) 
00237                 MEM_freeN(powers);
00238         }
00239             break;
00240             
00241         case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial */
00242         {
00243             float value= 1.0f, *cp=NULL;
00244             unsigned int i;
00245             
00246             /* for each coefficient pair, solve for that bracket before accumulating in value by multiplying */
00247             for (cp=data->coefficients, i=0; (cp) && (i < (unsigned int)data->poly_order); cp+=2, i++) 
00248                 value *= (cp[0]*evaltime + cp[1]);
00249                 
00250             /* only if something changed, write *cvalue in one go */
00251             if (data->poly_order) {
00252                 if (data->flag & FCM_GENERATOR_ADDITIVE)
00253                     *cvalue += value;
00254                 else
00255                     *cvalue= value;
00256             }
00257         }
00258             break;
00259     }
00260 }
00261 
00262 static FModifierTypeInfo FMI_GENERATOR = {
00263     FMODIFIER_TYPE_GENERATOR, /* type */
00264     sizeof(FMod_Generator), /* size */
00265     FMI_TYPE_GENERATE_CURVE, /* action type */
00266     FMI_REQUIRES_NOTHING, /* requirements */
00267     "Generator", /* name */
00268     "FMod_Generator", /* struct name */
00269     fcm_generator_free, /* free data */
00270     fcm_generator_copy, /* copy data */
00271     fcm_generator_new_data, /* new data */
00272     fcm_generator_verify, /* verify */
00273     NULL, /* evaluate time */
00274     fcm_generator_evaluate /* evaluate */
00275 };
00276 
00277 /* Built-In Function Generator F-Curve Modifier --------------------------- */
00278 
00279 /* This uses the general equation for equations:
00280  *      y = amplitude * fn(phase_multiplier*x + phase_offset) + y_offset
00281  *
00282  * where amplitude, phase_multiplier/offset, y_offset are user-defined coefficients,
00283  * x is the evaluation 'time', and 'y' is the resultant value
00284  *
00285  * Functions available are
00286  *  sin, cos, tan, sinc (normalised sin), natural log, square root 
00287  */
00288 
00289 static void fcm_fn_generator_new_data (void *mdata)
00290 {
00291     FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)mdata;
00292     
00293     /* set amplitude and phase multiplier to 1.0f so that something is generated */
00294     data->amplitude= 1.0f;
00295     data->phase_multiplier= 1.0f;
00296 }
00297 
00298 /* Unary 'normalised sine' function
00299  *  y = sin(PI + x) / (PI * x),
00300  * except for x = 0 when y = 1.
00301  */
00302 static double sinc (double x)
00303 {
00304     if (fabs(x) < 0.0001)
00305         return 1.0;
00306     else
00307         return sin(M_PI * x) / (M_PI * x);
00308 }
00309 
00310 static void fcm_fn_generator_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
00311 {
00312     FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)fcm->data;
00313     double arg= data->phase_multiplier*evaltime + data->phase_offset;
00314     double (*fn)(double v) = NULL;
00315     
00316     /* get function pointer to the func to use:
00317      * WARNING: must perform special argument validation hereto guard against crashes  
00318      */
00319     switch (data->type)
00320     {
00321         /* simple ones */           
00322         case FCM_GENERATOR_FN_SIN: /* sine wave */
00323             fn= sin;
00324             break;
00325         case FCM_GENERATOR_FN_COS: /* cosine wave */
00326             fn= cos;
00327             break;
00328         case FCM_GENERATOR_FN_SINC: /* normalised sine wave */
00329             fn= sinc;
00330             break;
00331             
00332         /* validation required */
00333         case FCM_GENERATOR_FN_TAN: /* tangent wave */
00334         {
00335             /* check that argument is not on one of the discontinuities (i.e. 90deg, 270 deg, etc) */
00336             if IS_EQ(fmod((arg - M_PI_2), M_PI), 0.0) {
00337                 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
00338                     *cvalue = 0.0f; /* no value possible here */
00339             }
00340             else
00341                 fn= tan;
00342         }
00343             break;
00344         case FCM_GENERATOR_FN_LN: /* natural log */
00345         {
00346             /* check that value is greater than 1? */
00347             if (arg > 1.0) {
00348                 fn= log;
00349             }
00350             else {
00351                 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
00352                     *cvalue = 0.0f; /* no value possible here */
00353             }
00354         }
00355             break;
00356         case FCM_GENERATOR_FN_SQRT: /* square root */
00357         {
00358             /* no negative numbers */
00359             if (arg > 0.0) {
00360                 fn= sqrt;
00361             }
00362             else {
00363                 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
00364                     *cvalue = 0.0f; /* no value possible here */
00365             }
00366         }
00367             break;
00368         
00369         default:
00370             printf("Invalid Function-Generator for F-Modifier - %d \n", data->type);
00371     }
00372     
00373     /* execute function callback to set value if appropriate */
00374     if (fn) {
00375         float value= (float)(data->amplitude*(float)fn(arg) + data->value_offset);
00376         
00377         if (data->flag & FCM_GENERATOR_ADDITIVE)
00378             *cvalue += value;
00379         else
00380             *cvalue= value;
00381     }
00382 }
00383 
00384 static FModifierTypeInfo FMI_FN_GENERATOR = {
00385     FMODIFIER_TYPE_FN_GENERATOR, /* type */
00386     sizeof(FMod_FunctionGenerator), /* size */
00387     FMI_TYPE_GENERATE_CURVE, /* action type */
00388     FMI_REQUIRES_NOTHING, /* requirements */
00389     "Built-In Function", /* name */
00390     "FMod_FunctionGenerator", /* struct name */
00391     NULL, /* free data */
00392     NULL, /* copy data */
00393     fcm_fn_generator_new_data, /* new data */
00394     NULL, /* verify */
00395     NULL, /* evaluate time */
00396     fcm_fn_generator_evaluate /* evaluate */
00397 };
00398 
00399 /* Envelope F-Curve Modifier --------------------------- */
00400 
00401 static void fcm_envelope_free (FModifier *fcm)
00402 {
00403     FMod_Envelope *env= (FMod_Envelope *)fcm->data;
00404     
00405     /* free envelope data array */
00406     if (env->data)
00407         MEM_freeN(env->data);
00408 }
00409 
00410 static void fcm_envelope_copy (FModifier *fcm, FModifier *src)
00411 {
00412     FMod_Envelope *env= (FMod_Envelope *)fcm->data;
00413     FMod_Envelope *oenv= (FMod_Envelope *)src->data;
00414     
00415     /* copy envelope data array */
00416     if (oenv->data)
00417         env->data= MEM_dupallocN(oenv->data);
00418 }
00419 
00420 static void fcm_envelope_new_data (void *mdata)
00421 {
00422     FMod_Envelope *env= (FMod_Envelope *)mdata;
00423     
00424     /* set default min/max ranges */
00425     env->min= -1.0f;
00426     env->max= 1.0f;
00427 }
00428 
00429 static void fcm_envelope_verify (FModifier *fcm)
00430 {
00431     FMod_Envelope *env= (FMod_Envelope *)fcm->data;
00432     
00433     /* if the are points, perform bubble-sort on them, as user may have changed the order */
00434     if (env->data) {
00435         // XXX todo...
00436     }
00437 }
00438 
00439 static void fcm_envelope_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
00440 {
00441     FMod_Envelope *env= (FMod_Envelope *)fcm->data;
00442     FCM_EnvelopeData *fed, *prevfed, *lastfed;
00443     float min=0.0f, max=0.0f, fac=0.0f;
00444     int a;
00445     
00446     /* get pointers */
00447     if (env->data == NULL) return;
00448     prevfed= env->data;
00449     fed= prevfed + 1;
00450     lastfed= prevfed + (env->totvert-1);
00451     
00452     /* get min/max values for envelope at evaluation time (relative to mid-value) */
00453     if (prevfed->time >= evaltime) {
00454         /* before or on first sample, so just extend value */
00455         min= prevfed->min;
00456         max= prevfed->max;
00457     }
00458     else if (lastfed->time <= evaltime) {
00459         /* after or on last sample, so just extend value */
00460         min= lastfed->min;
00461         max= lastfed->max;
00462     }
00463     else {
00464         /* evaltime occurs somewhere between segments */
00465         // TODO: implement binary search for this to make it faster?
00466         for (a=0; prevfed && fed && (a < env->totvert-1); a++, prevfed=fed, fed++) {  
00467             /* evaltime occurs within the interval defined by these two envelope points */
00468             if ((prevfed->time <= evaltime) && (fed->time >= evaltime)) {
00469                 float afac, bfac, diff;
00470                 
00471                 diff= fed->time - prevfed->time;
00472                 afac= (evaltime - prevfed->time) / diff;
00473                 bfac= (fed->time - evaltime) / diff;
00474                 
00475                 min= bfac*prevfed->min + afac*fed->min;
00476                 max= bfac*prevfed->max + afac*fed->max;
00477                 
00478                 break;
00479             }
00480         }
00481     }
00482     
00483     /* adjust *cvalue 
00484      *  - fac is the ratio of how the current y-value corresponds to the reference range
00485      *  - thus, the new value is found by mapping the old range to the new!
00486      */
00487     fac= (*cvalue - (env->midval + env->min)) / (env->max - env->min);
00488     *cvalue= min + fac*(max - min); 
00489 }
00490 
00491 static FModifierTypeInfo FMI_ENVELOPE = {
00492     FMODIFIER_TYPE_ENVELOPE, /* type */
00493     sizeof(FMod_Envelope), /* size */
00494     FMI_TYPE_REPLACE_VALUES, /* action type */
00495     0, /* requirements */
00496     "Envelope", /* name */
00497     "FMod_Envelope", /* struct name */
00498     fcm_envelope_free, /* free data */
00499     fcm_envelope_copy, /* copy data */
00500     fcm_envelope_new_data, /* new data */
00501     fcm_envelope_verify, /* verify */
00502     NULL, /* evaluate time */
00503     fcm_envelope_evaluate /* evaluate */
00504 };
00505 
00506 /* Cycles F-Curve Modifier  --------------------------- */
00507 
00508 /* This modifier changes evaltime to something that exists within the curve's frame-range, 
00509  * then re-evaluates modifier stack up to this point using the new time. This re-entrant behaviour
00510  * is very likely to be more time-consuming than the original approach... (which was tighly integrated into 
00511  * the calculation code...).
00512  *
00513  * 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
00514  * Possible TODO - store length of cycle information that can be initialised from the extents of the keyframes/sample-data, and adjusted
00515  *              as appropriate
00516  */
00517 
00518 /* temp data used during evaluation */
00519 typedef struct tFCMED_Cycles {
00520     float cycyofs;      /* y-offset to apply */
00521 } tFCMED_Cycles;
00522  
00523 static void fcm_cycles_new_data (void *mdata)
00524 {
00525     FMod_Cycles *data= (FMod_Cycles *)mdata;
00526     
00527     /* turn on cycles by default */
00528     data->before_mode= data->after_mode= FCM_EXTRAPOLATE_CYCLIC;
00529 }
00530 
00531 static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float UNUSED(cvalue), float evaltime)
00532 {
00533     FMod_Cycles *data= (FMod_Cycles *)fcm->data;
00534     float prevkey[2], lastkey[2], cycyofs=0.0f;
00535     short side=0, mode=0;
00536     int cycles=0, ofs=0;
00537     
00538     /* check if modifier is first in stack, otherwise disable ourself... */
00539     // FIXME...
00540     if (fcm->prev) {
00541         fcm->flag |= FMODIFIER_FLAG_DISABLED;
00542         return evaltime;
00543     }
00544     
00545     /* calculate new evaltime due to cyclic interpolation */
00546     if (fcu && fcu->bezt) {
00547         BezTriple *prevbezt= fcu->bezt;
00548         BezTriple *lastbezt= prevbezt + fcu->totvert-1;
00549         
00550         prevkey[0]= prevbezt->vec[1][0];
00551         prevkey[1]= prevbezt->vec[1][1];
00552         
00553         lastkey[0]= lastbezt->vec[1][0];
00554         lastkey[1]= lastbezt->vec[1][1];
00555     }
00556     else if (fcu && fcu->fpt) {
00557         FPoint *prevfpt= fcu->fpt;
00558         FPoint *lastfpt= prevfpt + fcu->totvert-1;
00559         
00560         prevkey[0]= prevfpt->vec[0];
00561         prevkey[1]= prevfpt->vec[1];
00562         
00563         lastkey[0]= lastfpt->vec[0];
00564         lastkey[1]= lastfpt->vec[1];
00565     }
00566     else
00567         return evaltime;
00568         
00569     /* check if modifier will do anything
00570      *  1) if in data range, definitely don't do anything
00571      *  2) if before first frame or after last frame, make sure some cycling is in use
00572      */
00573     if (evaltime < prevkey[0]) {
00574         if (data->before_mode)  {
00575             side= -1;
00576             mode= data->before_mode;
00577             cycles= data->before_cycles;
00578             ofs= prevkey[0];
00579         }
00580     }
00581     else if (evaltime > lastkey[0]) {
00582         if (data->after_mode) {
00583             side= 1;
00584             mode= data->after_mode;
00585             cycles= data->after_cycles;
00586             ofs= lastkey[0];
00587         }
00588     }
00589     if ELEM(0, side, mode)
00590         return evaltime;
00591         
00592     /* find relative place within a cycle */
00593     {
00594         float cycdx=0, cycdy=0;
00595         float cycle= 0, cyct=0;
00596         
00597         /* calculate period and amplitude (total height) of a cycle */
00598         cycdx= lastkey[0] - prevkey[0];
00599         cycdy= lastkey[1] - prevkey[1];
00600         
00601         /* check if cycle is infinitely small, to be point of being impossible to use */
00602         if (cycdx == 0)
00603             return evaltime;
00604             
00605         /* calculate the 'number' of the cycle */
00606         cycle= ((float)side * (evaltime - ofs) / cycdx);
00607         
00608         /* calculate the time inside the cycle */
00609         cyct= fmod(evaltime - ofs, cycdx);
00610         
00611         /* check that cyclic is still enabled for the specified time */
00612         if (cycles == 0) {
00613             /* catch this case so that we don't exit when we have cycles=0
00614              * as this indicates infinite cycles...
00615              */
00616         }
00617         else if (cycle > cycles) {
00618             /* we are too far away from range to evaluate
00619              * TODO: but we should still hold last value... 
00620              */
00621             return evaltime;
00622         }
00623         
00624         /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */
00625         if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
00626             if(side < 0)
00627                 cycyofs = (float)floor((evaltime - ofs) / cycdx);
00628             else
00629                 cycyofs = (float)ceil((evaltime - ofs) / cycdx);
00630             cycyofs *= cycdy;
00631         }
00632         
00633         /* special case for cycle start/end */
00634         if(cyct == 0.0f) {
00635             evaltime = (side == 1 ? lastkey[0] : prevkey[0]);
00636             
00637             if((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)cycle % 2))
00638                 evaltime = (side == 1 ? prevkey[0] : lastkey[0]);
00639         }
00640         /* calculate where in the cycle we are (overwrite evaltime to reflect this) */
00641         else if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle+1) % 2)) {
00642             /* when 'mirror' option is used and cycle number is odd, this cycle is played in reverse 
00643              *  - for 'before' extrapolation, we need to flip in a different way, otherwise values past
00644              *    then end of the curve get referenced (result of fmod will be negative, and with different phase)
00645              */
00646             if (side < 0)
00647                 evaltime= prevkey[0] - cyct;
00648             else
00649                 evaltime= lastkey[0] - cyct;
00650         }
00651         else {
00652             /* the cycle is played normally... */
00653             evaltime= prevkey[0] + cyct;
00654         }
00655         if (evaltime < prevkey[0]) evaltime += cycdx;
00656     }
00657     
00658     /* store temp data if needed */
00659     if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
00660         tFCMED_Cycles *edata;
00661         
00662         /* for now, this is just a float, but we could get more stuff... */
00663         fcm->edata= edata= MEM_callocN(sizeof(tFCMED_Cycles), "tFCMED_Cycles");
00664         edata->cycyofs= cycyofs;
00665     }
00666     
00667     /* return the new frame to evaluate */
00668     return evaltime;
00669 }
00670  
00671 static void fcm_cycles_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float UNUSED(evaltime))
00672 {
00673     tFCMED_Cycles *edata= (tFCMED_Cycles *)fcm->edata;
00674     
00675     /* use temp data */
00676     if (edata) {
00677         /* add cyclic offset - no need to check for now, otherwise the data wouldn't exist! */
00678         *cvalue += edata->cycyofs;
00679         
00680         /* free temp data */
00681         MEM_freeN(edata);
00682         fcm->edata= NULL;
00683     }
00684 }
00685 
00686 static FModifierTypeInfo FMI_CYCLES = {
00687     FMODIFIER_TYPE_CYCLES, /* type */
00688     sizeof(FMod_Cycles), /* size */
00689     FMI_TYPE_EXTRAPOLATION, /* action type */
00690     FMI_REQUIRES_ORIGINAL_DATA, /* requirements */
00691     "Cycles", /* name */
00692     "FMod_Cycles", /* struct name */
00693     NULL, /* free data */
00694     NULL, /* copy data */
00695     fcm_cycles_new_data, /* new data */
00696     NULL /*fcm_cycles_verify*/, /* verify */
00697     fcm_cycles_time, /* evaluate time */
00698     fcm_cycles_evaluate /* evaluate */
00699 };
00700 
00701 /* Noise F-Curve Modifier  --------------------------- */
00702 
00703 static void fcm_noise_new_data (void *mdata)
00704 {
00705     FMod_Noise *data= (FMod_Noise *)mdata;
00706     
00707     /* defaults */
00708     data->size= 1.0f;
00709     data->strength= 1.0f;
00710     data->phase= 1.0f;
00711     data->depth = 0;
00712     data->modification = FCM_NOISE_MODIF_REPLACE;
00713 }
00714  
00715 static void fcm_noise_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
00716 {
00717     FMod_Noise *data= (FMod_Noise *)fcm->data;
00718     float noise;
00719     
00720     /* generate noise using good ol' Blender Noise
00721      *  - 0.1 is passed as the 'z' value, otherwise evaluation fails for size = phase = 1
00722      *    with evaltime being an integer (which happens when evaluating on frame by frame basis)
00723      */
00724     noise = BLI_turbulence(data->size, evaltime, data->phase, 0.1f, data->depth);
00725     
00726     /* combine the noise with existing motion data */
00727     switch (data->modification) {
00728         case FCM_NOISE_MODIF_ADD:
00729             *cvalue= *cvalue + noise * data->strength;
00730             break;
00731         case FCM_NOISE_MODIF_SUBTRACT:
00732             *cvalue= *cvalue - noise * data->strength;
00733             break;
00734         case FCM_NOISE_MODIF_MULTIPLY:
00735             *cvalue= *cvalue * noise * data->strength;
00736             break;
00737         case FCM_NOISE_MODIF_REPLACE:
00738         default:
00739             *cvalue= *cvalue + (noise - 0.5f) * data->strength;
00740             break;
00741     }
00742 }
00743 
00744 static FModifierTypeInfo FMI_NOISE = {
00745     FMODIFIER_TYPE_NOISE, /* type */
00746     sizeof(FMod_Noise), /* size */
00747     FMI_TYPE_REPLACE_VALUES, /* action type */
00748     0, /* requirements */
00749     "Noise", /* name */
00750     "FMod_Noise", /* struct name */
00751     NULL, /* free data */
00752     NULL, /* copy data */
00753     fcm_noise_new_data, /* new data */
00754     NULL /*fcm_noise_verify*/, /* verify */
00755     NULL, /* evaluate time */
00756     fcm_noise_evaluate /* evaluate */
00757 };
00758 
00759 /* Filter F-Curve Modifier --------------------------- */
00760 
00761 #if 0 // XXX not yet implemented 
00762 static FModifierTypeInfo FMI_FILTER = {
00763     FMODIFIER_TYPE_FILTER, /* type */
00764     sizeof(FMod_Filter), /* size */
00765     FMI_TYPE_REPLACE_VALUES, /* action type */
00766     0, /* requirements */
00767     "Filter", /* name */
00768     "FMod_Filter", /* struct name */
00769     NULL, /* free data */
00770     NULL, /* copy data */
00771     NULL, /* new data */
00772     NULL /*fcm_filter_verify*/, /* verify */
00773     NULL, /* evlauate time */
00774     fcm_filter_evaluate /* evaluate */
00775 };
00776 #endif // XXX not yet implemented
00777 
00778 
00779 /* Python F-Curve Modifier --------------------------- */
00780 
00781 static void fcm_python_free (FModifier *fcm)
00782 {
00783     FMod_Python *data= (FMod_Python *)fcm->data;
00784     
00785     /* id-properties */
00786     IDP_FreeProperty(data->prop);
00787     MEM_freeN(data->prop);
00788 }
00789 
00790 static void fcm_python_new_data (void *mdata) 
00791 {
00792     FMod_Python *data= (FMod_Python *)mdata;
00793     
00794     /* everything should be set correctly by calloc, except for the prop->type constant.*/
00795     data->prop = MEM_callocN(sizeof(IDProperty), "PyFModifierProps");
00796     data->prop->type = IDP_GROUP;
00797 }
00798 
00799 static void fcm_python_copy (FModifier *fcm, FModifier *src)
00800 {
00801     FMod_Python *pymod = (FMod_Python *)fcm->data;
00802     FMod_Python *opymod = (FMod_Python *)src->data;
00803     
00804     pymod->prop = IDP_CopyProperty(opymod->prop);
00805 }
00806 
00807 static void fcm_python_evaluate (FCurve *UNUSED(fcu), FModifier *UNUSED(fcm), float *UNUSED(cvalue), float UNUSED(evaltime))
00808 {
00809 #ifdef WITH_PYTHON
00810     //FMod_Python *data= (FMod_Python *)fcm->data;
00811     
00812     /* FIXME... need to implement this modifier...
00813      *  It will need it execute a script using the custom properties 
00814      */
00815 #endif /* WITH_PYTHON */
00816 }
00817 
00818 static FModifierTypeInfo FMI_PYTHON = {
00819     FMODIFIER_TYPE_PYTHON, /* type */
00820     sizeof(FMod_Python), /* size */
00821     FMI_TYPE_GENERATE_CURVE, /* action type */
00822     FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
00823     "Python", /* name */
00824     "FMod_Python", /* struct name */
00825     fcm_python_free, /* free data */
00826     fcm_python_copy, /* copy data */
00827     fcm_python_new_data, /* new data */
00828     NULL /*fcm_python_verify*/, /* verify */
00829     NULL /*fcm_python_time*/, /* evaluate time */
00830     fcm_python_evaluate /* evaluate */
00831 };
00832 
00833 
00834 /* Limits F-Curve Modifier --------------------------- */
00835 
00836 static float fcm_limits_time (FCurve *UNUSED(fcu), FModifier *fcm, float UNUSED(cvalue), float evaltime)
00837 {
00838     FMod_Limits *data= (FMod_Limits *)fcm->data;
00839     
00840     /* check for the time limits */
00841     if ((data->flag & FCM_LIMIT_XMIN) && (evaltime < data->rect.xmin))
00842         return data->rect.xmin;
00843     if ((data->flag & FCM_LIMIT_XMAX) && (evaltime > data->rect.xmax))
00844         return data->rect.xmax;
00845         
00846     /* modifier doesn't change time */
00847     return evaltime;
00848 }
00849 
00850 static void fcm_limits_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float UNUSED(evaltime))
00851 {
00852     FMod_Limits *data= (FMod_Limits *)fcm->data;
00853     
00854     /* value limits now */
00855     if ((data->flag & FCM_LIMIT_YMIN) && (*cvalue < data->rect.ymin))
00856         *cvalue= data->rect.ymin;
00857     if ((data->flag & FCM_LIMIT_YMAX) && (*cvalue > data->rect.ymax))
00858         *cvalue= data->rect.ymax;
00859 }
00860 
00861 static FModifierTypeInfo FMI_LIMITS = {
00862     FMODIFIER_TYPE_LIMITS, /* type */
00863     sizeof(FMod_Limits), /* size */
00864     FMI_TYPE_GENERATE_CURVE, /* action type */  /* XXX... err... */   
00865     FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
00866     "Limits", /* name */
00867     "FMod_Limits", /* struct name */
00868     NULL, /* free data */
00869     NULL, /* copy data */
00870     NULL, /* new data */
00871     NULL, /* verify */
00872     fcm_limits_time, /* evaluate time */
00873     fcm_limits_evaluate /* evaluate */
00874 };
00875 
00876 /* Stepped F-Curve Modifier --------------------------- */
00877 
00878 static void fcm_stepped_new_data (void *mdata) 
00879 {
00880     FMod_Stepped *data= (FMod_Stepped *)mdata;
00881     
00882     /* just need to set the step-size to 2-frames by default */
00883     // XXX: or would 5 be more normal?
00884     data->step_size = 2.0f;
00885 }
00886 
00887 static float fcm_stepped_time (FCurve *UNUSED(fcu), FModifier *fcm, float UNUSED(cvalue), float evaltime)
00888 {
00889     FMod_Stepped *data= (FMod_Stepped *)fcm->data;
00890     int snapblock;
00891     
00892     /* check range clamping to see if we should alter the timing to achieve the desired results */
00893     if (data->flag & FCM_STEPPED_NO_BEFORE) {
00894         if (evaltime < data->start_frame)
00895             return evaltime;
00896     }
00897     if (data->flag & FCM_STEPPED_NO_AFTER) {
00898         if (evaltime > data->end_frame)
00899             return evaltime;
00900     }
00901     
00902     /* we snap to the start of the previous closest block of 'step_size' frames 
00903      * after the start offset has been discarded 
00904      *  - i.e. round down
00905      */
00906     snapblock = (int)((evaltime - data->offset) / data->step_size);
00907     
00908     /* reapply the offset, and multiple the snapblock by the size of the steps to get 
00909      * the new time to evaluate at 
00910      */
00911     return ((float)snapblock * data->step_size) + data->offset;
00912 }
00913 
00914 static FModifierTypeInfo FMI_STEPPED = {
00915     FMODIFIER_TYPE_STEPPED, /* type */
00916     sizeof(FMod_Limits), /* size */
00917     FMI_TYPE_GENERATE_CURVE, /* action type */  /* XXX... err... */   
00918     FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
00919     "Stepped", /* name */
00920     "FMod_Stepped", /* struct name */
00921     NULL, /* free data */
00922     NULL, /* copy data */
00923     fcm_stepped_new_data, /* new data */
00924     NULL, /* verify */
00925     fcm_stepped_time, /* evaluate time */
00926     NULL /* evaluate */
00927 };
00928 
00929 /* F-Curve Modifier API --------------------------- */
00930 /* All of the F-Curve Modifier api functions use FModifierTypeInfo structs to carry out
00931  * and operations that involve F-Curve modifier specific code.
00932  */
00933 
00934 /* These globals only ever get directly accessed in this file */
00935 static FModifierTypeInfo *fmodifiersTypeInfo[FMODIFIER_NUM_TYPES];
00936 static short FMI_INIT= 1; /* when non-zero, the list needs to be updated */
00937 
00938 /* This function only gets called when FMI_INIT is non-zero */
00939 static void fmods_init_typeinfo (void) 
00940 {
00941     fmodifiersTypeInfo[0]=  NULL;                   /* 'Null' F-Curve Modifier */
00942     fmodifiersTypeInfo[1]=  &FMI_GENERATOR;         /* Generator F-Curve Modifier */
00943     fmodifiersTypeInfo[2]=  &FMI_FN_GENERATOR;      /* Built-In Function Generator F-Curve Modifier */
00944     fmodifiersTypeInfo[3]=  &FMI_ENVELOPE;          /* Envelope F-Curve Modifier */
00945     fmodifiersTypeInfo[4]=  &FMI_CYCLES;            /* Cycles F-Curve Modifier */
00946     fmodifiersTypeInfo[5]=  &FMI_NOISE;             /* Apply-Noise F-Curve Modifier */
00947     fmodifiersTypeInfo[6]=  NULL/*&FMI_FILTER*/;            /* Filter F-Curve Modifier */  // XXX unimplemented
00948     fmodifiersTypeInfo[7]=  &FMI_PYTHON;            /* Custom Python F-Curve Modifier */
00949     fmodifiersTypeInfo[8]=  &FMI_LIMITS;            /* Limits F-Curve Modifier */
00950     fmodifiersTypeInfo[9]=  &FMI_STEPPED;           /* Stepped F-Curve Modifier */
00951 }
00952 
00953 /* This function should be used for getting the appropriate type-info when only
00954  * a F-Curve modifier type is known
00955  */
00956 FModifierTypeInfo *get_fmodifier_typeinfo (int type)
00957 {
00958     /* initialise the type-info list? */
00959     if (FMI_INIT) {
00960         fmods_init_typeinfo();
00961         FMI_INIT = 0;
00962     }
00963     
00964     /* only return for valid types */
00965     if ( (type >= FMODIFIER_TYPE_NULL) && 
00966          (type <= FMODIFIER_NUM_TYPES ) ) 
00967     {
00968         /* there shouldn't be any segfaults here... */
00969         return fmodifiersTypeInfo[type];
00970     }
00971     else {
00972         printf("No valid F-Curve Modifier type-info data available. Type = %i \n", type);
00973     }
00974     
00975     return NULL;
00976 } 
00977  
00978 /* This function should always be used to get the appropriate type-info, as it
00979  * has checks which prevent segfaults in some weird cases.
00980  */
00981 FModifierTypeInfo *fmodifier_get_typeinfo (FModifier *fcm)
00982 {
00983     /* only return typeinfo for valid modifiers */
00984     if (fcm)
00985         return get_fmodifier_typeinfo(fcm->type);
00986     else
00987         return NULL;
00988 }
00989 
00990 /* API --------------------------- */
00991 
00992 /* Add a new F-Curve Modifier to the given F-Curve of a certain type */
00993 FModifier *add_fmodifier (ListBase *modifiers, int type)
00994 {
00995     FModifierTypeInfo *fmi= get_fmodifier_typeinfo(type);
00996     FModifier *fcm;
00997     
00998     /* sanity checks */
00999     if ELEM(NULL, modifiers, fmi)
01000         return NULL;
01001     
01002     /* special checks for whether modifier can be added */
01003     if ((modifiers->first) && (type == FMODIFIER_TYPE_CYCLES)) {
01004         /* cycles modifier must be first in stack, so for now, don't add if it can't be */
01005         // TODO: perhaps there is some better way, but for now, 
01006         printf("Error: Cannot add 'Cycles' modifier to F-Curve, as 'Cycles' modifier can only be first in stack. \n");
01007         return NULL;
01008     }
01009     
01010     /* add modifier itself */
01011     fcm= MEM_callocN(sizeof(FModifier), "F-Curve Modifier");
01012     fcm->type = type;
01013     fcm->flag = FMODIFIER_FLAG_EXPANDED;
01014     fcm->influence = 1.0f;
01015     BLI_addtail(modifiers, fcm);
01016     
01017     /* tag modifier as "active" if no other modifiers exist in the stack yet */
01018     if (modifiers->first == modifiers->last)
01019         fcm->flag |= FMODIFIER_FLAG_ACTIVE;
01020     
01021     /* add modifier's data */
01022     fcm->data= MEM_callocN(fmi->size, fmi->structName);
01023     
01024     /* init custom settings if necessary */
01025     if (fmi->new_data)  
01026         fmi->new_data(fcm->data);
01027         
01028     /* return modifier for further editing */
01029     return fcm;
01030 }
01031 
01032 /* Make a copy of the specified F-Modifier */
01033 FModifier *copy_fmodifier (FModifier *src)
01034 {
01035     FModifierTypeInfo *fmi= fmodifier_get_typeinfo(src);
01036     FModifier *dst;
01037     
01038     /* sanity check */
01039     if (src == NULL)
01040         return NULL;
01041         
01042     /* copy the base data, clearing the links */
01043     dst = MEM_dupallocN(src);
01044     dst->next = dst->prev = NULL;
01045     
01046     /* make a new copy of the F-Modifier's data */
01047     dst->data = MEM_dupallocN(src->data);
01048     
01049     /* only do specific constraints if required */
01050     if (fmi && fmi->copy_data)
01051         fmi->copy_data(dst, src);
01052         
01053     /* return the new modifier */
01054     return dst;
01055 }
01056 
01057 /* Duplicate all of the F-Modifiers in the Modifier stacks */
01058 void copy_fmodifiers (ListBase *dst, ListBase *src)
01059 {
01060     FModifier *fcm, *srcfcm;
01061     
01062     if ELEM(NULL, dst, src)
01063         return;
01064     
01065     dst->first= dst->last= NULL;
01066     BLI_duplicatelist(dst, src);
01067     
01068     for (fcm=dst->first, srcfcm=src->first; fcm && srcfcm; srcfcm=srcfcm->next, fcm=fcm->next) {
01069         FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
01070         
01071         /* make a new copy of the F-Modifier's data */
01072         fcm->data = MEM_dupallocN(fcm->data);
01073         
01074         /* only do specific constraints if required */
01075         if (fmi && fmi->copy_data)
01076             fmi->copy_data(fcm, srcfcm);
01077     }
01078 }
01079 
01080 /* Remove and free the given F-Modifier from the given stack  */
01081 int remove_fmodifier (ListBase *modifiers, FModifier *fcm)
01082 {
01083     FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
01084     
01085     /* sanity check */
01086     if (fcm == NULL)
01087         return 0;
01088     
01089     /* free modifier's special data (stored inside fcm->data) */
01090     if (fcm->data) {
01091         if (fmi && fmi->free_data)
01092             fmi->free_data(fcm);
01093             
01094         /* free modifier's data (fcm->data) */
01095         MEM_freeN(fcm->data);
01096     }
01097     
01098     /* remove modifier from stack */
01099     if (modifiers) {
01100         BLI_freelinkN(modifiers, fcm);
01101         return 1;
01102     } 
01103     else {
01104         // XXX this case can probably be removed some day, as it shouldn't happen...
01105         printf("remove_fmodifier() - no modifier stack given \n");
01106         MEM_freeN(fcm);
01107         return 0;
01108     }
01109 }
01110 
01111 /* Remove all of a given F-Curve's modifiers */
01112 void free_fmodifiers (ListBase *modifiers)
01113 {
01114     FModifier *fcm, *fmn;
01115     
01116     /* sanity check */
01117     if (modifiers == NULL)
01118         return;
01119     
01120     /* free each modifier in order - modifier is unlinked from list and freed */
01121     for (fcm= modifiers->first; fcm; fcm= fmn) {
01122         fmn= fcm->next;
01123         remove_fmodifier(modifiers, fcm);
01124     }
01125 }
01126 
01127 /* Find the active F-Modifier */
01128 FModifier *find_active_fmodifier (ListBase *modifiers)
01129 {
01130     FModifier *fcm;
01131     
01132     /* sanity checks */
01133     if ELEM(NULL, modifiers, modifiers->first)
01134         return NULL;
01135     
01136     /* loop over modifiers until 'active' one is found */
01137     for (fcm= modifiers->first; fcm; fcm= fcm->next) {
01138         if (fcm->flag & FMODIFIER_FLAG_ACTIVE)
01139             return fcm;
01140     }
01141     
01142     /* no modifier is active */
01143     return NULL;
01144 }
01145 
01146 /* Set the active F-Modifier */
01147 void set_active_fmodifier (ListBase *modifiers, FModifier *fcm)
01148 {
01149     FModifier *fm;
01150     
01151     /* sanity checks */
01152     if ELEM(NULL, modifiers, modifiers->first)
01153         return;
01154     
01155     /* deactivate all, and set current one active */
01156     for (fm= modifiers->first; fm; fm= fm->next)
01157         fm->flag &= ~FMODIFIER_FLAG_ACTIVE;
01158     
01159     /* make given modifier active */
01160     if (fcm)
01161         fcm->flag |= FMODIFIER_FLAG_ACTIVE;
01162 }
01163 
01164 /* Do we have any modifiers which match certain criteria 
01165  *  - mtype - type of modifier (if 0, doesn't matter)
01166  *  - acttype - type of action to perform (if -1, doesn't matter)
01167  */
01168 short list_has_suitable_fmodifier (ListBase *modifiers, int mtype, short acttype)
01169 {
01170     FModifier *fcm;
01171     
01172     /* if there are no specific filtering criteria, just skip */
01173     if ((mtype == 0) && (acttype == 0))
01174         return (modifiers && modifiers->first);
01175         
01176     /* sanity checks */
01177     if ELEM(NULL, modifiers, modifiers->first)
01178         return 0;
01179         
01180     /* find the first mdifier fitting these criteria */
01181     for (fcm= modifiers->first; fcm; fcm= fcm->next) {
01182         FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
01183         short mOk=1, aOk=1; /* by default 1, so that when only one test, won't fail */
01184         
01185         /* check if applicable ones are fullfilled */
01186         if (mtype)
01187             mOk= (fcm->type == mtype);
01188         if (acttype > -1)
01189             aOk= (fmi->acttype == acttype);
01190             
01191         /* if both are ok, we've found a hit */
01192         if (mOk && aOk)
01193             return 1;
01194     }
01195     
01196     /* no matches */
01197     return 0;
01198 }  
01199 
01200 /* Evaluation API --------------------------- */
01201 
01202 /* helper function - calculate influence of FModifier */
01203 static float eval_fmodifier_influence (FModifier *fcm, float evaltime)
01204 {
01205     float influence;
01206     
01207     /* sanity check */
01208     if (fcm == NULL) 
01209         return 0.0f;
01210     
01211     /* should we use influence stored in modifier or not 
01212      * NOTE: this is really just a hack so that we don't need to version patch old files ;)
01213      */
01214     if (fcm->flag & FMODIFIER_FLAG_USEINFLUENCE)
01215         influence = fcm->influence;
01216     else
01217         influence = 1.0f;
01218         
01219     /* restricted range or full range? */
01220     if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) {
01221         if ((evaltime <= fcm->sfra) || (evaltime >= fcm->efra)) {
01222             /* out of range */
01223             return 0.0f;
01224         }
01225         else if ((evaltime > fcm->sfra) && (evaltime < fcm->sfra + fcm->blendin)) {
01226             /* blend in range */
01227             float a = fcm->sfra;
01228             float b = fcm->sfra + fcm->blendin;
01229             return influence * (evaltime - a) / (b - a);
01230         }
01231         else if ((evaltime < fcm->efra) && (evaltime > fcm->efra - fcm->blendout)) {
01232             /* blend out range */
01233             float a = fcm->efra;
01234             float b = fcm->efra - fcm->blendout;
01235             return influence * (evaltime - a) / (b - a);
01236         }
01237     }
01238     
01239     /* just return the influence of the modifier */
01240     return influence;
01241 }
01242 
01243 /* evaluate time modifications imposed by some F-Curve Modifiers
01244  *  - this step acts as an optimisation to prevent the F-Curve stack being evaluated 
01245  *    several times by modifiers requesting the time be modified, as the final result
01246  *    would have required using the modified time
01247  *  - modifiers only ever receive the unmodified time, as subsequent modifiers should be
01248  *    working on the 'global' result of the modified curve, not some localised segment,
01249  *    so nevaltime gets set to whatever the last time-modifying modifier likes...
01250  *  - we start from the end of the stack, as only the last one matters for now
01251  */
01252 float evaluate_time_fmodifiers (ListBase *modifiers, FCurve *fcu, float cvalue, float evaltime)
01253 {
01254     FModifier *fcm;
01255     
01256     /* sanity checks */
01257     if ELEM(NULL, modifiers, modifiers->last)
01258         return evaltime;
01259         
01260     /* Starting from the end of the stack, calculate the time effects of various stacked modifiers 
01261      * on the time the F-Curve should be evaluated at. 
01262      *
01263      * This is done in reverse order to standard evaluation, as when this is done in standard
01264      * order, each modifier would cause jumps to other points in the curve, forcing all
01265      * previous ones to be evaluated again for them to be correct. However, if we did in the 
01266      * reverse order as we have here, we can consider them a macro to micro type of waterfall
01267      * effect, which should get us the desired effects when using layered time manipulations
01268      * (such as multiple 'stepped' modifiers in sequence, causing different stepping rates)
01269      */
01270     for (fcm= modifiers->last; fcm; fcm= fcm->prev) {
01271         FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
01272         
01273         if (fmi == NULL) 
01274             continue;
01275         
01276         /* if modifier cannot be applied on this frame (whatever scale it is on, it won't affect the results)
01277          * hence we shouldn't bother seeing what it would do given the chance
01278          */
01279         if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT)==0 || 
01280             ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime)) )
01281         {
01282             /* only evaluate if there's a callback for this */
01283             if (fmi->evaluate_modifier_time) {
01284                 if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) {
01285                     float influence = eval_fmodifier_influence(fcm, evaltime);
01286                     float nval = fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
01287                     
01288                     evaltime = interpf(nval, evaltime, influence);
01289                 }
01290             }
01291         }
01292     }
01293     
01294     /* return the modified evaltime */
01295     return evaltime;
01296 }
01297 
01298 /* Evalautes the given set of F-Curve Modifiers using the given data
01299  * Should only be called after evaluate_time_fmodifiers() has been called...
01300  */
01301 void evaluate_value_fmodifiers (ListBase *modifiers, FCurve *fcu, float *cvalue, float evaltime)
01302 {
01303     FModifier *fcm;
01304     
01305     /* sanity checks */
01306     if ELEM(NULL, modifiers, modifiers->first)
01307         return;
01308     
01309     /* evaluate modifiers */
01310     for (fcm= modifiers->first; fcm; fcm= fcm->next) {
01311         FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
01312         
01313         if (fmi == NULL) 
01314             continue;
01315         
01316         /* only evaluate if there's a callback for this, and if F-Modifier can be evaluated on this frame */
01317         if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT)==0 || 
01318             ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime)) )
01319         {
01320             if (fmi->evaluate_modifier) {
01321                 if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) {
01322                     float influence = eval_fmodifier_influence(fcm, evaltime);
01323                     float nval = *cvalue;
01324                     
01325                     fmi->evaluate_modifier(fcu, fcm, &nval, evaltime);
01326                     *cvalue = interpf(nval, *cvalue, influence);
01327                 }
01328             }
01329         }
01330     }
01331 } 
01332 
01333 /* ---------- */
01334 
01335 /* Bake modifiers for given F-Curve to curve sample data, in the frame range defined
01336  * by start and end (inclusive).
01337  */
01338 void fcurve_bake_modifiers (FCurve *fcu, int start, int end)
01339 {
01340     ChannelDriver *driver;
01341     
01342     /* sanity checks */
01343     // TODO: make these tests report errors using reports not printf's
01344     if ELEM(NULL, fcu, fcu->modifiers.first) {
01345         printf("Error: No F-Curve with F-Curve Modifiers to Bake\n");
01346         return;
01347     }
01348     
01349     /* temporarily, disable driver while we sample, so that they don't influence the outcome */
01350     driver= fcu->driver;
01351     fcu->driver= NULL;
01352     
01353     /* bake the modifiers, by sampling the curve at each frame */
01354     fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
01355     
01356     /* free the modifiers now */
01357     free_fmodifiers(&fcu->modifiers);
01358     
01359     /* restore driver */
01360     fcu->driver= driver;
01361 }