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