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