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 <float.h>
25 #include <math.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <string.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_math.h" /* windows needs for M_PI */
41 #include "BLI_noise.h"
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 /* -------------------------------------------------------------------- */
50 /** \name F-Curve Modifier Types
51  * \{ */
52 
53 /* Info ------------------------------- */
54 
55 /* F-Modifiers are modifiers which operate on F-Curves. However, they can also be defined
56  * on NLA-Strips to affect all of the F-Curves referenced by the NLA-Strip.
57  */
58 
59 /* Template --------------------------- */
60 
61 /* Each modifier defines a set of functions, which will be called at the appropriate
62  * times. In addition to this, each modifier should have a type-info struct, where
63  * its functions are attached for use.
64  */
65 
66 /* Template for type-info data:
67  * - make a copy of this when creating new modifiers, and just change the functions
68  *   pointed to as necessary
69  * - although the naming of functions doesn't matter, it would help for code
70  *   readability, to follow the same naming convention as is presented here
71  * - any functions that a constraint doesn't need to define, don't define
72  *   for such cases, just use NULL
73  * - these should be defined after all the functions have been defined, so that
74  *   forward-definitions/prototypes don't need to be used!
75  * - keep this copy #if-def'd so that future modifier can get based off this
76  */
77 #if 0
78 static FModifierTypeInfo FMI_MODNAME = {
79     FMODIFIER_TYPE_MODNAME,        /* type */
80     sizeof(FMod_ModName),          /* size */
81     FMI_TYPE_SOME_ACTION,          /* action type */
82     FMI_REQUIRES_SOME_REQUIREMENT, /* requirements */
83     "Modifier Name",               /* name */
84     "FMod_ModName",                /* struct name */
85     0,                             /* storage size */
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  *     - Expanded form:
101  *       (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n])
102  *     - Factorized form:
103  *       (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1]))
104  */
105 
fcm_generator_free(FModifier * fcm)106 static void fcm_generator_free(FModifier *fcm)
107 {
108   FMod_Generator *data = (FMod_Generator *)fcm->data;
109 
110   /* free polynomial coefficients array */
111   if (data->coefficients) {
112     MEM_freeN(data->coefficients);
113   }
114 }
115 
fcm_generator_copy(FModifier * fcm,const FModifier * src)116 static void fcm_generator_copy(FModifier *fcm, const FModifier *src)
117 {
118   FMod_Generator *gen = (FMod_Generator *)fcm->data;
119   FMod_Generator *ogen = (FMod_Generator *)src->data;
120 
121   /* copy coefficients array? */
122   if (ogen->coefficients) {
123     gen->coefficients = MEM_dupallocN(ogen->coefficients);
124   }
125 }
126 
fcm_generator_new_data(void * mdata)127 static void fcm_generator_new_data(void *mdata)
128 {
129   FMod_Generator *data = (FMod_Generator *)mdata;
130   float *cp;
131 
132   /* set default generator to be linear 0-1 (gradient = 1, y-offset = 0) */
133   data->poly_order = 1;
134   data->arraysize = 2;
135   cp = data->coefficients = MEM_callocN(sizeof(float) * 2, "FMod_Generator_Coefs");
136   cp[0] = 0; /* y-offset */
137   cp[1] = 1; /* gradient */
138 }
139 
fcm_generator_verify(FModifier * fcm)140 static void fcm_generator_verify(FModifier *fcm)
141 {
142   FMod_Generator *data = (FMod_Generator *)fcm->data;
143 
144   /* requirements depend on mode */
145   switch (data->mode) {
146     case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
147     {
148       const int arraysize_new = data->poly_order + 1;
149       /* arraysize needs to be order+1, so resize if not */
150       if (data->arraysize != arraysize_new) {
151         data->coefficients = MEM_recallocN(data->coefficients, sizeof(float) * arraysize_new);
152         data->arraysize = arraysize_new;
153       }
154       break;
155     }
156     case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* expanded polynomial expression */
157     {
158       const int arraysize_new = data->poly_order * 2;
159       /* arraysize needs to be (2 * order), so resize if not */
160       if (data->arraysize != arraysize_new) {
161         data->coefficients = MEM_recallocN(data->coefficients, sizeof(float) * arraysize_new);
162         data->arraysize = arraysize_new;
163       }
164       break;
165     }
166   }
167 }
168 
fcm_generator_evaluate(FCurve * UNUSED (fcu),FModifier * fcm,float * cvalue,float evaltime,void * UNUSED (storage))169 static void fcm_generator_evaluate(
170     FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime, void *UNUSED(storage))
171 {
172   FMod_Generator *data = (FMod_Generator *)fcm->data;
173 
174   /* behavior depends on mode
175    * NOTE: the data in its default state is fine too
176    */
177   switch (data->mode) {
178     case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
179     {
180       /* we overwrite cvalue with the sum of the polynomial */
181       float *powers = MEM_callocN(sizeof(float) * data->arraysize, "Poly Powers");
182       float value = 0.0f;
183 
184       /* for each x^n, precalculate value based on previous one first... this should be
185        * faster that calling pow() for each entry
186        */
187       for (uint i = 0; i < data->arraysize; i++) {
188         /* first entry is x^0 = 1, otherwise, calculate based on previous */
189         if (i) {
190           powers[i] = powers[i - 1] * evaltime;
191         }
192         else {
193           powers[0] = 1;
194         }
195       }
196 
197       /* for each coefficient, add to value, which we'll write to *cvalue in one go */
198       for (uint i = 0; i < data->arraysize; i++) {
199         value += data->coefficients[i] * powers[i];
200       }
201 
202       /* only if something changed, write *cvalue in one go */
203       if (data->poly_order) {
204         if (data->flag & FCM_GENERATOR_ADDITIVE) {
205           *cvalue += value;
206         }
207         else {
208           *cvalue = value;
209         }
210       }
211 
212       /* cleanup */
213       if (powers) {
214         MEM_freeN(powers);
215       }
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,
224        * solve for that bracket before accumulating in value by multiplying. */
225       for (cp = data->coefficients, i = 0; (cp) && (i < (uint)data->poly_order); cp += 2, i++) {
226         value *= (cp[0] * evaltime + cp[1]);
227       }
228 
229       /* only if something changed, write *cvalue in one go */
230       if (data->poly_order) {
231         if (data->flag & FCM_GENERATOR_ADDITIVE) {
232           *cvalue += value;
233         }
234         else {
235           *cvalue = value;
236         }
237       }
238       break;
239     }
240   }
241 }
242 
243 static FModifierTypeInfo FMI_GENERATOR = {
244     FMODIFIER_TYPE_GENERATOR, /* type */
245     sizeof(FMod_Generator),   /* size */
246     FMI_TYPE_GENERATE_CURVE,  /* action type */
247     FMI_REQUIRES_NOTHING,     /* requirements */
248     N_("Generator"),          /* name */
249     "FMod_Generator",         /* struct name */
250     0,                        /* storage size */
251     fcm_generator_free,       /* free data */
252     fcm_generator_copy,       /* copy data */
253     fcm_generator_new_data,   /* new data */
254     fcm_generator_verify,     /* verify */
255     NULL,                     /* evaluate time */
256     fcm_generator_evaluate,   /* evaluate */
257 };
258 
259 /* Built-In Function Generator F-Curve Modifier --------------------------- */
260 
261 /* This uses the general equation for equations:
262  *   y = amplitude * fn(phase_multiplier * x + phase_offset) + y_offset
263  *
264  * where amplitude, phase_multiplier/offset, y_offset are user-defined coefficients,
265  * x is the evaluation 'time', and 'y' is the resultant value
266  *
267  * Functions available are
268  * sin, cos, tan, sinc (normalized sin), natural log, square root
269  */
270 
fcm_fn_generator_new_data(void * mdata)271 static void fcm_fn_generator_new_data(void *mdata)
272 {
273   FMod_FunctionGenerator *data = (FMod_FunctionGenerator *)mdata;
274 
275   /* set amplitude and phase multiplier to 1.0f so that something is generated */
276   data->amplitude = 1.0f;
277   data->phase_multiplier = 1.0f;
278 }
279 
280 /* Unary 'normalized sine' function
281  * y = sin(PI + x) / (PI * x),
282  * except for x = 0 when y = 1.
283  */
sinc(double x)284 static double sinc(double x)
285 {
286   if (fabs(x) < 0.0001) {
287     return 1.0;
288   }
289 
290   return sin(M_PI * x) / (M_PI * x);
291 }
292 
fcm_fn_generator_evaluate(FCurve * UNUSED (fcu),FModifier * fcm,float * cvalue,float evaltime,void * UNUSED (storage))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 
fcm_envelope_free(FModifier * fcm)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 
fcm_envelope_copy(FModifier * fcm,const FModifier * src)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 
fcm_envelope_new_data(void * mdata)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 
fcm_envelope_verify(FModifier * fcm)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 
fcm_envelope_evaluate(FCurve * UNUSED (fcu),FModifier * fcm,float * cvalue,float evaltime,void * UNUSED (storage))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 
BKE_fcm_envelope_find_index(FCM_EnvelopeData array[],float frame,int arraylen,bool * r_exists)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 
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   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   if (frame > framenum) {
549     return arraylen;
550   }
551 
552   /* most of the time, this loop is just to find where to put it
553    * - 'loopbreaker' is just here to prevent infinite loops
554    */
555   for (loopbreaker = 0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
556     /* compute and get midpoint */
557 
558     /* we calculate the midpoint this way to avoid int overflows... */
559     int mid = start + ((end - start) / 2);
560 
561     float midfra = array[mid].time;
562 
563     /* check if exactly equal to midpoint */
564     if (IS_EQT(frame, midfra, BINARYSEARCH_FRAMEEQ_THRESH)) {
565       *r_exists = true;
566       return mid;
567     }
568 
569     /* repeat in upper/lower half */
570     if (frame > midfra) {
571       start = mid + 1;
572     }
573     else if (frame < midfra) {
574       end = mid - 1;
575     }
576   }
577 
578   /* print error if loop-limit exceeded */
579   if (loopbreaker == (maxloop - 1)) {
580     CLOG_ERROR(&LOG, "binary search was taking too long");
581 
582     // include debug info
583     CLOG_ERROR(&LOG,
584                "\tround = %d: start = %d, end = %d, arraylen = %d",
585                loopbreaker,
586                start,
587                end,
588                arraylen);
589   }
590 
591   /* not found, so return where to place it */
592   return start;
593 }
594 #undef BINARYSEARCH_FRAMEEQ_THRESH
595 
596 /* Cycles F-Curve Modifier  --------------------------- */
597 
598 /* This modifier changes evaltime to something that exists within the curve's frame-range,
599  * then re-evaluates modifier stack up to this point using the new time. This re-entrant behavior
600  * is very likely to be more time-consuming than the original approach...
601  * (which was tightly integrated into the calculation code...).
602  *
603  * NOTE: this needs to be at the start of the stack to be of use,
604  * as it needs to know the extents of the keyframes/sample-data.
605  *
606  * Possible TODO - store length of cycle information that can be initialized from the extents of
607  * the keyframes/sample-data, and adjusted as appropriate.
608  */
609 
610 /* temp data used during evaluation */
611 typedef struct tFCMED_Cycles {
612   float cycyofs; /* y-offset to apply */
613 } tFCMED_Cycles;
614 
fcm_cycles_new_data(void * mdata)615 static void fcm_cycles_new_data(void *mdata)
616 {
617   FMod_Cycles *data = (FMod_Cycles *)mdata;
618 
619   /* turn on cycles by default */
620   data->before_mode = data->after_mode = FCM_EXTRAPOLATE_CYCLIC;
621 }
622 
fcm_cycles_time(FCurve * fcu,FModifier * fcm,float UNUSED (cvalue),float evaltime,void * storage_)623 static float fcm_cycles_time(
624     FCurve *fcu, FModifier *fcm, float UNUSED(cvalue), float evaltime, void *storage_)
625 {
626   FMod_Cycles *data = (FMod_Cycles *)fcm->data;
627   tFCMED_Cycles *storage = storage_;
628   float prevkey[2], lastkey[2], cycyofs = 0.0f;
629   short side = 0, mode = 0;
630   int cycles = 0;
631   float ofs = 0;
632 
633   /* Initialize storage. */
634   storage->cycyofs = 0;
635 
636   /* check if modifier is first in stack, otherwise disable ourself... */
637   /* FIXME... */
638   if (fcm->prev) {
639     fcm->flag |= FMODIFIER_FLAG_DISABLED;
640     return evaltime;
641   }
642 
643   /* calculate new evaltime due to cyclic interpolation */
644   if (fcu && fcu->bezt) {
645     BezTriple *prevbezt = fcu->bezt;
646     BezTriple *lastbezt = prevbezt + fcu->totvert - 1;
647 
648     prevkey[0] = prevbezt->vec[1][0];
649     prevkey[1] = prevbezt->vec[1][1];
650 
651     lastkey[0] = lastbezt->vec[1][0];
652     lastkey[1] = lastbezt->vec[1][1];
653   }
654   else if (fcu && fcu->fpt) {
655     FPoint *prevfpt = fcu->fpt;
656     FPoint *lastfpt = prevfpt + fcu->totvert - 1;
657 
658     prevkey[0] = prevfpt->vec[0];
659     prevkey[1] = prevfpt->vec[1];
660 
661     lastkey[0] = lastfpt->vec[0];
662     lastkey[1] = lastfpt->vec[1];
663   }
664   else {
665     return evaltime;
666   }
667 
668   /* check if modifier will do anything
669    * 1) if in data range, definitely don't do anything
670    * 2) if before first frame or after last frame, make sure some cycling is in use
671    */
672   if (evaltime < prevkey[0]) {
673     if (data->before_mode) {
674       side = -1;
675       mode = data->before_mode;
676       cycles = data->before_cycles;
677       ofs = prevkey[0];
678     }
679   }
680   else if (evaltime > lastkey[0]) {
681     if (data->after_mode) {
682       side = 1;
683       mode = data->after_mode;
684       cycles = data->after_cycles;
685       ofs = lastkey[0];
686     }
687   }
688   if ((ELEM(0, side, mode))) {
689     return evaltime;
690   }
691 
692   /* find relative place within a cycle */
693   {
694     float cycdx = 0, cycdy = 0;
695     float cycle = 0, cyct = 0;
696 
697     /* calculate period and amplitude (total height) of a cycle */
698     cycdx = lastkey[0] - prevkey[0];
699     cycdy = lastkey[1] - prevkey[1];
700 
701     /* check if cycle is infinitely small, to be point of being impossible to use */
702     if (cycdx == 0) {
703       return evaltime;
704     }
705 
706     /* calculate the 'number' of the cycle */
707     cycle = ((float)side * (evaltime - ofs) / cycdx);
708 
709     /* calculate the time inside the cycle */
710     cyct = fmod(evaltime - ofs, cycdx);
711 
712     /* check that cyclic is still enabled for the specified time */
713     if (cycles == 0) {
714       /* catch this case so that we don't exit when we have (cycles = 0)
715        * as this indicates infinite cycles...
716        */
717     }
718     else if (cycle > cycles) {
719       /* we are too far away from range to evaluate
720        * TODO: but we should still hold last value...
721        */
722       return evaltime;
723     }
724 
725     /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */
726     if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
727       if (side < 0) {
728         cycyofs = (float)floor((evaltime - ofs) / cycdx);
729       }
730       else {
731         cycyofs = (float)ceil((evaltime - ofs) / cycdx);
732       }
733       cycyofs *= cycdy;
734     }
735 
736     /* special case for cycle start/end */
737     if (cyct == 0.0f) {
738       evaltime = (side == 1 ? lastkey[0] : prevkey[0]);
739 
740       if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)cycle % 2)) {
741         evaltime = (side == 1 ? prevkey[0] : lastkey[0]);
742       }
743     }
744     /* calculate where in the cycle we are (overwrite evaltime to reflect this) */
745     else if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle + 1) % 2)) {
746       /* When 'mirror' option is used and cycle number is odd, this cycle is played in reverse
747        * - for 'before' extrapolation, we need to flip in a different way, otherwise values past
748        *   then end of the curve get referenced
749        *   (result of fmod will be negative, and with different phase).
750        */
751       if (side < 0) {
752         evaltime = prevkey[0] - cyct;
753       }
754       else {
755         evaltime = lastkey[0] - cyct;
756       }
757     }
758     else {
759       /* the cycle is played normally... */
760       evaltime = prevkey[0] + cyct;
761     }
762     if (evaltime < prevkey[0]) {
763       evaltime += cycdx;
764     }
765   }
766 
767   /* store temp data if needed */
768   if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
769     storage->cycyofs = cycyofs;
770   }
771 
772   /* return the new frame to evaluate */
773   return evaltime;
774 }
775 
fcm_cycles_evaluate(FCurve * UNUSED (fcu),FModifier * UNUSED (fcm),float * cvalue,float UNUSED (evaltime),void * storage_)776 static void fcm_cycles_evaluate(FCurve *UNUSED(fcu),
777                                 FModifier *UNUSED(fcm),
778                                 float *cvalue,
779                                 float UNUSED(evaltime),
780                                 void *storage_)
781 {
782   tFCMED_Cycles *storage = storage_;
783   *cvalue += storage->cycyofs;
784 }
785 
786 static FModifierTypeInfo FMI_CYCLES = {
787     FMODIFIER_TYPE_CYCLES,      /* type */
788     sizeof(FMod_Cycles),        /* size */
789     FMI_TYPE_EXTRAPOLATION,     /* action type */
790     FMI_REQUIRES_ORIGINAL_DATA, /* requirements */
791     N_("Cycles"),               /* name */
792     "FMod_Cycles",              /* struct name */
793     sizeof(tFCMED_Cycles),      /* storage size */
794     NULL,                       /* free data */
795     NULL,                       /* copy data */
796     fcm_cycles_new_data,        /* new data */
797     NULL /*fcm_cycles_verify*/, /* verify */
798     fcm_cycles_time,            /* evaluate time */
799     fcm_cycles_evaluate,        /* evaluate */
800 };
801 
802 /* Noise F-Curve Modifier  --------------------------- */
803 
fcm_noise_new_data(void * mdata)804 static void fcm_noise_new_data(void *mdata)
805 {
806   FMod_Noise *data = (FMod_Noise *)mdata;
807 
808   /* defaults */
809   data->size = 1.0f;
810   data->strength = 1.0f;
811   data->phase = 1.0f;
812   data->offset = 0.0f;
813   data->depth = 0;
814   data->modification = FCM_NOISE_MODIF_REPLACE;
815 }
816 
fcm_noise_evaluate(FCurve * UNUSED (fcu),FModifier * fcm,float * cvalue,float evaltime,void * UNUSED (storage))817 static void fcm_noise_evaluate(
818     FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime, void *UNUSED(storage))
819 {
820   FMod_Noise *data = (FMod_Noise *)fcm->data;
821   float noise;
822 
823   /* generate noise using good old Blender Noise
824    * - 0.1 is passed as the 'z' value, otherwise evaluation fails for size = phase = 1
825    *   with evaltime being an integer (which happens when evaluating on frame by frame basis)
826    */
827   noise = BLI_turbulence(data->size, evaltime - data->offset, data->phase, 0.1f, data->depth);
828 
829   /* combine the noise with existing motion data */
830   switch (data->modification) {
831     case FCM_NOISE_MODIF_ADD:
832       *cvalue = *cvalue + noise * data->strength;
833       break;
834     case FCM_NOISE_MODIF_SUBTRACT:
835       *cvalue = *cvalue - noise * data->strength;
836       break;
837     case FCM_NOISE_MODIF_MULTIPLY:
838       *cvalue = *cvalue * noise * data->strength;
839       break;
840     case FCM_NOISE_MODIF_REPLACE:
841     default:
842       *cvalue = *cvalue + (noise - 0.5f) * data->strength;
843       break;
844   }
845 }
846 
847 static FModifierTypeInfo FMI_NOISE = {
848     FMODIFIER_TYPE_NOISE,      /* type */
849     sizeof(FMod_Noise),        /* size */
850     FMI_TYPE_REPLACE_VALUES,   /* action type */
851     0,                         /* requirements */
852     N_("Noise"),               /* name */
853     "FMod_Noise",              /* struct name */
854     0,                         /* storage size */
855     NULL,                      /* free data */
856     NULL,                      /* copy data */
857     fcm_noise_new_data,        /* new data */
858     NULL /*fcm_noise_verify*/, /* verify */
859     NULL,                      /* evaluate time */
860     fcm_noise_evaluate,        /* evaluate */
861 };
862 
863 /* Python F-Curve Modifier --------------------------- */
864 
fcm_python_free(FModifier * fcm)865 static void fcm_python_free(FModifier *fcm)
866 {
867   FMod_Python *data = (FMod_Python *)fcm->data;
868 
869   /* id-properties */
870   IDP_FreeProperty(data->prop);
871 }
872 
fcm_python_new_data(void * mdata)873 static void fcm_python_new_data(void *mdata)
874 {
875   FMod_Python *data = (FMod_Python *)mdata;
876 
877   /* everything should be set correctly by calloc, except for the prop->type constant.*/
878   data->prop = MEM_callocN(sizeof(IDProperty), "PyFModifierProps");
879   data->prop->type = IDP_GROUP;
880 }
881 
fcm_python_copy(FModifier * fcm,const FModifier * src)882 static void fcm_python_copy(FModifier *fcm, const FModifier *src)
883 {
884   FMod_Python *pymod = (FMod_Python *)fcm->data;
885   FMod_Python *opymod = (FMod_Python *)src->data;
886 
887   pymod->prop = IDP_CopyProperty(opymod->prop);
888 }
889 
fcm_python_evaluate(FCurve * UNUSED (fcu),FModifier * UNUSED (fcm),float * UNUSED (cvalue),float UNUSED (evaltime),void * UNUSED (storage))890 static void fcm_python_evaluate(FCurve *UNUSED(fcu),
891                                 FModifier *UNUSED(fcm),
892                                 float *UNUSED(cvalue),
893                                 float UNUSED(evaltime),
894                                 void *UNUSED(storage))
895 {
896 #ifdef WITH_PYTHON
897   // FMod_Python *data = (FMod_Python *)fcm->data;
898 
899   /* FIXME... need to implement this modifier...
900    * It will need it execute a script using the custom properties
901    */
902 #endif /* WITH_PYTHON */
903 }
904 
905 static FModifierTypeInfo FMI_PYTHON = {
906     FMODIFIER_TYPE_PYTHON,      /* type */
907     sizeof(FMod_Python),        /* size */
908     FMI_TYPE_GENERATE_CURVE,    /* action type */
909     FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
910     N_("Python"),               /* name */
911     "FMod_Python",              /* struct name */
912     0,                          /* storage size */
913     fcm_python_free,            /* free data */
914     fcm_python_copy,            /* copy data */
915     fcm_python_new_data,        /* new data */
916     NULL /*fcm_python_verify*/, /* verify */
917     NULL /*fcm_python_time*/,   /* evaluate time */
918     fcm_python_evaluate,        /* evaluate */
919 };
920 
921 /* Limits F-Curve Modifier --------------------------- */
922 
fcm_limits_time(FCurve * UNUSED (fcu),FModifier * fcm,float UNUSED (cvalue),float evaltime,void * UNUSED (storage))923 static float fcm_limits_time(FCurve *UNUSED(fcu),
924                              FModifier *fcm,
925                              float UNUSED(cvalue),
926                              float evaltime,
927                              void *UNUSED(storage))
928 {
929   FMod_Limits *data = (FMod_Limits *)fcm->data;
930 
931   /* check for the time limits */
932   if ((data->flag & FCM_LIMIT_XMIN) && (evaltime < data->rect.xmin)) {
933     return data->rect.xmin;
934   }
935   if ((data->flag & FCM_LIMIT_XMAX) && (evaltime > data->rect.xmax)) {
936     return data->rect.xmax;
937   }
938 
939   /* modifier doesn't change time */
940   return evaltime;
941 }
942 
fcm_limits_evaluate(FCurve * UNUSED (fcu),FModifier * fcm,float * cvalue,float UNUSED (evaltime),void * UNUSED (storage))943 static void fcm_limits_evaluate(FCurve *UNUSED(fcu),
944                                 FModifier *fcm,
945                                 float *cvalue,
946                                 float UNUSED(evaltime),
947                                 void *UNUSED(storage))
948 {
949   FMod_Limits *data = (FMod_Limits *)fcm->data;
950 
951   /* value limits now */
952   if ((data->flag & FCM_LIMIT_YMIN) && (*cvalue < data->rect.ymin)) {
953     *cvalue = data->rect.ymin;
954   }
955   if ((data->flag & FCM_LIMIT_YMAX) && (*cvalue > data->rect.ymax)) {
956     *cvalue = data->rect.ymax;
957   }
958 }
959 
960 static FModifierTypeInfo FMI_LIMITS = {
961     FMODIFIER_TYPE_LIMITS, /* type */
962     sizeof(FMod_Limits),   /* size */
963     FMI_TYPE_GENERATE_CURVE,
964     /* action type */           /* XXX... err... */
965     FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
966     N_("Limits"),               /* name */
967     "FMod_Limits",              /* struct name */
968     0,                          /* storage size */
969     NULL,                       /* free data */
970     NULL,                       /* copy data */
971     NULL,                       /* new data */
972     NULL,                       /* verify */
973     fcm_limits_time,            /* evaluate time */
974     fcm_limits_evaluate,        /* evaluate */
975 };
976 
977 /* Stepped F-Curve Modifier --------------------------- */
978 
fcm_stepped_new_data(void * mdata)979 static void fcm_stepped_new_data(void *mdata)
980 {
981   FMod_Stepped *data = (FMod_Stepped *)mdata;
982 
983   /* just need to set the step-size to 2-frames by default */
984   /* XXX: or would 5 be more normal? */
985   data->step_size = 2.0f;
986 }
987 
fcm_stepped_time(FCurve * UNUSED (fcu),FModifier * fcm,float UNUSED (cvalue),float evaltime,void * UNUSED (storage))988 static float fcm_stepped_time(FCurve *UNUSED(fcu),
989                               FModifier *fcm,
990                               float UNUSED(cvalue),
991                               float evaltime,
992                               void *UNUSED(storage))
993 {
994   FMod_Stepped *data = (FMod_Stepped *)fcm->data;
995   int snapblock;
996 
997   /* check range clamping to see if we should alter the timing to achieve the desired results */
998   if (data->flag & FCM_STEPPED_NO_BEFORE) {
999     if (evaltime < data->start_frame) {
1000       return evaltime;
1001     }
1002   }
1003   if (data->flag & FCM_STEPPED_NO_AFTER) {
1004     if (evaltime > data->end_frame) {
1005       return evaltime;
1006     }
1007   }
1008 
1009   /* we snap to the start of the previous closest block of 'step_size' frames
1010    * after the start offset has been discarded
1011    * - i.e. round down
1012    */
1013   snapblock = (int)((evaltime - data->offset) / data->step_size);
1014 
1015   /* reapply the offset, and multiple the snapblock by the size of the steps to get
1016    * the new time to evaluate at
1017    */
1018   return ((float)snapblock * data->step_size) + data->offset;
1019 }
1020 
1021 static FModifierTypeInfo FMI_STEPPED = {
1022     FMODIFIER_TYPE_STEPPED, /* type */
1023     sizeof(FMod_Limits),    /* size */
1024     FMI_TYPE_GENERATE_CURVE,
1025     /* action type */           /* XXX... err... */
1026     FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
1027     N_("Stepped"),              /* name */
1028     "FMod_Stepped",             /* struct name */
1029     0,                          /* storage size */
1030     NULL,                       /* free data */
1031     NULL,                       /* copy data */
1032     fcm_stepped_new_data,       /* new data */
1033     NULL,                       /* verify */
1034     fcm_stepped_time,           /* evaluate time */
1035     NULL,                       /* evaluate */
1036 };
1037 
1038 /** \} */
1039 
1040 /* -------------------------------------------------------------------- */
1041 /** \name F-Curve Modifier Type API
1042  *
1043  * all of the f-curve modifier api functions use #fmodifiertypeinfo structs to carry out
1044  * and operations that involve f-curve modifier specific code.
1045  * \{ */
1046 
1047 /* These globals only ever get directly accessed in this file */
1048 static FModifierTypeInfo *fmodifiersTypeInfo[FMODIFIER_NUM_TYPES];
1049 static short FMI_INIT = 1; /* when non-zero, the list needs to be updated */
1050 
1051 /** This function only gets called when #FMI_INIT is non-zero. */
fmods_init_typeinfo(void)1052 static void fmods_init_typeinfo(void)
1053 {
1054   fmodifiersTypeInfo[0] = NULL;              /* 'Null' F-Curve Modifier */
1055   fmodifiersTypeInfo[1] = &FMI_GENERATOR;    /* Generator F-Curve Modifier */
1056   fmodifiersTypeInfo[2] = &FMI_FN_GENERATOR; /* Built-In Function Generator F-Curve Modifier */
1057   fmodifiersTypeInfo[3] = &FMI_ENVELOPE;     /* Envelope F-Curve Modifier */
1058   fmodifiersTypeInfo[4] = &FMI_CYCLES;       /* Cycles F-Curve Modifier */
1059   fmodifiersTypeInfo[5] = &FMI_NOISE;        /* Apply-Noise F-Curve Modifier */
1060   fmodifiersTypeInfo[6] = NULL /*&FMI_FILTER*/;
1061   /* Filter F-Curve Modifier */         /* XXX unimplemented. */
1062   fmodifiersTypeInfo[7] = &FMI_PYTHON;  /* Custom Python F-Curve Modifier */
1063   fmodifiersTypeInfo[8] = &FMI_LIMITS;  /* Limits F-Curve Modifier */
1064   fmodifiersTypeInfo[9] = &FMI_STEPPED; /* Stepped F-Curve Modifier */
1065 }
1066 
1067 /**
1068  * This function should be used for getting the appropriate type-info when only
1069  * a F-Curve modifier type is known.
1070  */
get_fmodifier_typeinfo(const int type)1071 const FModifierTypeInfo *get_fmodifier_typeinfo(const int type)
1072 {
1073   /* initialize the type-info list? */
1074   if (FMI_INIT) {
1075     fmods_init_typeinfo();
1076     FMI_INIT = 0;
1077   }
1078 
1079   /* only return for valid types */
1080   if ((type >= FMODIFIER_TYPE_NULL) && (type < FMODIFIER_NUM_TYPES)) {
1081     /* there shouldn't be any segfaults here... */
1082     return fmodifiersTypeInfo[type];
1083   }
1084 
1085   CLOG_ERROR(&LOG, "No valid F-Curve Modifier type-info data available. Type = %i", type);
1086 
1087   return NULL;
1088 }
1089 
1090 /**
1091  * This function should always be used to get the appropriate type-info,
1092  * as it has checks which prevent segfaults in some weird cases.
1093  */
fmodifier_get_typeinfo(const FModifier * fcm)1094 const FModifierTypeInfo *fmodifier_get_typeinfo(const FModifier *fcm)
1095 {
1096   /* only return typeinfo for valid modifiers */
1097   if (fcm) {
1098     return get_fmodifier_typeinfo(fcm->type);
1099   }
1100 
1101   return NULL;
1102 }
1103 
1104 /** \} */
1105 
1106 /* -------------------------------------------------------------------- */
1107 /** \name F-Curve Modifier Public API
1108  * \{ */
1109 
1110 /**
1111  * Add a new F-Curve Modifier to the given F-Curve of a certain type.
1112  */
add_fmodifier(ListBase * modifiers,int type,FCurve * owner_fcu)1113 FModifier *add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
1114 {
1115   const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
1116   FModifier *fcm;
1117 
1118   /* sanity checks */
1119   if (ELEM(NULL, modifiers, fmi)) {
1120     return NULL;
1121   }
1122 
1123   /* special checks for whether modifier can be added */
1124   if ((modifiers->first) && (type == FMODIFIER_TYPE_CYCLES)) {
1125     /* cycles modifier must be first in stack, so for now, don't add if it can't be */
1126     /* TODO: perhaps there is some better way, but for now, */
1127     CLOG_STR_ERROR(&LOG,
1128                    "Cannot add 'Cycles' modifier to F-Curve, as 'Cycles' modifier can only be "
1129                    "first in stack.");
1130     return NULL;
1131   }
1132 
1133   /* add modifier itself */
1134   fcm = MEM_callocN(sizeof(FModifier), "F-Curve Modifier");
1135   fcm->type = type;
1136   fcm->flag = FMODIFIER_FLAG_EXPANDED;
1137   fcm->curve = owner_fcu;
1138   fcm->influence = 1.0f;
1139   BLI_addtail(modifiers, fcm);
1140 
1141   /* tag modifier as "active" if no other modifiers exist in the stack yet */
1142   if (BLI_listbase_is_single(modifiers)) {
1143     fcm->flag |= FMODIFIER_FLAG_ACTIVE;
1144   }
1145 
1146   /* add modifier's data */
1147   fcm->data = MEM_callocN(fmi->size, fmi->structName);
1148 
1149   /* init custom settings if necessary */
1150   if (fmi->new_data) {
1151     fmi->new_data(fcm->data);
1152   }
1153 
1154   /* update the fcurve if the Cycles modifier is added */
1155   if ((owner_fcu) && (type == FMODIFIER_TYPE_CYCLES)) {
1156     calchandles_fcurve(owner_fcu);
1157   }
1158 
1159   /* return modifier for further editing */
1160   return fcm;
1161 }
1162 
1163 /**
1164  * Make a copy of the specified F-Modifier.
1165  */
copy_fmodifier(const FModifier * src)1166 FModifier *copy_fmodifier(const FModifier *src)
1167 {
1168   const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(src);
1169   FModifier *dst;
1170 
1171   /* sanity check */
1172   if (src == NULL) {
1173     return NULL;
1174   }
1175 
1176   /* copy the base data, clearing the links */
1177   dst = MEM_dupallocN(src);
1178   dst->next = dst->prev = NULL;
1179   dst->curve = NULL;
1180 
1181   /* make a new copy of the F-Modifier's data */
1182   dst->data = MEM_dupallocN(src->data);
1183 
1184   /* only do specific constraints if required */
1185   if (fmi && fmi->copy_data) {
1186     fmi->copy_data(dst, src);
1187   }
1188 
1189   /* return the new modifier */
1190   return dst;
1191 }
1192 
1193 /**
1194  * Duplicate all of the F-Modifiers in the Modifier stacks.
1195  */
copy_fmodifiers(ListBase * dst,const ListBase * src)1196 void copy_fmodifiers(ListBase *dst, const ListBase *src)
1197 {
1198   FModifier *fcm, *srcfcm;
1199 
1200   if (ELEM(NULL, dst, src)) {
1201     return;
1202   }
1203 
1204   BLI_listbase_clear(dst);
1205   BLI_duplicatelist(dst, src);
1206 
1207   for (fcm = dst->first, srcfcm = src->first; fcm && srcfcm;
1208        srcfcm = srcfcm->next, fcm = fcm->next) {
1209     const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
1210 
1211     /* make a new copy of the F-Modifier's data */
1212     fcm->data = MEM_dupallocN(fcm->data);
1213     fcm->curve = NULL;
1214 
1215     /* only do specific constraints if required */
1216     if (fmi && fmi->copy_data) {
1217       fmi->copy_data(fcm, srcfcm);
1218     }
1219   }
1220 }
1221 
1222 /**
1223  * Remove and free the given F-Modifier from the given stack.
1224  */
remove_fmodifier(ListBase * modifiers,FModifier * fcm)1225 bool remove_fmodifier(ListBase *modifiers, FModifier *fcm)
1226 {
1227   const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
1228 
1229   /* sanity check */
1230   if (fcm == NULL) {
1231     return false;
1232   }
1233 
1234   /* removing the cycles modifier requires a handle update */
1235   FCurve *update_fcu = (fcm->type == FMODIFIER_TYPE_CYCLES) ? fcm->curve : NULL;
1236 
1237   /* free modifier's special data (stored inside fcm->data) */
1238   if (fcm->data) {
1239     if (fmi && fmi->free_data) {
1240       fmi->free_data(fcm);
1241     }
1242 
1243     /* free modifier's data (fcm->data) */
1244     MEM_freeN(fcm->data);
1245   }
1246 
1247   /* remove modifier from stack */
1248   if (modifiers) {
1249     BLI_freelinkN(modifiers, fcm);
1250 
1251     /* update the fcurve if the Cycles modifier is removed */
1252     if (update_fcu) {
1253       calchandles_fcurve(update_fcu);
1254     }
1255 
1256     return true;
1257   }
1258 
1259   /* XXX this case can probably be removed some day, as it shouldn't happen... */
1260   CLOG_STR_ERROR(&LOG, "no modifier stack given");
1261   MEM_freeN(fcm);
1262   return false;
1263 }
1264 
1265 /**
1266  * Remove all of a given F-Curve's modifiers.
1267  */
free_fmodifiers(ListBase * modifiers)1268 void free_fmodifiers(ListBase *modifiers)
1269 {
1270   FModifier *fcm, *fmn;
1271 
1272   /* sanity check */
1273   if (modifiers == NULL) {
1274     return;
1275   }
1276 
1277   /* free each modifier in order - modifier is unlinked from list and freed */
1278   for (fcm = modifiers->first; fcm; fcm = fmn) {
1279     fmn = fcm->next;
1280     remove_fmodifier(modifiers, fcm);
1281   }
1282 }
1283 
1284 /**
1285  * Find the active F-Modifier.
1286  */
find_active_fmodifier(ListBase * modifiers)1287 FModifier *find_active_fmodifier(ListBase *modifiers)
1288 {
1289   FModifier *fcm;
1290 
1291   /* sanity checks */
1292   if (ELEM(NULL, modifiers, modifiers->first)) {
1293     return NULL;
1294   }
1295 
1296   /* loop over modifiers until 'active' one is found */
1297   for (fcm = modifiers->first; fcm; fcm = fcm->next) {
1298     if (fcm->flag & FMODIFIER_FLAG_ACTIVE) {
1299       return fcm;
1300     }
1301   }
1302 
1303   /* no modifier is active */
1304   return NULL;
1305 }
1306 
1307 /**
1308  * Set the active F-Modifier.
1309  */
set_active_fmodifier(ListBase * modifiers,FModifier * fcm)1310 void set_active_fmodifier(ListBase *modifiers, FModifier *fcm)
1311 {
1312   FModifier *fm;
1313 
1314   /* sanity checks */
1315   if (ELEM(NULL, modifiers, modifiers->first)) {
1316     return;
1317   }
1318 
1319   /* deactivate all, and set current one active */
1320   for (fm = modifiers->first; fm; fm = fm->next) {
1321     fm->flag &= ~FMODIFIER_FLAG_ACTIVE;
1322   }
1323 
1324   /* make given modifier active */
1325   if (fcm) {
1326     fcm->flag |= FMODIFIER_FLAG_ACTIVE;
1327   }
1328 }
1329 
1330 /**
1331  * Do we have any modifiers which match certain criteria.
1332  *
1333  * \param mtype: Type of modifier (if 0, doesn't matter).
1334  * \param acttype: Type of action to perform (if -1, doesn't matter).
1335  */
list_has_suitable_fmodifier(ListBase * modifiers,int mtype,short acttype)1336 bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype)
1337 {
1338   FModifier *fcm;
1339 
1340   /* if there are no specific filtering criteria, just skip */
1341   if ((mtype == 0) && (acttype == 0)) {
1342     return (modifiers && modifiers->first);
1343   }
1344 
1345   /* sanity checks */
1346   if (ELEM(NULL, modifiers, modifiers->first)) {
1347     return false;
1348   }
1349 
1350   /* Find the first modifier fitting these criteria. */
1351   for (fcm = modifiers->first; fcm; fcm = fcm->next) {
1352     const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
1353     short mOk = 1, aOk = 1; /* by default 1, so that when only one test, won't fail */
1354 
1355     /* check if applicable ones are fulfilled */
1356     if (mtype) {
1357       mOk = (fcm->type == mtype);
1358     }
1359     if (acttype > -1) {
1360       aOk = (fmi->acttype == acttype);
1361     }
1362 
1363     /* if both are ok, we've found a hit */
1364     if (mOk && aOk) {
1365       return true;
1366     }
1367   }
1368 
1369   /* no matches */
1370   return false;
1371 }
1372 
1373 /* Evaluation API --------------------------- */
1374 
evaluate_fmodifiers_storage_size_per_modifier(ListBase * modifiers)1375 uint evaluate_fmodifiers_storage_size_per_modifier(ListBase *modifiers)
1376 {
1377   /* Sanity checks. */
1378   if (ELEM(NULL, modifiers, modifiers->first)) {
1379     return 0;
1380   }
1381 
1382   uint max_size = 0;
1383 
1384   LISTBASE_FOREACH (FModifier *, fcm, modifiers) {
1385     const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
1386 
1387     if (fmi == NULL) {
1388       continue;
1389     }
1390 
1391     max_size = MAX2(max_size, fmi->storage_size);
1392   }
1393 
1394   return max_size;
1395 }
1396 
1397 /**
1398  * Helper function - calculate influence of #FModifier.
1399  */
eval_fmodifier_influence(FModifier * fcm,float evaltime)1400 static float eval_fmodifier_influence(FModifier *fcm, float evaltime)
1401 {
1402   float influence;
1403 
1404   /* sanity check */
1405   if (fcm == NULL) {
1406     return 0.0f;
1407   }
1408 
1409   /* should we use influence stored in modifier or not
1410    * NOTE: this is really just a hack so that we don't need to version patch old files ;)
1411    */
1412   if (fcm->flag & FMODIFIER_FLAG_USEINFLUENCE) {
1413     influence = fcm->influence;
1414   }
1415   else {
1416     influence = 1.0f;
1417   }
1418 
1419   /* restricted range or full range? */
1420   if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) {
1421     if ((evaltime <= fcm->sfra) || (evaltime >= fcm->efra)) {
1422       /* out of range */
1423       return 0.0f;
1424     }
1425     if ((evaltime > fcm->sfra) && (evaltime < fcm->sfra + fcm->blendin)) {
1426       /* blend in range */
1427       float a = fcm->sfra;
1428       float b = fcm->sfra + fcm->blendin;
1429       return influence * (evaltime - a) / (b - a);
1430     }
1431     if ((evaltime < fcm->efra) && (evaltime > fcm->efra - fcm->blendout)) {
1432       /* blend out range */
1433       float a = fcm->efra;
1434       float b = fcm->efra - fcm->blendout;
1435       return influence * (evaltime - a) / (b - a);
1436     }
1437   }
1438 
1439   /* just return the influence of the modifier */
1440   return influence;
1441 }
1442 
1443 /**
1444  * Evaluate time modifications imposed by some F-Curve Modifiers.
1445  *
1446  * - This step acts as an optimization to prevent the F-Curve stack being evaluated
1447  *   several times by modifiers requesting the time be modified, as the final result
1448  *   would have required using the modified time
1449  * - Modifiers only ever receive the unmodified time, as subsequent modifiers should be
1450  *   working on the 'global' result of the modified curve, not some localized segment,
1451  *   so \a evaltime gets set to whatever the last time-modifying modifier likes.
1452  * - We start from the end of the stack, as only the last one matters for now.
1453  *
1454  * \param fcu: Can be NULL.
1455  */
evaluate_time_fmodifiers(FModifiersStackStorage * storage,ListBase * modifiers,FCurve * fcu,float cvalue,float evaltime)1456 float evaluate_time_fmodifiers(FModifiersStackStorage *storage,
1457                                ListBase *modifiers,
1458                                FCurve *fcu,
1459                                float cvalue,
1460                                float evaltime)
1461 {
1462   /* sanity checks */
1463   if (ELEM(NULL, modifiers, modifiers->last)) {
1464     return evaltime;
1465   }
1466 
1467   if (fcu && fcu->flag & FCURVE_MOD_OFF) {
1468     return evaltime;
1469   }
1470 
1471   /* Starting from the end of the stack, calculate the time effects of various stacked modifiers
1472    * on the time the F-Curve should be evaluated at.
1473    *
1474    * This is done in reverse order to standard evaluation, as when this is done in standard
1475    * order, each modifier would cause jumps to other points in the curve, forcing all
1476    * previous ones to be evaluated again for them to be correct. However, if we did in the
1477    * reverse order as we have here, we can consider them a macro to micro type of waterfall
1478    * effect, which should get us the desired effects when using layered time manipulations
1479    * (such as multiple 'stepped' modifiers in sequence, causing different stepping rates)
1480    */
1481   uint fcm_index = storage->modifier_count - 1;
1482   for (FModifier *fcm = modifiers->last; fcm; fcm = fcm->prev, fcm_index--) {
1483     const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
1484 
1485     if (fmi == NULL) {
1486       continue;
1487     }
1488 
1489     /* If modifier cannot be applied on this frame
1490      * (whatever scale it is on, it won't affect the results)
1491      * hence we shouldn't bother seeing what it would do given the chance. */
1492     if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 ||
1493         ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime))) {
1494       /* only evaluate if there's a callback for this */
1495       if (fmi->evaluate_modifier_time) {
1496         if ((fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) == 0) {
1497           void *storage_ptr = POINTER_OFFSET(storage->buffer,
1498                                              fcm_index * storage->size_per_modifier);
1499 
1500           float nval = fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime, storage_ptr);
1501 
1502           float influence = eval_fmodifier_influence(fcm, evaltime);
1503           evaltime = interpf(nval, evaltime, influence);
1504         }
1505       }
1506     }
1507   }
1508 
1509   /* return the modified evaltime */
1510   return evaltime;
1511 }
1512 
1513 /**
1514  * Evaluates the given set of F-Curve Modifiers using the given data
1515  * Should only be called after evaluate_time_fmodifiers() has been called.
1516  */
evaluate_value_fmodifiers(FModifiersStackStorage * storage,ListBase * modifiers,FCurve * fcu,float * cvalue,float evaltime)1517 void evaluate_value_fmodifiers(FModifiersStackStorage *storage,
1518                                ListBase *modifiers,
1519                                FCurve *fcu,
1520                                float *cvalue,
1521                                float evaltime)
1522 {
1523   FModifier *fcm;
1524 
1525   /* sanity checks */
1526   if (ELEM(NULL, modifiers, modifiers->first)) {
1527     return;
1528   }
1529 
1530   if (fcu->flag & FCURVE_MOD_OFF) {
1531     return;
1532   }
1533 
1534   /* evaluate modifiers */
1535   uint fcm_index = 0;
1536   for (fcm = modifiers->first; fcm; fcm = fcm->next, fcm_index++) {
1537     const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
1538 
1539     if (fmi == NULL) {
1540       continue;
1541     }
1542 
1543     /* Only evaluate if there's a callback for this,
1544      * and if F-Modifier can be evaluated on this frame. */
1545     if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 ||
1546         ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime))) {
1547       if (fmi->evaluate_modifier) {
1548         if ((fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) == 0) {
1549           void *storage_ptr = POINTER_OFFSET(storage->buffer,
1550                                              fcm_index * storage->size_per_modifier);
1551 
1552           float nval = *cvalue;
1553           fmi->evaluate_modifier(fcu, fcm, &nval, evaltime, storage_ptr);
1554 
1555           float influence = eval_fmodifier_influence(fcm, evaltime);
1556           *cvalue = interpf(nval, *cvalue, influence);
1557         }
1558       }
1559     }
1560   }
1561 }
1562 
1563 /* ---------- */
1564 
1565 /**
1566  * Bake modifiers for given F-Curve to curve sample data, in the frame range defined
1567  * by start and end (inclusive).
1568  */
fcurve_bake_modifiers(FCurve * fcu,int start,int end)1569 void fcurve_bake_modifiers(FCurve *fcu, int start, int end)
1570 {
1571   ChannelDriver *driver;
1572 
1573   /* sanity checks */
1574   /* TODO: make these tests report errors using reports not CLOG's */
1575   if (ELEM(NULL, fcu, fcu->modifiers.first)) {
1576     CLOG_ERROR(&LOG, "No F-Curve with F-Curve Modifiers to Bake");
1577     return;
1578   }
1579 
1580   /* temporarily, disable driver while we sample, so that they don't influence the outcome */
1581   driver = fcu->driver;
1582   fcu->driver = NULL;
1583 
1584   /* bake the modifiers, by sampling the curve at each frame */
1585   fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
1586 
1587   /* free the modifiers now */
1588   free_fmodifiers(&fcu->modifiers);
1589 
1590   /* restore driver */
1591   fcu->driver = driver;
1592 }
1593 
1594 /** \} */
1595