package flare.animate.interpolate {
import flare.util.Property;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
/**
* Base class for value interpolators. This class also provides factory
* methods for creating concrete interpolator instances -- see the
* create
method for details about interpolator creation.
*/
public class Interpolator
{
/** The target object whose property is being interpolated. */
protected var _target:Object;
/** The property to interpolate. */
protected var _prop:Property;
/**
* Base constructor for Interpolator instances.
* @param target the object whose property is being interpolated
* @param property the property to interpolate
* @param value the target value of the interpolation
*/
public function Interpolator(target:Object, property:String,
start:Object, end:Object)
{
reset(target, property, start, end);
}
/**
* Re-initializes an exising interpolator instance.
* @param target the object whose property is being interpolated
* @param property the property to interpolate
* @param value the target value of the interpolation
*/
public function reset(target:Object, property:String,
start:Object, end:Object):void
{
_target = target;
_prop = Property.$(property);
init(start, end);
}
/**
* Performs initialization of an interpolator, typically by
* initializing the start and ending values. Subclasses should
* override this method for custom initialization.
* @param value the target value of the interpolation
*/
protected function init(start:Object, end:Object) : void
{
// for subclasses to override
}
/**
* Calculate and set an interpolated property value. Subclasses should
* override this method to implement custom interpolation routines.
* @param f the interpolation fraction (typically between 0 and 1)
*/
public function interpolate(f:Number) : void
{
throw new Error("This is an abstract method");
}
// -- Interpolator Factory --------------------------------------------
private static var _maxPoolSize:int = 10000;
private static var _pools:Object = [];
private static var _lookup:Object = buildLookupTable();
private static var _rules:Array = buildRules();
private static function buildLookupTable() : Object
{
// add variables to ensure classes are included by compiler
var ni:NumberInterpolator;
var di:DateInterpolator;
var pi:PointInterpolator;
var ri:RectangleInterpolator;
var mi:MatrixInterpolator;
var ai:ArrayInterpolator;
var vi:VectorInterpolator;
var ci:ColorInterpolator;
var oi:ObjectInterpolator;
// build the value->interpolator lookup table
var lut:Object = new Object();
lut["Number"] = "flare.animate.interpolate::NumberInterpolator";
lut["int"] = "flare.animate.interpolate::NumberInterpolator";
lut["Date"] = "flare.animate.interpolate::DateInterpolator";
lut["Array"] = "flare.animate.interpolate::ArrayInterpolator";
lut["__AS3__.vec::Vector.
The interpolator factory can be extended either by adding new * interpolation rule functions or by adding new mappings from * interpolation value types to custom interpolator classes.
*/ public static function create(target:Object, property:String, start:Object, end:Object): Interpolator { // first, check the rules list for an interpolator var name:String = null; for (var i:uint=0; name==null && i<_rules.length; ++i) { name = _rules[i](target, property, start, end); } // if no matching rule, use the type lookup table if (name == null) { name = _lookup[getQualifiedClassName(end)]; } // if that fails, use ObjectInterpolator as default if (name == null) { name = "flare.animate.interpolate::ObjectInterpolator"; } // now create the interpolator, recycling from the pool if possible var pool:Array = _pools[name] as Array; if (pool == null || pool.length == 0) { // nothing in the pool, create a new instance var Ref:Class = getDefinitionByName(name) as Class; return new Ref(target, property, start, end) as Interpolator; } else { // reuse an interpolator from the object pool var interp:Interpolator = pool.pop() as Interpolator; interp.reset(target, property, start, end); return interp; } } /** * Reclaims an interpolator for later recycling. The reclaimed * interpolator should not be in active use by any other classes. * @param interp the Interpolator to reclaim */ public static function reclaim(interp:Interpolator):void { var type:String = getQualifiedClassName(interp); var pool:Array = _pools[type] as Array; if (pool == null) { _pools[type] = [interp]; } else if (pool.length < _maxPoolSize) { pool.push(interp); } } } // end of class Interpolator }