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