package away3d.materials { import away3d.arcane; import away3d.core.utils.*; import flash.display.*; import flash.events.Event; import flash.geom.*; import flash.utils.getTimer; use namespace arcane; /** * Bitmap material that allows fast rendering of animations by caching bitmapdata objects for each frame. * Not suitable for use with long animations, where the initialisation time will be lengthy and the memory footprint large. * If interactive movieclip properties are required, please refer to MovieMaterial. */ public class AnimatedBitmapMaterial extends TransformBitmapMaterial implements ITriangleMaterial, IUVMaterial { private var _broadcaster:Sprite = new Sprite(); private var _playing:Boolean; private var _index:int; private var _cache:Array; private function update(event:Event = null):void { //increment _index if (_index < _cache.length - 1) _index++; else if (loop) _index = 0; _renderBitmap = _bitmap = _cache[_index]; _bitmapDirty = true; } /** * Indicates whether the animation will loop. */ public var loop:Boolean; /** * Indicates whether the animation will start playing on initialisation. * If false, only the first frame is displayed. */ public var autoplay:Boolean; /** * Creates a new AnimatedBitmapMaterial object. * * @param movie The movieclip to be bitmap cached for use in the material. * @param init [optional] An initialisation object for specifying default instance properties. */ public function AnimatedBitmapMaterial(movie:MovieClip, init:Object = null) { setMovie(movie); super(_cache[_index], init); loop = ini.getBoolean("loop", true); autoplay = ini.getBoolean("autoplay", true); _index = ini.getInt("_index", 0, {min:0, max:movie.totalFrames - 1}); //add event listener if (autoplay) play(); //trigger first frame if (loop || autoplay) update(); else _renderBitmap = _bitmap = _cache[_index]; } /** * Resumes playback of the animation */ public function play():void { if (!_playing) { _playing = true; _broadcaster.addEventListener(Event.ENTER_FRAME, update); } } /** * Halts playback of the animation */ public function stop():void { if (_playing) { _playing = false; _broadcaster.removeEventListener(Event.ENTER_FRAME, update); } } /** * Resets the movieclip used by the material. * * @param movie The movieclip to be bitmap cached for use in the material. */ public function setMovie(movie:MovieClip):void { _cache = new Array(); //determine boundaries of this movie var i:int; var rect:Rectangle; var minX:Number = 100000; var minY:Number = 100000; var maxX:Number = -100000; var maxY:Number = -100000; i = movie.totalFrames; while (i--) { movie.gotoAndStop(i); rect = movie.getBounds(movie); if (minX > rect.left) minX = rect.left; if (minY > rect.top) minY = rect.top; if (maxX < rect.right) maxX = rect.right; if (maxY < rect.bottom) maxY = rect.bottom; } //draw the cached bitmaps var W:int = maxX - minX; var H:int = maxY - minY; var mat:Matrix = new Matrix(1, 0, 0, 1, -minX, -minY); var tmp_bmd:BitmapData; var timer:int = getTimer(); for(i=1; i 2000) throw new Error("AnimatedBitmapMaterial contains too many frames. MovieMaterial should be used instead."); } } /** * Resets the cached bitmapData objects making up the animation with a pre-defined array. */ public function setFrames(sources:Array):void { var i:int; if(_cache.length>0){ for(i = 0; i<_cache.length;++i){ _cache[i].dispose(); } } _cache = []; if (_index > sources.length - 1) _index = sources.length - 1; for(i = 0; i_cache.length - 1)? _cache.length - 1 : f; _renderBitmap = _bitmap = _cache[_index]; } /** * returns the frame index of the animation. */ public function get index():int { return _index; } /** * Manually clears all frames of the animation. * a new series of bitmapdatas will be required using the setFrames handler. */ public function clear():void { stop(); if(_cache.length>0){ for(var i:int = 0; i<_cache.length;++i){ _cache[i].dispose(); } } _cache = []; } } }