package { import flash.events.Event; import flash.events.EventDispatcher; import flash.display.Shape; import flash.display.BitmapData; public class RenderGradient extends EventDispatcher { // ENTER_FRAME events dispatched by a composed DisplayObject // instance; one can be used for all RenderGradient instances private static var enterFrameDispatcher:Shape = new Shape(); // determines how many loop iterations are run before // waiting for the next ENTER_FRAME event private static const MAX_ITERATIONS:int = 500; private var bmp:BitmapData; // retained text to be processed private var topColor:uint; // color starting gradient private var bottomColor:uint; // color ending gradient private var savedX:int; // start index for each x loop private var savedY:int; // start index for each y loop /** * Constrctor for new RenderGradient instances. * @param text Text to apply a Caesar cipher to. * @param shift The number of characters to shift. */ public function RenderGradient(bmp:BitmapData, topColor:uint, bottomColor:uint) { this.bmp = bmp; this.topColor = topColor; this.bottomColor = bottomColor; } /** * Starts the ciphering process. An Event.COMPLETE event * will fire when its complete. The result is accessible * from the result property. */ public function run():void { // initialize values savedX = 0; savedY = 0; // set up ENTER_FRAME loop enterFrameDispatcher.addEventListener(Event.ENTER_FRAME, loopHandler, false, 0, true); // call the first iteration immediately loopHandler(null); } // ENTER_FRAME loop for asynchronous processing private function loopHandler(event:Event):void { // loop variable setup with bitmap validation var x:int; var y:int; try { // these references will fail if bitmap is disposed var xn:int = bmp.width; var yn:int = bmp.height; }catch(err:Error){ // validation failed, bitmap disposed // remove ENTER_FRAME event handler enterFrameDispatcher.removeEventListener(Event.ENTER_FRAME, loopHandler, false); // signal to listeners that processing is // was canceled dispatchEvent(new Event(Event.CANCEL)); } // count loop iterations to know when to exit var iterationCounter:int = 0; for (y=savedY; y= MAX_ITERATIONS){ savedX = x; savedY = y; return; } // process loop iteration: var xPercent:Number = x/xn; var yPercent:Number = y/yn; var finalColor:uint = 0; var channel:int; // red channel = xPercent * ((topColor >>> 16) & 0xFF); channel += yPercent * ((bottomColor >>> 16) & 0xFF); finalColor += Math.min(channel, 0xFF) << 16; // green channel = xPercent * ((topColor >>> 8) & 0xFF); channel += yPercent * ((bottomColor >>> 8) & 0xFF); finalColor += Math.min(channel, 0xFF) << 8; // blue channel = xPercent * (topColor & 0xFF); channel += yPercent * (bottomColor & 0xFF); finalColor += Math.min(channel, 0xFF); // draw pixel in referenced bitmap bmp.setPixel(x, y, finalColor); } // reset inner loop start index savedX = 0; } // loop has completed without exiting // process is complete // clean up references bmp = null; // remove ENTER_FRAME event handler enterFrameDispatcher.removeEventListener(Event.ENTER_FRAME, loopHandler, false); // signal to listeners that processing is complete // and the results value is available dispatchEvent(new Event(Event.COMPLETE)); } } }