package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BitmapDataChannel; import flash.display.Sprite; import flash.filters.BlurFilter; import flash.filters.DisplacementMapFilter; import flash.filters.DisplacementMapFilterMode; import flash.events.Event; import flash.geom.Point; [SWF(width=550, height=400, backgroundColor=0x111911)] /** * This class demonstrates how you can construct simple 3D models by rotating * multiple planes and rendering these within a single display object container. */ public class graphic_flex_image_effects_06_Flex_Forest extends Sprite { private static const TOTAL_TREES:uint = 10; // how many trees private static const TREE_DISPERSAL:uint = 400; // how far out from center the trees can be placed private static const TREE_SIZE:uint = 100; // the average pixel width/height of a tree private static const PLANES_IN_TREE:uint = 4; // the number of planes that are rotated to form a tree private var _forest:Sprite; /** * Constructor. This kicks off the drawing of the forest, rotates this sprite * to create an overhead view, and sets up an ENTER_FRAME listener to handle the animation. */ public function graphic_flex_image_effects_06_Flex_Forest() { creategraphic_flex_image_effects_06_Flex_Forest(); rotationX = 15; addEventListener(Event.ENTER_FRAME, onSpriteEnterFrame); } /** * Creates the sprite that will hold the trees, centers it, then runs through * loop to create each tree and adds it to the sprite. */ private function creategraphic_flex_image_effects_06_Flex_Forest():void { _forest = new Sprite(); _forest.x = stage.stageWidth/2; _forest.y = stage.stageHeight/2; // creates bitmap that will be used for tree texture var treeImage:BitmapData = createTreeImage(); for (var i:uint = 0; i < TOTAL_TREES; i++) { _forest.addChild(createTree(treeImage)); } addChild(_forest); } /** * Generates bitmap image that will be used for tree texture. * * @return The BitmapData instance containing the generated tree texture. */ private function createTreeImage():BitmapData { var point:Point = new Point(); // create transparent bitmap data instance of the appropriate size var treeImage:BitmapData = new BitmapData(TREE_SIZE, TREE_SIZE, true, 0x00000000); // create two additional bitmap data instance of the same size var leaves:BitmapData = treeImage.clone(); var noise:BitmapData = treeImage.clone(); // fill leaves with solid dark green leaves.fillRect(leaves.rect, 0xFF005500); // create grayscale noise noise.perlinNoise(TREE_SIZE/10, TREE_SIZE/8, 2, 0, false, true); // copy noise's red channel into greeen leaves alpha, introducing transparency leaves.copyChannel( noise, noise.rect, point, BitmapDataChannel.RED, BitmapDataChannel.ALPHA ); // draw leaves (with alpha) into triangle shape var sprite:Sprite = new Sprite(); sprite.graphics.beginBitmapFill(leaves); sprite.graphics.lineTo(TREE_SIZE/2, 10); sprite.graphics.lineTo(TREE_SIZE-10, TREE_SIZE-10); sprite.graphics.lineTo(10, TREE_SIZE-10); sprite.graphics.lineTo(TREE_SIZE/2, 10); sprite.graphics.endFill(); // draw triangle shape into bitmap data treeImage.draw(sprite); // apply displacement and slight blur to tree image var displaceFilter:DisplacementMapFilter = new DisplacementMapFilter( noise, new Point(), BitmapDataChannel.RED, BitmapDataChannel.RED, 0, -TREE_SIZE/4 ); var blurFilter:BlurFilter = new BlurFilter(4, 4); treeImage.applyFilter(treeImage, treeImage.rect, point, displaceFilter); treeImage.applyFilter(treeImage, treeImage.rect, point, blurFilter); // get rid of data no longer needed noise.dispose(); leaves.dispose(); return treeImage; } /** * Creates sprite containing multiple rotated planes holding tree texture. * * @param treeImage The BitmapData to apply to each plane in the tree. * * @return The sprite created. */ private function createTree(treeImage:BitmapData):Sprite { var tree:Sprite = new Sprite(); // create and add each plane for (var i:uint = 0; i < PLANES_IN_TREE; i++) { tree.addChild(createTreePlane(treeImage, i)); } // apply some random vertical scaling tree.scaleY = 1+Math.random()*.8; // apply random positioning within dispersal area tree.x = Math.random()*TREE_DISPERSAL-TREE_DISPERSAL/2; tree.z = Math.random()*TREE_DISPERSAL-TREE_DISPERSAL/2; return tree; } /** * Create single plane that will be used within tree "model". * * @param treeImage The BitmapData to apply to the plane. * @param index The index of the plane within the fuill tree, used to determine rotation. * * @return The sprite created. */ private function createTreePlane(treeImage:BitmapData, index:uint):Sprite { var bitmap:Bitmap = new Bitmap(treeImage); // center bitmap on registration point bitmap.x = -TREE_SIZE/2; bitmap.y = -TREE_SIZE/2; // place bitmap within sprite so it may be rotated around registration poin var treePlane:Sprite = new Sprite(); treePlane.rotationY = index*(180/PLANES_IN_TREE); treePlane.addChild(bitmap); return treePlane; } /** * Handler for ENTER_FRAME event. This rotates the forest. * * @param event Event dispatched by this sprite. */ private function onSpriteEnterFrame(event:Event):void { _forest.rotationY += 1; } } }