merge with/from trunk at r35190
[blender.git] / source / blender / blenkernel / intern / fmodifier.c
1 /*
2  * $Id: fmodifier.c 21537 2009-07-11 22:22:53Z gsrb3d $
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
21  * All rights reserved.
22  *
23  * Contributor(s): Joshua Leung (full recode)
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28
29 #include <math.h>
30 #include <stdio.h>
31 #include <stddef.h>
32 #include <string.h>
33 #include <float.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "DNA_anim_types.h"
38
39 #include "BLI_blenlib.h"
40 #include "BLI_math.h" /* windows needs for M_PI */
41 #include "BLI_utildefines.h"
42
43 #include "BKE_fcurve.h"
44 #include "BKE_idprop.h"
45
46
47 #define SMALL -1.0e-10
48 #define SELECT 1
49
50 /* ******************************** F-Modifiers ********************************* */
51
52 /* Info ------------------------------- */
53
54 /* F-Modifiers are modifiers which operate on F-Curves. However, they can also be defined
55  * on NLA-Strips to affect all of the F-Curves referenced by the NLA-Strip. 
56  */
57
58 /* Template --------------------------- */
59
60 /* Each modifier defines a set of functions, which will be called at the appropriate
61  * times. In addition to this, each modifier should have a type-info struct, where
62  * its functions are attached for use. 
63  */
64  
65 /* Template for type-info data:
66  *      - make a copy of this when creating new modifiers, and just change the functions
67  *        pointed to as necessary
68  *      - although the naming of functions doesn't matter, it would help for code
69  *        readability, to follow the same naming convention as is presented here
70  *      - any functions that a constraint doesn't need to define, don't define
71  *        for such cases, just use NULL 
72  *      - these should be defined after all the functions have been defined, so that
73  *        forward-definitions/prototypes don't need to be used!
74  *      - keep this copy #if-def'd so that future constraints can get based off this
75  */
76 #if 0
77 static FModifierTypeInfo FMI_MODNAME = {
78         FMODIFIER_TYPE_MODNAME, /* type */
79         sizeof(FMod_ModName), /* size */
80         FMI_TYPE_SOME_ACTION, /* action type */
81         FMI_REQUIRES_SOME_REQUIREMENT, /* requirements */
82         "Modifier Name", /* name */
83         "FMod_ModName", /* struct name */
84         fcm_modname_free, /* free data */
85         fcm_modname_relink, /* relink data */
86         fcm_modname_copy, /* copy data */
87         fcm_modname_new_data, /* new data */
88         fcm_modname_verify, /* verify */
89         fcm_modname_time, /* evaluate time */
90         fcm_modname_evaluate /* evaluate */
91 };
92 #endif
93
94 /* Generator F-Curve Modifier --------------------------- */
95
96 /* Generators available:
97  *      1) simple polynomial generator:
98  *              - Exanded form - (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n])  
99  *              - Factorised form - (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1]))
100  */
101
102 static void fcm_generator_free (FModifier *fcm)
103 {
104         FMod_Generator *data= (FMod_Generator *)fcm->data;
105         
106         /* free polynomial coefficients array */
107         if (data->coefficients)
108                 MEM_freeN(data->coefficients);
109 }
110
111 static void fcm_generator_copy (FModifier *fcm, FModifier *src)
112 {
113         FMod_Generator *gen= (FMod_Generator *)fcm->data;
114         FMod_Generator *ogen= (FMod_Generator *)src->data;
115         
116         /* copy coefficients array? */
117         if (ogen->coefficients)
118                 gen->coefficients= MEM_dupallocN(ogen->coefficients);
119 }
120
121 static void fcm_generator_new_data (void *mdata)
122 {
123         FMod_Generator *data= (FMod_Generator *)mdata;
124         float *cp;
125         
126         /* set default generator to be linear 0-1 (gradient = 1, y-offset = 0) */
127         data->poly_order= 1;
128         data->arraysize= 2;
129         cp= data->coefficients= MEM_callocN(sizeof(float)*2, "FMod_Generator_Coefs");
130         cp[0] = 0; // y-offset 
131         cp[1] = 1; // gradient
132 }
133
134 static void fcm_generator_verify (FModifier *fcm)
135 {
136         FMod_Generator *data= (FMod_Generator *)fcm->data;
137         
138         /* requirements depend on mode */
139         switch (data->mode) {
140                 case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
141                 {
142                         /* arraysize needs to be order+1, so resize if not */
143                         if (data->arraysize != (data->poly_order+1)) {
144                                 float *nc;
145                                 
146                                 /* make new coefficients array, and copy over as much data as can fit */
147                                 nc= MEM_callocN(sizeof(float)*(data->poly_order+1), "FMod_Generator_Coefs");
148                                 
149                                 if (data->coefficients) {
150                                         if ((int)data->arraysize > (data->poly_order+1))
151                                                 memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order+1));
152                                         else
153                                                 memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
154                                                 
155                                         /* free the old data */
156                                         MEM_freeN(data->coefficients);
157                                 }       
158                                 
159                                 /* set the new data */
160                                 data->coefficients= nc;
161                                 data->arraysize= data->poly_order+1;
162                         }
163                 }
164                         break;
165                 
166                 case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* expanded polynomial expression */
167                 {
168                         /* arraysize needs to be 2*order, so resize if not */
169                         if (data->arraysize != (data->poly_order * 2)) {
170                                 float *nc;
171                                 
172                                 /* make new coefficients array, and copy over as much data as can fit */
173                                 nc= MEM_callocN(sizeof(float)*(data->poly_order*2), "FMod_Generator_Coefs");
174                                 
175                                 if (data->coefficients) {
176                                         if (data->arraysize > (unsigned int)(data->poly_order * 2))
177                                                 memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order * 2));
178                                         else
179                                                 memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
180                                                 
181                                         /* free the old data */
182                                         MEM_freeN(data->coefficients);
183                                 }       
184                                 
185                                 /* set the new data */
186                                 data->coefficients= nc;
187                                 data->arraysize= data->poly_order * 2;
188                         }
189                 }
190                         break;  
191         }
192 }
193
194 static void fcm_generator_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
195 {
196         FMod_Generator *data= (FMod_Generator *)fcm->data;
197         
198         /* behaviour depends on mode 
199          * NOTE: the data in its default state is fine too
200          */
201         switch (data->mode) {
202                 case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
203                 {
204                         /* we overwrite cvalue with the sum of the polynomial */
205                         float *powers = MEM_callocN(sizeof(float)*data->arraysize, "Poly Powers");
206                         float value= 0.0f;
207                         unsigned int i;
208                         
209                         /* for each x^n, precalculate value based on previous one first... this should be 
210                          * faster that calling pow() for each entry
211                          */
212                         for (i=0; i < data->arraysize; i++) {
213                                 /* first entry is x^0 = 1, otherwise, calculate based on previous */
214                                 if (i)
215                                         powers[i]= powers[i-1] * evaltime;
216                                 else
217                                         powers[0]= 1;
218                         }
219                         
220                         /* for each coefficient, add to value, which we'll write to *cvalue in one go */
221                         for (i=0; i < data->arraysize; i++)
222                                 value += data->coefficients[i] * powers[i];
223                         
224                         /* only if something changed, write *cvalue in one go */
225                         if (data->poly_order) {
226                                 if (data->flag & FCM_GENERATOR_ADDITIVE)
227                                         *cvalue += value;
228                                 else
229                                         *cvalue= value;
230                         }
231                                 
232                         /* cleanup */
233                         if (powers) 
234                                 MEM_freeN(powers);
235                 }
236                         break;
237                         
238                 case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial */
239                 {
240                         float value= 1.0f, *cp=NULL;
241                         unsigned int i;
242                         
243                         /* for each coefficient pair, solve for that bracket before accumulating in value by multiplying */
244                         for (cp=data->coefficients, i=0; (cp) && (i < (unsigned int)data->poly_order); cp+=2, i++) 
245                                 value *= (cp[0]*evaltime + cp[1]);
246                                 
247                         /* only if something changed, write *cvalue in one go */
248                         if (data->poly_order) {
249                                 if (data->flag & FCM_GENERATOR_ADDITIVE)
250                                         *cvalue += value;
251                                 else
252                                         *cvalue= value;
253                         }
254                 }
255                         break;
256         }
257 }
258
259 static FModifierTypeInfo FMI_GENERATOR = {
260         FMODIFIER_TYPE_GENERATOR, /* type */
261         sizeof(FMod_Generator), /* size */
262         FMI_TYPE_GENERATE_CURVE, /* action type */
263         FMI_REQUIRES_NOTHING, /* requirements */
264         "Generator", /* name */
265         "FMod_Generator", /* struct name */
266         fcm_generator_free, /* free data */
267         fcm_generator_copy, /* copy data */
268         fcm_generator_new_data, /* new data */
269         fcm_generator_verify, /* verify */
270         NULL, /* evaluate time */
271         fcm_generator_evaluate /* evaluate */
272 };
273
274 /* Built-In Function Generator F-Curve Modifier --------------------------- */
275
276 /* This uses the general equation for equations:
277  *              y = amplitude * fn(phase_multiplier*x + phase_offset) + y_offset
278  *
279  * where amplitude, phase_multiplier/offset, y_offset are user-defined coefficients,
280  * x is the evaluation 'time', and 'y' is the resultant value
281  *
282  * Functions available are
283  *      sin, cos, tan, sinc (normalised sin), natural log, square root 
284  */
285
286 static void fcm_fn_generator_new_data (void *mdata)
287 {
288         FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)mdata;
289         
290         /* set amplitude and phase multiplier to 1.0f so that something is generated */
291         data->amplitude= 1.0f;
292         data->phase_multiplier= 1.0f;
293 }
294
295 /* Unary 'normalised sine' function
296  *      y = sin(PI + x) / (PI * x),
297  * except for x = 0 when y = 1.
298  */
299 static double sinc (double x)
300 {
301         if (fabs(x) < 0.0001)
302                 return 1.0;
303         else
304                 return sin(M_PI * x) / (M_PI * x);
305 }
306
307 static void fcm_fn_generator_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
308 {
309         FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)fcm->data;
310         double arg= data->phase_multiplier*evaltime + data->phase_offset;
311         double (*fn)(double v) = NULL;
312         
313         /* get function pointer to the func to use:
314          * WARNING: must perform special argument validation hereto guard against crashes  
315          */
316         switch (data->type)
317         {
318                 /* simple ones */                       
319                 case FCM_GENERATOR_FN_SIN: /* sine wave */
320                         fn= sin;
321                         break;
322                 case FCM_GENERATOR_FN_COS: /* cosine wave */
323                         fn= cos;
324                         break;
325                 case FCM_GENERATOR_FN_SINC: /* normalised sine wave */
326                         fn= sinc;
327                         break;
328                         
329                 /* validation required */
330                 case FCM_GENERATOR_FN_TAN: /* tangent wave */
331                 {
332                         /* check that argument is not on one of the discontinuities (i.e. 90deg, 270 deg, etc) */
333                         if IS_EQ(fmod((arg - M_PI_2), M_PI), 0.0) {
334                                 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
335                                         *cvalue = 0.0f; /* no value possible here */
336                         }
337                         else
338                                 fn= tan;
339                 }
340                         break;
341                 case FCM_GENERATOR_FN_LN: /* natural log */
342                 {
343                         /* check that value is greater than 1? */
344                         if (arg > 1.0f) {
345                                 fn= log;
346                         }
347                         else {
348                                 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
349                                         *cvalue = 0.0f; /* no value possible here */
350                         }
351                 }
352                         break;
353                 case FCM_GENERATOR_FN_SQRT: /* square root */
354                 {
355                         /* no negative numbers */
356                         if (arg > 0.0f) {
357                                 fn= sqrt;
358                         }
359                         else {
360                                 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
361                                         *cvalue = 0.0f; /* no value possible here */
362                         }
363                 }
364                         break;
365                 
366                 default:
367                         printf("Invalid Function-Generator for F-Modifier - %d \n", data->type);
368         }
369         
370         /* execute function callback to set value if appropriate */
371         if (fn) {
372                 float value= (float)(data->amplitude*fn(arg) + data->value_offset);
373                 
374                 if (data->flag & FCM_GENERATOR_ADDITIVE)
375                         *cvalue += value;
376                 else
377                         *cvalue= value;
378         }
379 }
380
381 static FModifierTypeInfo FMI_FN_GENERATOR = {
382         FMODIFIER_TYPE_FN_GENERATOR, /* type */
383         sizeof(FMod_FunctionGenerator), /* size */
384         FMI_TYPE_GENERATE_CURVE, /* action type */
385         FMI_REQUIRES_NOTHING, /* requirements */
386         "Built-In Function", /* name */
387         "FMod_FunctionGenerator", /* struct name */
388         NULL, /* free data */
389         NULL, /* copy data */
390         fcm_fn_generator_new_data, /* new data */
391         NULL, /* verify */
392         NULL, /* evaluate time */
393         fcm_fn_generator_evaluate /* evaluate */
394 };
395
396 /* Envelope F-Curve Modifier --------------------------- */
397
398 static void fcm_envelope_free (FModifier *fcm)
399 {
400         FMod_Envelope *env= (FMod_Envelope *)fcm->data;
401         
402         /* free envelope data array */
403         if (env->data)
404                 MEM_freeN(env->data);
405 }
406
407 static void fcm_envelope_copy (FModifier *fcm, FModifier *src)
408 {
409         FMod_Envelope *env= (FMod_Envelope *)fcm->data;
410         FMod_Envelope *oenv= (FMod_Envelope *)src->data;
411         
412         /* copy envelope data array */
413         if (oenv->data)
414                 env->data= MEM_dupallocN(oenv->data);
415 }
416
417 static void fcm_envelope_new_data (void *mdata)
418 {
419         FMod_Envelope *env= (FMod_Envelope *)mdata;
420         
421         /* set default min/max ranges */
422         env->min= -1.0f;
423         env->max= 1.0f;
424 }
425
426 static void fcm_envelope_verify (FModifier *fcm)
427 {
428         FMod_Envelope *env= (FMod_Envelope *)fcm->data;
429         
430         /* if the are points, perform bubble-sort on them, as user may have changed the order */
431         if (env->data) {
432                 // XXX todo...
433         }
434 }
435
436 static void fcm_envelope_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
437 {
438         FMod_Envelope *env= (FMod_Envelope *)fcm->data;
439         FCM_EnvelopeData *fed, *prevfed, *lastfed;
440         float min=0.0f, max=0.0f, fac=0.0f;
441         int a;
442         
443         /* get pointers */
444         if (env->data == NULL) return;
445         prevfed= env->data;
446         fed= prevfed + 1;
447         lastfed= prevfed + (env->totvert-1);
448         
449         /* get min/max values for envelope at evaluation time (relative to mid-value) */
450         if (prevfed->time >= evaltime) {
451                 /* before or on first sample, so just extend value */
452                 min= prevfed->min;
453                 max= prevfed->max;
454         }
455         else if (lastfed->time <= evaltime) {
456                 /* after or on last sample, so just extend value */
457                 min= lastfed->min;
458                 max= lastfed->max;
459         }
460         else {
461                 /* evaltime occurs somewhere between segments */
462                 // TODO: implement binary search for this to make it faster?
463                 for (a=0; prevfed && fed && (a < env->totvert-1); a++, prevfed=fed, fed++) {  
464                         /* evaltime occurs within the interval defined by these two envelope points */
465                         if ((prevfed->time <= evaltime) && (fed->time >= evaltime)) {
466                                 float afac, bfac, diff;
467                                 
468                                 diff= fed->time - prevfed->time;
469                                 afac= (evaltime - prevfed->time) / diff;
470                                 bfac= (fed->time - evaltime) / diff;
471                                 
472                                 min= bfac*prevfed->min + afac*fed->min;
473                                 max= bfac*prevfed->max + afac*fed->max;
474                                 
475                                 break;
476                         }
477                 }
478         }
479         
480         /* adjust *cvalue 
481          *      - fac is the ratio of how the current y-value corresponds to the reference range
482          *      - thus, the new value is found by mapping the old range to the new!
483          */
484         fac= (*cvalue - (env->midval + env->min)) / (env->max - env->min);
485         *cvalue= min + fac*(max - min); 
486 }
487
488 static FModifierTypeInfo FMI_ENVELOPE = {
489         FMODIFIER_TYPE_ENVELOPE, /* type */
490         sizeof(FMod_Envelope), /* size */
491         FMI_TYPE_REPLACE_VALUES, /* action type */
492         0, /* requirements */
493         "Envelope", /* name */
494         "FMod_Envelope", /* struct name */
495         fcm_envelope_free, /* free data */
496         fcm_envelope_copy, /* copy data */
497         fcm_envelope_new_data, /* new data */
498         fcm_envelope_verify, /* verify */
499         NULL, /* evaluate time */
500         fcm_envelope_evaluate /* evaluate */
501 };
502
503 /* Cycles F-Curve Modifier  --------------------------- */
504
505 /* This modifier changes evaltime to something that exists within the curve's frame-range, 
506  * then re-evaluates modifier stack up to this point using the new time. This re-entrant behaviour
507  * is very likely to be more time-consuming than the original approach... (which was tighly integrated into 
508  * the calculation code...).
509  *
510  * 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
511  * Possible TODO - store length of cycle information that can be initialised from the extents of the keyframes/sample-data, and adjusted
512  *                              as appropriate
513  */
514
515 /* temp data used during evaluation */
516 typedef struct tFCMED_Cycles {
517         float cycyofs;          /* y-offset to apply */
518 } tFCMED_Cycles;
519  
520 static void fcm_cycles_new_data (void *mdata)
521 {
522         FMod_Cycles *data= (FMod_Cycles *)mdata;
523         
524         /* turn on cycles by default */
525         data->before_mode= data->after_mode= FCM_EXTRAPOLATE_CYCLIC;
526 }
527
528 static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float UNUSED(cvalue), float evaltime)
529 {
530         FMod_Cycles *data= (FMod_Cycles *)fcm->data;
531         float prevkey[2], lastkey[2], cycyofs=0.0f;
532         short side=0, mode=0;
533         int cycles=0, ofs=0;
534         
535         /* check if modifier is first in stack, otherwise disable ourself... */
536         // FIXME...
537         if (fcm->prev) {
538                 fcm->flag |= FMODIFIER_FLAG_DISABLED;
539                 return evaltime;
540         }
541         
542         /* calculate new evaltime due to cyclic interpolation */
543         if (fcu && fcu->bezt) {
544                 BezTriple *prevbezt= fcu->bezt;
545                 BezTriple *lastbezt= prevbezt + fcu->totvert-1;
546                 
547                 prevkey[0]= prevbezt->vec[1][0];
548                 prevkey[1]= prevbezt->vec[1][1];
549                 
550                 lastkey[0]= lastbezt->vec[1][0];
551                 lastkey[1]= lastbezt->vec[1][1];
552         }
553         else if (fcu && fcu->fpt) {
554                 FPoint *prevfpt= fcu->fpt;
555                 FPoint *lastfpt= prevfpt + fcu->totvert-1;
556                 
557                 prevkey[0]= prevfpt->vec[0];
558                 prevkey[1]= prevfpt->vec[1];
559                 
560                 lastkey[0]= lastfpt->vec[0];
561                 lastkey[1]= lastfpt->vec[1];
562         }
563         else
564                 return evaltime;
565                 
566         /* check if modifier will do anything
567          *      1) if in data range, definitely don't do anything
568          *      2) if before first frame or after last frame, make sure some cycling is in use
569          */
570         if (evaltime < prevkey[0]) {
571                 if (data->before_mode)  {
572                         side= -1;
573                         mode= data->before_mode;
574                         cycles= data->before_cycles;
575                         ofs= prevkey[0];
576                 }
577         }
578         else if (evaltime > lastkey[0]) {
579                 if (data->after_mode) {
580                         side= 1;
581                         mode= data->after_mode;
582                         cycles= data->after_cycles;
583                         ofs= lastkey[0];
584                 }
585         }
586         if ELEM(0, side, mode)
587                 return evaltime;
588                 
589         /* find relative place within a cycle */
590         {
591                 float cycdx=0, cycdy=0;
592                 float cycle= 0, cyct=0;
593                 
594                 /* calculate period and amplitude (total height) of a cycle */
595                 cycdx= lastkey[0] - prevkey[0];
596                 cycdy= lastkey[1] - prevkey[1];
597                 
598                 /* check if cycle is infinitely small, to be point of being impossible to use */
599                 if (cycdx == 0)
600                         return evaltime;
601                         
602                 /* calculate the 'number' of the cycle */
603                 cycle= ((float)side * (evaltime - ofs) / cycdx);
604
605                 /* calculate the time inside the cycle */
606                 cyct= fmod(evaltime - ofs, cycdx);
607                 
608                 /* check that cyclic is still enabled for the specified time */
609                 if (cycles == 0) {
610                         /* catch this case so that we don't exit when we have cycles=0
611                          * as this indicates infinite cycles...
612                          */
613                 }
614                 else if (cycle > cycles) {
615                         /* we are too far away from range to evaluate
616                          * TODO: but we should still hold last value... 
617                          */
618                         return evaltime;
619                 }
620                 
621                 /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */
622                 if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
623                         if(side < 0)
624                                 cycyofs = (float)floor((evaltime - ofs) / cycdx);
625                         else
626                                 cycyofs = (float)ceil((evaltime - ofs) / cycdx);
627                         cycyofs *= cycdy;
628                 }
629
630                 /* special case for cycle start/end */
631                 if(cyct == 0.0f) {
632                         evaltime = (side == 1 ? lastkey[0] : prevkey[0]);
633
634                         if((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)cycle % 2))
635                                 evaltime = (side == 1 ? prevkey[0] : lastkey[0]);
636                 }
637                 /* calculate where in the cycle we are (overwrite evaltime to reflect this) */
638                 else if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle+1) % 2)) {
639                         /* when 'mirror' option is used and cycle number is odd, this cycle is played in reverse 
640                          *      - for 'before' extrapolation, we need to flip in a different way, otherwise values past
641                          *        then end of the curve get referenced (result of fmod will be negative, and with different phase)
642                          */
643                         if (side < 0)
644                                 evaltime= prevkey[0] - cyct;
645                         else
646                                 evaltime= lastkey[0] - cyct;
647                 }
648                 else {
649                         /* the cycle is played normally... */
650                         evaltime= prevkey[0] + cyct;
651                 }
652                 if (evaltime < prevkey[0]) evaltime += cycdx;
653         }
654         
655         /* store temp data if needed */
656         if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
657                 tFCMED_Cycles *edata;
658                 
659                 /* for now, this is just a float, but we could get more stuff... */
660                 fcm->edata= edata= MEM_callocN(sizeof(tFCMED_Cycles), "tFCMED_Cycles");
661                 edata->cycyofs= cycyofs;
662         }
663         
664         /* return the new frame to evaluate */
665         return evaltime;
666 }
667  
668 static void fcm_cycles_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float UNUSED(evaltime))
669 {
670         tFCMED_Cycles *edata= (tFCMED_Cycles *)fcm->edata;
671         
672         /* use temp data */
673         if (edata) {
674                 /* add cyclic offset - no need to check for now, otherwise the data wouldn't exist! */
675                 *cvalue += edata->cycyofs;
676                 
677                 /* free temp data */
678                 MEM_freeN(edata);
679                 fcm->edata= NULL;
680         }
681 }
682
683 static FModifierTypeInfo FMI_CYCLES = {
684         FMODIFIER_TYPE_CYCLES, /* type */
685         sizeof(FMod_Cycles), /* size */
686         FMI_TYPE_EXTRAPOLATION, /* action type */
687         FMI_REQUIRES_ORIGINAL_DATA, /* requirements */
688         "Cycles", /* name */
689         "FMod_Cycles", /* struct name */
690         NULL, /* free data */
691         NULL, /* copy data */
692         fcm_cycles_new_data, /* new data */
693         NULL /*fcm_cycles_verify*/, /* verify */
694         fcm_cycles_time, /* evaluate time */
695         fcm_cycles_evaluate /* evaluate */
696 };
697
698 /* Noise F-Curve Modifier  --------------------------- */
699
700 static void fcm_noise_new_data (void *mdata)
701 {
702         FMod_Noise *data= (FMod_Noise *)mdata;
703         
704         /* defaults */
705         data->size= 1.0f;
706         data->strength= 1.0f;
707         data->phase= 1.0f;
708         data->depth = 0;
709         data->modification = FCM_NOISE_MODIF_REPLACE;
710 }
711  
712 static void fcm_noise_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
713 {
714         FMod_Noise *data= (FMod_Noise *)fcm->data;
715         float noise;
716         
717         /* generate noise using good ol' Blender Noise
718          *      - 0.1 is passed as the 'z' value, otherwise evaluation fails for size = phase = 1
719          *        with evaltime being an integer (which happens when evaluating on frame by frame basis)
720          */
721         noise = BLI_turbulence(data->size, evaltime, data->phase, 0.1f, data->depth);
722         
723         /* combine the noise with existing motion data */
724         switch (data->modification) {
725                 case FCM_NOISE_MODIF_ADD:
726                         *cvalue= *cvalue + noise * data->strength;
727                         break;
728                 case FCM_NOISE_MODIF_SUBTRACT:
729                         *cvalue= *cvalue - noise * data->strength;
730                         break;
731                 case FCM_NOISE_MODIF_MULTIPLY:
732                         *cvalue= *cvalue * noise * data->strength;
733                         break;
734                 case FCM_NOISE_MODIF_REPLACE:
735                 default:
736                         *cvalue= *cvalue + (noise - 0.5f) * data->strength;
737                         break;
738         }
739 }
740
741 static FModifierTypeInfo FMI_NOISE = {
742         FMODIFIER_TYPE_NOISE, /* type */
743         sizeof(FMod_Noise), /* size */
744         FMI_TYPE_REPLACE_VALUES, /* action type */
745         0, /* requirements */
746         "Noise", /* name */
747         "FMod_Noise", /* struct name */
748         NULL, /* free data */
749         NULL, /* copy data */
750         fcm_noise_new_data, /* new data */
751         NULL /*fcm_noise_verify*/, /* verify */
752         NULL, /* evaluate time */
753         fcm_noise_evaluate /* evaluate */
754 };
755
756 /* Filter F-Curve Modifier --------------------------- */
757
758 #if 0 // XXX not yet implemented 
759 static FModifierTypeInfo FMI_FILTER = {
760         FMODIFIER_TYPE_FILTER, /* type */
761         sizeof(FMod_Filter), /* size */
762         FMI_TYPE_REPLACE_VALUES, /* action type */
763         0, /* requirements */
764         "Filter", /* name */
765         "FMod_Filter", /* struct name */
766         NULL, /* free data */
767         NULL, /* copy data */
768         NULL, /* new data */
769         NULL /*fcm_filter_verify*/, /* verify */
770         NULL, /* evlauate time */
771         fcm_filter_evaluate /* evaluate */
772 };
773 #endif // XXX not yet implemented
774
775
776 /* Python F-Curve Modifier --------------------------- */
777
778 static void fcm_python_free (FModifier *fcm)
779 {
780         FMod_Python *data= (FMod_Python *)fcm->data;
781         
782         /* id-properties */
783         IDP_FreeProperty(data->prop);
784         MEM_freeN(data->prop);
785 }
786
787 static void fcm_python_new_data (void *mdata) 
788 {
789         FMod_Python *data= (FMod_Python *)mdata;
790         
791         /* everything should be set correctly by calloc, except for the prop->type constant.*/
792         data->prop = MEM_callocN(sizeof(IDProperty), "PyFModifierProps");
793         data->prop->type = IDP_GROUP;
794 }
795
796 static void fcm_python_copy (FModifier *fcm, FModifier *src)
797 {
798         FMod_Python *pymod = (FMod_Python *)fcm->data;
799         FMod_Python *opymod = (FMod_Python *)src->data;
800         
801         pymod->prop = IDP_CopyProperty(opymod->prop);
802 }
803
804 static void fcm_python_evaluate (FCurve *UNUSED(fcu), FModifier *UNUSED(fcm), float *UNUSED(cvalue), float UNUSED(evaltime))
805 {
806 #ifdef WITH_PYTHON
807         //FMod_Python *data= (FMod_Python *)fcm->data;
808         
809         /* FIXME... need to implement this modifier...
810          *      It will need it execute a script using the custom properties 
811          */
812 #endif /* WITH_PYTHON */
813 }
814
815 static FModifierTypeInfo FMI_PYTHON = {
816         FMODIFIER_TYPE_PYTHON, /* type */
817         sizeof(FMod_Python), /* size */
818         FMI_TYPE_GENERATE_CURVE, /* action type */
819         FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
820         "Python", /* name */
821         "FMod_Python", /* struct name */
822         fcm_python_free, /* free data */
823         fcm_python_copy, /* copy data */
824         fcm_python_new_data, /* new data */
825         NULL /*fcm_python_verify*/, /* verify */
826         NULL /*fcm_python_time*/, /* evaluate time */
827         fcm_python_evaluate /* evaluate */
828 };
829
830
831 /* Limits F-Curve Modifier --------------------------- */
832
833 static float fcm_limits_time (FCurve *UNUSED(fcu), FModifier *fcm, float UNUSED(cvalue), float evaltime)
834 {
835         FMod_Limits *data= (FMod_Limits *)fcm->data;
836         
837         /* check for the time limits */
838         if ((data->flag & FCM_LIMIT_XMIN) && (evaltime < data->rect.xmin))
839                 return data->rect.xmin;
840         if ((data->flag & FCM_LIMIT_XMAX) && (evaltime > data->rect.xmax))
841                 return data->rect.xmax;
842                 
843         /* modifier doesn't change time */
844         return evaltime;
845 }
846
847 static void fcm_limits_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float UNUSED(evaltime))
848 {
849         FMod_Limits *data= (FMod_Limits *)fcm->data;
850         
851         /* value limits now */
852         if ((data->flag & FCM_LIMIT_YMIN) && (*cvalue < data->rect.ymin))
853                 *cvalue= data->rect.ymin;
854         if ((data->flag & FCM_LIMIT_YMAX) && (*cvalue > data->rect.ymax))
855                 *cvalue= data->rect.ymax;
856 }
857
858 static FModifierTypeInfo FMI_LIMITS = {
859         FMODIFIER_TYPE_LIMITS, /* type */
860         sizeof(FMod_Limits), /* size */
861         FMI_TYPE_GENERATE_CURVE, /* action type */  /* XXX... err... */   
862         FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
863         "Limits", /* name */
864         "FMod_Limits", /* struct name */
865         NULL, /* free data */
866         NULL, /* copy data */
867         NULL, /* new data */
868         NULL, /* verify */
869         fcm_limits_time, /* evaluate time */
870         fcm_limits_evaluate /* evaluate */
871 };
872
873 /* Stepped F-Curve Modifier --------------------------- */
874
875 static void fcm_stepped_new_data (void *mdata) 
876 {
877         FMod_Stepped *data= (FMod_Stepped *)mdata;
878         
879         /* just need to set the step-size to 2-frames by default */
880         // XXX: or would 5 be more normal?
881         data->step_size = 2.0f;
882 }
883
884 static float fcm_stepped_time (FCurve *UNUSED(fcu), FModifier *fcm, float UNUSED(cvalue), float evaltime)
885 {
886         FMod_Stepped *data= (FMod_Stepped *)fcm->data;
887         int snapblock;
888         
889         /* check range clamping to see if we should alter the timing to achieve the desired results */
890         if (data->flag & FCM_STEPPED_NO_BEFORE) {
891                 if (evaltime < data->start_frame)
892                         return evaltime;
893         }
894         if (data->flag & FCM_STEPPED_NO_AFTER) {
895                 if (evaltime > data->end_frame)
896                         return evaltime;
897         }
898         
899         /* we snap to the start of the previous closest block of 'step_size' frames 
900          * after the start offset has been discarded 
901          *      - i.e. round down
902          */
903         snapblock = (int)((evaltime - data->offset) / data->step_size);
904         
905         /* reapply the offset, and multiple the snapblock by the size of the steps to get 
906          * the new time to evaluate at 
907          */
908         return ((float)snapblock * data->step_size) + data->offset;
909 }
910
911 static FModifierTypeInfo FMI_STEPPED = {
912         FMODIFIER_TYPE_STEPPED, /* type */
913         sizeof(FMod_Limits), /* size */
914         FMI_TYPE_GENERATE_CURVE, /* action type */  /* XXX... err... */   
915         FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
916         "Stepped", /* name */
917         "FMod_Stepped", /* struct name */
918         NULL, /* free data */
919         NULL, /* copy data */
920         fcm_stepped_new_data, /* new data */
921         NULL, /* verify */
922         fcm_stepped_time, /* evaluate time */
923         NULL /* evaluate */
924 };
925
926 /* F-Curve Modifier API --------------------------- */
927 /* All of the F-Curve Modifier api functions use FModifierTypeInfo structs to carry out
928  * and operations that involve F-Curve modifier specific code.
929  */
930
931 /* These globals only ever get directly accessed in this file */
932 static FModifierTypeInfo *fmodifiersTypeInfo[FMODIFIER_NUM_TYPES];
933 static short FMI_INIT= 1; /* when non-zero, the list needs to be updated */
934
935 /* This function only gets called when FMI_INIT is non-zero */
936 static void fmods_init_typeinfo (void) 
937 {
938         fmodifiersTypeInfo[0]=  NULL;                                   /* 'Null' F-Curve Modifier */
939         fmodifiersTypeInfo[1]=  &FMI_GENERATOR;                 /* Generator F-Curve Modifier */
940         fmodifiersTypeInfo[2]=  &FMI_FN_GENERATOR;              /* Built-In Function Generator F-Curve Modifier */
941         fmodifiersTypeInfo[3]=  &FMI_ENVELOPE;                  /* Envelope F-Curve Modifier */
942         fmodifiersTypeInfo[4]=  &FMI_CYCLES;                    /* Cycles F-Curve Modifier */
943         fmodifiersTypeInfo[5]=  &FMI_NOISE;                             /* Apply-Noise F-Curve Modifier */
944         fmodifiersTypeInfo[6]=  NULL/*&FMI_FILTER*/;                    /* Filter F-Curve Modifier */  // XXX unimplemented
945         fmodifiersTypeInfo[7]=  &FMI_PYTHON;                    /* Custom Python F-Curve Modifier */
946         fmodifiersTypeInfo[8]=  &FMI_LIMITS;                    /* Limits F-Curve Modifier */
947         fmodifiersTypeInfo[9]=  &FMI_STEPPED;                   /* Stepped F-Curve Modifier */
948 }
949
950 /* This function should be used for getting the appropriate type-info when only
951  * a F-Curve modifier type is known
952  */
953 FModifierTypeInfo *get_fmodifier_typeinfo (int type)
954 {
955         /* initialise the type-info list? */
956         if (FMI_INIT) {
957                 fmods_init_typeinfo();
958                 FMI_INIT = 0;
959         }
960         
961         /* only return for valid types */
962         if ( (type >= FMODIFIER_TYPE_NULL) && 
963                  (type <= FMODIFIER_NUM_TYPES ) ) 
964         {
965                 /* there shouldn't be any segfaults here... */
966                 return fmodifiersTypeInfo[type];
967         }
968         else {
969                 printf("No valid F-Curve Modifier type-info data available. Type = %i \n", type);
970         }
971         
972         return NULL;
973
974  
975 /* This function should always be used to get the appropriate type-info, as it
976  * has checks which prevent segfaults in some weird cases.
977  */
978 FModifierTypeInfo *fmodifier_get_typeinfo (FModifier *fcm)
979 {
980         /* only return typeinfo for valid modifiers */
981         if (fcm)
982                 return get_fmodifier_typeinfo(fcm->type);
983         else
984                 return NULL;
985 }
986
987 /* API --------------------------- */
988
989 /* Add a new F-Curve Modifier to the given F-Curve of a certain type */
990 FModifier *add_fmodifier (ListBase *modifiers, int type)
991 {
992         FModifierTypeInfo *fmi= get_fmodifier_typeinfo(type);
993         FModifier *fcm;
994         
995         /* sanity checks */
996         if ELEM(NULL, modifiers, fmi)
997                 return NULL;
998         
999         /* special checks for whether modifier can be added */
1000         if ((modifiers->first) && (type == FMODIFIER_TYPE_CYCLES)) {
1001                 /* cycles modifier must be first in stack, so for now, don't add if it can't be */
1002                 // TODO: perhaps there is some better way, but for now, 
1003                 printf("Error: Cannot add 'Cycles' modifier to F-Curve, as 'Cycles' modifier can only be first in stack. \n");
1004                 return NULL;
1005         }
1006         
1007         /* add modifier itself */
1008         fcm= MEM_callocN(sizeof(FModifier), "F-Curve Modifier");
1009         fcm->type = type;
1010         fcm->flag = FMODIFIER_FLAG_EXPANDED;
1011         BLI_addtail(modifiers, fcm);
1012         
1013         /* tag modifier as "active" if no other modifiers exist in the stack yet */
1014         if (modifiers->first == modifiers->last)
1015                 fcm->flag |= FMODIFIER_FLAG_ACTIVE;
1016         
1017         /* add modifier's data */
1018         fcm->data= MEM_callocN(fmi->size, fmi->structName);
1019         
1020         /* init custom settings if necessary */
1021         if (fmi->new_data)      
1022                 fmi->new_data(fcm->data);
1023                 
1024         /* return modifier for further editing */
1025         return fcm;
1026 }
1027
1028 /* Make a copy of the specified F-Modifier */
1029 FModifier *copy_fmodifier (FModifier *src)
1030 {
1031         FModifierTypeInfo *fmi= fmodifier_get_typeinfo(src);
1032         FModifier *dst;
1033         
1034         /* sanity check */
1035         if (src == NULL)
1036                 return NULL;
1037                 
1038         /* copy the base data, clearing the links */
1039         dst = MEM_dupallocN(src);
1040         dst->next = dst->prev = NULL;
1041         
1042         /* make a new copy of the F-Modifier's data */
1043         dst->data = MEM_dupallocN(src->data);
1044         
1045         /* only do specific constraints if required */
1046         if (fmi && fmi->copy_data)
1047                 fmi->copy_data(dst, src);
1048                 
1049         /* return the new modifier */
1050         return dst;
1051 }
1052
1053 /* Duplicate all of the F-Modifiers in the Modifier stacks */
1054 void copy_fmodifiers (ListBase *dst, ListBase *src)
1055 {
1056         FModifier *fcm, *srcfcm;
1057         
1058         if ELEM(NULL, dst, src)
1059                 return;
1060         
1061         dst->first= dst->last= NULL;
1062         BLI_duplicatelist(dst, src);
1063         
1064         for (fcm=dst->first, srcfcm=src->first; fcm && srcfcm; srcfcm=srcfcm->next, fcm=fcm->next) {
1065                 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
1066                 
1067                 /* make a new copy of the F-Modifier's data */
1068                 fcm->data = MEM_dupallocN(fcm->data);
1069                 
1070                 /* only do specific constraints if required */
1071                 if (fmi && fmi->copy_data)
1072                         fmi->copy_data(fcm, srcfcm);
1073         }
1074 }
1075
1076 /* Remove and free the given F-Modifier from the given stack  */
1077 int remove_fmodifier (ListBase *modifiers, FModifier *fcm)
1078 {
1079         FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
1080         
1081         /* sanity check */
1082         if (fcm == NULL)
1083                 return 0;
1084         
1085         /* free modifier's special data (stored inside fcm->data) */
1086         if (fcm->data) {
1087                 if (fmi && fmi->free_data)
1088                         fmi->free_data(fcm);
1089                         
1090                 /* free modifier's data (fcm->data) */
1091                 MEM_freeN(fcm->data);
1092         }
1093         
1094         /* remove modifier from stack */
1095         if (modifiers) {
1096                 BLI_freelinkN(modifiers, fcm);
1097                 return 1;
1098         } 
1099         else {
1100                 // XXX this case can probably be removed some day, as it shouldn't happen...
1101                 printf("remove_fmodifier() - no modifier stack given \n");
1102                 MEM_freeN(fcm);
1103                 return 0;
1104         }
1105 }
1106
1107 /* Remove all of a given F-Curve's modifiers */
1108 void free_fmodifiers (ListBase *modifiers)
1109 {
1110         FModifier *fcm, *fmn;
1111         
1112         /* sanity check */
1113         if (modifiers == NULL)
1114                 return;
1115         
1116         /* free each modifier in order - modifier is unlinked from list and freed */
1117         for (fcm= modifiers->first; fcm; fcm= fmn) {
1118                 fmn= fcm->next;
1119                 remove_fmodifier(modifiers, fcm);
1120         }
1121 }
1122
1123 /* Find the active F-Modifier */
1124 FModifier *find_active_fmodifier (ListBase *modifiers)
1125 {
1126         FModifier *fcm;
1127         
1128         /* sanity checks */
1129         if ELEM(NULL, modifiers, modifiers->first)
1130                 return NULL;
1131         
1132         /* loop over modifiers until 'active' one is found */
1133         for (fcm= modifiers->first; fcm; fcm= fcm->next) {
1134                 if (fcm->flag & FMODIFIER_FLAG_ACTIVE)
1135                         return fcm;
1136         }
1137         
1138         /* no modifier is active */
1139         return NULL;
1140 }
1141
1142 /* Set the active F-Modifier */
1143 void set_active_fmodifier (ListBase *modifiers, FModifier *fcm)
1144 {
1145         FModifier *fm;
1146         
1147         /* sanity checks */
1148         if ELEM(NULL, modifiers, modifiers->first)
1149                 return;
1150         
1151         /* deactivate all, and set current one active */
1152         for (fm= modifiers->first; fm; fm= fm->next)
1153                 fm->flag &= ~FMODIFIER_FLAG_ACTIVE;
1154         
1155         /* make given modifier active */
1156         if (fcm)
1157                 fcm->flag |= FMODIFIER_FLAG_ACTIVE;
1158 }
1159
1160 /* Do we have any modifiers which match certain criteria 
1161  *      - mtype - type of modifier (if 0, doesn't matter)
1162  *      - acttype - type of action to perform (if -1, doesn't matter)
1163  */
1164 short list_has_suitable_fmodifier (ListBase *modifiers, int mtype, short acttype)
1165 {
1166         FModifier *fcm;
1167         
1168         /* if there are no specific filtering criteria, just skip */
1169         if ((mtype == 0) && (acttype == 0))
1170                 return (modifiers && modifiers->first);
1171                 
1172         /* sanity checks */
1173         if ELEM(NULL, modifiers, modifiers->first)
1174                 return 0;
1175                 
1176         /* find the first mdifier fitting these criteria */
1177         for (fcm= modifiers->first; fcm; fcm= fcm->next) {
1178                 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
1179                 short mOk=1, aOk=1; /* by default 1, so that when only one test, won't fail */
1180                 
1181                 /* check if applicable ones are fullfilled */
1182                 if (mtype)
1183                         mOk= (fcm->type == mtype);
1184                 if (acttype > -1)
1185                         aOk= (fmi->acttype == acttype);
1186                         
1187                 /* if both are ok, we've found a hit */
1188                 if (mOk && aOk)
1189                         return 1;
1190         }
1191         
1192         /* no matches */
1193         return 0;
1194 }  
1195
1196 /* Evaluation API --------------------------- */
1197
1198 /* evaluate time modifications imposed by some F-Curve Modifiers
1199  *      - this step acts as an optimisation to prevent the F-Curve stack being evaluated 
1200  *        several times by modifiers requesting the time be modified, as the final result
1201  *        would have required using the modified time
1202  *      - modifiers only ever receive the unmodified time, as subsequent modifiers should be
1203  *        working on the 'global' result of the modified curve, not some localised segment,
1204  *        so nevaltime gets set to whatever the last time-modifying modifier likes...
1205  *      - we start from the end of the stack, as only the last one matters for now
1206  */
1207 float evaluate_time_fmodifiers (ListBase *modifiers, FCurve *fcu, float cvalue, float evaltime)
1208 {
1209         FModifier *fcm;
1210         
1211         /* sanity checks */
1212         if ELEM(NULL, modifiers, modifiers->last)
1213                 return evaltime;
1214                 
1215         /* Starting from the end of the stack, calculate the time effects of various stacked modifiers 
1216          * on the time the F-Curve should be evaluated at. 
1217          *
1218          * This is done in reverse order to standard evaluation, as when this is done in standard
1219          * order, each modifier would cause jumps to other points in the curve, forcing all
1220          * previous ones to be evaluated again for them to be correct. However, if we did in the 
1221          * reverse order as we have here, we can consider them a macro to micro type of waterfall
1222          * effect, which should get us the desired effects when using layered time manipulations
1223          * (such as multiple 'stepped' modifiers in sequence, causing different stepping rates)
1224          */
1225         for (fcm= modifiers->last; fcm; fcm= fcm->prev) {
1226                 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
1227                 
1228                 /* only evaluate if there's a callback for this */
1229                 // TODO: implement the 'influence' control feature...
1230                 if (fmi && fmi->evaluate_modifier_time) {
1231                         if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
1232                                 evaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
1233                 }
1234         }
1235         
1236         /* return the modified evaltime */
1237         return evaltime;
1238 }
1239
1240 /* Evalautes the given set of F-Curve Modifiers using the given data
1241  * Should only be called after evaluate_time_fmodifiers() has been called...
1242  */
1243 void evaluate_value_fmodifiers (ListBase *modifiers, FCurve *fcu, float *cvalue, float evaltime)
1244 {
1245         FModifier *fcm;
1246         
1247         /* sanity checks */
1248         if ELEM(NULL, modifiers, modifiers->first)
1249                 return;
1250         
1251         /* evaluate modifiers */
1252         for (fcm= modifiers->first; fcm; fcm= fcm->next) {
1253                 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
1254                 
1255                 /* only evaluate if there's a callback for this */
1256                 // TODO: implement the 'influence' control feature...
1257                 if (fmi && fmi->evaluate_modifier) {
1258                         if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
1259                                 fmi->evaluate_modifier(fcu, fcm, cvalue, evaltime);
1260                 }
1261         }
1262
1263
1264 /* ---------- */
1265
1266 /* Bake modifiers for given F-Curve to curve sample data, in the frame range defined
1267  * by start and end (inclusive).
1268  */
1269 void fcurve_bake_modifiers (FCurve *fcu, int start, int end)
1270 {
1271         ChannelDriver *driver;
1272         
1273         /* sanity checks */
1274         // TODO: make these tests report errors using reports not printf's
1275         if ELEM(NULL, fcu, fcu->modifiers.first) {
1276                 printf("Error: No F-Curve with F-Curve Modifiers to Bake\n");
1277                 return;
1278         }
1279         
1280         /* temporarily, disable driver while we sample, so that they don't influence the outcome */
1281         driver= fcu->driver;
1282         fcu->driver= NULL;
1283         
1284         /* bake the modifiers, by sampling the curve at each frame */
1285         fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
1286         
1287         /* free the modifiers now */
1288         free_fmodifiers(&fcu->modifiers);
1289         
1290         /* restore driver */
1291         fcu->driver= driver;
1292 }