// Original (java): http://www.hyuki.com/math/ // AS3 ported by flashrod package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.events.Event; [SWF(width="465", height="465", backgroundColor="0xFFFFFF", frameRate="30")] public class Tree extends Sprite { private static const LEVEL:Number = 12.0; private var t:Turtle; public function Tree() { var bd:BitmapData = new BitmapData(465, 465); addChild(new Bitmap(bd)); var queue:Array = []; t = new Turtle(new AnimatedCanvas(new BitmapCanvas(bd), queue)); t.setxy(465 * .5, 465 * .8); t.pendown(); drawtree(LEVEL); addEventListener(Event.ENTER_FRAME, function(ev:Event):void { for (var i:int = 0; i < 10; ++i) { if (queue.length > 0) { queue.shift()(); } } }); } private function drawtree(n:Number):void { if (n > 0) { var level:Number = (LEVEL - n) / LEVEL; var len:Number = n * 3.6; t.left(18); t.pendown(); t.setcolor(gray(level), 1-level); t.forward(len); drawtree(n - 1); t.penup(); t.back(len); t.right(18); t.right(18); t.pendown(); t.setcolor(gray(level), 1-level); t.forward(len); drawtree(n - 1); t.penup(); t.back(len); t.left(18); } } private static function gray(n:Number):uint { var a:int = n * 255; return (a << 16) + (a << 8) + a; } } } class Turtle { private var canvas:Canvas; private var down:Boolean = false; private var angle:Number = 0.0; private var posx:Number = 0.0; private var posy:Number = 0.0; private var color:uint = 0x000000; private var alpha:Number = 1.0; public function Turtle(canvas:Canvas) { this.canvas = canvas; } public function setcolor(color:uint, alpha:Number=1.0):void { this.color = color; this.alpha = alpha; } public function pendown():void { down = true; } public function penup():void { down = false; } public function setxy(x:Number, y:Number):void { if (down) { canvas.line(posx, posy, x, y, color, alpha); } this.posx = x; this.posy = y; } public function forward(length:Number):void { setxy(posx + length * Math.sin(angle), posy - length * Math.cos(angle)); } public function back(length:Number):void { forward(-length); } public function right(a:Number):void { angle += a * Math.PI / 180; } public function left(a:Number):void { right(-a); } } interface Canvas { function line(x0:int, y0:int, x1:int, y1:int, c:uint, a:Number):void; } class AnimatedCanvas implements Canvas { private var canvas:Canvas; private var queue:Array; public function AnimatedCanvas(canvas:Canvas, queue:Array) { this.canvas = canvas; this.queue = queue; } public function line(x0:int, y0:int, x1:int, y1:int, c:uint, a:Number):void { queue.push(function():void { canvas.line(x0, y0, x1, y1, c, a); }); } } import flash.display.BitmapData; class BitmapCanvas implements Canvas { private var bd:BitmapData; public function BitmapCanvas(bd:BitmapData) { this.bd = bd; } /** Bresenham's line algorithm * @param x0 x0 * @param x0 y0 * @param x1 x1 * @param y1 y1 * @param c color * @param a alpha value */ public function line(x0:int, y0:int, x1:int, y1:int, c:uint, a:Number):void { var steep:Boolean = Math.abs(y1 - y0) > Math.abs(x1 - x0); var t:int; if (steep) { t=x0; x0=y0; y0=t; t=x1; x1=y1; y1=t; } if (x0 > x1) { t=x0; x0=x1; x1=t; t=y0; y0=y1; y1=t; } var deltax:int = x1 - x0; var deltay:int = Math.abs(y1 - y0); var error:int = 0; var ystep:int = (y0 < y1) ? 1 : -1; var y:int = y0; for (var x:int = x0; x <= x1; ++x) { if (steep) { plot(y,x, c, a); } else { plot(x,y, c, a); } error += deltay; if (2*error >= deltax) { y += ystep; error -= deltax; } } } public function plot(x:int, y:int, c:uint, a:Number):void { bd.setPixel(x, y, blend(bd.getPixel(x, y), c, a)); } private static function blend(d:uint, s:uint, a:Number):uint { var rd:int = (d >> 16) & 0xFF; var gd:int = (d >> 8) & 0xFF; var bd:int = d & 0xFF; var rs:int = (s >> 16) & 0xFF; var gs:int = (s >> 8) & 0xFF; var bs:int = s & 0xFF; var e:Number = 1 - a; var r:int = rd * e + rs * a; var g:int = gd * e + gs * a; var b:int = bd * e + bs * a; return (r << 16) | (g << 8) | b; } } Tree