package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BitmapDataChannel; import flash.events.MouseEvent; import flash.filters.DisplacementMapFilter; import flash.filters.DisplacementMapFilterMode; import flash.geom.Point; [SWF(width=640, height=480, backgroundColor=0x202020)] /** * Demonstrates how DisplacementMapFilter can be used to displace an image in a spherizing/fisheye lens distortion. */ public class graphic_flex_image_effects_04_Flex_FisheyeLensTest extends graphic_flex_image_effects_04_Flex_AbstractImageLoader { private static const DIAMETER:uint = 200; private var _bitmapData:BitmapData; private var _lens:BitmapData; private var _lensBitmap:Bitmap; /** * Constructor. Passes path of image to load to super class. */ public function graphic_flex_image_effects_04_Flex_FisheyeLensTest() { super("graphic-flex-image-effects-04-assets-checkers.jpg"); } /** * Run after the image loads in super class. This creates the displacement map to be used on the loaded image, * uses this data in a new bitmap that is moved about the stage to show the map in its current position, and * sets up listeners for the mouse on the stage. */ override protected function runPostImageLoad():void { _bitmapData = _loadedBitmap.bitmapData.clone(); // creates the data that will be used as the displacement map _lens = createLens(DIAMETER); // bitmap just used to help visualize the distortion, but is not needed for the effect _lensBitmap = new Bitmap(_lens); // made invisible initially, but can be made visible by mouse click _lensBitmap.visible = false; // apply initial distortion applyLens(); addChild(_loadedBitmap); addChild(_lensBitmap); stage.addEventListener(MouseEvent.MOUSE_MOVE, onStageMouseMove); stage.addEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown); stage.addEventListener(MouseEvent.MOUSE_UP, onStageMouseUp); } /** * Creates a displacement map for the fisheye lens effect. * * @param diameter The diameter of the lens to create. * @param amount The amount of distortion the map should enable. * * @return The map needed for the displacement. */ private function createLens(diameter:uint, amount:Number=0.8):BitmapData { // by default, map is filled with medium gray, which results in no displacement var lens:BitmapData = new BitmapData(diameter, diameter, false, 0xFF808080); // values are the same, but kept separate just for clarity var center:Number = diameter/2; var radius:Number = center; // run through full height of map for (var y:uint=0; y < diameter; ++y) { // current y coordinate in relation to the center of the map var ycoord:int = y - center; // run through full width of map for (var x:uint = 0; x < diameter; ++x) { // current x coordinate in relation to the center of the map var xcoord:int = x - center; // the distance from the current coordinates to the map center var distance:Number = Math.sqrt(xcoord*xcoord + ycoord*ycoord); // only if we are within the radius of the lens do we need to recolor if (distance < radius) { // a number between 0 and 1 based on the distance from center and the amount of distortion var t:Number = Math.pow(Math.sin(Math.PI/2 * distance/radius), amount); // the amount of distortion on each axis determines the amount to recolor // the pixel at the current coordinate, using the blue channel for horizontal distortion // and the green channel for vertical distortion var dx:Number = xcoord * (t - 1)/diameter; var dy:Number = ycoord * (t - 1)/diameter; var blue:uint = 0x80 + dx * 0xFF; var green:uint = 0x80 + dy * 0xFF; lens.setPixel(x, y, green << 8 | blue); } } } return lens; } /** * Reapplies the displacement map on the image based on the current mouse position. */ private function applyLens():void { // the point of displacement is determined by the mouse position var displacementMapFilter:DisplacementMapFilter = new DisplacementMapFilter( _lens, new Point(stage.mouseX-DIAMETER/2, stage.mouseY-DIAMETER/2), BitmapDataChannel.BLUE, BitmapDataChannel.GREEN, DIAMETER, DIAMETER, DisplacementMapFilterMode.CLAMP ); // displacement is applied _loadedBitmap.bitmapData.applyFilter( _bitmapData, _bitmapData.rect, new Point(), displacementMapFilter ); } /** * Handler for when the mouse is moved about the stage. This moves the displacement map image * and reapplies the displacement. * * @param event Event dispatched by stage. */ private function onStageMouseMove(event:MouseEvent):void { _lensBitmap.x = stage.mouseX - DIAMETER/2; _lensBitmap.y = stage.mouseY - DIAMETER/2; applyLens(); event.updateAfterEvent(); } /** * Handler for when the mouse is pressed on the stage. This makes visible the displacement map. * * @param event Event dispatched by stage. */ private function onStageMouseDown(event:MouseEvent):void { _lensBitmap.visible = true; } /** * Handler for when the mouse is released on the stage. This removes visibility of the displacement map. * * @param event Event dispatched by stage. */ private function onStageMouseUp(event:MouseEvent):void { _lensBitmap.visible = false; } } }