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