1 /* Testing code for new animation system in 2.5
2 * Copyright 2009, Joshua Leung
15 #include "MEM_guardedalloc.h"
17 #include "DNA_anim_types.h"
19 #include "BLI_blenlib.h"
20 #include "BLI_arithb.h"
22 #include "BKE_fcurve.h"
23 #include "BKE_curve.h"
24 #include "BKE_global.h"
25 #include "BKE_idprop.h"
26 #include "BKE_utildefines.h"
28 #include "RNA_access.h"
29 #include "RNA_types.h"
31 #ifndef DISABLE_PYTHON
32 #include "BPY_extern.h" /* for BPY_pydriver_eval() */
35 #define SMALL -1.0e-10
38 /* ************************** Data-Level Functions ************************* */
40 /* ---------------------- Freeing --------------------------- */
42 /* Frees the F-Curve itself too, so make sure BLI_remlink is called before calling this... */
43 void free_fcurve (FCurve *fcu)
50 if (fcu->bezt) MEM_freeN(fcu->bezt);
51 if (fcu->fpt) MEM_freeN(fcu->fpt);
54 /* free RNA-path, as this were allocated when getting the path string */
56 MEM_freeN(fcu->rna_path);
58 /* free extra data - i.e. modifiers, and driver */
59 fcurve_free_driver(fcu);
60 fcurve_free_modifiers(fcu);
62 /* free f-curve itself */
66 /* Frees a list of F-Curves */
67 void free_fcurves (ListBase *list)
75 /* free data - no need to call remlink before freeing each curve,
76 * as we store reference to next, and freeing only touches the curve
79 for (fcu= list->first; fcu; fcu= fcn) {
84 /* clear pointers just in case */
85 list->first= list->last= NULL;
88 /* ---------------------- Copy --------------------------- */
90 /* duplicate an F-Curve */
91 FCurve *copy_fcurve (FCurve *fcu)
100 fcu_d= MEM_dupallocN(fcu);
101 fcu_d->next= fcu_d->prev= NULL;
103 /* copy curve data */
104 fcu_d->bezt= MEM_dupallocN(fcu_d->bezt);
105 fcu_d->fpt= MEM_dupallocN(fcu_d->fpt);
108 fcu_d->rna_path= MEM_dupallocN(fcu_d->rna_path);
111 fcu_d->driver= fcurve_copy_driver(fcu_d->driver);
114 fcurve_copy_modifiers(&fcu_d->modifiers, &fcu->modifiers);
116 /* return new data */
120 /* duplicate a list of F-Curves */
121 void copy_fcurves (ListBase *dst, ListBase *src)
126 if ELEM(NULL, dst, src)
129 /* clear destination list first */
130 dst->first= dst->last= NULL;
132 /* copy one-by-one */
133 for (sfcu= src->first; sfcu; sfcu= sfcu->next) {
134 dfcu= copy_fcurve(sfcu);
135 BLI_addtail(dst, dfcu);
139 /* ---------------------- Relink --------------------------- */
142 /* uses id->newid to match pointers with other copied data
143 * - called after single-user or other such
146 ID_NEW(icu->driver->ob);
149 /* --------------------- Finding -------------------------- */
151 /* Find the F-Curve affecting the given RNA-access path + index, in the list of F-Curves provided */
152 FCurve *list_find_fcurve (ListBase *list, const char rna_path[], const int array_index)
157 if ( ELEM(NULL, list, rna_path) || (array_index < 0) )
160 /* check paths of curves, then array indices... */
161 for (fcu= list->first; fcu; fcu= fcu->next) {
162 /* simple string-compare (this assumes that they have the same root...) */
163 if (strcmp(fcu->rna_path, rna_path) == 0) {
164 /* now check indicies */
165 if (fcu->array_index == array_index)
174 /* Calculate the extents of F-Curve's data */
175 void calc_fcurve_bounds (FCurve *fcu, float *xmin, float *xmax, float *ymin, float *ymax)
177 float xminv=999999999.0f, xmaxv=-999999999.0f;
178 float yminv=999999999.0f, ymaxv=-999999999.0f;
184 /* frame range can be directly calculated from end verts */
186 xminv= MIN2(xminv, fcu->bezt[0].vec[1][0]);
187 xmaxv= MAX2(xmaxv, fcu->bezt[fcu->totvert-1].vec[1][0]);
190 /* only loop over keyframes to find extents for values if needed */
194 for (bezt=fcu->bezt, i=0; i < fcu->totvert; bezt++, i++) {
195 yminv= MIN2(yminv, bezt->vec[1][1]);
196 ymaxv= MAX2(ymaxv, bezt->vec[1][1]);
201 /* frame range can be directly calculated from end verts */
203 xminv= MIN2(xminv, fcu->fpt[0].vec[0]);
204 xmaxv= MAX2(xmaxv, fcu->fpt[fcu->totvert-1].vec[0]);
207 /* only loop over keyframes to find extents for values if needed */
211 for (fpt=fcu->fpt, i=0; i < fcu->totvert; fpt++, i++) {
212 yminv= MIN2(yminv, fpt->vec[1]);
213 ymaxv= MAX2(ymaxv, fpt->vec[1]);
221 /* minimum sizes are 1.0f */
223 if (xminv == xmaxv) xmaxv += 1.0f;
224 if (yminv == ymaxv) ymaxv += 1.0f;
226 if (xmin) *xmin= xminv;
227 if (xmax) *xmax= xmaxv;
229 if (ymin) *ymin= yminv;
230 if (ymax) *ymax= ymaxv;
233 if (xmin) *xmin= 0.0f;
234 if (xmax) *xmax= 0.0f;
236 if (ymin) *ymin= 1.0f;
237 if (ymax) *ymax= 1.0f;
241 /* Calculate the extents of F-Curve's keyframes */
242 void calc_fcurve_range (FCurve *fcu, float *start, float *end)
244 float min=999999999.0f, max=-999999999.0f;
249 min= MIN2(min, fcu->bezt[0].vec[1][0]);
250 max= MAX2(max, fcu->bezt[fcu->totvert-1].vec[1][0]);
253 min= MIN2(min, fcu->fpt[0].vec[0]);
254 max= MAX2(max, fcu->fpt[fcu->totvert-1].vec[0]);
260 /* minimum length is 1 frame */
262 if (min == max) max += 1.0f;
272 /* ***************************** Keyframe Column Tools ********************************* */
274 /* add a BezTriple to a column */
275 void bezt_add_to_cfra_elem (ListBase *lb, BezTriple *bezt)
279 for (ce= lb->first; ce; ce= ce->next) {
281 if (ce->cfra == bezt->vec[1][0]) {
282 if (bezt->f2 & SELECT) ce->sel= bezt->f2;
285 /* should key be inserted before this column? */
286 else if (ce->cfra > bezt->vec[1][0]) break;
289 /* create a new column */
290 cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem");
291 if (ce) BLI_insertlinkbefore(lb, ce, cen);
292 else BLI_addtail(lb, cen);
294 cen->cfra= bezt->vec[1][0];
298 /* ***************************** Samples Utilities ******************************* */
299 /* Some utilities for working with FPoints (i.e. 'sampled' animation curve data, such as
300 * data imported from BVH/Mocap files), which are specialised for use with high density datasets,
301 * which BezTriples/Keyframe data are ill equipped to do.
305 /* Basic sampling callback which acts as a wrapper for evaluate_fcurve()
306 * 'data' arg here is unneeded here...
308 float fcurve_samplingcb_evalcurve (FCurve *fcu, void *data, float evaltime)
310 /* assume any interference from drivers on the curve is intended... */
311 return evaluate_fcurve(fcu, evaltime);
315 /* Main API function for creating a set of sampled curve data, given some callback function
316 * used to retrieve the values to store.
318 void fcurve_store_samples (FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb)
320 FPoint *fpt, *new_fpt;
324 // TODO: make these tests report errors using reports not printf's
325 if ELEM(NULL, fcu, sample_cb) {
326 printf("Error: No F-Curve with F-Curve Modifiers to Bake\n");
330 printf("Error: Frame range for Sampled F-Curve creation is inappropriate \n");
334 /* set up sample data */
335 fpt= new_fpt= MEM_callocN(sizeof(FPoint)*(end-start+1), "FPoint Samples");
337 /* use the sampling callback at 1-frame intervals from start to end frames */
338 for (cfra= start; cfra <= end; cfra++, fpt++) {
339 fpt->vec[0]= (float)cfra;
340 fpt->vec[1]= sample_cb(fcu, data, (float)cfra);
343 /* free any existing sample/keyframe data on curve */
344 if (fcu->bezt) MEM_freeN(fcu->bezt);
345 if (fcu->fpt) MEM_freeN(fcu->fpt);
347 /* store the samples */
350 fcu->totvert= end - start + 1;
353 /* ***************************** F-Curve Sanity ********************************* */
354 /* The functions here are used in various parts of Blender, usually after some editing
355 * of keyframe data has occurred. They ensure that keyframe data is properly ordered and
356 * that the handles are correctly
359 /* This function recalculates the handles of an F-Curve
360 * If the BezTriples have been rearranged, sort them first before using this.
362 void calchandles_fcurve (FCurve *fcu)
364 BezTriple *bezt, *prev, *next;
368 * - need at least two points
370 * - only bezier-interpolation has handles (for now)
372 if (ELEM(NULL, fcu, fcu->bezt) || (a < 2) /*|| ELEM(fcu->ipo, BEZT_IPO_CONST, BEZT_IPO_LIN)*/)
375 /* get initial pointers */
380 /* loop over all beztriples, adjusting handles */
382 /* clamp timing of handles to be on either side of beztriple */
383 if (bezt->vec[0][0] > bezt->vec[1][0]) bezt->vec[0][0]= bezt->vec[1][0];
384 if (bezt->vec[2][0] < bezt->vec[1][0]) bezt->vec[2][0]= bezt->vec[1][0];
386 /* calculate auto-handles */
387 if (fcu->flag & FCURVE_AUTO_HANDLES)
388 calchandleNurb(bezt, prev, next, 2); /* 2==special autohandle && keep extrema horizontal */
390 calchandleNurb(bezt, prev, next, 1); /* 1==special autohandle */
392 /* for automatic ease in and out */
393 if ((bezt->h1==HD_AUTO) && (bezt->h2==HD_AUTO)) {
394 /* only do this on first or last beztriple */
395 if ((a == 0) || (a == fcu->totvert-1)) {
396 /* set both handles to have same horizontal value as keyframe */
397 if (fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT) {
398 bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
403 /* advance pointers for next iteration */
405 if (a == 1) next= NULL;
411 /* Use when F-Curve with handles has changed
412 * It treats all BezTriples with the following rules:
413 * - PHASE 1: do types have to be altered?
414 * -> Auto handles: become aligned when selection status is NOT(000 || 111)
415 * -> Vector handles: become 'nothing' when (one half selected AND other not)
416 * - PHASE 2: recalculate handles
418 void testhandles_fcurve (FCurve *fcu)
423 /* only beztriples have handles (bpoints don't though) */
424 if ELEM(NULL, fcu, fcu->bezt)
427 /* loop over beztriples */
428 for (a=0, bezt=fcu->bezt; a < fcu->totvert; a++, bezt++) {
431 /* flag is initialised as selection status
432 * of beztriple control-points (labelled 0,1,2)
434 if (bezt->f1 & SELECT) flag |= (1<<0); // == 1
435 if (bezt->f2 & SELECT) flag |= (1<<1); // == 2
436 if (bezt->f3 & SELECT) flag |= (1<<2); // == 4
438 /* one or two handles selected only */
439 if (ELEM(flag, 0, 7)==0) {
440 /* auto handles become aligned */
441 if (bezt->h1==HD_AUTO)
443 if (bezt->h2==HD_AUTO)
446 /* vector handles become 'free' when only one half selected */
447 if (bezt->h1==HD_VECT) {
448 /* only left half (1 or 2 or 1+2) */
452 if (bezt->h2==HD_VECT) {
453 /* only right half (4 or 2+4) */
460 /* recalculate handles */
461 calchandles_fcurve(fcu);
464 /* This function sorts BezTriples so that they are arranged in chronological order,
465 * as tools working on F-Curves expect that the BezTriples are in order.
467 void sort_time_fcurve (FCurve *fcu)
471 /* keep adjusting order of beztriples until nothing moves (bubble-sort) */
475 /* currently, will only be needed when there are beztriples */
480 /* loop over ALL points to adjust position in array and recalculate handles */
481 for (a=0, bezt=fcu->bezt; a < fcu->totvert; a++, bezt++) {
482 /* check if thee's a next beztriple which we could try to swap with current */
483 if (a < (fcu->totvert-1)) {
484 /* swap if one is after the other (and indicate that order has changed) */
485 if (bezt->vec[1][0] > (bezt+1)->vec[1][0]) {
486 SWAP(BezTriple, *bezt, *(bezt+1));
490 /* if either one of both of the points exceeds crosses over the keyframe time... */
491 if ( (bezt->vec[0][0] > bezt->vec[1][0]) && (bezt->vec[2][0] < bezt->vec[1][0]) ) {
492 /* swap handles if they have switched sides for some reason */
493 SWAP(float, bezt->vec[0][0], bezt->vec[2][0]);
494 SWAP(float, bezt->vec[0][1], bezt->vec[2][1]);
498 if (bezt->vec[0][0] > bezt->vec[1][0])
499 bezt->vec[0][0]= bezt->vec[1][0];
500 if (bezt->vec[2][0] < bezt->vec[1][0])
501 bezt->vec[2][0]= bezt->vec[1][0];
509 /* This function tests if any BezTriples are out of order, thus requiring a sort */
510 short test_time_fcurve (FCurve *fcu)
518 /* currently, only need to test beztriples */
522 /* loop through all BezTriples, stopping when one exceeds the one after it */
523 for (a=0, bezt= fcu->bezt; a < (fcu->totvert - 1); a++, bezt++) {
524 if (bezt->vec[1][0] > (bezt+1)->vec[1][0])
531 /* loop through all FPoints, stopping when one exceeds the one after it */
532 for (a=0, fpt= fcu->fpt; a < (fcu->totvert - 1); a++, fpt++) {
533 if (fpt->vec[0] > (fpt+1)->vec[0])
538 /* none need any swapping */
542 /* ***************************** Drivers ********************************* */
544 /* Driver API --------------------------------- */
546 /* This frees the driver itself */
547 void fcurve_free_driver(FCurve *fcu)
549 ChannelDriver *driver;
552 if ELEM(NULL, fcu, fcu->driver)
556 /* free RNA-paths, as these were allocated when getting the path string */
557 if (driver->rna_path) MEM_freeN(driver->rna_path);
558 if (driver->rna_path2) MEM_freeN(driver->rna_path2);
560 /* free driver itself, then set F-Curve's point to this to NULL (as the curve may still be used) */
565 /* This makes a copy of the given driver */
566 ChannelDriver *fcurve_copy_driver (ChannelDriver *driver)
568 ChannelDriver *ndriver;
575 ndriver= MEM_dupallocN(driver);
576 ndriver->rna_path= MEM_dupallocN(ndriver->rna_path);
577 ndriver->rna_path2= MEM_dupallocN(ndriver->rna_path2);
579 /* return the new driver */
583 /* Driver Evaluation -------------------------- */
585 /* Helper function to obtain a value using RNA from the specified source (for evaluating drivers)
586 * - target: used to specify which of the two driver-targets to use
588 static float driver_get_driver_value (ChannelDriver *driver, short target)
590 PointerRNA id_ptr, ptr;
597 /* get RNA-pointer for the ID-block given in driver */
600 RNA_id_pointer_create(driver->id2, &id_ptr);
602 path= driver->rna_path2;
603 index= driver->array_index2;
606 /* first/main target */
607 RNA_id_pointer_create(driver->id, &id_ptr);
609 path= driver->rna_path;
610 index= driver->array_index;
613 /* error check for missing pointer... */
615 printf("Error: driver doesn't have any valid target to use \n");
616 if (G.f & G_DEBUG) printf("\tpath = %s [%d] \n", path, index);
617 driver->flag |= DRIVER_FLAG_INVALID;
621 /* get property to read from, and get value as appropriate */
622 if (RNA_path_resolve(&id_ptr, path, &ptr, &prop)) {
623 switch (RNA_property_type(&ptr, prop)) {
625 if (RNA_property_array_length(&ptr, prop))
626 value= (float)RNA_property_boolean_get_index(&ptr, prop, index);
628 value= (float)RNA_property_boolean_get(&ptr, prop);
631 if (RNA_property_array_length(&ptr, prop))
632 value= (float)RNA_property_int_get_index(&ptr, prop, index);
634 value= (float)RNA_property_int_get(&ptr, prop);
637 if (RNA_property_array_length(&ptr, prop))
638 value= RNA_property_float_get_index(&ptr, prop, index);
640 value= RNA_property_float_get(&ptr, prop);
643 value= (float)RNA_property_enum_get(&ptr, prop);
653 /* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime"
654 * - "evaltime" is the frame at which F-Curve is being evaluated
655 * - has to return a float value
657 static float evaluate_driver (ChannelDriver *driver, float evaltime)
659 /* check if driver can be evaluated */
660 if (driver->flag & DRIVER_FLAG_DISABLED)
663 switch (driver->type) {
664 case DRIVER_TYPE_CHANNEL: /* channel/setting drivers channel/setting */
665 return driver_get_driver_value(driver, 0);
668 case DRIVER_TYPE_PYTHON: /* expression */
670 #ifndef DISABLE_PYTHON
671 /* check for empty or invalid expression */
672 if ( (driver->expression[0] == '\0') ||
673 (driver->flag & DRIVER_FLAG_INVALID) )
678 /* this evaluates the expression using Python,and returns its result:
679 * - on errors it reports, then returns 0.0f
681 return BPY_pydriver_eval(driver);
682 #endif /* DISABLE_PYTHON*/
687 case DRIVER_TYPE_ROTDIFF: /* difference of rotations of 2 bones (should be in same armature) */
690 float q1[4], q2[4], quat[4], angle;
692 Mat4ToQuat(pchan->pose_mat, q1);
693 Mat4ToQuat(pchan2->pose_mat, q2);
696 QuatMul(quat, q1, q2);
697 angle = 2.0f * (saacos(quat[0]));
700 return (angle > M_PI) ? (float)((2.0f * M_PI) - angle) : (float)(angle);
707 /* special 'hack' - just use stored value
708 * This is currently used as the mechanism which allows animated settings to be able
709 * to be changed via the UI.
711 return driver->curval;
715 /* return 0.0f, as couldn't find relevant data to use */
719 /* ***************************** Curve Calculations ********************************* */
721 /* The total length of the handles is not allowed to be more
722 * than the horizontal distance between (v1-v4).
723 * This is to prevent curve loops.
725 void correct_bezpart (float *v1, float *v2, float *v3, float *v4)
727 float h1[2], h2[2], len1, len2, len, fac;
729 /* calculate handle deltas */
730 h1[0]= v1[0] - v2[0];
731 h1[1]= v1[1] - v2[1];
733 h2[0]= v4[0] - v3[0];
734 h2[1]= v4[1] - v3[1];
736 /* calculate distances:
737 * - len = span of time between keyframes
738 * - len1 = length of handle of start key
739 * - len2 = length of handle of end key
742 len1= (float)fabs(h1[0]);
743 len2= (float)fabs(h2[0]);
745 /* if the handles have no length, no need to do any corrections */
746 if ((len1+len2) == 0.0f)
749 /* the two handles cross over each other, so force them
750 * apart using the proportion they overlap
752 if ((len1+len2) > len) {
753 fac= len / (len1+len2);
755 v2[0]= (v1[0] - fac*h1[0]);
756 v2[1]= (v1[1] - fac*h1[1]);
758 v3[0]= (v4[0] - fac*h2[0]);
759 v3[1]= (v4[1] - fac*h2[1]);
763 /* find root ('zero') */
764 int findzero (float x, float q0, float q1, float q2, float q3, float *o)
766 double c0, c1, c2, c3, a, b, c, p, q, d, t, phi;
771 c2= 3.0 * (q0 - 2.0*q1 + q2);
772 c3= q3 - q0 + 3.0 * (q1 - q2);
781 q= (2*a*a*a - a*b + c) / 2;
786 o[0]= (float)(Sqrt3d(-q+t) + Sqrt3d(-q-t) - a);
788 if ((o[0] >= SMALL) && (o[0] <= 1.000001)) return 1;
793 o[0]= (float)(2*t - a);
795 if ((o[0] >= SMALL) && (o[0] <= 1.000001)) nr++;
796 o[nr]= (float)(-t-a);
798 if ((o[nr] >= SMALL) && (o[nr] <= 1.000001)) return nr+1;
802 phi= acos(-q / sqrt(-(p*p*p)));
806 o[0]= (float)(2*t*p - a);
808 if ((o[0] >= SMALL) && (o[0] <= 1.000001)) nr++;
809 o[nr]= (float)(-t * (p + q) - a);
811 if ((o[nr] >= SMALL) && (o[nr] <= 1.000001)) nr++;
812 o[nr]= (float)(-t * (p - q) - a);
814 if ((o[nr] >= SMALL) && (o[nr] <= 1.000001)) return nr+1;
829 o[0]= (float)((-b-p) / (2 * a));
831 if ((o[0] >= SMALL) && (o[0] <= 1.000001)) nr++;
832 o[nr]= (float)((-b+p)/(2*a));
834 if ((o[nr] >= SMALL) && (o[nr] <= 1.000001)) return nr+1;
838 o[0]= (float)(-b / (2 * a));
839 if ((o[0] >= SMALL) && (o[0] <= 1.000001)) return 1;
846 if ((o[0] >= SMALL) && (o[0] <= 1.000001)) return 1;
858 void berekeny (float f1, float f2, float f3, float f4, float *o, int b)
860 float t, c0, c1, c2, c3;
864 c1= 3.0f * (f2 - f1);
865 c2= 3.0f * (f1 - 2.0f*f2 + f3);
866 c3= f4 - f1 + 3.0f * (f2 - f3);
868 for (a=0; a < b; a++) {
870 o[a]= c0 + t*c1 + t*t*c2 + t*t*t*c3;
874 void berekenx (float *f, float *o, int b)
876 float t, c0, c1, c2, c3;
880 c1= 3.0f * (f[3] - f[0]);
881 c2= 3.0f * (f[0] - 2.0f*f[3] + f[6]);
882 c3= f[9] - f[0] + 3.0f * (f[3] - f[6]);
884 for (a=0; a < b; a++) {
886 o[a]= c0 + t*c1 + t*t*c2 + t*t*t*c3;
891 /* -------------------------- */
893 /* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */
894 static float fcurve_eval_keyframes (FCurve *fcu, BezTriple *bezts, float evaltime)
896 BezTriple *bezt, *prevbezt, *lastbezt;
897 float v1[2], v2[2], v3[2], v4[2], opl[32], dx, fac;
906 lastbezt= prevbezt + a;
908 /* evaluation time at or past endpoints? */
909 if (prevbezt->vec[1][0] >= evaltime) {
910 /* before or on first keyframe */
911 if ((fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (prevbezt->ipo != BEZT_IPO_CONST)) {
912 /* linear or bezier interpolation */
913 if (prevbezt->ipo==BEZT_IPO_LIN) {
914 /* Use the next center point instead of our own handle for
915 * linear interpolated extrapolate
917 if (fcu->totvert == 1)
918 cvalue= prevbezt->vec[1][1];
921 dx= prevbezt->vec[1][0] - evaltime;
922 fac= bezt->vec[1][0] - prevbezt->vec[1][0];
924 /* prevent division by zero */
926 fac= (bezt->vec[1][1] - prevbezt->vec[1][1]) / fac;
927 cvalue= prevbezt->vec[1][1] - (fac * dx);
930 cvalue= prevbezt->vec[1][1];
934 /* Use the first handle (earlier) of first BezTriple to calculate the
935 * gradient and thus the value of the curve at evaltime
937 dx= prevbezt->vec[1][0] - evaltime;
938 fac= prevbezt->vec[1][0] - prevbezt->vec[0][0];
940 /* prevent division by zero */
942 fac= (prevbezt->vec[1][1] - prevbezt->vec[0][1]) / fac;
943 cvalue= prevbezt->vec[1][1] - (fac * dx);
946 cvalue= prevbezt->vec[1][1];
950 /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation,
951 * so just extend first keyframe's value
953 cvalue= prevbezt->vec[1][1];
956 else if (lastbezt->vec[1][0] <= evaltime) {
957 /* after or on last keyframe */
958 if ((fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (lastbezt->ipo != BEZT_IPO_CONST)) {
959 /* linear or bezier interpolation */
960 if (lastbezt->ipo==BEZT_IPO_LIN) {
961 /* Use the next center point instead of our own handle for
962 * linear interpolated extrapolate
964 if (fcu->totvert == 1)
965 cvalue= lastbezt->vec[1][1];
967 prevbezt = lastbezt - 1;
968 dx= evaltime - lastbezt->vec[1][0];
969 fac= lastbezt->vec[1][0] - prevbezt->vec[1][0];
971 /* prevent division by zero */
973 fac= (lastbezt->vec[1][1] - prevbezt->vec[1][1]) / fac;
974 cvalue= lastbezt->vec[1][1] + (fac * dx);
977 cvalue= lastbezt->vec[1][1];
981 /* Use the gradient of the second handle (later) of last BezTriple to calculate the
982 * gradient and thus the value of the curve at evaltime
984 dx= evaltime - lastbezt->vec[1][0];
985 fac= lastbezt->vec[2][0] - lastbezt->vec[1][0];
987 /* prevent division by zero */
989 fac= (lastbezt->vec[2][1] - lastbezt->vec[1][1]) / fac;
990 cvalue= lastbezt->vec[1][1] + (fac * dx);
993 cvalue= lastbezt->vec[1][1];
997 /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation,
998 * so just extend last keyframe's value
1000 cvalue= lastbezt->vec[1][1];
1004 /* evaltime occurs somewhere in the middle of the curve */
1005 for (a=0; prevbezt && bezt && (a < fcu->totvert-1); a++, prevbezt=bezt, bezt++) {
1006 /* evaltime occurs within the interval defined by these two keyframes */
1007 if ((prevbezt->vec[1][0] <= evaltime) && (bezt->vec[1][0] >= evaltime)) {
1008 /* value depends on interpolation mode */
1009 if (prevbezt->ipo == BEZT_IPO_CONST) {
1010 /* constant (evaltime not relevant, so no interpolation needed) */
1011 cvalue= prevbezt->vec[1][1];
1013 else if (prevbezt->ipo == BEZT_IPO_LIN) {
1014 /* linear - interpolate between values of the two keyframes */
1015 fac= bezt->vec[1][0] - prevbezt->vec[1][0];
1017 /* prevent division by zero */
1019 fac= (evaltime - prevbezt->vec[1][0]) / fac;
1020 cvalue= prevbezt->vec[1][1] + (fac * (bezt->vec[1][1] - prevbezt->vec[1][1]));
1023 cvalue= prevbezt->vec[1][1];
1026 /* bezier interpolation */
1027 /* v1,v2 are the first keyframe and its 2nd handle */
1028 v1[0]= prevbezt->vec[1][0];
1029 v1[1]= prevbezt->vec[1][1];
1030 v2[0]= prevbezt->vec[2][0];
1031 v2[1]= prevbezt->vec[2][1];
1032 /* v3,v4 are the last keyframe's 1st handle + the last keyframe */
1033 v3[0]= bezt->vec[0][0];
1034 v3[1]= bezt->vec[0][1];
1035 v4[0]= bezt->vec[1][0];
1036 v4[1]= bezt->vec[1][1];
1038 /* adjust handles so that they don't overlap (forming a loop) */
1039 correct_bezpart(v1, v2, v3, v4);
1041 /* try to get a value for this position - if failure, try another set of points */
1042 b= findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl);
1044 berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1);
1057 /* Calculate F-Curve value for 'evaltime' using FPoint samples */
1058 static float fcurve_eval_samples (FCurve *fcu, FPoint *fpts, float evaltime)
1060 FPoint *prevfpt, *lastfpt, *fpt;
1065 lastfpt= prevfpt + fcu->totvert-1;
1067 /* evaluation time at or past endpoints? */
1068 if (prevfpt->vec[0] >= evaltime) {
1069 /* before or on first sample, so just extend value */
1070 cvalue= prevfpt->vec[1];
1072 else if (lastfpt->vec[0] <= evaltime) {
1073 /* after or on last sample, so just extend value */
1074 cvalue= lastfpt->vec[1];
1077 /* find the one on the right frame (assume that these are spaced on 1-frame intervals) */
1078 fpt= prevfpt + (int)(evaltime - prevfpt->vec[0]);
1079 cvalue= fpt->vec[1];
1086 /* ******************************** F-Curve Modifiers ********************************* */
1088 /* Template --------------------------- */
1090 /* Each modifier defines a set of functions, which will be called at the appropriate
1091 * times. In addition to this, each modifier should have a type-info struct, where
1092 * its functions are attached for use.
1095 /* Template for type-info data:
1096 * - make a copy of this when creating new modifiers, and just change the functions
1097 * pointed to as necessary
1098 * - although the naming of functions doesn't matter, it would help for code
1099 * readability, to follow the same naming convention as is presented here
1100 * - any functions that a constraint doesn't need to define, don't define
1101 * for such cases, just use NULL
1102 * - these should be defined after all the functions have been defined, so that
1103 * forward-definitions/prototypes don't need to be used!
1104 * - keep this copy #if-def'd so that future constraints can get based off this
1107 static FModifierTypeInfo FMI_MODNAME = {
1108 FMODIFIER_TYPE_MODNAME, /* type */
1109 sizeof(FMod_ModName), /* size */
1110 FMI_TYPE_SOME_ACTION, /* action type */
1111 FMI_REQUIRES_SOME_REQUIREMENT, /* requirements */
1112 "Modifier Name", /* name */
1113 "FMod_ModName", /* struct name */
1114 fcm_modname_free, /* free data */
1115 fcm_modname_relink, /* relink data */
1116 fcm_modname_copy, /* copy data */
1117 fcm_modname_new_data, /* new data */
1118 fcm_modname_verify, /* verify */
1119 fcm_modname_evaluate /* evaluate */
1123 /* Generator F-Curve Modifier --------------------------- */
1125 /* Generators available:
1126 * 1) simple polynomial generator:
1127 * - Exanded form - (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n])
1128 * - Factorised form - (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1]))
1129 * 2) simple builin 'functions':
1130 * of the form (y = C[0] * fn( C[1]*x + C[2] ) + C[3])
1131 * where fn() can be any one of:
1132 * sin, cos, tan, ln, sqrt
1136 static void fcm_generator_free (FModifier *fcm)
1138 FMod_Generator *data= (FMod_Generator *)fcm->data;
1140 /* free polynomial coefficients array */
1141 if (data->coefficients)
1142 MEM_freeN(data->coefficients);
1145 static void fcm_generator_copy (FModifier *fcm, FModifier *src)
1147 FMod_Generator *gen= (FMod_Generator *)fcm->data;
1148 FMod_Generator *ogen= (FMod_Generator *)src->data;
1150 /* copy coefficients array? */
1151 if (ogen->coefficients)
1152 gen->coefficients= MEM_dupallocN(ogen->coefficients);
1155 static void fcm_generator_new_data (void *mdata)
1157 FMod_Generator *data= (FMod_Generator *)mdata;
1160 /* set default generator to be linear 0-1 (gradient = 1, y-offset = 0) */
1161 data->poly_order= 1;
1163 cp= data->coefficients= MEM_callocN(sizeof(float)*2, "FMod_Generator_Coefs");
1164 cp[0] = 0; // y-offset
1165 cp[1] = 1; // gradient
1168 static void fcm_generator_verify (FModifier *fcm)
1170 FMod_Generator *data= (FMod_Generator *)fcm->data;
1172 /* requirements depend on mode */
1173 switch (data->mode) {
1174 case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
1176 /* arraysize needs to be order+1, so resize if not */
1177 if (data->arraysize != (data->poly_order+1)) {
1180 /* make new coefficients array, and copy over as much data as can fit */
1181 nc= MEM_callocN(sizeof(float)*(data->poly_order+1), "FMod_Generator_Coefs");
1183 if (data->coefficients) {
1184 if (data->arraysize > (data->poly_order+1))
1185 memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order+1));
1187 memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
1189 /* free the old data */
1190 MEM_freeN(data->coefficients);
1193 /* set the new data */
1194 data->coefficients= nc;
1195 data->arraysize= data->poly_order+1;
1200 case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* expanded polynomial expression */
1202 /* arraysize needs to be 2*order, so resize if not */
1203 if (data->arraysize != (data->poly_order * 2)) {
1206 /* make new coefficients array, and copy over as much data as can fit */
1207 nc= MEM_callocN(sizeof(float)*(data->poly_order*2), "FMod_Generator_Coefs");
1209 if (data->coefficients) {
1210 if (data->arraysize > (data->poly_order * 2))
1211 memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order * 2));
1213 memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
1215 /* free the old data */
1216 MEM_freeN(data->coefficients);
1219 /* set the new data */
1220 data->coefficients= nc;
1221 data->arraysize= data->poly_order * 2;
1226 case FCM_GENERATOR_FUNCTION: /* builtin function */
1228 /* arraysize needs to be 4*/
1229 if (data->arraysize != 4) {
1232 /* free the old data */
1233 if (data->coefficients)
1234 MEM_freeN(data->coefficients);
1236 /* make new coefficients array, and init using default values */
1237 nc= data->coefficients= MEM_callocN(sizeof(float)*4, "FMod_Generator_Coefs");
1250 static void fcm_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
1252 FMod_Generator *data= (FMod_Generator *)fcm->data;
1254 /* behaviour depends on mode
1255 * NOTE: the data in its default state is fine too
1257 switch (data->mode) {
1258 case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
1260 /* we overwrite cvalue with the sum of the polynomial */
1261 float *powers = MEM_callocN(sizeof(float)*data->arraysize, "Poly Powers");
1265 /* for each x^n, precalculate value based on previous one first... this should be
1266 * faster that calling pow() for each entry
1268 for (i=0; i < data->arraysize; i++) {
1269 /* first entry is x^0 = 1, otherwise, calculate based on previous */
1271 powers[i]= powers[i-1] * evaltime;
1276 /* for each coefficient, add to value, which we'll write to *cvalue in one go */
1277 for (i=0; i < data->arraysize; i++)
1278 value += data->coefficients[i] * powers[i];
1280 /* only if something changed, write *cvalue in one go */
1281 if (data->poly_order) {
1282 if (data->flag & FCM_GENERATOR_ADDITIVE)
1294 case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial */
1296 float value= 1.0f, *cp=NULL;
1299 /* for each coefficient pair, solve for that bracket before accumulating in value by multiplying */
1300 for (cp=data->coefficients, i=0; (cp) && (i < data->poly_order); cp+=2, i++)
1301 value *= (cp[0]*evaltime + cp[1]);
1303 /* only if something changed, write *cvalue in one go */
1304 if (data->poly_order) {
1305 if (data->flag & FCM_GENERATOR_ADDITIVE)
1313 case FCM_GENERATOR_FUNCTION: /* builtin function */
1315 double arg= data->coefficients[1]*evaltime + data->coefficients[2];
1316 double (*fn)(double v) = NULL;
1318 /* get function pointer to the func to use:
1319 * WARNING: must perform special argument validation hereto guard against crashes
1321 switch (data->func_type)
1324 case FCM_GENERATOR_FN_SIN: /* sine wave */
1327 case FCM_GENERATOR_FN_COS: /* cosine wave */
1331 /* validation required */
1332 case FCM_GENERATOR_FN_TAN: /* tangent wave */
1334 /* check that argument is not on one of the discontinuities (i.e. 90deg, 270 deg, etc) */
1335 if IS_EQ(fmod((arg - M_PI_2), M_PI), 0.0) {
1336 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
1337 *cvalue = 0.0f; /* no value possible here */
1343 case FCM_GENERATOR_FN_LN: /* natural log */
1345 /* check that value is greater than 1? */
1350 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
1351 *cvalue = 0.0f; /* no value possible here */
1355 case FCM_GENERATOR_FN_SQRT: /* square root */
1357 /* no negative numbers */
1362 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
1363 *cvalue = 0.0f; /* no value possible here */
1369 printf("Invalid Function-Generator for F-Modifier - %d \n", data->func_type);
1372 /* execute function callback to set value if appropriate */
1374 float value= data->coefficients[0]*fn(arg) + data->coefficients[3];
1376 if (data->flag & FCM_GENERATOR_ADDITIVE)
1384 #ifndef DISABLE_PYTHON
1385 case FCM_GENERATOR_EXPRESSION: /* py-expression */
1388 #endif /* DISABLE_PYTHON */
1392 static FModifierTypeInfo FMI_GENERATOR = {
1393 FMODIFIER_TYPE_GENERATOR, /* type */
1394 sizeof(FMod_Generator), /* size */
1395 FMI_TYPE_GENERATE_CURVE, /* action type */
1396 FMI_REQUIRES_NOTHING, /* requirements */
1397 "Generator", /* name */
1398 "FMod_Generator", /* struct name */
1399 fcm_generator_free, /* free data */
1400 fcm_generator_copy, /* copy data */
1401 fcm_generator_new_data, /* new data */
1402 fcm_generator_verify, /* verify */
1403 fcm_generator_evaluate /* evaluate */
1406 /* Envelope F-Curve Modifier --------------------------- */
1408 static void fcm_envelope_free (FModifier *fcm)
1410 FMod_Envelope *env= (FMod_Envelope *)fcm->data;
1412 /* free envelope data array */
1414 MEM_freeN(env->data);
1417 static void fcm_envelope_copy (FModifier *fcm, FModifier *src)
1419 FMod_Envelope *env= (FMod_Envelope *)fcm->data;
1420 FMod_Envelope *oenv= (FMod_Envelope *)src->data;
1422 /* copy envelope data array */
1424 env->data= MEM_dupallocN(oenv->data);
1427 static void fcm_envelope_new_data (void *mdata)
1429 FMod_Envelope *env= (FMod_Envelope *)mdata;
1431 /* set default min/max ranges */
1436 static void fcm_envelope_verify (FModifier *fcm)
1438 FMod_Envelope *env= (FMod_Envelope *)fcm->data;
1440 /* if the are points, perform bubble-sort on them, as user may have changed the order */
1446 static void fcm_envelope_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
1448 FMod_Envelope *env= (FMod_Envelope *)fcm->data;
1449 FCM_EnvelopeData *fed, *prevfed, *lastfed;
1450 float min=0.0f, max=0.0f, fac=0.0f;
1454 if (env->data == NULL) return;
1457 lastfed= prevfed + (env->totvert-1);
1459 /* get min/max values for envelope at evaluation time (relative to mid-value) */
1460 if (prevfed->time >= evaltime) {
1461 /* before or on first sample, so just extend value */
1465 else if (lastfed->time <= evaltime) {
1466 /* after or on last sample, so just extend value */
1471 /* evaltime occurs somewhere between segments */
1472 // TODO: implement binary search for this to make it faster?
1473 for (a=0; prevfed && fed && (a < env->totvert-1); a++, prevfed=fed, fed++) {
1474 /* evaltime occurs within the interval defined by these two envelope points */
1475 if ((prevfed->time <= evaltime) && (fed->time >= evaltime)) {
1476 float afac, bfac, diff;
1478 diff= fed->time - prevfed->time;
1479 afac= (evaltime - prevfed->time) / diff;
1480 bfac= (fed->time - evaltime) / diff;
1482 min= bfac*prevfed->min + afac*fed->min;
1483 max= bfac*prevfed->max + afac*fed->max;
1491 * - fac is the ratio of how the current y-value corresponds to the reference range
1492 * - thus, the new value is found by mapping the old range to the new!
1494 fac= (*cvalue - (env->midval + env->min)) / (env->max - env->min);
1495 *cvalue= min + fac*(max - min);
1498 static FModifierTypeInfo FMI_ENVELOPE = {
1499 FMODIFIER_TYPE_ENVELOPE, /* type */
1500 sizeof(FMod_Envelope), /* size */
1501 FMI_TYPE_REPLACE_VALUES, /* action type */
1502 0, /* requirements */
1503 "Envelope", /* name */
1504 "FMod_Envelope", /* struct name */
1505 fcm_envelope_free, /* free data */
1506 fcm_envelope_copy, /* copy data */
1507 fcm_envelope_new_data, /* new data */
1508 fcm_envelope_verify, /* verify */
1509 fcm_envelope_evaluate /* evaluate */
1512 /* Cycles F-Curve Modifier --------------------------- */
1514 /* This modifier changes evaltime to something that exists within the curve's frame-range,
1515 * then re-evaluates modifier stack up to this point using the new time. This re-entrant behaviour
1516 * is very likely to be more time-consuming than the original approach... (which was tighly integrated into
1517 * the calculation code...).
1519 * 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
1520 * Possible TODO - store length of cycle information that can be initialised from the extents of the keyframes/sample-data, and adjusted
1524 static void fcm_cycles_new_data (void *mdata)
1526 FMod_Cycles *data= (FMod_Cycles *)mdata;
1528 /* turn on cycles by default */
1529 data->before_mode= data->after_mode= FCM_EXTRAPOLATE_CYCLIC;
1532 static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
1534 FMod_Cycles *data= (FMod_Cycles *)fcm->data;
1535 ListBase mods = {NULL, NULL};
1536 float prevkey[2], lastkey[2], cycyofs=0.0f;
1538 short side=0, mode=0;
1541 /* check if modifier is first in stack, otherwise disable ourself... */
1544 fcm->flag |= FMODIFIER_FLAG_DISABLED;
1548 /* calculate new evaltime due to cyclic interpolation */
1549 if (fcu && fcu->bezt) {
1550 BezTriple *prevbezt= fcu->bezt;
1551 BezTriple *lastbezt= prevbezt + fcu->totvert-1;
1553 prevkey[0]= prevbezt->vec[1][0];
1554 prevkey[1]= prevbezt->vec[1][1];
1556 lastkey[0]= lastbezt->vec[1][0];
1557 lastkey[1]= lastbezt->vec[1][1];
1559 else if (fcu && fcu->fpt) {
1560 FPoint *prevfpt= fcu->fpt;
1561 FPoint *lastfpt= prevfpt + fcu->totvert-1;
1563 prevkey[0]= prevfpt->vec[0];
1564 prevkey[1]= prevfpt->vec[1];
1566 lastkey[0]= lastfpt->vec[0];
1567 lastkey[1]= lastfpt->vec[1];
1572 /* check if modifier will do anything
1573 * 1) if in data range, definitely don't do anything
1574 * 2) if before first frame or after last frame, make sure some cycling is in use
1576 if (evaltime < prevkey[0]) {
1577 if (data->before_mode) {
1579 mode= data->before_mode;
1580 cycles= data->before_cycles;
1583 else if (evaltime > lastkey[0]) {
1584 if (data->after_mode) {
1586 mode= data->after_mode;
1587 cycles= data->after_cycles;
1590 if ELEM(0, side, mode)
1593 /* find relative place within a cycle */
1595 float cycdx=0, cycdy=0, ofs=0;
1597 /* ofs is start frame of cycle */
1600 /* calculate period and amplitude (total height) of a cycle */
1601 cycdx= lastkey[0] - prevkey[0];
1602 cycdy= lastkey[1] - prevkey[1];
1604 /* check if cycle is infinitely small, to be point of being impossible to use */
1608 /* check that cyclic is still enabled for the specified time */
1610 /* catch this case so that we don't exit when we have cycles=0
1611 * as this indicates infinite cycles...
1614 else if ( ((float)side * (evaltime - ofs) / cycdx) > (cycles+1) ) {
1615 /* we are too far away from range to evaluate
1616 * TODO: but we should still hold last value...
1621 /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */
1622 if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
1623 cycyofs = (float)floor((evaltime - ofs) / cycdx);
1627 /* calculate where in the cycle we are (overwrite evaltime to reflect this) */
1628 evaltime= (float)(fmod(evaltime-ofs, cycdx) + ofs);
1629 if (evaltime < ofs) evaltime += cycdx;
1633 /* store modifiers after (and including ourself) before recalculating curve with new evaltime */
1634 mods= fcu->modifiers;
1635 fcu->modifiers.first= fcu->modifiers.last= NULL;
1637 /* re-enter the evaluation loop (but without the burden of evaluating any modifiers, so 'should' be relatively quick) */
1638 new_value= evaluate_fcurve(fcu, evaltime);
1640 /* restore modifiers, and set new value (don't assume everything is still ok after being re-entrant) */
1641 fcu->modifiers= mods;
1642 *cvalue= new_value + cycyofs;
1645 static FModifierTypeInfo FMI_CYCLES = {
1646 FMODIFIER_TYPE_CYCLES, /* type */
1647 sizeof(FMod_Cycles), /* size */
1648 FMI_TYPE_EXTRAPOLATION, /* action type */
1649 FMI_REQUIRES_ORIGINAL_DATA, /* requirements */
1650 "Cycles", /* name */
1651 "FMod_Cycles", /* struct name */
1652 NULL, /* free data */
1653 NULL, /* copy data */
1654 fcm_cycles_new_data, /* new data */
1655 NULL /*fcm_cycles_verify*/, /* verify */
1656 fcm_cycles_evaluate /* evaluate */
1659 /* Noise F-Curve Modifier --------------------------- */
1661 #if 0 // XXX not yet implemented
1662 static FModifierTypeInfo FMI_NOISE = {
1663 FMODIFIER_TYPE_NOISE, /* type */
1664 sizeof(FMod_Noise), /* size */
1665 FMI_TYPE_REPLACE_VALUES, /* action type */
1666 0, /* requirements */
1668 "FMod_Noise", /* struct name */
1669 NULL, /* free data */
1670 NULL, /* copy data */
1671 fcm_noise_new_data, /* new data */
1672 NULL /*fcm_noise_verify*/, /* verify */
1673 fcm_noise_evaluate /* evaluate */
1675 #endif // XXX not yet implemented
1677 /* Filter F-Curve Modifier --------------------------- */
1679 #if 0 // XXX not yet implemented
1680 static FModifierTypeInfo FMI_FILTER = {
1681 FMODIFIER_TYPE_FILTER, /* type */
1682 sizeof(FMod_Filter), /* size */
1683 FMI_TYPE_REPLACE_VALUES, /* action type */
1684 0, /* requirements */
1685 "Filter", /* name */
1686 "FMod_Filter", /* struct name */
1687 NULL, /* free data */
1688 NULL, /* copy data */
1689 NULL, /* new data */
1690 NULL /*fcm_filter_verify*/, /* verify */
1691 fcm_filter_evaluate /* evaluate */
1693 #endif // XXX not yet implemented
1696 /* Python F-Curve Modifier --------------------------- */
1698 static void fcm_python_free (FModifier *fcm)
1700 FMod_Python *data= (FMod_Python *)fcm->data;
1703 IDP_FreeProperty(data->prop);
1704 MEM_freeN(data->prop);
1707 static void fcm_python_new_data (void *mdata)
1709 FMod_Python *data= (FMod_Python *)mdata;
1711 /* everything should be set correctly by calloc, except for the prop->type constant.*/
1712 data->prop = MEM_callocN(sizeof(IDProperty), "PyFModifierProps");
1713 data->prop->type = IDP_GROUP;
1716 static void fcm_python_copy (FModifier *fcm, FModifier *src)
1718 FMod_Python *pymod = (FMod_Python *)fcm->data;
1719 FMod_Python *opymod = (FMod_Python *)src->data;
1721 pymod->prop = IDP_CopyProperty(opymod->prop);
1724 static void fcm_python_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
1726 #ifndef DISABLE_PYTHON
1727 //FMod_Python *data= (FMod_Python *)fcm->data;
1729 /* FIXME... need to implement this modifier...
1730 * It will need it execute a script using the custom properties
1732 #endif /* DISABLE_PYTHON */
1735 static FModifierTypeInfo FMI_PYTHON = {
1736 FMODIFIER_TYPE_PYTHON, /* type */
1737 sizeof(FMod_Python), /* size */
1738 FMI_TYPE_GENERATE_CURVE, /* action type */
1739 FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
1740 "Python", /* name */
1741 "FMod_Python", /* struct name */
1742 fcm_python_free, /* free data */
1743 fcm_python_copy, /* copy data */
1744 fcm_python_new_data, /* new data */
1745 NULL /*fcm_python_verify*/, /* verify */
1746 fcm_python_evaluate /* evaluate */
1750 /* F-Curve Modifier API --------------------------- */
1751 /* All of the F-Curve Modifier api functions use FModifierTypeInfo structs to carry out
1752 * and operations that involve F-Curve modifier specific code.
1755 /* These globals only ever get directly accessed in this file */
1756 static FModifierTypeInfo *fmodifiersTypeInfo[FMODIFIER_NUM_TYPES];
1757 static short FMI_INIT= 1; /* when non-zero, the list needs to be updated */
1759 /* This function only gets called when FMI_INIT is non-zero */
1760 static void fmods_init_typeinfo ()
1762 fmodifiersTypeInfo[0]= NULL; /* 'Null' F-Curve Modifier */
1763 fmodifiersTypeInfo[1]= &FMI_GENERATOR; /* Generator F-Curve Modifier */
1764 fmodifiersTypeInfo[2]= &FMI_ENVELOPE; /* Envelope F-Curve Modifier */
1765 fmodifiersTypeInfo[3]= &FMI_CYCLES; /* Cycles F-Curve Modifier */
1766 fmodifiersTypeInfo[4]= NULL/*&FMI_NOISE*/; /* Apply-Noise F-Curve Modifier */ // XXX unimplemented
1767 fmodifiersTypeInfo[5]= NULL/*&FMI_FILTER*/; /* Filter F-Curve Modifier */ // XXX unimplemented
1768 fmodifiersTypeInfo[6]= &FMI_PYTHON; /* Custom Python F-Curve Modifier */
1771 /* This function should be used for getting the appropriate type-info when only
1772 * a F-Curve modifier type is known
1774 FModifierTypeInfo *get_fmodifier_typeinfo (int type)
1776 /* initialise the type-info list? */
1778 fmods_init_typeinfo();
1782 /* only return for valid types */
1783 if ( (type >= FMODIFIER_TYPE_NULL) &&
1784 (type <= FMODIFIER_NUM_TYPES ) )
1786 /* there shouldn't be any segfaults here... */
1787 return fmodifiersTypeInfo[type];
1790 printf("No valid F-Curve Modifier type-info data available. Type = %i \n", type);
1796 /* This function should always be used to get the appropriate type-info, as it
1797 * has checks which prevent segfaults in some weird cases.
1799 FModifierTypeInfo *fmodifier_get_typeinfo (FModifier *fcm)
1801 /* only return typeinfo for valid modifiers */
1803 return get_fmodifier_typeinfo(fcm->type);
1808 /* API --------------------------- */
1810 /* Add a new F-Curve Modifier to the given F-Curve of a certain type */
1811 FModifier *fcurve_add_modifier (FCurve *fcu, int type)
1813 FModifierTypeInfo *fmi= get_fmodifier_typeinfo(type);
1817 if ELEM(NULL, fcu, fmi)
1820 /* special checks for whether modifier can be added */
1821 if ((fcu->modifiers.first) && (type == FMODIFIER_TYPE_CYCLES)) {
1822 /* cycles modifier must be first in stack, so for now, don't add if it can't be */
1823 // TODO: perhaps there is some better way, but for now,
1824 printf("Error: Cannot add 'Cycles' modifier to F-Curve, as 'Cycles' modifier can only be first in stack. \n");
1828 /* add modifier itself */
1829 fcm= MEM_callocN(sizeof(FModifier), "F-Curve Modifier");
1831 fcm->flag = FMODIFIER_FLAG_EXPANDED;
1832 BLI_addtail(&fcu->modifiers, fcm);
1834 /* add modifier's data */
1835 fcm->data= MEM_callocN(fmi->size, fmi->structName);
1837 /* init custom settings if necessary */
1839 fmi->new_data(fcm->data);
1841 /* return modifier for further editing */
1845 /* Duplicate all of the F-Curve Modifiers in the Modifier stacks */
1846 void fcurve_copy_modifiers (ListBase *dst, ListBase *src)
1848 FModifier *fcm, *srcfcm;
1850 if ELEM(NULL, dst, src)
1853 dst->first= dst->last= NULL;
1854 BLI_duplicatelist(dst, src);
1856 for (fcm=dst->first, srcfcm=src->first; fcm && srcfcm; srcfcm=srcfcm->next, fcm=fcm->next) {
1857 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
1859 /* make a new copy of the F-Modifier's data */
1860 fcm->data = MEM_dupallocN(fcm->data);
1862 /* only do specific constraints if required */
1863 if (fmi && fmi->copy_data)
1864 fmi->copy_data(fcm, srcfcm);
1868 /* Remove and free the given F-Curve Modifier from the given F-Curve's stack */
1869 void fcurve_remove_modifier (FCurve *fcu, FModifier *fcm)
1871 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
1877 /* free modifier's special data (stored inside fcm->data) */
1879 if (fmi && fmi->free_data)
1880 fmi->free_data(fcm);
1882 /* free modifier's data (fcm->data) */
1883 MEM_freeN(fcm->data);
1886 /* remove modifier from stack */
1888 BLI_freelinkN(&fcu->modifiers, fcm);
1890 // XXX this case can probably be removed some day, as it shouldn't happen...
1891 printf("fcurve_remove_modifier() - no fcurve \n");
1896 /* Remove all of a given F-Curve's modifiers */
1897 void fcurve_free_modifiers (FCurve *fcu)
1899 FModifier *fcm, *fmn;
1905 /* free each modifier in order - modifier is unlinked from list and freed */
1906 for (fcm= fcu->modifiers.first; fcm; fcm= fmn) {
1908 fcurve_remove_modifier(fcu, fcm);
1912 /* Bake modifiers for given F-Curve to curve sample data, in the frame range defined
1913 * by start and end (inclusive).
1915 void fcurve_bake_modifiers (FCurve *fcu, int start, int end)
1917 ChannelDriver *driver;
1920 // TODO: make these tests report errors using reports not printf's
1921 if ELEM(NULL, fcu, fcu->modifiers.first) {
1922 printf("Error: No F-Curve with F-Curve Modifiers to Bake\n");
1926 /* temporarily, disable driver while we sample, so that they don't influence the outcome */
1927 driver= fcu->driver;
1930 /* bake the modifiers, by sampling the curve at each frame */
1931 fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
1933 /* free the modifiers now */
1934 fcurve_free_modifiers(fcu);
1936 /* restore driver */
1937 fcu->driver= driver;
1940 /* Find the active F-Curve Modifier */
1941 FModifier *fcurve_find_active_modifier (FCurve *fcu)
1946 if ELEM(NULL, fcu, fcu->modifiers.first)
1949 /* loop over modifiers until 'active' one is found */
1950 for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {
1951 if (fcm->flag & FMODIFIER_FLAG_ACTIVE)
1955 /* no modifier is active */
1959 /* Set the active F-Curve Modifier */
1960 void fcurve_set_active_modifier (FCurve *fcu, FModifier *fcm)
1965 if ELEM(NULL, fcu, fcu->modifiers.first)
1968 /* deactivate all, and set current one active */
1969 for (fm= fcu->modifiers.first; fm; fm= fm->next)
1970 fm->flag &= ~FMODIFIER_FLAG_ACTIVE;
1972 /* make given modifier active */
1974 fcm->flag |= FMODIFIER_FLAG_ACTIVE;
1977 /* ***************************** F-Curve - Evaluation ********************************* */
1979 /* Evaluate and return the value of the given F-Curve at the specified frame ("evaltime")
1980 * Note: this is also used for drivers
1982 float evaluate_fcurve (FCurve *fcu, float evaltime)
1985 float cvalue = 0.0f;
1987 /* if there is a driver (only if this F-Curve is acting as 'driver'), evaluate it to find value to use as "evaltime"
1988 * - this value will also be returned as the value of the 'curve', if there are no keyframes
1991 /* evaltime now serves as input for the curve */
1992 evaltime= cvalue= evaluate_driver(fcu->driver, evaltime);
1995 /* evaluate curve-data */
1997 cvalue= fcurve_eval_keyframes(fcu, fcu->bezt, evaltime);
1999 cvalue= fcurve_eval_samples(fcu, fcu->fpt, evaltime);
2001 /* evaluate modifiers */
2002 for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {
2003 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
2005 /* only evaluate if there's a callback for this */
2006 // TODO: implement the 'influence' control feature...
2007 if (fmi && fmi->evaluate_modifier) {
2008 if ((fcm->flag & FMODIFIER_FLAG_DISABLED) == 0)
2009 fmi->evaluate_modifier(fcu, fcm, &cvalue, evaltime);
2013 /* if curve can only have integral values, perform truncation (i.e. drop the decimal part)
2014 * here so that the curve can be sampled correctly
2016 if (fcu->flag & FCURVE_INT_VALUES)
2017 cvalue= (float)((int)cvalue);
2019 /* return evaluated value */
2023 /* Calculate the value of the given F-Curve at the given frame, and set its curval */
2024 // TODO: will this be necessary?
2025 void calculate_fcurve (FCurve *fcu, float ctime)
2027 /* calculate and set curval (evaluates driver too) */
2028 fcu->curval= evaluate_fcurve(fcu, ctime);