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