Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Leung <aligorith@gmail.com>2009-05-03 17:00:59 +0400
committerJoshua Leung <aligorith@gmail.com>2009-05-03 17:00:59 +0400
commit2e93dc4037b815a97c9b9d03fe28742e01458e43 (patch)
treecdd6f48f76973a110c4552ab74c0d9f23f248d94 /source/blender/blenkernel/intern/fcurve.c
parent99cc61edbcaf339a0ff9aefa932b4520d7dfe1e7 (diff)
F-Curve Modifiers: Time-Modifying F-Modifiers Cleanup
Time-Modifying F-Curve Modifiers now get special callbacks to allow them to specify what frame they need to be evaluated on, instead of forcing a re-evaluation of the preceeding curve + modifier-stack. This should be more robust than the old way in general. It still remains to be seen if some tweaks to this are still needed, as the full consequences of the propogation of modified time-spaces have yet to be fully explored. For now though, evaluation works by finding the last modifier on the stack which modifies time, and asks it what time it modifies the given time to. This modified time is used to evaluate the F-Curve data only. The modifier stack gets evaluated using the original time instead.
Diffstat (limited to 'source/blender/blenkernel/intern/fcurve.c')
-rw-r--r--source/blender/blenkernel/intern/fcurve.c151
1 files changed, 92 insertions, 59 deletions
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index a0e631cfe8f..3bc80d64329 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -1253,50 +1253,11 @@ static FModifierTypeInfo FMI_MODNAME = {
fcm_modname_copy, /* copy data */
fcm_modname_new_data, /* new data */
fcm_modname_verify, /* verify */
+ fcm_modname_time, /* evaluate time */
fcm_modname_evaluate /* evaluate */
};
#endif
-/* Utilities For F-Curve Modifiers ---------------------- */
-
-/* Recalculate the F-Curve at evaltime, as modified by the given F-Curve
- *
- * While this may sound wrong (and be potentially very slow), it is invalid for F-Curve modifiers to actually
- * modify the evaltime in such a way that those after it will end up evaluating in the wrong time space.
- */
-static float fcm_reevaluate_fcurve (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime)
-{
- ListBase modifiers = {NULL, NULL};
- float new_value = 0.0f;
-
- /* sanity checking */
- if ELEM(NULL, fcu, fcm)
- return cvalue;
-
- /* unlink given modifier from previous modifiers, keeping the previous ones on the F-Curve,
- * but ones after off the F-Curve (so that we avoid the infinitely re-entrant situation).
- */
- modifiers.first= fcm;
- modifiers.last= fcu->modifiers.last;
-
- if (fcm->prev) {
- fcm->prev->next= NULL;
- fcu->modifiers.last= fcm->prev;
- }
- else
- fcu->modifiers.first= fcu->modifiers.last= NULL;
- fcm->prev= NULL;
-
- /* re-enter the evaluation loop (but without the burden of evaluating any modifiers, so 'should' be relatively quick) */
- new_value= evaluate_fcurve(fcu, evaltime);
-
- /* restore modifiers (don't assume everything is still ok after being re-entrant) */
- addlisttolist(&fcu->modifiers, &modifiers);
-
- /* return the new value */
- return new_value;
-}
-
/* Generator F-Curve Modifier --------------------------- */
/* Generators available:
@@ -1548,7 +1509,7 @@ static void fcm_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue,
/* execute function callback to set value if appropriate */
if (fn) {
- float value= data->coefficients[0]*fn(arg) + data->coefficients[3];
+ float value= (float)(data->coefficients[0]*fn(arg) + data->coefficients[3]);
if (data->flag & FCM_GENERATOR_ADDITIVE)
*cvalue += value;
@@ -1577,6 +1538,7 @@ static FModifierTypeInfo FMI_GENERATOR = {
fcm_generator_copy, /* copy data */
fcm_generator_new_data, /* new data */
fcm_generator_verify, /* verify */
+ NULL, /* evaluate time */
fcm_generator_evaluate /* evaluate */
};
@@ -1683,6 +1645,7 @@ static FModifierTypeInfo FMI_ENVELOPE = {
fcm_envelope_copy, /* copy data */
fcm_envelope_new_data, /* new data */
fcm_envelope_verify, /* verify */
+ NULL, /* evaluate time */
fcm_envelope_evaluate /* evaluate */
};
@@ -1698,6 +1661,11 @@ static FModifierTypeInfo FMI_ENVELOPE = {
* as appropriate
*/
+/* temp data used during evaluation */
+typedef struct tFCMED_Cycles {
+ float cycyofs; /* y-offset to apply */
+} tFCMED_Cycles;
+
static void fcm_cycles_new_data (void *mdata)
{
FMod_Cycles *data= (FMod_Cycles *)mdata;
@@ -1705,8 +1673,8 @@ static void fcm_cycles_new_data (void *mdata)
/* turn on cycles by default */
data->before_mode= data->after_mode= FCM_EXTRAPOLATE_CYCLIC;
}
-
-static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+
+static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime)
{
FMod_Cycles *data= (FMod_Cycles *)fcm->data;
float prevkey[2], lastkey[2], cycyofs=0.0f;
@@ -1717,7 +1685,7 @@ static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, flo
// FIXME...
if (fcm->prev) {
fcm->flag |= FMODIFIER_FLAG_DISABLED;
- return;
+ return evaltime;
}
/* calculate new evaltime due to cyclic interpolation */
@@ -1742,7 +1710,7 @@ static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, flo
lastkey[1]= lastfpt->vec[1];
}
else
- return;
+ return evaltime;
/* check if modifier will do anything
* 1) if in data range, definitely don't do anything
@@ -1763,7 +1731,7 @@ static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, flo
}
}
if ELEM(0, side, mode)
- return;
+ return evaltime;
/* find relative place within a cycle */
{
@@ -1778,7 +1746,7 @@ static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, flo
/* check if cycle is infinitely small, to be point of being impossible to use */
if (cycdx == 0)
- return;
+ return evaltime;
/* check that cyclic is still enabled for the specified time */
if (cycles == 0) {
@@ -1790,7 +1758,7 @@ static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, flo
/* we are too far away from range to evaluate
* TODO: but we should still hold last value...
*/
- return;
+ return evaltime;
}
/* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */
@@ -1804,8 +1772,32 @@ static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, flo
if (evaltime < ofs) evaltime += cycdx;
}
- /* reevaluate F-Curve at the new time that we've decided on */
- *cvalue= fcm_reevaluate_fcurve(fcu, fcm, *cvalue, evaltime) + cycyofs;
+ /* store temp data if needed */
+ if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
+ tFCMED_Cycles *edata;
+
+ /* for now, this is just a float, but we could get more stuff... */
+ fcm->edata= edata= MEM_callocN(sizeof(tFCMED_Cycles), "tFCMED_Cycles");
+ edata->cycyofs= cycyofs;
+ }
+
+ /* return the new frame to evaluate */
+ return evaltime;
+}
+
+static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+{
+ tFCMED_Cycles *edata= (tFCMED_Cycles *)fcm->edata;
+
+ /* use temp data */
+ if (edata) {
+ /* add cyclic offset - no need to check for now, otherwise the data wouldn't exist! */
+ *cvalue += edata->cycyofs;
+
+ /* free temp data */
+ MEM_freeN(edata);
+ fcm->edata= NULL;
+ }
}
static FModifierTypeInfo FMI_CYCLES = {
@@ -1819,6 +1811,7 @@ static FModifierTypeInfo FMI_CYCLES = {
NULL, /* copy data */
fcm_cycles_new_data, /* new data */
NULL /*fcm_cycles_verify*/, /* verify */
+ fcm_cycles_time, /* evaluate time */
fcm_cycles_evaluate /* evaluate */
};
@@ -1871,6 +1864,7 @@ static FModifierTypeInfo FMI_NOISE = {
NULL, /* copy data */
fcm_noise_new_data, /* new data */
NULL /*fcm_noise_verify*/, /* verify */
+ NULL, /* evaluate time */
fcm_noise_evaluate /* evaluate */
};
@@ -1888,6 +1882,7 @@ static FModifierTypeInfo FMI_FILTER = {
NULL, /* copy data */
NULL, /* new data */
NULL /*fcm_filter_verify*/, /* verify */
+ NULL, /* evlauate time */
fcm_filter_evaluate /* evaluate */
};
#endif // XXX not yet implemented
@@ -1943,21 +1938,30 @@ static FModifierTypeInfo FMI_PYTHON = {
fcm_python_copy, /* copy data */
fcm_python_new_data, /* new data */
NULL /*fcm_python_verify*/, /* verify */
+ NULL /*fcm_python_time*/, /* evaluate time */
fcm_python_evaluate /* evaluate */
};
/* Limits F-Curve Modifier --------------------------- */
-static void fcm_limits_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+static float fcm_limits_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime)
{
FMod_Limits *data= (FMod_Limits *)fcm->data;
- /* time limits first */
+ /* check for the time limits */
if ((data->flag & FCM_LIMIT_XMIN) && (evaltime < data->rect.xmin))
- *cvalue= fcm_reevaluate_fcurve(fcu, fcm, *cvalue, data->rect.xmin);
+ return data->rect.xmin;
if ((data->flag & FCM_LIMIT_XMAX) && (evaltime > data->rect.xmax))
- *cvalue= fcm_reevaluate_fcurve(fcu, fcm, *cvalue, data->rect.xmax);
+ return data->rect.xmax;
+
+ /* modifier doesn't change time */
+ return evaltime;
+}
+
+static void fcm_limits_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
+{
+ FMod_Limits *data= (FMod_Limits *)fcm->data;
/* value limits now */
if ((data->flag & FCM_LIMIT_YMIN) && (*cvalue < data->rect.ymin))
@@ -1976,7 +1980,8 @@ static FModifierTypeInfo FMI_LIMITS = {
NULL, /* free data */
NULL, /* copy data */
NULL, /* new data */
- NULL /*fcm_python_verify*/, /* verify */
+ NULL, /* verify */
+ fcm_limits_time, /* evaluate time */
fcm_limits_evaluate /* evaluate */
};
@@ -2216,9 +2221,11 @@ void fcurve_set_active_modifier (FCurve *fcu, FModifier *fcm)
float evaluate_fcurve (FCurve *fcu, float evaltime)
{
FModifier *fcm;
- float cvalue = 0.0f;
+ float cvalue= 0.0f;
+ float devaltime;
/* if there is a driver (only if this F-Curve is acting as 'driver'), evaluate it to find value to use as "evaltime"
+ * since drivers essentially act as alternative input (i.e. in place of 'time') for F-Curves
* - this value will also be returned as the value of the 'curve', if there are no keyframes
*/
if (fcu->driver) {
@@ -2226,11 +2233,37 @@ float evaluate_fcurve (FCurve *fcu, float evaltime)
evaltime= cvalue= evaluate_driver(fcu->driver, evaltime);
}
- /* evaluate curve-data */
+ /* evaluate time modifications imposed by some F-Curve Modifiers
+ * - this step acts as an optimisation to prevent the F-Curve stack being evaluated
+ * several times by modifiers requesting the time be modified, as the final result
+ * would have required using the modified time
+ * - modifiers only ever recieve the unmodified time, as subsequent modifiers should be
+ * working on the 'global' result of the modified curve, not some localised segment,
+ * so nevaltime gets set to whatever the last time-modifying modifier likes...
+ * - we start from the end of the stack, as only the last one matters for now
+ */
+ devaltime= evaltime;
+
+ for (fcm= fcu->modifiers.last; fcm; fcm= fcm->prev) {
+ FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
+
+ /* only evaluate if there's a callback for this */
+ // TODO: implement the 'influence' control feature...
+ if (fmi && fmi->evaluate_modifier_time) {
+ if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
+ devaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
+ break;
+ }
+ }
+
+ /* evaluate curve-data
+ * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying
+ * F-Curve modifier on the stack requested the curve to be evaluated at
+ */
if (fcu->bezt)
- cvalue= fcurve_eval_keyframes(fcu, fcu->bezt, evaltime);
+ cvalue= fcurve_eval_keyframes(fcu, fcu->bezt, devaltime);
else if (fcu->fpt)
- cvalue= fcurve_eval_samples(fcu, fcu->fpt, evaltime);
+ cvalue= fcurve_eval_samples(fcu, fcu->fpt, devaltime);
/* evaluate modifiers */
for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {