4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
21 * All rights reserved.
23 * Contributor(s): Joshua Leung (full recode)
25 * ***** END GPL LICENSE BLOCK *****
35 #include "MEM_guardedalloc.h"
37 #include "DNA_anim_types.h"
39 #include "BLI_blenlib.h"
40 #include "BLI_math.h" /* windows needs for M_PI */
42 #include "BKE_fcurve.h"
43 #include "BKE_idprop.h"
44 #include "BKE_utildefines.h"
46 #define SMALL -1.0e-10
49 /* ******************************** F-Modifiers ********************************* */
51 /* Info ------------------------------- */
53 /* F-Modifiers are modifiers which operate on F-Curves. However, they can also be defined
54 * on NLA-Strips to affect all of the F-Curves referenced by the NLA-Strip.
57 /* Template --------------------------- */
59 /* Each modifier defines a set of functions, which will be called at the appropriate
60 * times. In addition to this, each modifier should have a type-info struct, where
61 * its functions are attached for use.
64 /* Template for type-info data:
65 * - make a copy of this when creating new modifiers, and just change the functions
66 * pointed to as necessary
67 * - although the naming of functions doesn't matter, it would help for code
68 * readability, to follow the same naming convention as is presented here
69 * - any functions that a constraint doesn't need to define, don't define
70 * for such cases, just use NULL
71 * - these should be defined after all the functions have been defined, so that
72 * forward-definitions/prototypes don't need to be used!
73 * - keep this copy #if-def'd so that future constraints can get based off this
76 static FModifierTypeInfo FMI_MODNAME = {
77 FMODIFIER_TYPE_MODNAME, /* type */
78 sizeof(FMod_ModName), /* size */
79 FMI_TYPE_SOME_ACTION, /* action type */
80 FMI_REQUIRES_SOME_REQUIREMENT, /* requirements */
81 "Modifier Name", /* name */
82 "FMod_ModName", /* struct name */
83 fcm_modname_free, /* free data */
84 fcm_modname_relink, /* relink data */
85 fcm_modname_copy, /* copy data */
86 fcm_modname_new_data, /* new data */
87 fcm_modname_verify, /* verify */
88 fcm_modname_time, /* evaluate time */
89 fcm_modname_evaluate /* evaluate */
93 /* Generator F-Curve Modifier --------------------------- */
95 /* Generators available:
96 * 1) simple polynomial generator:
97 * - Exanded form - (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n])
98 * - Factorised form - (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1]))
101 static void fcm_generator_free (FModifier *fcm)
103 FMod_Generator *data= (FMod_Generator *)fcm->data;
105 /* free polynomial coefficients array */
106 if (data->coefficients)
107 MEM_freeN(data->coefficients);
110 static void fcm_generator_copy (FModifier *fcm, FModifier *src)
112 FMod_Generator *gen= (FMod_Generator *)fcm->data;
113 FMod_Generator *ogen= (FMod_Generator *)src->data;
115 /* copy coefficients array? */
116 if (ogen->coefficients)
117 gen->coefficients= MEM_dupallocN(ogen->coefficients);
120 static void fcm_generator_new_data (void *mdata)
122 FMod_Generator *data= (FMod_Generator *)mdata;
125 /* set default generator to be linear 0-1 (gradient = 1, y-offset = 0) */
128 cp= data->coefficients= MEM_callocN(sizeof(float)*2, "FMod_Generator_Coefs");
129 cp[0] = 0; // y-offset
130 cp[1] = 1; // gradient
133 static void fcm_generator_verify (FModifier *fcm)
135 FMod_Generator *data= (FMod_Generator *)fcm->data;
137 /* requirements depend on mode */
138 switch (data->mode) {
139 case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
141 /* arraysize needs to be order+1, so resize if not */
142 if (data->arraysize != (data->poly_order+1)) {
145 /* make new coefficients array, and copy over as much data as can fit */
146 nc= MEM_callocN(sizeof(float)*(data->poly_order+1), "FMod_Generator_Coefs");
148 if (data->coefficients) {
149 if (data->arraysize > (data->poly_order+1))
150 memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order+1));
152 memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
154 /* free the old data */
155 MEM_freeN(data->coefficients);
158 /* set the new data */
159 data->coefficients= nc;
160 data->arraysize= data->poly_order+1;
165 case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* expanded polynomial expression */
167 /* arraysize needs to be 2*order, so resize if not */
168 if (data->arraysize != (data->poly_order * 2)) {
171 /* make new coefficients array, and copy over as much data as can fit */
172 nc= MEM_callocN(sizeof(float)*(data->poly_order*2), "FMod_Generator_Coefs");
174 if (data->coefficients) {
175 if (data->arraysize > (data->poly_order * 2))
176 memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order * 2));
178 memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
180 /* free the old data */
181 MEM_freeN(data->coefficients);
184 /* set the new data */
185 data->coefficients= nc;
186 data->arraysize= data->poly_order * 2;
193 static void fcm_generator_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
195 FMod_Generator *data= (FMod_Generator *)fcm->data;
197 /* behaviour depends on mode
198 * NOTE: the data in its default state is fine too
200 switch (data->mode) {
201 case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
203 /* we overwrite cvalue with the sum of the polynomial */
204 float *powers = MEM_callocN(sizeof(float)*data->arraysize, "Poly Powers");
208 /* for each x^n, precalculate value based on previous one first... this should be
209 * faster that calling pow() for each entry
211 for (i=0; i < data->arraysize; i++) {
212 /* first entry is x^0 = 1, otherwise, calculate based on previous */
214 powers[i]= powers[i-1] * evaltime;
219 /* for each coefficient, add to value, which we'll write to *cvalue in one go */
220 for (i=0; i < data->arraysize; i++)
221 value += data->coefficients[i] * powers[i];
223 /* only if something changed, write *cvalue in one go */
224 if (data->poly_order) {
225 if (data->flag & FCM_GENERATOR_ADDITIVE)
237 case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial */
239 float value= 1.0f, *cp=NULL;
242 /* for each coefficient pair, solve for that bracket before accumulating in value by multiplying */
243 for (cp=data->coefficients, i=0; (cp) && (i < data->poly_order); cp+=2, i++)
244 value *= (cp[0]*evaltime + cp[1]);
246 /* only if something changed, write *cvalue in one go */
247 if (data->poly_order) {
248 if (data->flag & FCM_GENERATOR_ADDITIVE)
258 static FModifierTypeInfo FMI_GENERATOR = {
259 FMODIFIER_TYPE_GENERATOR, /* type */
260 sizeof(FMod_Generator), /* size */
261 FMI_TYPE_GENERATE_CURVE, /* action type */
262 FMI_REQUIRES_NOTHING, /* requirements */
263 "Generator", /* name */
264 "FMod_Generator", /* struct name */
265 fcm_generator_free, /* free data */
266 fcm_generator_copy, /* copy data */
267 fcm_generator_new_data, /* new data */
268 fcm_generator_verify, /* verify */
269 NULL, /* evaluate time */
270 fcm_generator_evaluate /* evaluate */
273 /* Built-In Function Generator F-Curve Modifier --------------------------- */
275 /* This uses the general equation for equations:
276 * y = amplitude * fn(phase_multiplier*x + phase_offset) + y_offset
278 * where amplitude, phase_multiplier/offset, y_offset are user-defined coefficients,
279 * x is the evaluation 'time', and 'y' is the resultant value
281 * Functions available are
282 * sin, cos, tan, sinc (normalised sin), natural log, square root
285 static void fcm_fn_generator_new_data (void *mdata)
287 FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)mdata;
289 /* set amplitude and phase multiplier to 1.0f so that something is generated */
290 data->amplitude= 1.0f;
291 data->phase_multiplier= 1.0f;
294 /* Unary 'normalised sine' function
295 * y = sin(PI + x) / (PI * x),
296 * except for x = 0 when y = 1.
298 static double sinc (double x)
300 if (fabs(x) < 0.0001)
303 return sin(M_PI * x) / (M_PI * x);
306 static void fcm_fn_generator_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
308 FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)fcm->data;
309 double arg= data->phase_multiplier*evaltime + data->phase_offset;
310 double (*fn)(double v) = NULL;
312 /* get function pointer to the func to use:
313 * WARNING: must perform special argument validation hereto guard against crashes
318 case FCM_GENERATOR_FN_SIN: /* sine wave */
321 case FCM_GENERATOR_FN_COS: /* cosine wave */
324 case FCM_GENERATOR_FN_SINC: /* normalised sine wave */
328 /* validation required */
329 case FCM_GENERATOR_FN_TAN: /* tangent wave */
331 /* check that argument is not on one of the discontinuities (i.e. 90deg, 270 deg, etc) */
332 if IS_EQ(fmod((arg - M_PI_2), M_PI), 0.0) {
333 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
334 *cvalue = 0.0f; /* no value possible here */
340 case FCM_GENERATOR_FN_LN: /* natural log */
342 /* check that value is greater than 1? */
347 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
348 *cvalue = 0.0f; /* no value possible here */
352 case FCM_GENERATOR_FN_SQRT: /* square root */
354 /* no negative numbers */
359 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
360 *cvalue = 0.0f; /* no value possible here */
366 printf("Invalid Function-Generator for F-Modifier - %d \n", data->type);
369 /* execute function callback to set value if appropriate */
371 float value= (float)(data->amplitude*fn(arg) + data->value_offset);
373 if (data->flag & FCM_GENERATOR_ADDITIVE)
380 static FModifierTypeInfo FMI_FN_GENERATOR = {
381 FMODIFIER_TYPE_FN_GENERATOR, /* type */
382 sizeof(FMod_FunctionGenerator), /* size */
383 FMI_TYPE_GENERATE_CURVE, /* action type */
384 FMI_REQUIRES_NOTHING, /* requirements */
385 "Built-In Function", /* name */
386 "FMod_FunctionGenerator", /* struct name */
387 NULL, /* free data */
388 NULL, /* copy data */
389 fcm_fn_generator_new_data, /* new data */
391 NULL, /* evaluate time */
392 fcm_fn_generator_evaluate /* evaluate */
395 /* Envelope F-Curve Modifier --------------------------- */
397 static void fcm_envelope_free (FModifier *fcm)
399 FMod_Envelope *env= (FMod_Envelope *)fcm->data;
401 /* free envelope data array */
403 MEM_freeN(env->data);
406 static void fcm_envelope_copy (FModifier *fcm, FModifier *src)
408 FMod_Envelope *env= (FMod_Envelope *)fcm->data;
409 FMod_Envelope *oenv= (FMod_Envelope *)src->data;
411 /* copy envelope data array */
413 env->data= MEM_dupallocN(oenv->data);
416 static void fcm_envelope_new_data (void *mdata)
418 FMod_Envelope *env= (FMod_Envelope *)mdata;
420 /* set default min/max ranges */
425 static void fcm_envelope_verify (FModifier *fcm)
427 FMod_Envelope *env= (FMod_Envelope *)fcm->data;
429 /* if the are points, perform bubble-sort on them, as user may have changed the order */
435 static void fcm_envelope_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
437 FMod_Envelope *env= (FMod_Envelope *)fcm->data;
438 FCM_EnvelopeData *fed, *prevfed, *lastfed;
439 float min=0.0f, max=0.0f, fac=0.0f;
443 if (env->data == NULL) return;
446 lastfed= prevfed + (env->totvert-1);
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 */
454 else if (lastfed->time <= evaltime) {
455 /* after or on last sample, so just extend value */
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;
467 diff= fed->time - prevfed->time;
468 afac= (evaltime - prevfed->time) / diff;
469 bfac= (fed->time - evaltime) / diff;
471 min= bfac*prevfed->min + afac*fed->min;
472 max= bfac*prevfed->max + afac*fed->max;
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!
483 fac= (*cvalue - (env->midval + env->min)) / (env->max - env->min);
484 *cvalue= min + fac*(max - min);
487 static FModifierTypeInfo FMI_ENVELOPE = {
488 FMODIFIER_TYPE_ENVELOPE, /* type */
489 sizeof(FMod_Envelope), /* size */
490 FMI_TYPE_REPLACE_VALUES, /* action type */
491 0, /* requirements */
492 "Envelope", /* name */
493 "FMod_Envelope", /* struct name */
494 fcm_envelope_free, /* free data */
495 fcm_envelope_copy, /* copy data */
496 fcm_envelope_new_data, /* new data */
497 fcm_envelope_verify, /* verify */
498 NULL, /* evaluate time */
499 fcm_envelope_evaluate /* evaluate */
502 /* Cycles F-Curve Modifier --------------------------- */
504 /* This modifier changes evaltime to something that exists within the curve's frame-range,
505 * then re-evaluates modifier stack up to this point using the new time. This re-entrant behaviour
506 * is very likely to be more time-consuming than the original approach... (which was tighly integrated into
507 * the calculation code...).
509 * NOTE: this needs to be at the start of the stack to be of use, as it needs to know the extents of the keyframes/sample-data
510 * Possible TODO - store length of cycle information that can be initialised from the extents of the keyframes/sample-data, and adjusted
514 /* temp data used during evaluation */
515 typedef struct tFCMED_Cycles {
516 float cycyofs; /* y-offset to apply */
519 static void fcm_cycles_new_data (void *mdata)
521 FMod_Cycles *data= (FMod_Cycles *)mdata;
523 /* turn on cycles by default */
524 data->before_mode= data->after_mode= FCM_EXTRAPOLATE_CYCLIC;
527 static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float UNUSED(cvalue), float evaltime)
529 FMod_Cycles *data= (FMod_Cycles *)fcm->data;
530 float prevkey[2], lastkey[2], cycyofs=0.0f;
531 short side=0, mode=0;
534 /* check if modifier is first in stack, otherwise disable ourself... */
537 fcm->flag |= FMODIFIER_FLAG_DISABLED;
541 /* calculate new evaltime due to cyclic interpolation */
542 if (fcu && fcu->bezt) {
543 BezTriple *prevbezt= fcu->bezt;
544 BezTriple *lastbezt= prevbezt + fcu->totvert-1;
546 prevkey[0]= prevbezt->vec[1][0];
547 prevkey[1]= prevbezt->vec[1][1];
549 lastkey[0]= lastbezt->vec[1][0];
550 lastkey[1]= lastbezt->vec[1][1];
552 else if (fcu && fcu->fpt) {
553 FPoint *prevfpt= fcu->fpt;
554 FPoint *lastfpt= prevfpt + fcu->totvert-1;
556 prevkey[0]= prevfpt->vec[0];
557 prevkey[1]= prevfpt->vec[1];
559 lastkey[0]= lastfpt->vec[0];
560 lastkey[1]= lastfpt->vec[1];
565 /* check if modifier will do anything
566 * 1) if in data range, definitely don't do anything
567 * 2) if before first frame or after last frame, make sure some cycling is in use
569 if (evaltime < prevkey[0]) {
570 if (data->before_mode) {
572 mode= data->before_mode;
573 cycles= data->before_cycles;
577 else if (evaltime > lastkey[0]) {
578 if (data->after_mode) {
580 mode= data->after_mode;
581 cycles= data->after_cycles;
585 if ELEM(0, side, mode)
588 /* find relative place within a cycle */
590 float cycdx=0, cycdy=0;
591 float cycle= 0, cyct=0;
593 /* calculate period and amplitude (total height) of a cycle */
594 cycdx= lastkey[0] - prevkey[0];
595 cycdy= lastkey[1] - prevkey[1];
597 /* check if cycle is infinitely small, to be point of being impossible to use */
601 /* calculate the 'number' of the cycle */
602 cycle= ((float)side * (evaltime - ofs) / cycdx);
604 /* calculate the time inside the cycle */
605 cyct= fmod(evaltime - ofs, cycdx);
607 /* check that cyclic is still enabled for the specified time */
609 /* catch this case so that we don't exit when we have cycles=0
610 * as this indicates infinite cycles...
613 else if (cycle > cycles) {
614 /* we are too far away from range to evaluate
615 * TODO: but we should still hold last value...
620 /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */
621 if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
623 cycyofs = (float)floor((evaltime - ofs) / cycdx);
625 cycyofs = (float)ceil((evaltime - ofs) / cycdx);
629 /* special case for cycle start/end */
631 evaltime = (side == 1 ? lastkey[0] : prevkey[0]);
633 if((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)cycle % 2))
634 evaltime = (side == 1 ? prevkey[0] : lastkey[0]);
636 /* calculate where in the cycle we are (overwrite evaltime to reflect this) */
637 else if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle+1) % 2)) {
638 /* when 'mirror' option is used and cycle number is odd, this cycle is played in reverse
639 * - for 'before' extrapolation, we need to flip in a different way, otherwise values past
640 * then end of the curve get referenced (result of fmod will be negative, and with different phase)
643 evaltime= prevkey[0] - cyct;
645 evaltime= lastkey[0] - cyct;
648 /* the cycle is played normally... */
649 evaltime= prevkey[0] + cyct;
651 if (evaltime < prevkey[0]) evaltime += cycdx;
654 /* store temp data if needed */
655 if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
656 tFCMED_Cycles *edata;
658 /* for now, this is just a float, but we could get more stuff... */
659 fcm->edata= edata= MEM_callocN(sizeof(tFCMED_Cycles), "tFCMED_Cycles");
660 edata->cycyofs= cycyofs;
663 /* return the new frame to evaluate */
667 static void fcm_cycles_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float UNUSED(evaltime))
669 tFCMED_Cycles *edata= (tFCMED_Cycles *)fcm->edata;
673 /* add cyclic offset - no need to check for now, otherwise the data wouldn't exist! */
674 *cvalue += edata->cycyofs;
682 static FModifierTypeInfo FMI_CYCLES = {
683 FMODIFIER_TYPE_CYCLES, /* type */
684 sizeof(FMod_Cycles), /* size */
685 FMI_TYPE_EXTRAPOLATION, /* action type */
686 FMI_REQUIRES_ORIGINAL_DATA, /* requirements */
688 "FMod_Cycles", /* struct name */
689 NULL, /* free data */
690 NULL, /* copy data */
691 fcm_cycles_new_data, /* new data */
692 NULL /*fcm_cycles_verify*/, /* verify */
693 fcm_cycles_time, /* evaluate time */
694 fcm_cycles_evaluate /* evaluate */
697 /* Noise F-Curve Modifier --------------------------- */
699 static void fcm_noise_new_data (void *mdata)
701 FMod_Noise *data= (FMod_Noise *)mdata;
705 data->strength= 1.0f;
708 data->modification = FCM_NOISE_MODIF_REPLACE;
711 static void fcm_noise_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
713 FMod_Noise *data= (FMod_Noise *)fcm->data;
716 /* generate noise using good ol' Blender Noise
717 * - 0.1 is passed as the 'z' value, otherwise evaluation fails for size = phase = 1
718 * with evaltime being an integer (which happens when evaluating on frame by frame basis)
720 noise = BLI_turbulence(data->size, evaltime, data->phase, 0.1f, data->depth);
722 /* combine the noise with existing motion data */
723 switch (data->modification) {
724 case FCM_NOISE_MODIF_ADD:
725 *cvalue= *cvalue + noise * data->strength;
727 case FCM_NOISE_MODIF_SUBTRACT:
728 *cvalue= *cvalue - noise * data->strength;
730 case FCM_NOISE_MODIF_MULTIPLY:
731 *cvalue= *cvalue * noise * data->strength;
733 case FCM_NOISE_MODIF_REPLACE:
735 *cvalue= *cvalue + (noise - 0.5f) * data->strength;
740 static FModifierTypeInfo FMI_NOISE = {
741 FMODIFIER_TYPE_NOISE, /* type */
742 sizeof(FMod_Noise), /* size */
743 FMI_TYPE_REPLACE_VALUES, /* action type */
744 0, /* requirements */
746 "FMod_Noise", /* struct name */
747 NULL, /* free data */
748 NULL, /* copy data */
749 fcm_noise_new_data, /* new data */
750 NULL /*fcm_noise_verify*/, /* verify */
751 NULL, /* evaluate time */
752 fcm_noise_evaluate /* evaluate */
755 /* Filter F-Curve Modifier --------------------------- */
757 #if 0 // XXX not yet implemented
758 static FModifierTypeInfo FMI_FILTER = {
759 FMODIFIER_TYPE_FILTER, /* type */
760 sizeof(FMod_Filter), /* size */
761 FMI_TYPE_REPLACE_VALUES, /* action type */
762 0, /* requirements */
764 "FMod_Filter", /* struct name */
765 NULL, /* free data */
766 NULL, /* copy data */
768 NULL /*fcm_filter_verify*/, /* verify */
769 NULL, /* evlauate time */
770 fcm_filter_evaluate /* evaluate */
772 #endif // XXX not yet implemented
775 /* Python F-Curve Modifier --------------------------- */
777 static void fcm_python_free (FModifier *fcm)
779 FMod_Python *data= (FMod_Python *)fcm->data;
782 IDP_FreeProperty(data->prop);
783 MEM_freeN(data->prop);
786 static void fcm_python_new_data (void *mdata)
788 FMod_Python *data= (FMod_Python *)mdata;
790 /* everything should be set correctly by calloc, except for the prop->type constant.*/
791 data->prop = MEM_callocN(sizeof(IDProperty), "PyFModifierProps");
792 data->prop->type = IDP_GROUP;
795 static void fcm_python_copy (FModifier *fcm, FModifier *src)
797 FMod_Python *pymod = (FMod_Python *)fcm->data;
798 FMod_Python *opymod = (FMod_Python *)src->data;
800 pymod->prop = IDP_CopyProperty(opymod->prop);
803 static void fcm_python_evaluate (FCurve *UNUSED(fcu), FModifier *UNUSED(fcm), float *UNUSED(cvalue), float UNUSED(evaltime))
805 #ifndef DISABLE_PYTHON
806 //FMod_Python *data= (FMod_Python *)fcm->data;
808 /* FIXME... need to implement this modifier...
809 * It will need it execute a script using the custom properties
811 #endif /* DISABLE_PYTHON */
814 static FModifierTypeInfo FMI_PYTHON = {
815 FMODIFIER_TYPE_PYTHON, /* type */
816 sizeof(FMod_Python), /* size */
817 FMI_TYPE_GENERATE_CURVE, /* action type */
818 FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
820 "FMod_Python", /* struct name */
821 fcm_python_free, /* free data */
822 fcm_python_copy, /* copy data */
823 fcm_python_new_data, /* new data */
824 NULL /*fcm_python_verify*/, /* verify */
825 NULL /*fcm_python_time*/, /* evaluate time */
826 fcm_python_evaluate /* evaluate */
830 /* Limits F-Curve Modifier --------------------------- */
832 static float fcm_limits_time (FCurve *UNUSED(fcu), FModifier *fcm, float UNUSED(cvalue), float evaltime)
834 FMod_Limits *data= (FMod_Limits *)fcm->data;
836 /* check for the time limits */
837 if ((data->flag & FCM_LIMIT_XMIN) && (evaltime < data->rect.xmin))
838 return data->rect.xmin;
839 if ((data->flag & FCM_LIMIT_XMAX) && (evaltime > data->rect.xmax))
840 return data->rect.xmax;
842 /* modifier doesn't change time */
846 static void fcm_limits_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float UNUSED(evaltime))
848 FMod_Limits *data= (FMod_Limits *)fcm->data;
850 /* value limits now */
851 if ((data->flag & FCM_LIMIT_YMIN) && (*cvalue < data->rect.ymin))
852 *cvalue= data->rect.ymin;
853 if ((data->flag & FCM_LIMIT_YMAX) && (*cvalue > data->rect.ymax))
854 *cvalue= data->rect.ymax;
857 static FModifierTypeInfo FMI_LIMITS = {
858 FMODIFIER_TYPE_LIMITS, /* type */
859 sizeof(FMod_Limits), /* size */
860 FMI_TYPE_GENERATE_CURVE, /* action type */ /* XXX... err... */
861 FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
863 "FMod_Limits", /* struct name */
864 NULL, /* free data */
865 NULL, /* copy data */
868 fcm_limits_time, /* evaluate time */
869 fcm_limits_evaluate /* evaluate */
872 /* Stepped F-Curve Modifier --------------------------- */
874 static void fcm_stepped_new_data (void *mdata)
876 FMod_Stepped *data= (FMod_Stepped *)mdata;
878 /* just need to set the step-size to 2-frames by default */
879 // XXX: or would 5 be more normal?
880 data->step_size = 2.0f;
883 static float fcm_stepped_time (FCurve *UNUSED(fcu), FModifier *fcm, float UNUSED(cvalue), float evaltime)
885 FMod_Stepped *data= (FMod_Stepped *)fcm->data;
888 /* check range clamping to see if we should alter the timing to achieve the desired results */
889 if (data->flag & FCM_STEPPED_NO_BEFORE) {
890 if (evaltime < data->start_frame)
893 if (data->flag & FCM_STEPPED_NO_AFTER) {
894 if (evaltime > data->end_frame)
898 /* we snap to the start of the previous closest block of 'step_size' frames
899 * after the start offset has been discarded
902 snapblock = (int)((evaltime - data->offset) / data->step_size);
904 /* reapply the offset, and multiple the snapblock by the size of the steps to get
905 * the new time to evaluate at
907 return ((float)snapblock * data->step_size) + data->offset;
910 static FModifierTypeInfo FMI_STEPPED = {
911 FMODIFIER_TYPE_STEPPED, /* type */
912 sizeof(FMod_Limits), /* size */
913 FMI_TYPE_GENERATE_CURVE, /* action type */ /* XXX... err... */
914 FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
915 "Stepped", /* name */
916 "FMod_Stepped", /* struct name */
917 NULL, /* free data */
918 NULL, /* copy data */
919 fcm_stepped_new_data, /* new data */
921 fcm_stepped_time, /* evaluate time */
925 /* F-Curve Modifier API --------------------------- */
926 /* All of the F-Curve Modifier api functions use FModifierTypeInfo structs to carry out
927 * and operations that involve F-Curve modifier specific code.
930 /* These globals only ever get directly accessed in this file */
931 static FModifierTypeInfo *fmodifiersTypeInfo[FMODIFIER_NUM_TYPES];
932 static short FMI_INIT= 1; /* when non-zero, the list needs to be updated */
934 /* This function only gets called when FMI_INIT is non-zero */
935 static void fmods_init_typeinfo ()
937 fmodifiersTypeInfo[0]= NULL; /* 'Null' F-Curve Modifier */
938 fmodifiersTypeInfo[1]= &FMI_GENERATOR; /* Generator F-Curve Modifier */
939 fmodifiersTypeInfo[2]= &FMI_FN_GENERATOR; /* Built-In Function Generator F-Curve Modifier */
940 fmodifiersTypeInfo[3]= &FMI_ENVELOPE; /* Envelope F-Curve Modifier */
941 fmodifiersTypeInfo[4]= &FMI_CYCLES; /* Cycles F-Curve Modifier */
942 fmodifiersTypeInfo[5]= &FMI_NOISE; /* Apply-Noise F-Curve Modifier */
943 fmodifiersTypeInfo[6]= NULL/*&FMI_FILTER*/; /* Filter F-Curve Modifier */ // XXX unimplemented
944 fmodifiersTypeInfo[7]= &FMI_PYTHON; /* Custom Python F-Curve Modifier */
945 fmodifiersTypeInfo[8]= &FMI_LIMITS; /* Limits F-Curve Modifier */
946 fmodifiersTypeInfo[9]= &FMI_STEPPED; /* Stepped F-Curve Modifier */
949 /* This function should be used for getting the appropriate type-info when only
950 * a F-Curve modifier type is known
952 FModifierTypeInfo *get_fmodifier_typeinfo (int type)
954 /* initialise the type-info list? */
956 fmods_init_typeinfo();
960 /* only return for valid types */
961 if ( (type >= FMODIFIER_TYPE_NULL) &&
962 (type <= FMODIFIER_NUM_TYPES ) )
964 /* there shouldn't be any segfaults here... */
965 return fmodifiersTypeInfo[type];
968 printf("No valid F-Curve Modifier type-info data available. Type = %i \n", type);
974 /* This function should always be used to get the appropriate type-info, as it
975 * has checks which prevent segfaults in some weird cases.
977 FModifierTypeInfo *fmodifier_get_typeinfo (FModifier *fcm)
979 /* only return typeinfo for valid modifiers */
981 return get_fmodifier_typeinfo(fcm->type);
986 /* API --------------------------- */
988 /* Add a new F-Curve Modifier to the given F-Curve of a certain type */
989 FModifier *add_fmodifier (ListBase *modifiers, int type)
991 FModifierTypeInfo *fmi= get_fmodifier_typeinfo(type);
995 if ELEM(NULL, modifiers, fmi)
998 /* special checks for whether modifier can be added */
999 if ((modifiers->first) && (type == FMODIFIER_TYPE_CYCLES)) {
1000 /* cycles modifier must be first in stack, so for now, don't add if it can't be */
1001 // TODO: perhaps there is some better way, but for now,
1002 printf("Error: Cannot add 'Cycles' modifier to F-Curve, as 'Cycles' modifier can only be first in stack. \n");
1006 /* add modifier itself */
1007 fcm= MEM_callocN(sizeof(FModifier), "F-Curve Modifier");
1009 fcm->flag = FMODIFIER_FLAG_EXPANDED;
1010 BLI_addtail(modifiers, fcm);
1012 /* add modifier's data */
1013 fcm->data= MEM_callocN(fmi->size, fmi->structName);
1015 /* init custom settings if necessary */
1017 fmi->new_data(fcm->data);
1019 /* return modifier for further editing */
1023 /* Make a copy of the specified F-Modifier */
1024 FModifier *copy_fmodifier (FModifier *src)
1026 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(src);
1033 /* copy the base data, clearing the links */
1034 dst = MEM_dupallocN(src);
1035 dst->next = dst->prev = NULL;
1037 /* make a new copy of the F-Modifier's data */
1038 dst->data = MEM_dupallocN(src->data);
1040 /* only do specific constraints if required */
1041 if (fmi && fmi->copy_data)
1042 fmi->copy_data(dst, src);
1044 /* return the new modifier */
1048 /* Duplicate all of the F-Modifiers in the Modifier stacks */
1049 void copy_fmodifiers (ListBase *dst, ListBase *src)
1051 FModifier *fcm, *srcfcm;
1053 if ELEM(NULL, dst, src)
1056 dst->first= dst->last= NULL;
1057 BLI_duplicatelist(dst, src);
1059 for (fcm=dst->first, srcfcm=src->first; fcm && srcfcm; srcfcm=srcfcm->next, fcm=fcm->next) {
1060 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
1062 /* make a new copy of the F-Modifier's data */
1063 fcm->data = MEM_dupallocN(fcm->data);
1065 /* only do specific constraints if required */
1066 if (fmi && fmi->copy_data)
1067 fmi->copy_data(fcm, srcfcm);
1071 /* Remove and free the given F-Modifier from the given stack */
1072 int remove_fmodifier (ListBase *modifiers, FModifier *fcm)
1074 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
1080 /* free modifier's special data (stored inside fcm->data) */
1082 if (fmi && fmi->free_data)
1083 fmi->free_data(fcm);
1085 /* free modifier's data (fcm->data) */
1086 MEM_freeN(fcm->data);
1089 /* remove modifier from stack */
1091 BLI_freelinkN(modifiers, fcm);
1095 // XXX this case can probably be removed some day, as it shouldn't happen...
1096 printf("remove_fmodifier() - no modifier stack given \n");
1102 /* Remove all of a given F-Curve's modifiers */
1103 void free_fmodifiers (ListBase *modifiers)
1105 FModifier *fcm, *fmn;
1108 if (modifiers == NULL)
1111 /* free each modifier in order - modifier is unlinked from list and freed */
1112 for (fcm= modifiers->first; fcm; fcm= fmn) {
1114 remove_fmodifier(modifiers, fcm);
1118 /* Find the active F-Modifier */
1119 FModifier *find_active_fmodifier (ListBase *modifiers)
1124 if ELEM(NULL, modifiers, modifiers->first)
1127 /* loop over modifiers until 'active' one is found */
1128 for (fcm= modifiers->first; fcm; fcm= fcm->next) {
1129 if (fcm->flag & FMODIFIER_FLAG_ACTIVE)
1133 /* no modifier is active */
1137 /* Set the active F-Modifier */
1138 void set_active_fmodifier (ListBase *modifiers, FModifier *fcm)
1143 if ELEM(NULL, modifiers, modifiers->first)
1146 /* deactivate all, and set current one active */
1147 for (fm= modifiers->first; fm; fm= fm->next)
1148 fm->flag &= ~FMODIFIER_FLAG_ACTIVE;
1150 /* make given modifier active */
1152 fcm->flag |= FMODIFIER_FLAG_ACTIVE;
1155 /* Do we have any modifiers which match certain criteria
1156 * - mtype - type of modifier (if 0, doesn't matter)
1157 * - acttype - type of action to perform (if -1, doesn't matter)
1159 short list_has_suitable_fmodifier (ListBase *modifiers, int mtype, short acttype)
1163 /* if there are no specific filtering criteria, just skip */
1164 if ((mtype == 0) && (acttype == 0))
1165 return (modifiers && modifiers->first);
1168 if ELEM(NULL, modifiers, modifiers->first)
1171 /* find the first mdifier fitting these criteria */
1172 for (fcm= modifiers->first; fcm; fcm= fcm->next) {
1173 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
1174 short mOk=1, aOk=1; /* by default 1, so that when only one test, won't fail */
1176 /* check if applicable ones are fullfilled */
1178 mOk= (fcm->type == mtype);
1180 aOk= (fmi->acttype == acttype);
1182 /* if both are ok, we've found a hit */
1191 /* Evaluation API --------------------------- */
1193 /* evaluate time modifications imposed by some F-Curve Modifiers
1194 * - this step acts as an optimisation to prevent the F-Curve stack being evaluated
1195 * several times by modifiers requesting the time be modified, as the final result
1196 * would have required using the modified time
1197 * - modifiers only ever receive the unmodified time, as subsequent modifiers should be
1198 * working on the 'global' result of the modified curve, not some localised segment,
1199 * so nevaltime gets set to whatever the last time-modifying modifier likes...
1200 * - we start from the end of the stack, as only the last one matters for now
1202 float evaluate_time_fmodifiers (ListBase *modifiers, FCurve *fcu, float cvalue, float evaltime)
1207 if ELEM(NULL, modifiers, modifiers->last)
1210 /* Starting from the end of the stack, calculate the time effects of various stacked modifiers
1211 * on the time the F-Curve should be evaluated at.
1213 * This is done in reverse order to standard evaluation, as when this is done in standard
1214 * order, each modifier would cause jumps to other points in the curve, forcing all
1215 * previous ones to be evaluated again for them to be correct. However, if we did in the
1216 * reverse order as we have here, we can consider them a macro to micro type of waterfall
1217 * effect, which should get us the desired effects when using layered time manipulations
1218 * (such as multiple 'stepped' modifiers in sequence, causing different stepping rates)
1220 for (fcm= modifiers->last; fcm; fcm= fcm->prev) {
1221 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
1223 /* only evaluate if there's a callback for this */
1224 // TODO: implement the 'influence' control feature...
1225 if (fmi && fmi->evaluate_modifier_time) {
1226 if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
1227 evaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
1231 /* return the modified evaltime */
1235 /* Evalautes the given set of F-Curve Modifiers using the given data
1236 * Should only be called after evaluate_time_fmodifiers() has been called...
1238 void evaluate_value_fmodifiers (ListBase *modifiers, FCurve *fcu, float *cvalue, float evaltime)
1243 if ELEM(NULL, modifiers, modifiers->first)
1246 /* evaluate modifiers */
1247 for (fcm= modifiers->first; fcm; fcm= fcm->next) {
1248 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
1250 /* only evaluate if there's a callback for this */
1251 // TODO: implement the 'influence' control feature...
1252 if (fmi && fmi->evaluate_modifier) {
1253 if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
1254 fmi->evaluate_modifier(fcu, fcm, cvalue, evaltime);
1261 /* Bake modifiers for given F-Curve to curve sample data, in the frame range defined
1262 * by start and end (inclusive).
1264 void fcurve_bake_modifiers (FCurve *fcu, int start, int end)
1266 ChannelDriver *driver;
1269 // TODO: make these tests report errors using reports not printf's
1270 if ELEM(NULL, fcu, fcu->modifiers.first) {
1271 printf("Error: No F-Curve with F-Curve Modifiers to Bake\n");
1275 /* temporarily, disable driver while we sample, so that they don't influence the outcome */
1276 driver= fcu->driver;
1279 /* bake the modifiers, by sampling the curve at each frame */
1280 fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
1282 /* free the modifiers now */
1283 free_fmodifiers(&fcu->modifiers);
1285 /* restore driver */
1286 fcu->driver= driver;