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