- package
- {
- import flash.display.*;
- import flash.events.*;
- import flash.text.*;
- import flash.ui.Keyboard;
- import flash.utils.getTimer;
-
- [SWF(width="465", height="465",
- backgroundColor="0x000000", frameRate="30")]
- public class Donuts02 extends Sprite
- {
- private var _donuts:Donuts;
- private var _matrix:Matrix3D;
- private var _render:Render;
-
- private var _textField:TextField;
-
- private var _rx:Number = 0;
- private var _ry:Number = 0;
- private var _rz:Number = 0;
-
- private var _isAutoPlay:Boolean = false;
-
- private const STAGE_WIDTH:Number = stage.stageWidth;
- private const STAGE_HEIGHT:Number = stage.stageHeight;
-
- public function Donuts02()
- {
- configure();
-
- var pi:Number = Math.PI;
- var start:int;
- var i:int;
-
- _donuts = new Donuts(16, 0.7);
- _matrix = new Matrix3D();
- _render = new Render(graphics, _matrix);
-
- addTextField();
-
- mainLoop(null);
-
- stage.addEventListener(MouseEvent.CLICK, changePlayMode);
-
- _textField.text =
- "Partitions : " + _donuts.numPartitions + "\n" +
- "Vertices : " + _donuts.vertices.length + "\n" +
- "Stretch : " + _donuts.stretch;
- }
-
- private function configure():void
- {
- stage.align = StageAlign.TOP_LEFT;
- stage.scaleMode = StageScaleMode.NO_SCALE;
- stage.showDefaultContextMenu = false;
- }
-
- private function addTextField():void
- {
- _textField = new TextField();
- _textField.defaultTextFormat = new TextFormat(
- null, null, 0xFFFFFF, null, null, null, null, null, TextFormatAlign.RIGHT);
- _textField.autoSize = TextFieldAutoSize.RIGHT;
- _textField.background = true;
- _textField.backgroundColor = 0x000000;
- _textField.selectable = false;
- _textField.x = STAGE_WIDTH - _textField.width;
-
- addChild(_textField);
-
- var announce:TextField = new TextField();
- announce.defaultTextFormat = new TextFormat(
- null, null, 0xFFFFFF, null, null, null, null, null, TextFormatAlign.LEFT);
- announce.autoSize = TextFieldAutoSize.LEFT;
- announce.background = true;
- announce.backgroundColor = 0x000000;
- announce.selectable = false;
- announce.text =
- "\"DOWN\" : Partitions -\n" +
- "\"UP\" : Partitions +\n" +
- "\"LEFT\" : Stretch -\n" +
- "\"RIGHT\" : Stretch +\n" +
- "\"Z\" : Polygon on/off\n" +
- "\"X\" : Wireframe on/off";
- announce.y = STAGE_HEIGHT - announce.height;
-
- addChild(announce);
- }
-
- private function mainLoop(event:Event):void
- {
- _matrix.identity();
- _matrix.scale(50, 50, 50);
- _matrix.rotateX(_rx);
- _matrix.rotateY(_ry);
- _matrix.rotateZ(_rz);
- _matrix.translate(STAGE_WIDTH / 2, STAGE_HEIGHT / 2, 0);
-
- graphics.clear();
-
- _render.drawIndexedPrimitive(
- Render.PRIMITIVE_POLYGON, _donuts.vertices, _donuts.indices);
-
- _rx += 0.04;
- _ry += 0.08;
- _rz += 0.02;
- }
-
- private function changePlayMode(event:MouseEvent):void
- {
- if (_isAutoPlay)
- {
- removeEventListener(Event.ENTER_FRAME, mainLoop);
- stage.removeEventListener(KeyboardEvent.KEY_DOWN, changeDonuts);
- }
- else
- {
- addEventListener(Event.ENTER_FRAME, mainLoop);
- stage.addEventListener(KeyboardEvent.KEY_DOWN, changeDonuts);
- }
-
- _isAutoPlay = !_isAutoPlay;
- }
-
- private function changeDonuts(event:KeyboardEvent):void
- {
- var numPartitions:int = _donuts.numPartitions;
-
- switch (event.keyCode)
- {
- case Keyboard.UP:
- if (numPartitions >= 0)
- {
- _donuts.numPartitions += 1;
- }
- break;
- case Keyboard.DOWN:
- if (numPartitions > 0)
- {
- _donuts.numPartitions -= 1;
- }
- break;
- case Keyboard.LEFT:
- _donuts.stretch -= 0.02;
- break;
- case Keyboard.RIGHT:
- _donuts.stretch += 0.02;
- break;
- case 88:
-
- _render.wireframeEnabled = !_render.wireframeEnabled;
- break;
- case 90:
-
- _render.polygonEnabled = !_render.polygonEnabled;
- break;
- }
-
- _textField.text =
- "Partitions : " + _donuts.numPartitions + "\n" +
- "Vertices : " + _donuts.vertices.length + "\n" +
- "Stretch : " + _donuts.stretch.toString().substr(0, 4);
- }
- }
- }
- import flash.display.Graphics;
- class Render
- {
- public static const PRIMITIVE_POLYGON:int = 1;
-
- private var _graphics:Graphics;
- private var _matrix:Matrix3D;
- private var _mode:int;
-
- private var _polygonEnabled:Boolean = true;
- private var _wireframeEnabled:Boolean = false;
-
-
- private var _light:Vector3D = new Vector3D( 0.0, 0.0, -1.0);
-
-
- private var _ambient:Vector3D = new Vector3D( 0.2, 0.2, 0.2);
-
- private var _diffuse:Vector3D = new Vector3D( 0.8, 0.8, 0.8);
-
-
- public function Render(
- graphics:Graphics = null, matrix:Matrix3D = null, mode:int = 1):void
- {
- _graphics = graphics;
- _matrix = matrix;
- _mode = mode;
- }
-
- public function drawIndexedPrimitive(type:int, vertices:Array, indices:Array):void
- {
- var i:int;
- var l:int;
-
- var tv:Array = [];
-
-
- for (i = 0, l = vertices.length; i < l; ++i)
- {
- tv.push(_matrix.transform(vertices[i]));
- }
-
-
- switch (type)
- {
- case PRIMITIVE_POLYGON:
-
- var triangles:Array = [];
-
- for (i = 0, l = indices.length; i < l; i += 3)
- {
- triangles.push(new Triangle3D(
- tv[indices[i ]],
- tv[indices[i + 1]],
- tv[indices[i + 2]]
- ));
- }
-
-
- triangles.sortOn("depth", Array.DESCENDING | Array.NUMERIC);
-
- for each (var triangle:Triangle3D in triangles)
- {
- drawPolygon(triangle);
- }
-
- break;
- }
- }
-
- private function drawPolygon(triangle:Triangle3D):void
- {
- if (polygonEnabled)
- {
-
- var n:Vector3D = triangle.normal();
-
-
- var w:Number = n.dot(_light);
-
-
-
- if (w < 0)
- {
- return;
- }
-
- var r:int = (_ambient.x + w * _diffuse.x) * 255;
- var g:int = (_ambient.y + w * _diffuse.y) * 255;
- var b:int = (_ambient.z + w * _diffuse.z) * 255;
-
- r = (r < 0) ? 0 : (r > 255) ? 255 : r;
- g = (g < 0) ? 0 : (g > 255) ? 255 : g;
- b = (b < 0) ? 0 : (b > 255) ? 255 : b;
-
- _graphics.beginFill(r << 16 | g << 8 | b);
- }
-
- if (wireframeEnabled)
- {
- _graphics.lineStyle(0, 0xFF0000);
- }
-
- _graphics.moveTo(triangle.v1.x, triangle.v1.y);
- _graphics.lineTo(triangle.v2.x, triangle.v2.y);
- _graphics.lineTo(triangle.v3.x, triangle.v3.y);
- _graphics.lineTo(triangle.v1.x, triangle.v1.y);
-
- _graphics.endFill();
- }
-
- public function get graphics():Graphics
- {
- return _graphics;
- }
-
- public function set graphics(value:Graphics):void
- {
- _graphics = value;
- }
-
- public function get matrix():Matrix3D
- {
- return _matrix;
- }
-
- public function set matrix(value:Matrix3D):void
- {
- _matrix = value;
- }
-
- public function get polygonEnabled():Boolean
- {
- return _polygonEnabled;
- }
-
- public function set polygonEnabled(value:Boolean):void
- {
- _polygonEnabled = value;
- }
-
- public function get wireframeEnabled():Boolean
- {
- return _wireframeEnabled;
- }
-
- public function set wireframeEnabled(value:Boolean):void
- {
- _wireframeEnabled = value;
- }
- }
- class Donuts
- {
- private var _vertices:Array;
- private var _indices:Array;
- private var _numPartitions:int;
- private var _stretch:Number;
-
-
- public function Donuts(numPartitions:int = 16, stretch:Number = 1):void
- {
- _numPartitions = numPartitions;
- _stretch = stretch;
-
- setup(numPartitions, stretch);
- }
-
-
- private function setup(numPartitions:int, stretch:Number):void
- {
- var n:int = numPartitions;
-
- var i:int;
- var j:int;
-
- var a:Number = 0;
- var c:Number = 0;
- var addc:Number = Math.PI * 2 / n;
-
- var s:Number;
- var z:Number;
- var x:Number;
- var y:Number;
-
- _vertices = [];
-
- for (i = 0; i < n; ++i)
- {
- s = Math.sin(c) + 2;
- z = Math.cos(c);
-
- for (j = 0; j < n; ++j)
- {
- x = Math.cos(a);
- y = Math.sin(a);
-
- _vertices.push(new Vector3D(
- x * s * stretch,
- y * s * stretch,
- z * stretch
- ));
-
- a += Math.PI / n * 2;
- }
-
- c += addc;
- }
-
- var m:int = n * n;
- var off:Number;
-
- _indices = [];
-
- for (i = 0; i < n; ++i)
- {
- off = i * n;
-
- for (j = 0; j < n; ++j)
- {
- _indices.push((off + n) % m + (j + 1) % n);
- _indices.push( off + (j + 1) % n);
- _indices.push( off + j );
- _indices.push((off + n) % m + j );
- _indices.push((off + n) % m + (j + 1) % n);
- _indices.push( off + j );
- }
- }
- }
-
- public function get vertices():Array
- {
- return _vertices.concat();
- }
-
- public function get indices():Array
- {
- return _indices.concat();
- }
-
- public function get numPartitions():int
- {
- return _numPartitions;
- }
-
- public function set numPartitions(value:int):void
- {
- _numPartitions = value;
-
- setup(value, stretch);
- }
-
- public function get stretch():Number
- {
- return _stretch;
- }
-
- public function set stretch(value:Number):void
- {
- _stretch = value;
-
- setup(numPartitions, value);
- }
- }
- class Triangle3D
- {
- private var _v1:Vector3D;
- private var _v2:Vector3D;
- private var _v3:Vector3D;
-
-
- public function Triangle3D(v1:Vector3D, v2:Vector3D, v3:Vector3D):void
- {
- _v1 = v1;
- _v2 = v2;
- _v3 = v3;
- }
-
- public function get v1():Vector3D
- {
- return _v1;
- }
-
- public function set v1(value:Vector3D):void
- {
- _v1 = value;
- }
-
- public function get v2():Vector3D
- {
- return _v2;
- }
-
- public function set v2(value:Vector3D):void
- {
- _v2 = value;
- }
-
- public function get v3():Vector3D
- {
- return _v3;
- }
-
- public function set v3(value:Vector3D):void
- {
- _v3 = value;
- }
-
-
- public function get depth():Number
- {
- var min:Number = (v1.z < v2.z) ? v1.z : v2.z;
- return (min < v3.z) ? min : v3.z;
- }
-
-
- public function normal():Vector3D
- {
- var n:Vector3D = new Vector3D();
- n.cross(v1.distance(v2), v1.distance(v3));
- n.normalize();
-
- return n;
- }
-
-
- public function toString():String
- {
- var temp:String = "Triangle3D {\n" +
- "\tv1 : " + v1 + "\n" +
- "\tv2 : " + v2 + "\n" +
- "\tv3 : " + v3 + "\n}";
-
- return temp;
- }
- }
- class Matrix3D
- {
- private var _matrix:Array;
-
-
- public function Matrix3D():void
- {
- identity();
- }
-
- public function identity():void
- {
- _matrix = [
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1
- ];
- }
-
- public function scale(sx:Number, sy:Number, sz:Number)
- {
- _matrix = _multiply(_matrix, [
- sx, 0, 0, 0,
- 0, sy, 0, 0,
- 0, 0, sz, 0,
- 0, 0, 0, 1
- ]);
- }
-
- public function translate(dx:Number, dy:Number, dz:Number)
- {
- _matrix = _multiply(_matrix, [
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- dx, dy, dz, 1
- ]);
- }
-
- public function rotateX(angleRadians:Number)
- {
- var sin = Math.sin(angleRadians);
- var cos = Math.cos(angleRadians);
-
- _matrix = _multiply(_matrix, [
- 1, 0, 0, 0,
- 0, cos, sin, 0,
- 0, -sin, cos, 0,
- 0, 0, 0, 1
- ]);
- }
-
- public function rotateY(angleRadians:Number)
- {
- var sin = Math.sin(angleRadians);
- var cos = Math.cos(angleRadians);
-
- _matrix = _multiply(_matrix, [
- cos, 0, -sin, 0,
- 0, 1, 0, 0,
- sin, 0, cos, 0,
- 0, 0, 0, 1
- ]);
- }
-
- public function rotateZ(angleRadians:Number)
- {
- var sin = Math.sin(angleRadians);
- var cos = Math.cos(angleRadians);
-
- _matrix = _multiply(_matrix, [
- cos, sin, 0, 0,
- -sin, cos, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1
- ]);
- }
-
-
- public function transform(v:Vector3D):Vector3D
- {
- var temp:Vector3D = new Vector3D();
- var m:Array = _matrix;
-
- temp.x = m[0] * v.x + m[4] * v.y + m[ 8] * v.z + m[12];
- temp.y = m[1] * v.x + m[5] * v.y + m[ 9] * v.z + m[13];
- temp.z = m[2] * v.x + m[6] * v.y + m[10] * v.z + m[14];
-
- return temp;
- }
-
-
- public function multiply(m:Matrix3D):void
- {
- _matrix = _multiply(m.toArray(), _matrix);
- }
-
-
- private function _multiply(m1:Array, m2:Array):Array
- {
- var temp:Array = [];
- var i:int = 0;
-
- for (var y:int = 0; y < 4; ++y)
- {
- for (var x:int = 0; x < 4; ++x)
- {
- temp[x + i] =
- m1[i ] * m2[x ] +
- m1[i + 1] * m2[x + 4] +
- m1[i + 2] * m2[x + 8] +
- m1[i + 3] * m2[x + 12];
- }
- i += 4;
- }
-
- return temp;
- }
-
-
- public function toArray():Array
- {
- return _matrix.concat();
- }
-
-
- public function toString():String
- {
- var temp:String = "Matrix3D [\n";
-
- for (var i:int = 0, l:int = _matrix.length; i < l; ++i)
- {
- if (i % 4 == 0)
- {
- if (i != 0)
- {
- temp += "\n";
- }
- temp += "\t";
- }
- if (i != l - 1)
- {
- temp += _matrix[i] + ", ";
- }
- else
- {
- temp += _matrix[i] + "\n]";
- }
- }
-
- return temp;
- }
- }
- class Vector3D
- {
- private var _x:Number;
- private var _y:Number;
- private var _z:Number;
-
-
- public function Vector3D(x:Number = 0, y:Number = 0, z:Number = 0):void
- {
- _x = x;
- _y = y;
- _z = z;
- }
-
- public function get x():Number
- {
- return _x;
- }
-
- public function set x(value:Number):void
- {
- _x = value;
- }
-
- public function get y():Number
- {
- return _y;
- }
-
- public function set y(value:Number):void
- {
- _y = value;
- }
-
- public function get z():Number
- {
- return _z;
- }
-
- public function set z(value:Number):void
- {
- _z = value;
- }
-
-
- public function normalize():void
- {
- var l:Number = 1 / Math.sqrt(x * x + y * y + z * z);
-
- x *= l;
- y *= l;
- z *= l;
- }
-
-
- public function cross(v1:Vector3D, v2:Vector3D):void
- {
- x = v1.y * v2.z - v1.z * v2.y;
- y = v1.z * v2.x - v1.x * v2.z;
- z = v1.x * v2.y - v1.y * v2.x;
- }
-
-
- public function dot(v:Vector3D):Number
- {
- return x * v.x + y * v.y + z * v.z;
- }
-
-
- public static function dot(v1:Vector3D, v2:Vector3D):Number
- {
- return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
- }
-
-
- public function invert():void
- {
- x *= -1;
- y *= -1;
- z *= -1;
- }
-
-
- public function distance(v:Vector3D):Vector3D
- {
- return new Vector3D(x - v.x, y - v.y, z - v.z);
- }
-
-
- public function clone():Vector3D
- {
- return new Vector3D(x, y, z);
- }
-
-
- public function toString():String
- {
- return "Vector3D {x:" + x + ", y:" + y + ", z:" + z + "}";
- }
- }