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