//@ alien(s) demo package { import aether.effects.shaders.ShaderEffect; import aether.utils.ImageUtil; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BitmapDataChannel; import flash.display.Sprite; import flash.events.Event; import flash.filters.DisplacementMapFilter; import flash.filters.DisplacementMapFilterMode; import flash.geom.ColorTransform; import flash.geom.Matrix; import flash.geom.Point; // [SWF(width=490, height=370, backgroundColor=0x000000)] //@ shader effect(s) /** * Demonstrates how a shader effect can be applied to a video, updating each video frame. * This example loads in a video in which a color can be isolated using the IsolateColorEffect, * then generates an effect on just the isolated pixels. */ //@ class public class graphic_flex_image_effects_10_Flex_Alien extends Sprite { // controls the amount of movement visible in the flames that are generated private static const FLICKER_RATE:Number = 10; private var _flame:BitmapData; private var _perlinNoise:BitmapData; private var _perlinOffsets:Array; private var _perlinSeed:int; private var _video:graphic_flex_image_effects_10_Flex_VideoLoader; private var _filteredScreen:Bitmap; private var _shaderEffect:graphic_flex_image_effects_10_Flex_IsolateColorEffect; //@ constructor /** * Constructor. This initiates load of external shader file. */ public function graphic_flex_image_effects_10_Flex_Alien() { ShaderEffect.shaderFilePath = "graphic-flex-image-effects-10-assets-"; _shaderEffect = new graphic_flex_image_effects_10_Flex_IsolateColorEffect(0x00FF00, 5, 50, true); _shaderEffect.addEventListener(Event.COMPLETE, onShaderReady); } //@ shader loaded / handler /** * Handler for when the shader file has loaded. This adds the video loader and sets up the * properties used for the flame effect. * * @param event Event dispatched by ShaderEffect. */ // private function onShaderReady(event:Event):void { _shaderEffect.removeEventListener(Event.COMPLETE, onShaderReady); addVideo(); makeFlame(); makeNoise(); _filteredScreen = new Bitmap(); addChild(_filteredScreen); } //@ video update(s) / handler /** * Handler for when the video frame updates. This draws the current video frame into the * bitmap data and applies an image effect. * * @param event Event dispatched by VideoLoader. */ private function onVideoRender(event:Event):void { var bitmapData:BitmapData = new BitmapData(_video.width, _video.height); // draws video frame into bitmap data, making sure it is at proper scale var matrix:Matrix = new Matrix(); matrix.scale(_video.scaleX, _video.scaleY); bitmapData.draw(_video, matrix); // isolates color in copied data _shaderEffect.apply(bitmapData); _filteredScreen.bitmapData = bitmapData; // updates flame image drawFlame(); } //@ video loader /** * Instantiates a video loader to load video and sets up listener for progress. */ private function addVideo():void { _video = new graphic_flex_image_effects_10_Flex_VideoLoader(490, 370, "graphic-flex-image-effects-10-assets-alien.flv"); addChild(_video); _video.addEventListener(Event.RENDER, onVideoRender); } //@ bitmap to draw /** * Creates the bitmap data that will be used to draw the flames. */ private function makeFlame():void { // flame image is same size as stage, fully transparent _flame = new BitmapData( stage.stageWidth, stage.stageHeight, true, 0x00000000 ); addChild(new Bitmap(_flame)); } //@ perlin noise generator /** * Initializes Perlin noise properties that will be used in flame animation. */ private function makeNoise():void { // noise bitmap data is same size as flame bitmap data _perlinNoise = _flame.clone(); _perlinSeed = int(new Date()); // one octave requires one point _perlinOffsets = [new Point()]; } //@ apply perlin noise /** * Applies the Perlin noise to the bitmap data, offsetting the octave displacement * by the FLICKER_RATE each time this method is called. */ private function applyNoise():void { _perlinNoise.perlinNoise( 20, 20, 1, _perlinSeed, false, true, BitmapDataChannel.RED, true, _perlinOffsets ); // altering offset contributes to upward animation of flames (_perlinOffsets[0] as Point).y += FLICKER_RATE; } //@ draw flame(s0 /** * Updates the flame bitmap data each frame, creating the animation. */ private function drawFlame():void { // move the flame image up slightly, creating upward movement of flames _flame.scroll(0, -3); // draw the current filtered image into flame at a reduced alpha _flame.draw( _filteredScreen, null, new ColorTransform(1, 1, 1, .1) ); // // apply new Perlin noise with altered offset applyNoise(); // displacement flame image with updates Perlin noise ImageUtil.applyFilter( _flame, new DisplacementMapFilter( _perlinNoise, new Point(), BitmapDataChannel.RED, BitmapDataChannel.RED, 2, 8, DisplacementMapFilterMode.CLAMP ) ); } } }