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