[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [20039] branches/blender2.5/blender/source /blender: F-Curve Modifiers: Time-Modifying F-Modifiers Cleanup

Joshua Leung aligorith at gmail.com
Sun May 3 15:00:59 CEST 2009


Revision: 20039
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=20039
Author:   aligorith
Date:     2009-05-03 15:00:59 +0200 (Sun, 03 May 2009)

Log Message:
-----------
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.

Modified Paths:
--------------
    branches/blender2.5/blender/source/blender/blenkernel/BKE_fcurve.h
    branches/blender2.5/blender/source/blender/blenkernel/intern/fcurve.c
    branches/blender2.5/blender/source/blender/blenloader/intern/readfile.c
    branches/blender2.5/blender/source/blender/makesdna/DNA_anim_types.h

Modified: branches/blender2.5/blender/source/blender/blenkernel/BKE_fcurve.h
===================================================================
--- branches/blender2.5/blender/source/blender/blenkernel/BKE_fcurve.h	2009-05-03 12:06:43 UTC (rev 20038)
+++ branches/blender2.5/blender/source/blender/blenkernel/BKE_fcurve.h	2009-05-03 13:00:59 UTC (rev 20039)
@@ -68,6 +68,8 @@
 	void (*verify_data)(struct FModifier *fcm);
 	
 	/* evaluation */
+		/* evaluate time that the modifier requires the F-Curve to be evaluated at */
+	float (*evaluate_modifier_time)(struct FCurve *fcu, struct FModifier *fcm, float cvalue, float evaltime);
 		/* evaluate the modifier for the given time and 'accumulated' value */
 	void (*evaluate_modifier)(struct FCurve *fcu, struct FModifier *fcm, float *cvalue, float evaltime);
 } FModifierTypeInfo;

Modified: branches/blender2.5/blender/source/blender/blenkernel/intern/fcurve.c
===================================================================
--- branches/blender2.5/blender/source/blender/blenkernel/intern/fcurve.c	2009-05-03 12:06:43 UTC (rev 20038)
+++ branches/blender2.5/blender/source/blender/blenkernel/intern/fcurve.c	2009-05-03 13:00:59 UTC (rev 20039)
@@ -1253,50 +1253,11 @@
 	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 @@
 			
 			/* 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 @@
 	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 @@
 	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 @@
  * 				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 @@
 	/* 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 @@
 	// FIXME...
 	if (fcm->prev) {
 		fcm->flag |= FMODIFIER_FLAG_DISABLED;
-		return;
+		return evaltime;
 	}
 	
 	/* calculate new evaltime due to cyclic interpolation */
@@ -1742,7 +1710,7 @@
 		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 @@
 		}
 	}
 	if ELEM(0, side, mode)
-		return;
+		return evaltime;
 		
 	/* find relative place within a cycle */
 	{
@@ -1778,7 +1746,7 @@
 		
 		/* 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 @@
 			/* 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,9 +1772,33 @@
 		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 = {
 	FMODIFIER_TYPE_CYCLES, /* type */
@@ -1819,6 +1811,7 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 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 @@
 		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);

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list