notice: Flash editor updated! Join the development! Thanks to MiniBuilder


forked from : keim_at_Si's Depth buffer test [diff(394)]

embed

FORKED
  1. // forked from keim_at_Si's Screen Space Ambient Occlusion
  2. // forked from keim_at_Si's Depth buffer test
  3. // forked from keim_at_Si's Regular Solid Structures
  4. // forked from keim_at_Si's Code based Structure Synth
  5. // Code based Structure Synth
  6. //  Structure Synth; http://structuresynth.sourceforge.net/
  7. //------------------------------------------------------------
  8. package {
  9.     import flash.display.*;
  10.     import flash.events.*;
  11.     import flash.geom.*;
  12.     import flash.utils.*;
  13.     import flash.filters.*;
  14.     import flash.text.*;
  15.     [SWF(width='465', height='465', backgroundColor='#000000', frameRate='30')]
  16.     public class main extends Sprite {
  17.         private const WIDTH:int = 450;
  18.         // 3D renders
  19.         private var _materials:Vector.<Material> = new Vector.<Material>();
  20.         private var _light:Light = new Light(1,0.5,0.25);
  21.         private var _screen:BitmapData = new BitmapData(WIDTH, WIDTH, false0);
  22.         private var _matbuf:Matrix = new Matrix(1001225225);
  23.         private var gl:Render3D = new Render3D(300,1);
  24.         private var ss:StructureSynth = new StructureSynth();
  25.         private var tf:TextField = new TextField();
  26.         // objects
  27.         private var camera:Vector3D;
  28.         private var struct:Vector.<ProjectionMesh> = new Vector.<ProjectionMesh>(5true);
  29.         private var _depth:BitmapData;
  30.         private var _ssao :BitmapData;
  31.         private var _mask :BitmapData;
  32.         
  33.         // motions
  34.         private var clicked:Boolean = false;
  35.         private var frame:int = 0;
  36.         
  37.         // entry point
  38.         function main() {
  39.             stage.quality = "low";
  40.             Wonderfl.capture_delay(3);
  41.             
  42.             camera = new Vector3D(00, -50);
  43.             _depth = new BitmapData(WIDTH, WIDTH, false0);
  44.             _ssao  = new BitmapData(WIDTH, WIDTH, false0);
  45.             _mask  = new BitmapData(WIDTH, WIDTH, false0);
  46.             
  47.             _materials.push((new Material()).setColor(0xff8080, 64192840),
  48.                             (new Material()).setColor(0xd0d080, 64192840),
  49.                             (new Material()).setColor(0x80ff80, 64192840),
  50.                             (new Material()).setColor(0x80c0c0, 64192840),
  51.                             (new Material()).setColor(0x8080ff, 64192840));
  52.             
  53.             tf.autoSize = "left";
  54.             tf.htmlText = "<font face='_typewriter'>Click to switch on/off ambient occlusion.</font>";
  55.             addChild(gl).visible = false;
  56.             with(addChild(new Bitmap(_screen))) { x = y = 7; }
  57.             with(addChild(tf)) { x = y = 7; }
  58.             addEventListener("enterFrame", _onEnterFrame);
  59.             stage.addEventListener("click", _onClick);
  60.             
  61.             // register meshes
  62.             ss.primitive("tetra",  SolidFactory.tetrahedron (new Mesh(), 10));  // 4vertices/4triangles
  63.             ss.primitive("box",    SolidFactory.hexahedron  (new Mesh(), 11));  // 8vertices/12triangles
  64.             ss.primitive("octa",   SolidFactory.octahedron  (new Mesh(), 12));  // 6vertices/8triangles
  65.             ss.primitive("dodeca", SolidFactory.dodecahedron(new Mesh(), 13));  // 12vertices/36triangles
  66.             ss.primitive("icosa",  SolidFactory.icosahedron (new Mesh(), 14));  // 20vertices/20triangles
  67.             
  68.             // struct[0]
  69.             ss.root("md6""{s4}{x-4y-4z-4}s4rx");
  70.             ss.rule("s4rx""""{s1.5}icosa{z2x2}s4rz{y2z2}s4ry{x2y2}s4rx");
  71.             ss.rule("s4ry""""{s1.5}icosa{z2x2}s4rz{y2z2}s4ry");
  72.             ss.rule("s4rz""""{s1.5}icosa{z2x2}s4rz");
  73.             struct[0] = new ProjectionMesh(ss.exec(new Mesh(_materials)).updateFaces());
  74.         }
  75.         private function _onEnterFrame(e:Event) : void {
  76.             frame++;
  77.             
  78.             // projection
  79.             _light.transformBy(gl.id().tv(camera).rx((400-mouseY)*0.25).ry((232-mouseX)*0.75).matrix);
  80.             gl.push().rx(frame).project(struct[0]).pop();
  81.             struct[0].nearZ = -10;
  82.             struct[0].farZ = -80;
  83.             // calculate screen space mbient occlusion
  84.             _depth.fillRect(_depth.rect, 0);
  85.             _depth.draw(gl.renderDepth(struct[0]), _matbuf);
  86.             _ssao.applyFilter(_depth, _depth.rect, _depth.rect.topLeft, blur);
  87.             _ssao.draw(_depth, nullnull"subtract");
  88.             _ssao.threshold(_depth, _depth.rect, _depth.rect.topLeft, "=="00255);
  89.             
  90.             // draw
  91.             _screen.fillRect(_screen.rect, 0xffffff);
  92.             _screen.draw(gl.renderSolid(struct[0], _light), _matbuf);
  93.             if (!clicked) _screen.draw(_ssao, null, colt, "multiply");
  94.         }
  95.         private var blur:BlurFilter = new BlurFilter(6464);
  96.         private var colt:ColorTransform = new ColorTransform(-8, -8, -812552552550);
  97.         
  98.         private function _onClick(e:Event) : void { clicked = !clicked; }
  99.     }
  100. }
  101. import flash.display.*;
  102. import flash.geom.*;
  103. // Solid Factory
  104. //----------------------------------------------------------------------------------------------------
  105. class SolidFactory {
  106.     // regular solids
  107.     //--------------------------------------------------
  108.     static public function tetrahedron(mesh:Mesh, size:Number, mat:int=0) : Mesh {
  109.         mesh.vertices.push(size,size,size, size,-size,-size, -size,size,-size, -size,-size,size);
  110.         mesh.qface(0,2,1,3,mat).qface(1,3,0,2,mat);
  111.         return mesh.updateFaces(true);
  112.     }
  113.     
  114.     static public function hexahedron(mesh:Mesh, size:Number, mat:int=0, div:Boolean=true) : Mesh {
  115.         for (var i:int=0; i<8; i++) mesh.vertices.push((i&1)?size:-size, ((i>>1)&1)?size:-size, (i>>2)?size:-size);
  116.         mesh.qface(0,1,2,3,mat,div).qface(1,0,5,4,mat,div).qface(0,2,4,6,mat,div);
  117.         mesh.qface(2,3,6,7,mat,div).qface(3,1,7,5,mat,div).qface(5,4,7,6,mat,div);
  118.         return mesh.updateFaces(true,179);
  119.     }
  120.     
  121.     static public function octahedron(mesh:Mesh, size:Number, mat:int=0) : Mesh {
  122.         mesh.vertices.push(0,0,-size, -size,0,00,-size,0, size,0,00,size,00,0,size);
  123.         mesh.qface(0,1,2,5,mat).qface(0,2,3,5,mat).qface(0,3,4,5,mat).qface(0,4,1,5,mat);
  124.         return mesh.updateFaces(true);
  125.     }
  126.     
  127.     static public function dodecahedron(mesh:Mesh, size:Number, mat:int=0, div:Boolean=true) : Mesh {
  128.         var a:Number=size*0.149071198, b:Number=size*0.241202266, c:Number=size*0.283550269
  129.             d:Number=size*0.390273464, e:Number=size*0.458793973, f:Number=size*0.631475730
  130.             g:Number=size*0.742344243;
  131.         mesh.vertices.push(c,f,d, e,f,-a, 0,f,-b-b, -e,f,-a, -c,f,d);
  132.         mesh.vertices.push(e,a,f, g,a,-b, 0,a,-d-d, -g,a,-b, -e,a,f);
  133.         mesh.vertices.push(0,-a,d+d, g,-a,b, e,-a,-f, -e,-a,-f, -g,-a,b);
  134.         mesh.vertices.push(0,-f,b+b, e,-f,a, c,-f,-d, -c,-f,-d, -e,-f,a);
  135.         mesh.qface(0,3,1,2,mat,div).face(0,4,3,mat).qface(4,5,9,10,mat,div).face(4,0,5,mat);
  136.         mesh.qface(0,6,5,11,mat,div).face(0,1,6,mat).qface(1,7,6,12,mat,div).face(1,2,7,mat);
  137.         mesh.qface(2,8,7,13,mat,div).face(2,3,8,mat).qface(3,9,8,14,mat,div).face(3,4,9,mat);
  138.         mesh.qface(17,11,12,6,mat,div).face(17,16,11,mat).qface(16,10,11,5,mat,div).face(16,15,10,mat);
  139.         mesh.qface(15,14,10,9,mat,div).face(15,19,14,mat).qface(19,13,14,8,mat,div).face(19,18,13,mat);
  140.         mesh.qface(18,12,13,7,mat,div).face(18,17,12,mat).qface(16,18,15,19,mat,div).face(16,17,18,mat);
  141.         return mesh.updateFaces(true,179);
  142.     }
  143.     
  144.     static public function icosahedron(mesh:Mesh, size:Number, mat:int=0) : Mesh {
  145.         var a:Number=size*0.276393202, b:Number=size*0.447213595, c:Number=size*0.525731112
  146.             d:Number=size*0.723606798, e:Number=size*0.850650808;
  147.         mesh.vertices.push(0,size,00,b,b+b, e,b,a, c,b,-d, -c,b,-d, -e,b,a);
  148.         mesh.vertices.push(e,-b,-a, c,-b,d, -c,-b,d, -e,-b,-a, 0,-b,-b-b, 0,-size,0);
  149.         mesh.qface(0,2,1,7,mat).qface(0,3,2,6,mat).qface(0,4,3,10,mat).qface(0,5,4,9,mat).qface(0,1,5,8,mat);
  150.         mesh.qface(1,7,8,11,mat).qface(2,6,7,11,mat).qface(3,10,6,11,mat).qface(4,9,10,11,mat).qface(5,8,9,11,mat);
  151.         return mesh.updateFaces(true);
  152.     }
  153.     
  154.     static public function sphere(mesh:Mesh, size:Number, mat:int=0) : Mesh {
  155.         return icosahedron(mesh, size, mat);
  156.     }
  157. }
  158. // Structure Synth
  159. //----------------------------------------------------------------------------------------------------
  160. class StructureSynth {
  161.     private var _mesh:Mesh;
  162.     private var _rules:* = new Object();
  163.     private var _depthLimit:int, _objectsLimit:int;
  164.     private var _maxDepth:int, _maxObjects:int;
  165.     private var _depth:int, _objects:int;
  166.     private var _core:Render3D = new Render3D();
  167.     private var _rootSequence:SSRuleSequence = new SSRuleSequence(new Vector.<SSRuleCaller>());
  168.     static private var _rexContent:RegExp = /((\d+)[\s*]*)?\{(.*?)\}\s*|([^{},\s]+)\s*/g;
  169.     static private var _rexOption :RegExp = /([a-zA-Z]+|>)[\s=:()]*([\-\d.]+|\w+)/g;
  170.     static private var _rexRootOpt:RegExp = /(set)?[\s=:()]*([a-z]+)[\s=:()]*([\-\d.]+)/g;
  171.     static private var _rexOperate:RegExp = /(r?[x-z]|s)([\-\d.\s,:=()]*)/g;
  172.     
  173.     /** constructor. do nothing */
  174.     function StructureSynth(depthLimit:int=512, objectsLimit:int=4096) {
  175.         _depthLimit = depthLimit;
  176.         _objectsLimit = objectsLimit;
  177.     }
  178.     
  179.     /** register primitive */
  180.     public function primitive(name:String, mesh:Mesh) : StructureSynth {
  181.         if (!(name in _rules)) _rules[name] = new SSRule(name);
  182.         _rules[name].newMesh(mesh);
  183.         return this;
  184.     }
  185.     
  186.     /** register rule */
  187.     public function rule(name:String, option:String, content:String) : StructureSynth {
  188.         var opt:* = new Object(), res:*;
  189.         res = _rexOption.exec(option);
  190.         while (res) {
  191.             opt[res[1]] = res[2];
  192.             res = _rexOption.exec(option);
  193.         }
  194.         if (!(name in _rules)) _rules[name] = new SSRule(name);
  195.         _rules[name].newRule(parseContent(new Vector.<SSRuleCaller>(), content), opt);
  196.         return this;
  197.     }
  198.     
  199.     /** register root rule */
  200.     public function root(option:String, content:String, initialize:Boolean=true) : StructureSynth {
  201.         if (initialize) {
  202.             _rootSequence.callers.length = 0;
  203.             _maxDepth = _depthLimit;
  204.             _maxObjects = _objectsLimit;
  205.         }
  206.         var opt:* = new Object(), res:*;
  207.         res = _rexRootOpt.exec(option);
  208.         while (res) {
  209.             switch(res[2]) {
  210.             case "maxdepth":   case "md":   _maxDepth   = int(res[3]); break;
  211.             case "maxobjects"case "mo":   _maxObjects = int(res[3]); break;
  212.             case "background"case "seed":  break;
  213.             }
  214.             res = _rexRootOpt.exec(option);
  215.         }
  216.         _rootSequence.callers = parseContent(_rootSequence.callers, content);
  217.         return this;
  218.     }
  219.     /** execute */
  220.     public function exec(mesh:Mesh) : Mesh {
  221.         _mesh = mesh;
  222.         for each (var rule:SSRule in _rules) rule.init();
  223.         _depth = _objects = 0;
  224.         _core.id();
  225.         _exec(_rootSequence);
  226.         return mesh;
  227.     }
  228.     
  229.     /** parse contents of rule. */
  230.     static public function parseContent(rcList:Vector.<SSRuleCaller>, content:String) : Vector.<SSRuleCaller> {
  231.         var res:*, operations:Array = [];
  232.         res = _rexContent.exec(content);
  233.         while (res) {
  234.             if (res[3]) {
  235.                 operations.unshift(new SSOperation(res[2]||1, parseOperation(new Matrix3D(), res[3])));
  236.             } else if (res[4]) {
  237.                 rcList.push(new SSRuleCaller(res[4], operations));
  238.                 operations = [];
  239.             }
  240.             res = _rexContent.exec(content);
  241.         }
  242.         return rcList;
  243.     }
  244.     
  245.     /** parse matrix opreations. */
  246.     static public function parseOperation(matrix:Matrix3D, operation:String) : Matrix3D {
  247.         var res:*, param:Array, p0:Number, p1:Number, p2:Number;
  248.         res = _rexOperate.exec(operation);
  249.         while(res) {
  250.             param = res[2].match(/[\-\d.]+/g);
  251.             if (param) {
  252.                 p0 = Number(param[0]);
  253.                 switch (res[1]) {
  254.                 case 'x':  matrix.prependTranslation(p0,0,0); break;
  255.                 case 'y':  matrix.prependTranslation(0,p0,0); break;
  256.                 case 'z':  matrix.prependTranslation(0,0,p0); break;
  257.                 case 'rx': matrix.prependRotation(p0, Vector3D.X_AXIS); break;
  258.                 case 'ry': matrix.prependRotation(p0, Vector3D.Y_AXIS); break;
  259.                 case 'rz': matrix.prependRotation(p0, Vector3D.Z_AXIS); break;
  260.                 case 's':
  261.                     p1 = (param.length<2) ? p0 : Number(param[1]),
  262.                     p2 = (param.length<3) ? p1 : Number(param[2]);
  263.                     matrix.prependScale(p0, p1, p2);
  264.                     break;
  265.                 case 'm':
  266.                     if (param.length >= 9) {
  267.                         matrix.prepend(new Matrix3D(Vector.<Number>([
  268.                             Number(param[0]), Number(param[1]), Number(param[2]), 0,
  269.                             Number(param[3]), Number(param[4]), Number(param[5]), 0,
  270.                             Number(param[6]), Number(param[7]), Number(param[8]), 0,
  271.                             0,0,0,1
  272.                         ])));
  273.                     }
  274.                     break;
  275.                 }
  276.             }
  277.             res = _rexOperate.exec(operation);
  278.         }
  279.         return matrix;
  280.     }
  281.     
  282.     private function _exec(seq:SSRuleSequence) : void {
  283.         if (_depth < _maxDepth) {
  284.             _depth++;
  285.             if (seq.depth < seq.maxdepth) {
  286.                 seq.depth++;
  287.                 for each (var rc:SSRuleCaller in seq.callers) $s(rc, rc.operations.length-1);
  288.                 --seq.depth;
  289.             } else {
  290.                 if (seq.finalRuleName) $r(seq.finalRuleName);
  291.             }
  292.             --_depth;
  293.         }
  294.         function $s(rc:SSRuleCaller, index:int) : void {
  295.             var imax:int      = rc.operations[index].repeat, 
  296.                 mat :Matrix3D = rc.operations[index].matrix;
  297.             _core.push();
  298.             for (var i:int=0; i<imax; i++) {
  299.                 _core.mult(mat);
  300.                 if (index) $s(rc, index-1);
  301.                 else $r(rc.ruleName);
  302.             }
  303.             _core.pop();
  304.         }
  305.         function $r(ruleName:String) : void {
  306.             var rule:SSRule = _rules[ruleName];
  307.             if (rule.mesh) {
  308.                 if (++_objects == _maxObjects) _depth = int.MAX_VALUE;
  309.                 _core.project(rule.mesh);
  310.                 _mesh.put(rule.mesh);
  311.             } else {
  312.                 _exec(rule.getSequence());
  313.             }
  314.         }
  315.     }
  316. }
  317. class SSRule {
  318.     public var name:String;
  319.     public var mesh:ProjectionMesh = null;
  320.     private var _totalWeight:Number = 0;
  321.     private var _sequences:Vector.<SSRuleSequence> = new Vector.<SSRuleSequence>();
  322.     
  323.     function SSRule(name:String) { this.name = name; }
  324.     
  325.     public function newMesh(mesh:Mesh) : void {
  326.         this.mesh = new ProjectionMesh(mesh);
  327.     }
  328.     
  329.     public function newRule(callers:Vector.<SSRuleCaller>, option:*) : void {
  330.         var seq:SSRuleSequence = new SSRuleSequence(callers, option);
  331.         _sequences.push(seq);
  332.         _totalWeight += seq.weight;
  333.         mesh = null;
  334.     }
  335.     public function init() : void { 
  336.         for each (var seq:SSRuleSequence in _sequences) seq.depth = 0;
  337.     }
  338.     
  339.     public function getSequence() : SSRuleSequence {
  340.         var w:Number = 0, rand:Number = Math.random() * _totalWeight;
  341.         for each (var seq:SSRuleSequence in _sequences) {
  342.             w += seq.weight;
  343.             if (rand <= w) return seq;
  344.         }
  345.         throw new Error("no sequences in rule:" + name);
  346.     }
  347. }
  348. class SSRuleSequence {
  349.     public var callers:Vector.<SSRuleCaller>;
  350.     public var weight:Number;
  351.     public var maxdepth:int;
  352.     public var finalRuleName:String;
  353.     public var depth:int = 0;
  354.     
  355.     function SSRuleSequence(callers:Vector.<SSRuleCaller>, option:*=undefined) {
  356.         option = option || new Object();
  357.         this.callers = callers;
  358.         this.weight = option["w"] || option["weight"] || 1;
  359.         this.maxdepth = option["md"] || option["maxdepth"] || int.MAX_VALUE;
  360.         this.finalRuleName = option[">"] || null;
  361.     }
  362. }
  363. class SSRuleCaller {
  364.     public var ruleName:String, operations:Vector.<SSOperation>;
  365.     function SSRuleCaller(name:String, ope:Array) { 
  366.         ruleName = name;
  367.         if (ope.length == 0) ope = [new SSOperation(1new Matrix3D())];
  368.         operations = Vector.<SSOperation>(ope);
  369.     }
  370. }
  371. class SSOperation {
  372.     public var repeat:int, matrix:Matrix3D;
  373.     function SSOperation(rep:int, mat:Matrix3D) { repeat=rep; matrix=mat; }
  374. }
  375. // 3D Engine
  376. //----------------------------------------------------------------------------------------------------
  377. /** Core */
  378. class Render3D extends Shape {
  379.     /** model view matrix */
  380.     public var matrix:Matrix3D;
  381.     private var _projectionMatrix:Matrix3D;                              // projection matrix
  382.     private var _matrixStac:Vector.<Matrix3D> = new Vector.<Matrix3D>(); // matrix stac
  383.     private var _cmdWire:Vector.<int> = Vector.<int>([1,2]);             // commands to draw wire
  384.     private var _cmdTriangle:Vector.<int> = Vector.<int>([1,2,2]);       // commands to draw triangle
  385.     private var _cmdQuadrangle:Vector.<int> = Vector.<int>([1,2,2,2]);   // commands to draw quadrangle
  386.     private var _data:Vector.<Number> = new Vector.<Number>(8true);    // data to draw shape
  387.     private var _clippingZ:Number;                                       // clipping z value
  388.     private var _depthMap:BitmapData = new BitmapData(256256false);  // texture for depth buffer rendering
  389.     
  390.     /** constructor */
  391.     function Render3D(focus:Number=300, clippingZ:Number=-0.1) {
  392.         var projector:PerspectiveProjection = new PerspectiveProjection()
  393.         projector.focalLength = focus;
  394.         _projectionMatrix = projector.toMatrix3D();
  395.         _clippingZ = -clippingZ;
  396.         matrix = new Matrix3D();
  397.         _matrixStac.length = 1;
  398.         _matrixStac[0] = matrix;
  399.         var u:int, v:int;
  400.         for (v=0; v<256; v++) 
  401.             for (u=0; u<256; u++) 
  402.                 //_depthMap.setPixel(255-u, 255-v, (v<<8)|u);
  403.                 _depthMap.setPixel(255-u, 255-v, (u<<16)|(u<<8)|u);
  404.     }
  405.     // control matrix
  406.     //--------------------------------------------------
  407.     public function clear() : Render3D { matrix = _matrixStac[0]; _matrixStac.length = 1return this; }
  408.     public function push() : Render3D { _matrixStac.push(matrix.clone()); return this; }
  409.     public function pop() : Render3D { matrix = (_matrixStac.length == 1) ? matrix : _matrixStac.pop(); return this; }
  410.     public function id() : Render3D { matrix.identity(); return this; }
  411.     public function t(x:Number, y:Number, z:Number) : Render3D { matrix.prependTranslation(x, y, z); return this; }
  412.     public function tv(v:Vector3D) : Render3D { matrix.prependTranslation(v.x, v.y, v.z); return this; }
  413.     public function s(x:Number, y:Number, z:Number) : Render3D { matrix.prependScale(x, y, z); return this; }
  414.     public function sv(v:Vector3D) : Render3D { matrix.prependScale(v.x, v.y, v.z); return this; }
  415.     public function r(angle:Number, axis:Vector3D) : Render3D { matrix.prependRotation(angle, axis); return this; }
  416.     public function rv(v:Vector3D) : Render3D { matrix.prependRotation(v.w, v); return this; }
  417.     public function rx(angle:Number) : Render3D { matrix.prependRotation(angle, Vector3D.X_AXIS); return this; }
  418.     public function ry(angle:Number) : Render3D { matrix.prependRotation(angle, Vector3D.Y_AXIS); return this; }
  419.     public function rz(angle:Number) : Render3D { matrix.prependRotation(angle, Vector3D.Z_AXIS); return this; }
  420.     public function mult(mat:Matrix3D) : Render3D { matrix.prepend(mat); return this; }
  421.     
  422.     // projections
  423.     //--------------------------------------------------
  424.     /** project */
  425.     public function project(mesh:ProjectionMesh) : Render3D {
  426.         matrix.transformVectors(mesh.base.vertices, mesh.verticesOnWorld);
  427.         var fn:Vector3D, fnw:Vector3D, vs:Vector.<Number> = mesh.verticesOnWorld,
  428.             nearZ:Number = -Number.MAX_VALUE, farZ:Number = _clippingZ,
  429.             flist:Vector.<Face> = mesh.base.faces;
  430.         var m:Vector.<Number> = matrix.rawData, 
  431.             m00:Number = m[0], m01:Number = m[1], m02:Number = m[2], 
  432.             m10:Number = m[4], m11:Number = m[5], m12:Number = m[6], 
  433.             m20:Number = m[8], m21:Number = m[9], m22:Number = m[10];
  434.         mesh.facesProjected.length = 0;
  435.         for each (var f:Face in flist) {
  436.             var i0:int=(f.i0<<1)+f.i0, i1:int=(f.i1<<1)+f.i1, i2:int=(f.i2<<1)+f.i2,
  437.                 x0:Number=vs[i0++], x1:Number=vs[i1++], x2:Number=vs[i2++],
  438.                 y0:Number=vs[i0++], y1:Number=vs[i1++], y2:Number=vs[i2++],
  439.                 z0:Number=vs[i0],   z1:Number=vs[i1],   z2:Number=vs[i2];
  440.             if (z0<_clippingZ && z1<_clippingZ && z2<_clippingZ) {
  441.                 fn  = f.normal;
  442.                 fnw = mesh.normalsProjected[f.index];
  443.                 fnw.x = fn.x * m00 + fn.y * m10 + fn.z * m20;
  444.                 fnw.y = fn.x * m01 + fn.y * m11 + fn.z * m21;
  445.                 fnw.z = fn.x * m02 + fn.y * m12 + fn.z * m22;
  446.                 if (vs[f.gpi-2]*fnw.x + vs[f.gpi-1]*fnw.y + vs[f.gpi]*fnw.z <= 0) {
  447.                     if (nearZ < z0) nearZ = z0;
  448.                     if (nearZ < z1) nearZ = z1;
  449.                     if (nearZ < z2) nearZ = z2;
  450.                     if (farZ  > z0) farZ  = z0;
  451.                     if (farZ  > z1) farZ  = z1;
  452.                     if (farZ  > z2) farZ  = z2;
  453.                     mesh.facesProjected.push(f);
  454.                 }
  455.             }
  456.         }
  457.         mesh.nearZ = nearZ;
  458.         mesh.farZ  = farZ;
  459.         mesh.facesProjected.sort(function(f1:Face, f2:Face):Numberreturn vs[f1.gpi] - vs[f2.gpi]; });
  460.         mesh.indexDirty = true;
  461.         mesh.screenProjected = false;
  462.         return this;
  463.     }
  464.     
  465.     /** project slower than transformVectors() but Vector3D.w considerable. */
  466.     public function projectPoint3D(points:Vector.<Point3D>) : Render3D {
  467.         var m:Vector.<Number> = matrix.rawData, p:Point3D, 
  468.             m00:Number = m[0],  m01:Number = m[1],  m02:Number = m[2], 
  469.             m10:Number = m[4],  m11:Number = m[5],  m12:Number = m[6], 
  470.             m20:Number = m[8],  m21:Number = m[9],  m22:Number = m[10], 
  471.             m30:Number = m[12], m31:Number = m[13], m32:Number = m[14];
  472.         for each (p in points) {
  473.             p.world.x = p.x * m00 + p.y * m10 + p.z * m20 + p.w * m30;
  474.             p.world.y = p.x * m01 + p.y * m11 + p.z * m21 + p.w * m31;
  475.             p.world.z = p.x * m02 + p.y * m12 + p.z * m22 + p.w * m32;
  476.         }
  477.         return this;
  478.     }
  479.     // rendering
  480.     //--------------------------------------------------
  481.     /** render solid */
  482.     public function renderSolid(mesh:ProjectionMesh, light:Light) : Render3D {
  483.         var idx:int, mat:Material, materials:Vector.<Material> = mesh.base.materials,
  484.             vout:Vector.<Number> = mesh.verticesOnScreen;
  485.         if (!mesh.screenProjected) {
  486.             Utils3D.projectVectors(_projectionMatrix, mesh.verticesOnWorld, vout, mesh.base.texCoord);
  487.             mesh.screenProjected = true;
  488.         }
  489.         graphics.clear();
  490.         for each (var face:Face in mesh.facesProjected) {
  491.             mat = materials[face.mat];
  492.             graphics.beginFill(mat.getColor(light, mesh.normalsProjected[face.index]), mat.alpha);
  493.             idx = face.i0<<1;
  494.             _data[0] = vout[idx]; idx++;
  495.             _data[1] = vout[idx];
  496.             idx = face.i1<<1;
  497.             _data[2] = vout[idx]; idx++;
  498.             _data[3] = vout[idx];
  499.             idx = face.i2<<1;
  500.             _data[4] = vout[idx]; idx++;
  501.             _data[5] = vout[idx];
  502.             if (face.i3 == -1) {
  503.                 graphics.drawPath(_cmdTriangle, _data);
  504.             } else {
  505.                 idx = face.i3<<1;
  506.                 _data[6] = vout[idx]; idx++;
  507.                 _data[7] = vout[idx];
  508.                 graphics.drawPath(_cmdQuadrangle, _data);
  509.             }
  510.             graphics.endFill();
  511.         }
  512.         return this;
  513.     }
  514.     
  515.     /** render wireframe */
  516.     public function renderWire(mesh:ProjectionMesh, color:uint, alpha:Number=1, width:Number=1) : Render3D {
  517.         var idx:int, vout:Vector.<Number> = mesh.verticesOnScreen;
  518.         if (!mesh.screenProjected) {
  519.             Utils3D.projectVectors(_projectionMatrix, mesh.verticesOnWorld, vout, mesh.base.texCoord);
  520.             mesh.screenProjected = true;
  521.         }
  522.         graphics.clear();
  523.         graphics.lineStyle(width, color, alpha);
  524.         for each (var wire:Wire in mesh.base.wires) {
  525.             idx = wire.i0<<1;
  526.             _data[0] = vout[idx]; idx++;
  527.             _data[1] = vout[idx];
  528.             idx = wire.i1<<1;
  529.             _data[2] = vout[idx]; idx++;
  530.             _data[3] = vout[idx];
  531.             graphics.drawPath(_cmdWire, _data);
  532.         }
  533.         return this;
  534.     }
  535.     
  536.     /** render with texture */
  537.     public function renderTexture(mesh:ProjectionMesh, texture:BitmapData) : Render3D {
  538.         var vout:Vector.<Number> = mesh.verticesOnScreen;
  539.         if (!mesh.screenProjected) {
  540.             Utils3D.projectVectors(_projectionMatrix, mesh.verticesOnWorld, vout, mesh.base.texCoord);
  541.             mesh.screenProjected = true;
  542.         }
  543.         graphics.clear();
  544.         graphics.beginBitmapFill(texture, nullfalsetrue);
  545.         graphics.drawTriangles(vout, mesh.indicesProjected, mesh.base.texCoord);
  546.         graphics.endFill();
  547.         return this;
  548.     }
  549.     /** render depth buffer */
  550.     public function renderDepth(mesh:ProjectionMesh) : Render3D {
  551.         var i:int, imax:int = mesh.vertexImax, 
  552.             nearZ:Number = (_clippingZ < mesh.nearZ) ? _clippingZ : mesh.nearZ,
  553.             r:Number = 1/(mesh.farZ - nearZ), duvt:Vector.<Number> = _depthUVT;
  554.         duvt.length = 0;
  555.         for (i=2; i<imax; i+=3) duvt.push((mesh.verticesOnWorld[i]-nearZ)*r, 00);
  556.         Utils3D.projectVectors(_projectionMatrix, mesh.verticesOnWorld, mesh.verticesOnScreen, duvt);
  557.         graphics.clear();
  558.         graphics.beginBitmapFill(_depthMap, nullfalsetrue);
  559.         graphics.drawTriangles(mesh.verticesOnScreen, mesh.indicesProjected, duvt);
  560.         graphics.endFill();
  561.         return this;
  562.     }
  563.     private var _depthUVT:Vector.<Number> = new Vector.<Number>();
  564. }
  565. /** Point3D */
  566. class Point3D extends Vector3D {
  567.     public var world:Vector3D;
  568.     function Point3D(x:Number=0, y:Number=0, z:Number=0, w:Number=1) { super(x,y,z,w); world=clone(); }
  569. }
  570. /** Face */
  571. class Face {
  572.     public var index:int, i0:int, i1:int, i2:int, i3:int, gpi:int, mat:int, normal:Vector3D;
  573.     static private var _freeList:Vector.<Face> = new Vector.<Face>();
  574.     static public function free(face:Face) : void { _freeList.push(face); }
  575.     static public function alloc(index:int, i0:int, i1:int, i2:int, i3:int, mat:int) : Face { 
  576.         var f:Face = _freeList.pop() || new Face();
  577.         f.index=index; f.i0=i0; f.i1=i1; f.i2=i2; f.i3=i3; f.gpi=0; f.mat=mat;
  578.         return f;
  579.     }
  580. }
  581. /** Line */
  582. class Wire {
  583.     public var index:int, i0:int, i1:int;
  584.     static private var _freeList:Vector.<Wire> = new Vector.<Wire>();
  585.     static public function free(wire:Wire) : void { _freeList.push(wire); }
  586.     static public function alloc(index:int, i0:int, i1:int) : Wire { 
  587.         var w:Wire = _freeList.pop() || new Wire();
  588.         w.index=index; w.i0=i0; w.i1=i1;
  589.         return w;
  590.     }
  591. }
  592. /** Mesh */
  593. class Mesh {
  594.     public var materials:Vector.<Material>;                 // material list
  595.     public var vertices:Vector.<Number>;                    // vertex
  596.     public var verticesCount:int;                           // vertex count
  597.     public var texCoord:Vector.<Number>;                    // texture coordinate
  598.     public var faces:Vector.<Face> = new Vector.<Face>();   // face list
  599.     public var wires:Vector.<Wire> = new Vector.<Wire>();   // wireframe list
  600.     
  601.     /** constructor */
  602.     function Mesh(materials:Vector.<Material>=null) {
  603.         this.materials = materials;
  604.         this.vertices = new Vector.<Number>();
  605.         this.texCoord = new Vector.<Number>();
  606.         this.verticesCount = 0;
  607.     }
  608.     
  609.     /** clear all faces */
  610.     public function clear() : Mesh {
  611.         for each (var face:Face in faces) Face.free(face);
  612.         faces.length = 0;
  613.         return this;
  614.     }
  615.     
  616.     /** register face */
  617.     public function face(i0:int, i1:int, i2:int, mat:int=0) : Mesh {
  618.         faces.push(Face.alloc(faces.length, i0, i1, i2, -1, mat));
  619.         return this;
  620.     }
  621.     
  622.     /** register quadrangle face. set div=true to divide into 2 triangles. */
  623.     public function qface(i0:int, i1:int, i2:int, i3:int, mat:int=0, div:Boolean=true) : Mesh {
  624.         if (div) {
  625.             faces.push(Face.alloc(faces.length,   i0, i1, i2, -1, mat), 
  626.                        Face.alloc(faces.length+1, i3, i2, i1, -1, mat));
  627.         }
  628.         else faces.push(Face.alloc(faces.length, i0, i1, i3, i2, mat));
  629.         return this;
  630.     }
  631.     
  632.     /** register wire */
  633.     public function wire(i0:int, i1:int) : Mesh {
  634.         wires.push(Wire.alloc(wires.length, i0, i1));
  635.         return this;
  636.     }
  637.     
  638.     /** put mesh on world coordinate. */
  639.     public function put(src:ProjectionMesh, mat:int=-1) : Mesh {
  640.         var i0:int=vertices.length, imax:int=src.vertexImax, flist:Vector.<Face>=src.base.faces;
  641.         vertices.length += imax;
  642.         for (var i:int=0; i<imax; i++) vertices[i0+i] = src.verticesOnWorld[i];
  643.         i0 /= 3;
  644.         for each (var f:Face in flist) {
  645.             i = (mat == -1) ? f.mat : mat;
  646.             if (f.i3==-1) face (f.i0+i0, f.i1+i0, f.i2+i0, i);
  647.             else          qface(f.i0+i0, f.i1+i0, f.i3+i0, f.i2+i0, i, false);
  648.         }
  649.         return this;
  650.     }
  651.     
  652.     /** update face gravity point and normal. create fireframe lines when createWire==true */
  653.     public function updateFaces(createWire:Boolean = false, facetAngle:Number = 180) : Mesh {
  654.         verticesCount = vertices.length/3;
  655.         var vs:Vector.<Number> = vertices;
  656.         for each (var f:Face in faces) {
  657.             f.gpi = vs.length+2;
  658.             var i0:int=(f.i0<<1)+f.i0, i1:int=(f.i1<<1)+f.i1, i2:int=(f.i2<<1)+f.i2;
  659.             var x01:Number=vs[i1]-vs[i0], x02:Number=vs[i2]-vs[i0];
  660.             vs.push((vs[i0++] + vs[i1++] + vs[i2++]) * 0.333333333333);
  661.             var y01:Number=vs[i1]-vs[i0], y02:Number=vs[i2]-vs[i0];
  662.             vs.push((vs[i0++] + vs[i1++] + vs[i2++]) * 0.333333333333);
  663.             var z01:Number=vs[i1]-vs[i0], z02:Number=vs[i2]-vs[i0];
  664.             vs.push((vs[i0++] + vs[i1++] + vs[i2++]) * 0.333333333333);
  665.             f.normal = new Point3D(y02*z01-y01*z02, z02*x01-z01*x02, x02*y01-x01*y02, 0);
  666.             f.normal.normalize();
  667.             if (f.i3 != -1) {
  668.                 var i3:int = (f.i3<<1)+f.i3;
  669.                 vs[f.gpi-2] = vs[f.gpi-2]*0.75 + vs[i3++]*0.25;
  670.                 vs[f.gpi-1] = vs[f.gpi-1]*0.75 + vs[i3++]*0.25;
  671.                 vs[f.gpi]   = vs[f.gpi]  *0.75 + vs[i3]  *0.25;
  672.             }
  673.         }
  674.         if (createWire) {
  675.             var facetCos:Number = Math.cos((180-facetAngle)*57.29577951308232);
  676.             for each (var f0:Face in faces) {
  677.                 _wire(f0, f0.i0, f0.i1);
  678.                 _wire(f0, f0.i1, f0.i2);
  679.                 if (f0.i3==-1) _wire(f0, f0.i2, f0.i0);
  680.                 else { _wire(f0, f0.i2, f0.i3); _wire(f0, f0.i3, f0.i0); }
  681.             }
  682.         }
  683.         return this;
  684.         
  685.         function _wire(f0:Face, i0:int, i1:int) : void {
  686.             var f1:Face = _findFace(i0, i1);
  687.             if (f1==null || facetCos >= f0.normal.dotProduct(f1.normal)) {
  688.                 if (_findWire(i0, i1) == null) wire(i0, i1);
  689.             }
  690.         }
  691.         function _findFace(i0:int, i1:int) : Face {
  692.             for each (var f:Face in faces) {
  693.                 if ((f.i0==i0 && f.i1==i1) || (f.i0==i1 && f.i1==i0) ||
  694.                     (f.i1==i0 && f.i2==i1) || (f.i1==i1 && f.i2==i0)) return f;
  695.                 if (f.i3==-1if ((f.i2==i0 && f.i0==i1) || (f.i2==i1 && f.i0==i0)) return f;
  696.                 else if ((f.i2==i0 && f.i3==i1) || (f.i2==i1 && f.i3==i0) ||
  697.                          (f.i3==i0 && f.i0==i1) || (f.i3==i1 && f.i0==i0)) return f;
  698.             }
  699.             return null;
  700.         }
  701.         function _findWire(i0:int, i1:int) : Wire {
  702.             for each (var w:Wire in wires) {
  703.                 if ((w.i0==i0 && w.i1==i1) || (w.i0==i1 && w.i1==i0)) return w;
  704.             }
  705.             return null;
  706.         }
  707.     }
  708. }
  709. /** mesh for projection */
  710. class ProjectionMesh {
  711.     public var verticesOnWorld:Vector.<Number>;     // vertex on camera coordinate
  712.     public var verticesOnScreen:Vector.<Number>;    // vertex on screen
  713.     public var facesProjected:Vector.<Face>;        // projected face
  714.     public var normalsProjected:Vector.<Vector3D>;  // projected normals
  715.     public var vnormals:Vector.<Vector3D>;          // vertex normal
  716.     public var nearZ:Number, farZ:Number;           // z buffer range
  717.     public var screenProjected:Boolean = false;     // flag to projection on screen
  718.     private var _projectedFaceIndices:Vector.<int> = new Vector.<int>();
  719.     private var _base:Mesh;
  720.     
  721.     /** indices of projected faces */
  722.     public function get indicesProjected() : Vector.<int> {
  723.         var idx:Vector.<int> = _projectedFaceIndices;
  724.         if (idx.length == 0for each (var f:Face in facesProjected) idx.push(f.i0, f.i1, f.i2);
  725.         return idx;
  726.     }
  727.     
  728.     public function set indexDirty(b:Boolean) : void {
  729.         if (b) _projectedFaceIndices.length = 0;
  730.     }
  731.     public function get base() : Mesh { return _base; }
  732.     public function set base(m:Mesh) : void {
  733.         if (m && normalsProjected.length < m.faces.length) {
  734.             var i:int = normalsProjected.length, imax:int = m.faces.length;
  735.             normalsProjected.length = imax;
  736.             for (; i<imax; i++) normalsProjected[i] = new Vector3D();
  737.         }
  738.         _base = m;
  739.     }
  740.     
  741.     public function get vertexImax() : int { return (_base.verticesCount<<1) + _base.verticesCount; }
  742.     
  743.     /** constructor */
  744.     function ProjectionMesh(m:Mesh=null) {
  745.         this.verticesOnWorld = new Vector.<Number>();
  746.         this.verticesOnScreen = new Vector.<Number>();
  747.         this.facesProjected = new Vector.<Face>();
  748.         this.normalsProjected= new Vector.<Vector3D>();
  749.         this.vnormals = null;
  750.         this.base = m;
  751.     }
  752. }
  753. /** Light */
  754. class Light extends Point3D {
  755.     public var halfVector:Vector3D = new Vector3D();
  756.     
  757.     /** constructor (set position) */
  758.     function Light(x:Number=1, y:Number=1, z:Number=1) {
  759.         super(x, y, z, 0);
  760.         normalize();
  761.     }
  762.     /** projection */
  763.     public function transformBy(matrix:Matrix3D) : void {
  764.         world = matrix.deltaTransformVector(this);
  765.         halfVector.x = world.x;
  766.         halfVector.y = world.y;
  767.         halfVector.z = world.z + 1
  768.         halfVector.normalize();
  769.     }
  770. }
  771. /** Material */
  772. class Material extends BitmapData {
  773.     public var alpha:Number = 1;    // The alpha value is available for renderSolid()
  774.     public var doubleSided:int = 0// set doubleSided=-1 if double sided material
  775.     
  776.     /** constructor */
  777.     function Material(dif:int=128, spc:int=128) { super(dif, spc, false); }
  778.     
  779.     /** set color. */
  780.     public function setColor(col:uint, amb:int=64, dif:int=192, spc:int=0,  pow:Number=8) : Material {
  781.         fillRect(rect, col);
  782.         var lmap:LightMap = new LightMap(width, height);
  783.         draw(lmap.diffusion(amb, dif), nullnull"hardlight");
  784.         draw(lmap.specular (spc, pow), nullnull"add");
  785.         lmap.dispose();
  786.         return this;
  787.     }
  788.     
  789.     /** calculate color by light and normal vector. */
  790.     public function getColor(l:Light, n:Vector3D) : uint {
  791.         var dir:Vector3D = l.world, hv:Vector3D = l.halfVector;
  792.         var ln:int = int((dir.x * n.x + dir.y * n.y + dir.z * n.z) * (width-1)),
  793.             hn:int = int((hv.x  * n.x + hv.y  * n.y + hv.z  * n.z) * (height-1));
  794.         if (ln<0) ln = (-ln) & doubleSided;
  795.         if (hn<0) hn = (-hn) & doubleSided;
  796.         return getPixel(ln, hn);
  797.     }
  798. }
  799. class LightMap extends BitmapData {
  800.     function LightMap(dif:int, spc:int) { super(dif, spc, false); }
  801.     
  802.     public function diffusion(amb:int, dif:int) : BitmapData {
  803.         var col:int, rc:Rectangle = new Rectangle(001, height), ipk:Number = 1 / width;
  804.         for (rc.x=0; rc.x<width; rc.x+=1) {
  805.             col = ((rc.x * (dif - amb)) * ipk) + amb;
  806.             fillRect(rc, (col<<16)|(col<<8)|col);
  807.         }
  808.         return this;
  809.     }
  810.     
  811.     public function specular(spc:int, pow:Number) : BitmapData {
  812.         var col:int, rc:Rectangle = new Rectangle(00, width, 1),
  813.             mpk:Number = (pow + 2) * 0.15915494309189534, ipk:Number = 1 / height;
  814.         for (rc.y=0; rc.y<height; rc.y+=1) {
  815.             col = Math.pow(rc.y * ipk, pow) * spc * mpk;
  816.             if (col > 255) col = 255;
  817.             fillRect(rc, (col<<16)|(col<<8)|col);
  818.         }
  819.         return this;
  820.     }
  821. }
noswf
  1. // forked from keim_at_Si's Screen Space Ambient Occlusion
  2. // forked from keim_at_Si's Depth buffer test
  3. // forked from keim_at_Si's Regular Solid Structures
  4. // forked from keim_at_Si's Code based Structure Synth
  5. // Code based Structure Synth
  6. //  Structure Synth; http://structuresynth.sourceforge.net/
  7. //------------------------------------------------------------
  8. package {
  9.     import flash.display.*;
  10.     import flash.events.*;
  11.     import flash.geom.*;
  12.     import flash.utils.*;
  13.     import flash.filters.*;
  14.     import flash.text.*;
  15.     [SWF(width='465', height='465', backgroundColor='#000000', frameRate='30')]
  16.     public class main extends Sprite {
  17.         private const WIDTH:int = 450;
  18.         // 3D renders
  19.         private var _materials:Vector.<Material> = new Vector.<Material>();
  20.         private var _light:Light = new Light(1,0.5,0.25);
  21.         private var _screen:BitmapData = new BitmapData(WIDTH, WIDTH, false0);
  22.         private var _matbuf:Matrix = new Matrix(1001225225);
  23.         private var gl:Render3D = new Render3D(300,1);
  24.         private var ss:StructureSynth = new StructureSynth();
  25.         private var tf:TextField = new TextField();
  26.         // objects
  27.         private var camera:Vector3D;
  28.         private var struct:Vector.<ProjectionMesh> = new Vector.<ProjectionMesh>(5true);
  29.         private var _depth:BitmapData;
  30.         private var _ssao :BitmapData;
  31.         private var _mask :BitmapData;
  32.         
  33.         // motions
  34.         private var clicked:Boolean = false;
  35.         private var frame:int = 0;
  36.         
  37.         // entry point
  38.         function main() {
  39.             stage.quality = "low";
  40.             Wonderfl.capture_delay(3);
  41.             
  42.             camera = new Vector3D(00, -50);
  43.             _depth = new BitmapData(WIDTH, WIDTH, false0);
  44.             _ssao  = new BitmapData(WIDTH, WIDTH, false0);
  45.             _mask  = new BitmapData(WIDTH, WIDTH, false0);
  46.             
  47.             _materials.push((new Material()).setColor(0xff8080, 64192840),
  48.                             (new Material()).setColor(0xd0d080, 64192840),
  49.                             (new Material()).setColor(0x80ff80, 64192840),
  50.                             (new Material()).setColor(0x80c0c0, 64192840),
  51.                             (new Material()).setColor(0x8080ff, 64192840));
  52.             
  53.             tf.autoSize = "left";
  54.             tf.htmlText = "<font face='_typewriter'>Click to switch on/off ambient occlusion.</font>";
  55.             addChild(gl).visible = false;
  56.             with(addChild(new Bitmap(_screen))) { x = y = 7; }
  57.             with(addChild(tf)) { x = y = 7; }
  58.             addEventListener("enterFrame", _onEnterFrame);
  59.             stage.addEventListener("click", _onClick);
  60.             
  61.             // register meshes
  62.             ss.primitive("tetra",  SolidFactory.tetrahedron (new Mesh(), 10));  // 4vertices/4triangles
  63.             ss.primitive("box",    SolidFactory.hexahedron  (new Mesh(), 11));  // 8vertices/12triangles
  64.             ss.primitive("octa",   SolidFactory.octahedron  (new Mesh(), 12));  // 6vertices/8triangles
  65.             ss.primitive("dodeca", SolidFactory.dodecahedron(new Mesh(), 13));  // 12vertices/36triangles
  66.             ss.primitive("icosa",  SolidFactory.icosahedron (new Mesh(), 14));  // 20vertices/20triangles
  67.             
  68.             // struct[0]
  69.             ss.root("md6""{s4}{x-4y-4z-4}s4rx");
  70.             ss.rule("s4rx""""{s1.5}icosa{z2x2}s4rz{y2z2}s4ry{x2y2}s4rx");
  71.             ss.rule("s4ry""""{s1.5}icosa{z2x2}s4rz{y2z2}s4ry");
  72.             ss.rule("s4rz""""{s1.5}icosa{z2x2}s4rz");
  73.             struct[0] = new ProjectionMesh(ss.exec(new Mesh(_materials)).updateFaces());
  74.         }
  75.         private function _onEnterFrame(e:Event) : void {
  76.             frame++;
  77.             
  78.             // projection
  79.             _light.transformBy(gl.id().tv(camera).rx((400-mouseY)*0.25).ry((232-mouseX)*0.75).matrix);
  80.             gl.push().rx(frame).project(struct[0]).pop();
  81.             struct[0].nearZ = -10;
  82.             struct[0].farZ = -80;
  83.             // calculate screen space mbient occlusion
  84.             _depth.fillRect(_depth.rect, 0);
  85.             _depth.draw(gl.renderDepth(struct[0]), _matbuf);
  86.             _ssao.applyFilter(_depth, _depth.rect, _depth.rect.topLeft, blur);
  87.             _ssao.draw(_depth, nullnull"subtract");
  88.             _ssao.threshold(_depth, _depth.rect, _depth.rect.topLeft, "=="00255);
  89.             
  90.             // draw
  91.             _screen.fillRect(_screen.rect, 0xffffff);
  92.             _screen.draw(gl.renderSolid(struct[0], _light), _matbuf);
  93.             if (!clicked) _screen.draw(_ssao, null, colt, "multiply");
  94.         }
  95.         private var blur:BlurFilter = new BlurFilter(6464);
  96.         private var colt:ColorTransform = new ColorTransform(-8, -8, -812552552550);
  97.         
  98.         private function _onClick(e:Event) : void { clicked = !clicked; }
  99.     }
  100. }
  101. import flash.display.*;
  102. import flash.geom.*;
  103. // Solid Factory
  104. //----------------------------------------------------------------------------------------------------
  105. class SolidFactory {
  106.     // regular solids
  107.     //--------------------------------------------------
  108.     static public function tetrahedron(mesh:Mesh, size:Number, mat:int=0) : Mesh {
  109.         mesh.vertices.push(size,size,size, size,-size,-size, -size,size,-size, -size,-size,size);
  110.         mesh.qface(0,2,1,3,mat).qface(1,3,0,2,mat);
  111.         return mesh.updateFaces(true);
  112.     }
  113.     
  114.     static public function hexahedron(mesh:Mesh, size:Number, mat:int=0, div:Boolean=true) : Mesh {
  115.         for (var i:int=0; i<8; i++) mesh.vertices.push((i&1)?size:-size, ((i>>1)&1)?size:-size, (i>>2)?size:-size);
  116.         mesh.qface(0,1,2,3,mat,div).qface(1,0,5,4,mat,div).qface(0,2,4,6,mat,div);
  117.         mesh.qface(2,3,6,7,mat,div).qface(3,1,7,5,mat,div).qface(5,4,7,6,mat,div);
  118.         return mesh.updateFaces(true,179);
  119.     }
  120.     
  121.     static public function octahedron(mesh:Mesh, size:Number, mat:int=0) : Mesh {
  122.         mesh.vertices.push(0,0,-size, -size,0,00,-size,0, size,0,00,size,00,0,size);
  123.         mesh.qface(0,1,2,5,mat).qface(0,2,3,5,mat).qface(0,3,4,5,mat).qface(0,4,1,5,mat);
  124.         return mesh.updateFaces(true);
  125.     }
  126.     
  127.     static public function dodecahedron(mesh:Mesh, size:Number, mat:int=0, div:Boolean=true) : Mesh {
  128.         var a:Number=size*0.149071198, b:Number=size*0.241202266, c:Number=size*0.283550269
  129.             d:Number=size*0.390273464, e:Number=size*0.458793973, f:Number=size*0.631475730
  130.             g:Number=size*0.742344243;
  131.         mesh.vertices.push(c,f,d, e,f,-a, 0,f,-b-b, -e,f,-a, -c,f,d);
  132.         mesh.vertices.push(e,a,f, g,a,-b, 0,a,-d-d, -g,a,-b, -e,a,f);
  133.         mesh.vertices.push(0,-a,d+d, g,-a,b, e,-a,-f, -e,-a,-f, -g,-a,b);
  134.         mesh.vertices.push(0,-f,b+b, e,-f,a, c,-f,-d, -c,-f,-d, -e,-f,a);
  135.         mesh.qface(0,3,1,2,mat,div).face(0,4,3,mat).qface(4,5,9,10,mat,div).face(4,0,5,mat);
  136.         mesh.qface(0,6,5,11,mat,div).face(0,1,6,mat).qface(1,7,6,12,mat,div).face(1,2,7,mat);
  137.         mesh.qface(2,8,7,13,mat,div).face(2,3,8,mat).qface(3,9,8,14,mat,div).face(3,4,9,mat);
  138.         mesh.qface(17,11,12,6,mat,div).face(17,16,11,mat).qface(16,10,11,5,mat,div).face(16,15,10,mat);
  139.         mesh.qface(15,14,10,9,mat,div).face(15,19,14,mat).qface(19,13,14,8,mat,div).face(19,18,13,mat);
  140.         mesh.qface(18,12,13,7,mat,div).face(18,17,12,mat).qface(16,18,15,19,mat,div).face(16,17,18,mat);
  141.         return mesh.updateFaces(true,179);
  142.     }
  143.     
  144.     static public function icosahedron(mesh:Mesh, size:Number, mat:int=0) : Mesh {
  145.         var a:Number=size*0.276393202, b:Number=size*0.447213595, c:Number=size*0.525731112
  146.             d:Number=size*0.723606798, e:Number=size*0.850650808;
  147.         mesh.vertices.push(0,size,00,b,b+b, e,b,a, c,b,-d, -c,b,-d, -e,b,a);
  148.         mesh.vertices.push(e,-b,-a, c,-b,d, -c,-b,d, -e,-b,-a, 0,-b,-b-b, 0,-size,0);
  149.         mesh.qface(0,2,1,7,mat).qface(0,3,2,6,mat).qface(0,4,3,10,mat).qface(0,5,4,9,mat).qface(0,1,5,8,mat);
  150.         mesh.qface(1,7,8,11,mat).qface(2,6,7,11,mat).qface(3,10,6,11,mat).qface(4,9,10,11,mat).qface(5,8,9,11,mat);
  151.         return mesh.updateFaces(true);
  152.     }
  153.     
  154.     static public function sphere(mesh:Mesh, size:Number, mat:int=0) : Mesh {
  155.         return icosahedron(mesh, size, mat);
  156.     }
  157. }
  158. // Structure Synth
  159. //----------------------------------------------------------------------------------------------------
  160. class StructureSynth {
  161.     private var _mesh:Mesh;
  162.     private var _rules:* = new Object();
  163.     private var _depthLimit:int, _objectsLimit:int;
  164.     private var _maxDepth:int, _maxObjects:int;
  165.     private var _depth:int, _objects:int;
  166.     private var _core:Render3D = new Render3D();
  167.     private var _rootSequence:SSRuleSequence = new SSRuleSequence(new Vector.<SSRuleCaller>());
  168.     static private var _rexContent:RegExp = /((\d+)[\s*]*)?\{(.*?)\}\s*|([^{},\s]+)\s*/g;
  169.     static private var _rexOption :RegExp = /([a-zA-Z]+|>)[\s=:()]*([\-\d.]+|\w+)/g;
  170.     static private var _rexRootOpt:RegExp = /(set)?[\s=:()]*([a-z]+)[\s=:()]*([\-\d.]+)/g;
  171.     static private var _rexOperate:RegExp = /(r?[x-z]|s)([\-\d.\s,:=()]*)/g;
  172.     
  173.     /** constructor. do nothing */
  174.     function StructureSynth(depthLimit:int=512, objectsLimit:int=4096) {
  175.         _depthLimit = depthLimit;
  176.         _objectsLimit = objectsLimit;
  177.     }
  178.     
  179.     /** register primitive */
  180.     public function primitive(name:String, mesh:Mesh) : StructureSynth {
  181.         if (!(name in _rules)) _rules[name] = new SSRule(name);
  182.         _rules[name].newMesh(mesh);
  183.         return this;
  184.     }
  185.     
  186.     /** register rule */
  187.     public function rule(name:String, option:String, content:String) : StructureSynth {
  188.         var opt:* = new Object(), res:*;
  189.         res = _rexOption.exec(option);
  190.         while (res) {
  191.             opt[res[1]] = res[2];
  192.             res = _rexOption.exec(option);
  193.         }
  194.         if (!(name in _rules)) _rules[name] = new SSRule(name);
  195.         _rules[name].newRule(parseContent(new Vector.<SSRuleCaller>(), content), opt);
  196.         return this;
  197.     }
  198.     
  199.     /** register root rule */
  200.     public function root(option:String, content:String, initialize:Boolean=true) : StructureSynth {
  201.         if (initialize) {
  202.             _rootSequence.callers.length = 0;
  203.             _maxDepth = _depthLimit;
  204.             _maxObjects = _objectsLimit;
  205.         }
  206.         var opt:* = new Object(), res:*;
  207.         res = _rexRootOpt.exec(option);
  208.         while (res) {
  209.             switch(res[2]) {
  210.             case "maxdepth":   case "md":   _maxDepth   = int(res[3]); break;
  211.             case "maxobjects"case "mo":   _maxObjects = int(res[3]); break;
  212.             case "background"case "seed":  break;
  213.             }
  214.             res = _rexRootOpt.exec(option);
  215.         }
  216.         _rootSequence.callers = parseContent(_rootSequence.callers, content);
  217.         return this;
  218.     }
  219.     /** execute */
  220.     public function exec(mesh:Mesh) : Mesh {
  221.         _mesh = mesh;
  222.         for each (var rule:SSRule in _rules) rule.init();
  223.         _depth = _objects = 0;
  224.         _core.id();
  225.         _exec(_rootSequence);
  226.         return mesh;
  227.     }
  228.     
  229.     /** parse contents of rule. */
  230.     static public function parseContent(rcList:Vector.<SSRuleCaller>, content:String) : Vector.<SSRuleCaller> {
  231.         var res:*, operations:Array = [];
  232.         res = _rexContent.exec(content);
  233.         while (res) {
  234.             if (res[3]) {
  235.                 operations.unshift(new SSOperation(res[2]||1, parseOperation(new Matrix3D(), res[3])));
  236.             } else if (res[4]) {
  237.                 rcList.push(new SSRuleCaller(res[4], operations));
  238.                 operations = [];
  239.             }
  240.             res = _rexContent.exec(content);
  241.         }
  242.         return rcList;
  243.     }
  244.     
  245.     /** parse matrix opreations. */
  246.     static public function parseOperation(matrix:Matrix3D, operation:String) : Matrix3D {
  247.         var res:*, param:Array, p0:Number, p1:Number, p2:Number;
  248.         res = _rexOperate.exec(operation);
  249.         while(res) {
  250.             param = res[2].match(/[\-\d.]+/g);
  251.             if (param) {
  252.                 p0 = Number(param[0]);
  253.                 switch (res[1]) {
  254.                 case 'x':  matrix.prependTranslation(p0,0,0); break;
  255.                 case 'y':  matrix.prependTranslation(0,p0,0); break;
  256.                 case 'z':  matrix.prependTranslation(0,0,p0); break;
  257.                 case 'rx': matrix.prependRotation(p0, Vector3D.X_AXIS); break;
  258.                 case 'ry': matrix.prependRotation(p0, Vector3D.Y_AXIS); break;
  259.                 case 'rz': matrix.prependRotation(p0, Vector3D.Z_AXIS); break;
  260.                 case 's':
  261.                     p1 = (param.length<2) ? p0 : Number(param[1]),
  262.                     p2 = (param.length<3) ? p1 : Number(param[2]);
  263.                     matrix.prependScale(p0, p1, p2);
  264.                     break;
  265.                 case 'm':
  266.                     if (param.length >= 9) {
  267.                         matrix.prepend(new Matrix3D(Vector.<Number>([
  268.                             Number(param[0]), Number(param[1]), Number(param[2]), 0,
  269.                             Number(param[3]), Number(param[4]), Number(param[5]), 0,
  270.                             Number(param[6]), Number(param[7]), Number(param[8]), 0,
  271.                             0,0,0,1
  272.                         ])));
  273.                     }
  274.                     break;
  275.                 }
  276.             }
  277.             res = _rexOperate.exec(operation);
  278.         }
  279.         return matrix;
  280.     }
  281.     
  282.     private function _exec(seq:SSRuleSequence) : void {
  283.         if (_depth < _maxDepth) {
  284.             _depth++;
  285.             if (seq.depth < seq.maxdepth) {
  286.                 seq.depth++;
  287.                 for each (var rc:SSRuleCaller in seq.callers) $s(rc, rc.operations.length-1);
  288.                 --seq.depth;
  289.             } else {
  290.                 if (seq.finalRuleName) $r(seq.finalRuleName);
  291.             }
  292.             --_depth;
  293.         }
  294.         function $s(rc:SSRuleCaller, index:int) : void {
  295.             var imax:int      = rc.operations[index].repeat, 
  296.                 mat :Matrix3D = rc.operations[index].matrix;
  297.             _core.push();
  298.             for (var i:int=0; i<imax; i++) {
  299.                 _core.mult(mat);
  300.                 if (index) $s(rc, index-1);
  301.                 else $r(rc.ruleName);
  302.             }
  303.             _core.pop();
  304.         }
  305.         function $r(ruleName:String) : void {
  306.             var rule:SSRule = _rules[ruleName];
  307.             if (rule.mesh) {
  308.                 if (++_objects == _maxObjects) _depth = int.MAX_VALUE;
  309.                 _core.project(rule.mesh);
  310.                 _mesh.put(rule.mesh);
  311.             } else {
  312.                 _exec(rule.getSequence());
  313.             }
  314.         }
  315.     }
  316. }
  317. class SSRule {
  318.     public var name:String;
  319.     public var mesh:ProjectionMesh = null;
  320.     private var _totalWeight:Number = 0;
  321.     private var _sequences:Vector.<SSRuleSequence> = new Vector.<SSRuleSequence>();
  322.     
  323.     function SSRule(name:String) { this.name = name; }
  324.     
  325.     public function newMesh(mesh:Mesh) : void {
  326.         this.mesh = new ProjectionMesh(mesh);
  327.     }
  328.     
  329.     public function newRule(callers:Vector.<SSRuleCaller>, option:*) : void {
  330.         var seq:SSRuleSequence = new SSRuleSequence(callers, option);
  331.         _sequences.push(seq);
  332.         _totalWeight += seq.weight;
  333.         mesh = null;
  334.     }
  335.     public function init() : void { 
  336.         for each (var seq:SSRuleSequence in _sequences) seq.depth = 0;
  337.     }
  338.     
  339.     public function getSequence() : SSRuleSequence {
  340.         var w:Number = 0, rand:Number = Math.random() * _totalWeight;
  341.         for each (var seq:SSRuleSequence in _sequences) {
  342.             w += seq.weight;
  343.             if (rand <= w) return seq;
  344.         }
  345.         throw new Error("no sequences in rule:" + name);
  346.     }
  347. }
  348. class SSRuleSequence {
  349.     public var callers:Vector.<SSRuleCaller>;
  350.     public var weight:Number;
  351.     public var maxdepth:int;
  352.     public var finalRuleName:String;
  353.     public var depth:int = 0;
  354.     
  355.     function SSRuleSequence(callers:Vector.<SSRuleCaller>, option:*=undefined) {
  356.         option = option || new Object();
  357.         this.callers = callers;
  358.         this.weight = option["w"] || option["weight"] || 1;
  359.         this.maxdepth = option["md"] || option["maxdepth"] || int.MAX_VALUE;
  360.         this.finalRuleName = option[">"] || null;
  361.     }
  362. }
  363. class SSRuleCaller {
  364.     public var ruleName:String, operations:Vector.<SSOperation>;
  365.     function SSRuleCaller(name:String, ope:Array) { 
  366.         ruleName = name;
  367.         if (ope.length == 0) ope = [new SSOperation(1new Matrix3D())];
  368.         operations = Vector.<SSOperation>(ope);
  369.     }
  370. }
  371. class SSOperation {
  372.     public var repeat:int, matrix:Matrix3D;
  373.     function SSOperation(rep:int, mat:Matrix3D) { repeat=rep; matrix=mat; }
  374. }
  375. // 3D Engine
  376. //----------------------------------------------------------------------------------------------------
  377. /** Core */
  378. class Render3D extends Shape {
  379.     /** model view matrix */
  380.     public var matrix:Matrix3D;
  381.     private var _projectionMatrix:Matrix3D;                              // projection matrix
  382.     private var _matrixStac:Vector.<Matrix3D> = new Vector.<Matrix3D>(); // matrix stac
  383.     private var _cmdWire:Vector.<int> = Vector.<int>([1,2]);             // commands to draw wire
  384.     private var _cmdTriangle:Vector.<int> = Vector.<int>([1,2,2]);       // commands to draw triangle
  385.     private var _cmdQuadrangle:Vector.<int> = Vector.<int>([1,2,2,2]);   // commands to draw quadrangle
  386.     private var _data:Vector.<Number> = new Vector.<Number>(8true);    // data to draw shape
  387.     private var _clippingZ:Number;                                       // clipping z value
  388.     private var _depthMap:BitmapData = new BitmapData(256256false);  // texture for depth buffer rendering
  389.     
  390.     /** constructor */
  391.     function Render3D(focus:Number=300, clippingZ:Number=-0.1) {
  392.         var projector:PerspectiveProjection = new PerspectiveProjection()
  393.         projector.focalLength = focus;
  394.         _projectionMatrix = projector.toMatrix3D();
  395.         _clippingZ = -clippingZ;
  396.         matrix = new Matrix3D();
  397.         _matrixStac.length = 1;
  398.         _matrixStac[0] = matrix;
  399.         var u:int, v:int;
  400.         for (v=0; v<256; v++) 
  401.             for (u=0; u<256; u++) 
  402.                 //_depthMap.setPixel(255-u, 255-v, (v<<8)|u);
  403.                 _depthMap.setPixel(255-u, 255-v, (u<<16)|(u<<8)|u);
  404.     }
  405.     // control matrix
  406.     //--------------------------------------------------
  407.     public function clear() : Render3D { matrix = _matrixStac[0]; _matrixStac.length = 1return this; }
  408.     public function push() : Render3D { _matrixStac.push(matrix.clone()); return this; }
  409.     public function pop() : Render3D { matrix = (_matrixStac.length == 1) ? matrix : _matrixStac.pop(); return this; }
  410.     public function id() : Render3D { matrix.identity(); return this; }
  411.     public function t(x:Number, y:Number, z:Number) : Render3D { matrix.prependTranslation(x, y, z); return this; }
  412.     public function tv(v:Vector3D) : Render3D { matrix.prependTranslation(v.x, v.y, v.z); return this; }
  413.     public function s(x:Number, y:Number, z:Number) : Render3D { matrix.prependScale(x, y, z); return this; }
  414.     public function sv(v:Vector3D) : Render3D { matrix.prependScale(v.x, v.y, v.z); return this; }
  415.     public function r(angle:Number, axis:Vector3D) : Render3D { matrix.prependRotation(angle, axis); return this; }
  416.     public function rv(v:Vector3D) : Render3D { matrix.prependRotation(v.w, v); return this; }
  417.     public function rx(angle:Number) : Render3D { matrix.prependRotation(angle, Vector3D.X_AXIS); return this; }
  418.     public function ry(angle:Number) : Render3D { matrix.prependRotation(angle, Vector3D.Y_AXIS); return this; }
  419.     public function rz(angle:Number) : Render3D { matrix.prependRotation(angle, Vector3D.Z_AXIS); return this; }
  420.     public function mult(mat:Matrix3D) : Render3D { matrix.prepend(mat); return this; }
  421.     
  422.     // projections
  423.     //--------------------------------------------------
  424.     /** project */
  425.     public function project(mesh:ProjectionMesh) : Render3D {
  426.         matrix.transformVectors(mesh.base.vertices, mesh.verticesOnWorld);
  427.         var fn:Vector3D, fnw:Vector3D, vs:Vector.<Number> = mesh.verticesOnWorld,
  428.             nearZ:Number = -Number.MAX_VALUE, farZ:Number = _clippingZ,
  429.             flist:Vector.<Face> = mesh.base.faces;
  430.         var m:Vector.<Number> = matrix.rawData, 
  431.             m00:Number = m[0], m01:Number = m[1], m02:Number = m[2], 
  432.             m10:Number = m[4], m11:Number = m[5], m12:Number = m[6], 
  433.             m20:Number = m[8], m21:Number = m[9], m22:Number = m[10];
  434.         mesh.facesProjected.length = 0;
  435.         for each (var f:Face in flist) {
  436.             var i0:int=(f.i0<<1)+f.i0, i1:int=(f.i1<<1)+f.i1, i2:int=(f.i2<<1)+f.i2,
  437.                 x0:Number=vs[i0++], x1:Number=vs[i1++], x2:Number=vs[i2++],
  438.                 y0:Number=vs[i0++], y1:Number=vs[i1++], y2:Number=vs[i2++],
  439.                 z0:Number=vs[i0],   z1:Number=vs[i1],   z2:Number=vs[i2];
  440.             if (z0<_clippingZ && z1<_clippingZ && z2<_clippingZ) {
  441.                 fn  = f.normal;
  442.                 fnw = mesh.normalsProjected[f.index];
  443.                 fnw.x = fn.x * m00 + fn.y * m10 + fn.z * m20;
  444.                 fnw.y = fn.x * m01 + fn.y * m11 + fn.z * m21;
  445.                 fnw.z = fn.x * m02 + fn.y * m12 + fn.z * m22;
  446.                 if (vs[f.gpi-2]*fnw.x + vs[f.gpi-1]*fnw.y + vs[f.gpi]*fnw.z <= 0) {
  447.                     if (nearZ < z0) nearZ = z0;
  448.                     if (nearZ < z1) nearZ = z1;
  449.                     if (nearZ < z2) nearZ = z2;
  450.                     if (farZ  > z0) farZ  = z0;
  451.                     if (farZ  > z1) farZ  = z1;
  452.                     if (farZ  > z2) farZ  = z2;
  453.                     mesh.facesProjected.push(f);
  454.                 }
  455.             }
  456.         }
  457.         mesh.nearZ = nearZ;
  458.         mesh.farZ  = farZ;
  459.         mesh.facesProjected.sort(function(f1:Face, f2:Face):Numberreturn vs[f1.gpi] - vs[f2.gpi]; });
  460.         mesh.indexDirty = true;
  461.         mesh.screenProjected = false;
  462.         return this;
  463.     }
  464.     
  465.     /** project slower than transformVectors() but Vector3D.w considerable. */
  466.     public function projectPoint3D(points:Vector.<Point3D>) : Render3D {
  467.         var m:Vector.<Number> = matrix.rawData, p:Point3D, 
  468.             m00:Number = m[0],  m01:Number = m[1],  m02:Number = m[2], 
  469.             m10:Number = m[4],  m11:Number = m[5],  m12:Number = m[6], 
  470.             m20:Number = m[8],  m21:Number = m[9],  m22:Number = m[10], 
  471.             m30:Number = m[12], m31:Number = m[13], m32:Number = m[14];
  472.         for each (p in points) {
  473.             p.world.x = p.x * m00 + p.y * m10 + p.z * m20 + p.w * m30;
  474.             p.world.y = p.x * m01 + p.y * m11 + p.z * m21 + p.w * m31;
  475.             p.world.z = p.x * m02 + p.y * m12 + p.z * m22 + p.w * m32;
  476.         }
  477.         return this;
  478.     }
  479.     // rendering
  480.     //--------------------------------------------------
  481.     /** render solid */
  482.     public function renderSolid(mesh:ProjectionMesh, light:Light) : Render3D {
  483.         var idx:int, mat:Material, materials:Vector.<Material> = mesh.base.materials,
  484.             vout:Vector.<Number> = mesh.verticesOnScreen;
  485.         if (!mesh.screenProjected) {
  486.             Utils3D.projectVectors(_projectionMatrix, mesh.verticesOnWorld, vout, mesh.base.texCoord);
  487.             mesh.screenProjected = true;
  488.         }
  489.         graphics.clear();
  490.         for each (var face:Face in mesh.facesProjected) {
  491.             mat = materials[face.mat];
  492.             graphics.beginFill(mat.getColor(light, mesh.normalsProjected[face.index]), mat.alpha);
  493.             idx = face.i0<<1;
  494.             _data[0] = vout[idx]; idx++;
  495.             _data[1] = vout[idx];
  496.             idx = face.i1<<1;
  497.             _data[2] = vout[idx]; idx++;
  498.             _data[3] = vout[idx];
  499.             idx = face.i2<<1;
  500.             _data[4] = vout[idx]; idx++;
  501.             _data[5] = vout[idx];
  502.             if (face.i3 == -1) {
  503.                 graphics.drawPath(_cmdTriangle, _data);
  504.             } else {
  505.                 idx = face.i3<<1;
  506.                 _data[6] = vout[idx]; idx++;
  507.                 _data[7] = vout[idx];
  508.                 graphics.drawPath(_cmdQuadrangle, _data);
  509.             }
  510.             graphics.endFill();
  511.         }
  512.         return this;
  513.     }
  514.     
  515.     /** render wireframe */
  516.     public function renderWire(mesh:ProjectionMesh, color:uint, alpha:Number=1, width:Number=1) : Render3D {
  517.         var idx:int, vout:Vector.<Number> = mesh.verticesOnScreen;
  518.         if (!mesh.screenProjected) {
  519.             Utils3D.projectVectors(_projectionMatrix, mesh.verticesOnWorld, vout, mesh.base.texCoord);
  520.             mesh.screenProjected = true;
  521.         }
  522.         graphics.clear();
  523.         graphics.lineStyle(width, color, alpha);
  524.         for each (var wire:Wire in mesh.base.wires) {
  525.             idx = wire.i0<<1;
  526.             _data[0] = vout[idx]; idx++;
  527.             _data[1] = vout[idx];
  528.             idx = wire.i1<<1;
  529.             _data[2] = vout[idx]; idx++;
  530.             _data[3] = vout[idx];
  531.             graphics.drawPath(_cmdWire, _data);
  532.         }
  533.         return this;
  534.     }
  535.     
  536.     /** render with texture */
  537.     public function renderTexture(mesh:ProjectionMesh, texture:BitmapData) : Render3D {
  538.         var vout:Vector.<Number> = mesh.verticesOnScreen;
  539.         if (!mesh.screenProjected) {
  540.             Utils3D.projectVectors(_projectionMatrix, mesh.verticesOnWorld, vout, mesh.base.texCoord);
  541.             mesh.screenProjected = true;
  542.         }
  543.         graphics.clear();
  544.         graphics.beginBitmapFill(texture, nullfalsetrue);
  545.         graphics.drawTriangles(vout, mesh.indicesProjected, mesh.base.texCoord);
  546.         graphics.endFill();
  547.         return this;
  548.     }
  549.     /** render depth buffer */
  550.     public function renderDepth(mesh:ProjectionMesh) : Render3D {
  551.         var i:int, imax:int = mesh.vertexImax, 
  552.             nearZ:Number = (_clippingZ < mesh.nearZ) ? _clippingZ : mesh.nearZ,
  553.             r:Number = 1/(mesh.farZ - nearZ), duvt:Vector.<Number> = _depthUVT;
  554.         duvt.length = 0;
  555.         for (i=2; i<imax; i+=3) duvt.push((mesh.verticesOnWorld[i]-nearZ)*r, 00);
  556.         Utils3D.projectVectors(_projectionMatrix, mesh.verticesOnWorld, mesh.verticesOnScreen, duvt);
  557.         graphics.clear();
  558.         graphics.beginBitmapFill(_depthMap, nullfalsetrue);
  559.         graphics.drawTriangles(mesh.verticesOnScreen, mesh.indicesProjected, duvt);
  560.         graphics.endFill();
  561.         return this;
  562.     }
  563.     private var _depthUVT:Vector.<Number> = new Vector.<Number>();
  564. }
  565. /** Point3D */
  566. class Point3D extends Vector3D {
  567.     public var world:Vector3D;
  568.     function Point3D(x:Number=0, y:Number=0, z:Number=0, w:Number=1) { super(x,y,z,w); world=clone(); }
  569. }
  570. /** Face */
  571. class Face {
  572.     public var index:int, i0:int, i1:int, i2:int, i3:int, gpi:int, mat:int, normal:Vector3D;
  573.     static private var _freeList:Vector.<Face> = new Vector.<Face>();
  574.     static public function free(face:Face) : void { _freeList.push(face); }
  575.     static public function alloc(index:int, i0:int, i1:int, i2:int, i3:int, mat:int) : Face { 
  576.         var f:Face = _freeList.pop() || new Face();
  577.         f.index=index; f.i0=i0; f.i1=i1; f.i2=i2; f.i3=i3; f.gpi=0; f.mat=mat;
  578.         return f;
  579.     }
  580. }
  581. /** Line */
  582. class Wire {
  583.     public var index:int, i0:int, i1:int;
  584.     static private var _freeList:Vector.<Wire> = new Vector.<Wire>();
  585.     static public function free(wire:Wire) : void { _freeList.push(wire); }
  586.     static public function alloc(index:int, i0:int, i1:int) : Wire { 
  587.         var w:Wire = _freeList.pop() || new Wire();
  588.         w.index=index; w.i0=i0; w.i1=i1;
  589.         return w;
  590.     }
  591. }
  592. /** Mesh */
  593. class Mesh {
  594.     public var materials:Vector.<Material>;                 // material list
  595.     public var vertices:Vector.<Number>;                    // vertex
  596.     public var verticesCount:int;                           // vertex count
  597.     public var texCoord:Vector.<Number>;                    // texture coordinate
  598.     public var faces:Vector.<Face> = new Vector.<Face>();   // face list
  599.     public var wires:Vector.<Wire> = new Vector.<Wire>();   // wireframe list
  600.     
  601.     /** constructor */
  602.     function Mesh(materials:Vector.<Material>=null) {
  603.         this.materials = materials;
  604.         this.vertices = new Vector.<Number>();
  605.         this.texCoord = new Vector.<Number>();
  606.         this.verticesCount = 0;
  607.     }
  608.     
  609.     /** clear all faces */
  610.     public function clear() : Mesh {
  611.         for each (var face:Face in faces) Face.free(face);
  612.         faces.length = 0;
  613.         return this;
  614.     }
  615.     
  616.     /** register face */
  617.     public function face(i0:int, i1:int, i2:int, mat:int=0) : Mesh {
  618.         faces.push(Face.alloc(faces.length, i0, i1, i2, -1, mat));
  619.         return this;
  620.     }
  621.     
  622.     /** register quadrangle face. set div=true to divide into 2 triangles. */
  623.     public function qface(i0:int, i1:int, i2:int, i3:int, mat:int=0, div:Boolean=true) : Mesh {
  624.         if (div) {
  625.             faces.push(Face.alloc(faces.length,   i0, i1, i2, -1, mat), 
  626.                        Face.alloc(faces.length+1, i3, i2, i1, -1, mat));
  627.         }
  628.         else faces.push(Face.alloc(faces.length, i0, i1, i3, i2, mat));
  629.         return this;
  630.     }
  631.     
  632.     /** register wire */
  633.     public function wire(i0:int, i1:int) : Mesh {
  634.         wires.push(Wire.alloc(wires.length, i0, i1));
  635.         return this;
  636.     }
  637.     
  638.     /** put mesh on world coordinate. */
  639.     public function put(src:ProjectionMesh, mat:int=-1) : Mesh {
  640.         var i0:int=vertices.length, imax:int=src.vertexImax, flist:Vector.<Face>=src.base.faces;
  641.         vertices.length += imax;
  642.         for (var i:int=0; i<imax; i++) vertices[i0+i] = src.verticesOnWorld[i];
  643.         i0 /= 3;
  644.         for each (var f:Face in flist) {
  645.             i = (mat == -1) ? f.mat : mat;
  646.             if (f.i3==-1) face (f.i0+i0, f.i1+i0, f.i2+i0, i);
  647.             else          qface(f.i0+i0, f.i1+i0, f.i3+i0, f.i2+i0, i, false);
  648.         }
  649.         return this;
  650.     }
  651.     
  652.     /** update face gravity point and normal. create fireframe lines when createWire==true */
  653.     public function updateFaces(createWire:Boolean = false, facetAngle:Number = 180) : Mesh {
  654.         verticesCount = vertices.length/3;
  655.         var vs:Vector.<Number> = vertices;
  656.         for each (var f:Face in faces) {
  657.             f.gpi = vs.length+2;
  658.             var i0:int=(f.i0<<1)+f.i0, i1:int=(f.i1<<1)+f.i1, i2:int=(f.i2<<1)+f.i2;
  659.             var x01:Number=vs[i1]-vs[i0], x02:Number=vs[i2]-vs[i0];
  660.             vs.push((vs[i0++] + vs[i1++] + vs[i2++]) * 0.333333333333);
  661.             var y01:Number=vs[i1]-vs[i0], y02:Number=vs[i2]-vs[i0];
  662.             vs.push((vs[i0++] + vs[i1++] + vs[i2++]) * 0.333333333333);
  663.             var z01:Number=vs[i1]-vs[i0], z02:Number=vs[i2]-vs[i0];
  664.             vs.push((vs[i0++] + vs[i1++] + vs[i2++]) * 0.333333333333);
  665.             f.normal = new Point3D(y02*z01-y01*z02, z02*x01-z01*x02, x02*y01-x01*y02, 0);
  666.             f.normal.normalize();
  667.             if (f.i3 != -1) {
  668.                 var i3:int = (f.i3<<1)+f.i3;
  669.                 vs[f.gpi-2] = vs[f.gpi-2]*0.75 + vs[i3++]*0.25;
  670.                 vs[f.gpi-1] = vs[f.gpi-1]*0.75 + vs[i3++]*0.25;
  671.                 vs[f.gpi]   = vs[f.gpi]  *0.75 + vs[i3]  *0.25;
  672.             }
  673.         }
  674.         if (createWire) {
  675.             var facetCos:Number = Math.cos((180-facetAngle)*57.29577951308232);
  676.             for each (var f0:Face in faces) {
  677.                 _wire(f0, f0.i0, f0.i1);
  678.                 _wire(f0, f0.i1, f0.i2);
  679.                 if (f0.i3==-1) _wire(f0, f0.i2, f0.i0);
  680.                 else { _wire(f0, f0.i2, f0.i3); _wire(f0, f0.i3, f0.i0); }
  681.             }
  682.         }
  683.         return this;
  684.         
  685.         function _wire(f0:Face, i0:int, i1:int) : void {
  686.             var f1:Face = _findFace(i0, i1);
  687.             if (f1==null || facetCos >= f0.normal.dotProduct(f1.normal)) {
  688.                 if (_findWire(i0, i1) == null) wire(i0, i1);
  689.             }
  690.         }
  691.         function _findFace(i0:int, i1:int) : Face {
  692.             for each (var f:Face in faces) {
  693.                 if ((f.i0==i0 && f.i1==i1) || (f.i0==i1 && f.i1==i0) ||
  694.                     (f.i1==i0 && f.i2==i1) || (f.i1==i1 && f.i2==i0)) return f;
  695.                 if (f.i3==-1if ((f.i2==i0 && f.i0==i1) || (f.i2==i1 && f.i0==i0)) return f;
  696.                 else if ((f.i2==i0 && f.i3==i1) || (f.i2==i1 && f.i3==i0) ||
  697.                          (f.i3==i0 && f.i0==i1) || (f.i3==i1 && f.i0==i0)) return f;
  698.             }
  699.             return null;
  700.         }
  701.         function _findWire(i0:int, i1:int) : Wire {
  702.             for each (var w:Wire in wires) {
  703.                 if ((w.i0==i0 && w.i1==i1) || (w.i0==i1 && w.i1==i0)) return w;
  704.             }
  705.             return null;
  706.         }
  707.     }
  708. }
  709. /** mesh for projection */
  710. class ProjectionMesh {
  711.     public var verticesOnWorld:Vector.<Number>;     // vertex on camera coordinate
  712.     public var verticesOnScreen:Vector.<Number>;    // vertex on screen
  713.     public var facesProjected:Vector.<Face>;        // projected face
  714.     public var normalsProjected:Vector.<Vector3D>;  // projected normals
  715.     public var vnormals:Vector.<Vector3D>;          // vertex normal
  716.     public var nearZ:Number, farZ:Number;           // z buffer range
  717.     public var screenProjected:Boolean = false;     // flag to projection on screen
  718.     private var _projectedFaceIndices:Vector.<int> = new Vector.<int>();
  719.     private var _base:Mesh;
  720.     
  721.     /** indices of projected faces */
  722.     public function get indicesProjected() : Vector.<int> {
  723.         var idx:Vector.<int> = _projectedFaceIndices;
  724.         if (idx.length == 0for each (var f:Face in facesProjected) idx.push(f.i0, f.i1, f.i2);
  725.         return idx;
  726.     }
  727.     
  728.     public function set indexDirty(b:Boolean) : void {
  729.         if (b) _projectedFaceIndices.length = 0;
  730.     }
  731.     public function get base() : Mesh { return _base; }
  732.     public function set base(m:Mesh) : void {
  733.         if (m && normalsProjected.length < m.faces.length) {
  734.             var i:int = normalsProjected.length, imax:int = m.faces.length;
  735.             normalsProjected.length = imax;
  736.             for (; i<imax; i++) normalsProjected[i] = new Vector3D();
  737.         }
  738.         _base = m;
  739.     }
  740.     
  741.     public function get vertexImax() : int { return (_base.verticesCount<<1) + _base.verticesCount; }
  742.     
  743.     /** constructor */
  744.     function ProjectionMesh(m:Mesh=null) {
  745.         this.verticesOnWorld = new Vector.<Number>();
  746.         this.verticesOnScreen = new Vector.<Number>();
  747.         this.facesProjected = new Vector.<Face>();
  748.         this.normalsProjected= new Vector.<Vector3D>();
  749.         this.vnormals = null;
  750.         this.base = m;
  751.     }
  752. }
  753. /** Light */
  754. class Light extends Point3D {
  755.     public var halfVector:Vector3D = new Vector3D();
  756.     
  757.     /** constructor (set position) */
  758.     function Light(x:Number=1, y:Number=1, z:Number=1) {
  759.         super(x, y, z, 0);
  760.         normalize();
  761.     }
  762.     /** projection */
  763.     public function transformBy(matrix:Matrix3D) : void {
  764.         world = matrix.deltaTransformVector(this);
  765.         halfVector.x = world.x;
  766.         halfVector.y = world.y;
  767.         halfVector.z = world.z + 1
  768.         halfVector.normalize();
  769.     }
  770. }
  771. /** Material */
  772. class Material extends BitmapData {
  773.     public var alpha:Number = 1;    // The alpha value is available for renderSolid()
  774.     public var doubleSided:int = 0// set doubleSided=-1 if double sided material
  775.     
  776.     /** constructor */
  777.     function Material(dif:int=128, spc:int=128) { super(dif, spc, false); }
  778.     
  779.     /** set color. */
  780.     public function setColor(col:uint, amb:int=64, dif:int=192, spc:int=0,  pow:Number=8) : Material {
  781.         fillRect(rect, col);
  782.         var lmap:LightMap = new LightMap(width, height);
  783.         draw(lmap.diffusion(amb, dif), nullnull"hardlight");
  784.         draw(lmap.specular (spc, pow), nullnull"add");
  785.         lmap.dispose();
  786.         return this;
  787.     }
  788.     
  789.     /** calculate color by light and normal vector. */
  790.     public function getColor(l:Light, n:Vector3D) : uint {
  791.         var dir:Vector3D = l.world, hv:Vector3D = l.halfVector;
  792.         var ln:int = int((dir.x * n.x + dir.y * n.y + dir.z * n.z) * (width-1)),
  793.             hn:int = int((hv.x  * n.x + hv.y  * n.y + hv.z  * n.z) * (height-1));
  794.         if (ln<0) ln = (-ln) & doubleSided;
  795.         if (hn<0) hn = (-hn) & doubleSided;
  796.         return getPixel(ln, hn);
  797.     }
  798. }
  799. class LightMap extends BitmapData {
  800.     function LightMap(dif:int, spc:int) { super(dif, spc, false); }
  801.     
  802.     public function diffusion(amb:int, dif:int) : BitmapData {
  803.         var col:int, rc:Rectangle = new Rectangle(001, height), ipk:Number = 1 / width;
  804.         for (rc.x=0; rc.x<width; rc.x+=1) {
  805.             col = ((rc.x * (dif - amb)) * ipk) + amb;
  806.             fillRect(rc, (col<<16)|(col<<8)|col);
  807.         }
  808.         return this;
  809.     }
  810.     
  811.     public function specular(spc:int, pow:Number) : BitmapData {
  812.         var col:int, rc:Rectangle = new Rectangle(00, width, 1),
  813.             mpk:Number = (pow + 2) * 0.15915494309189534, ipk:Number = 1 / height;
  814.         for (rc.y=0; rc.y<height; rc.y+=1) {
  815.             col = Math.pow(rc.y * ipk, pow) * spc * mpk;
  816.             if (col > 255) col = 255;
  817.             fillRect(rc, (col<<16)|(col<<8)|col);
  818.         }
  819.         return this;
  820.     }
  821. }
noswf
  1. // forked from keim_at_Si's Screen Space Ambient Occlusion
  2. // forked from keim_at_Si's Depth buffer test
  3. // forked from keim_at_Si's Regular Solid Structures
  4. // forked from keim_at_Si's Code based Structure Synth
  5. // Code based Structure Synth
  6. //  Structure Synth; http://structuresynth.sourceforge.net/
  7. //------------------------------------------------------------
  8. package {
  9.     import flash.display.*;
  10.     import flash.events.*;
  11.     import flash.geom.*;
  12.     import flash.utils.*;
  13.     import flash.filters.*;
  14.     import flash.text.*;
  15.     [SWF(width='465', height='465', backgroundColor='#000000', frameRate='30')]
  16.     public class main extends Sprite {
  17.         private const WIDTH:int = 450;
  18.         // 3D renders
  19.         private var _materials:Vector.<Material> = new Vector.<Material>();
  20.         private var _light:Light = new Light(1,0.5,0.25);
  21.         private var _screen:BitmapData = new BitmapData(WIDTH, WIDTH, false0);
  22.         private var _matbuf:Matrix = new Matrix(1001225225);
  23.         private var gl:Render3D = new Render3D(300,1);
  24.         private var ss:StructureSynth = new StructureSynth();
  25.         private var tf:TextField = new TextField();
  26.         // objects
  27.         private var camera:Vector3D;
  28.         private var struct:Vector.<ProjectionMesh> = new Vector.<ProjectionMesh>(5true);
  29.         private var _depth:BitmapData;
  30.         private var _ssao :BitmapData;
  31.         private var _mask :BitmapData;
  32.         
  33.         // motions
  34.         private var clicked:Boolean = false;
  35.         private var frame:int = 0;
  36.         
  37.         // entry point
  38.         function main() {
  39.             stage.quality = "low";
  40.             Wonderfl.capture_delay(3);
  41.             
  42.             camera = new Vector3D(00, -50);
  43.             _depth = new BitmapData(WIDTH, WIDTH, false0);
  44.             _ssao  = new BitmapData(WIDTH, WIDTH, false0);
  45.             _mask  = new BitmapData(WIDTH, WIDTH, false0);
  46.             
  47.             _materials.push((new Material()).setColor(0xff8080, 64192840),
  48.                             (new Material()).setColor(0xd0d080, 64192840),
  49.                             (new Material()).setColor(0x80ff80, 64192840),
  50.                             (new Material()).setColor(0x80c0c0, 64192840),
  51.                             (new Material()).setColor(0x8080ff, 64192840));
  52.             
  53.             tf.autoSize = "left";
  54.             tf.htmlText = "<font face='_typewriter'>Click to switch on/off ambient occlusion.</font>";
  55.             addChild(gl).visible = false;
  56.             with(addChild(new Bitmap(_screen))) { x = y = 7; }
  57.             with(addChild(tf)) { x = y = 7; }
  58.             addEventListener("enterFrame", _onEnterFrame);
  59.             stage.addEventListener("click", _onClick);
  60.             
  61.             // register meshes
  62.             ss.primitive("tetra",  SolidFactory.tetrahedron (new Mesh(), 10));  // 4vertices/4triangles
  63.             ss.primitive("box",    SolidFactory.hexahedron  (new Mesh(), 11));  // 8vertices/12triangles
  64.             ss.primitive("octa",   SolidFactory.octahedron  (new Mesh(), 12));  // 6vertices/8triangles
  65.             ss.primitive("dodeca", SolidFactory.dodecahedron(new Mesh(), 13));  // 12vertices/36triangles
  66.             ss.primitive("icosa",  SolidFactory.icosahedron (new Mesh(), 14));  // 20vertices/20triangles
  67.             
  68.             // struct[0]
  69.             ss.root("md6""{s4}{x-4y-4z-4}s4rx");
  70.             ss.rule("s4rx""""{s1.5}icosa{z2x2}s4rz{y2z2}s4ry{x2y2}s4rx");
  71.             ss.rule("s4ry""""{s1.5}icosa{z2x2}s4rz{y2z2}s4ry");
  72.             ss.rule("s4rz""""{s1.5}icosa{z2x2}s4rz");
  73.             struct[0] = new ProjectionMesh(ss.exec(new Mesh(_materials)).updateFaces());
  74.         }
  75.         private function _onEnterFrame(e:Event) : void {
  76.             frame++;
  77.             
  78.             // projection
  79.             _light.transformBy(gl.id().tv(camera).rx((400-mouseY)*0.25).ry((232-mouseX)*0.75).matrix);
  80.             gl.push().rx(frame).project(struct[0]).pop();
  81.             struct[0].nearZ = -10;
  82.             struct[0].farZ = -80;
  83.             // calculate screen space mbient occlusion
  84.             _depth.fillRect(_depth.rect, 0);
  85.             _depth.draw(gl.renderDepth(struct[0]), _matbuf);
  86.             _ssao.applyFilter(_depth, _depth.rect, _depth.rect.topLeft, blur);
  87.             _ssao.draw(_depth, nullnull"subtract");
  88.             _ssao.threshold(_depth, _depth.rect, _depth.rect.topLeft, "=="00255);
  89.             
  90.             // draw
  91.             _screen.fillRect(_screen.rect, 0xffffff);
  92.             _screen.draw(gl.renderSolid(struct[0], _light), _matbuf);
  93.             if (!clicked) _screen.draw(_ssao, null, colt, "multiply");
  94.         }
  95.         private var blur:BlurFilter = new BlurFilter(6464);
  96.         private var colt:ColorTransform = new ColorTransform(-8, -8, -812552552550);
  97.         
  98.         private function _onClick(e:Event) : void { clicked = !clicked; }
  99.     }
  100. }
  101. import flash.display.*;
  102. import flash.geom.*;
  103. // Solid Factory
  104. //----------------------------------------------------------------------------------------------------
  105. class SolidFactory {
  106.     // regular solids
  107.     //--------------------------------------------------
  108.     static public function tetrahedron(mesh:Mesh, size:Number, mat:int=0) : Mesh {
  109.         mesh.vertices.push(size,size,size, size,-size,-size, -size,size,-size, -size,-size,size);
  110.         mesh.qface(0,2,1,3,mat).qface(1,3,0,2,mat);
  111.         return mesh.updateFaces(true);
  112.     }
  113.     
  114.     static public function hexahedron(mesh:Mesh, size:Number, mat:int=0, div:Boolean=true) : Mesh {
  115.         for (var i:int=0; i<8; i++) mesh.vertices.push((i&1)?size:-size, ((i>>1)&1)?size:-size, (i>>2)?size:-size);
  116.         mesh.qface(0,1,2,3,mat,div).qface(1,0,5,4,mat,div).qface(0,2,4,6,mat,div);
  117.         mesh.qface(2,3,6,7,mat,div).qface(3,1,7,5,mat,div).qface(5,4,7,6,mat,div);
  118.         return mesh.updateFaces(true,179);
  119.     }
  120.     
  121.     static public function octahedron(mesh:Mesh, size:Number, mat:int=0) : Mesh {
  122.         mesh.vertices.push(0,0,-size, -size,0,00,-size,0, size,0,00,size,00,0,size);
  123.         mesh.qface(0,1,2,5,mat).qface(0,2,3,5,mat).qface(0,3,4,5,mat).qface(0,4,1,5,mat);
  124.         return mesh.updateFaces(true);
  125.     }
  126.     
  127.     static public function dodecahedron(mesh:Mesh, size:Number, mat:int=0, div:Boolean=true) : Mesh {
  128.         var a:Number=size*0.149071198, b:Number=size*0.241202266, c:Number=size*0.283550269
  129.             d:Number=size*0.390273464, e:Number=size*0.458793973, f:Number=size*0.631475730
  130.             g:Number=size*0.742344243;
  131.         mesh.vertices.push(c,f,d, e,f,-a, 0,f,-b-b, -e,f,-a, -c,f,d);
  132.         mesh.vertices.push(e,a,f, g,a,-b, 0,a,-d-d, -g,a,-b, -e,a,f);
  133.         mesh.vertices.push(0,-a,d+d, g,-a,b, e,-a,-f, -e,-a,-f, -g,-a,b);
  134.         mesh.vertices.push(0,-f,b+b, e,-f,a, c,-f,-d, -c,-f,-d, -e,-f,a);
  135.         mesh.qface(0,3,1,2,mat,div).face(0,4,3,mat).qface(4,5,9,10,mat,div).face(4,0,5,mat);
  136.         mesh.qface(0,6,5,11,mat,div).face(0,1,6,mat).qface(1,7,6,12,mat,div).face(1,2,7,mat);
  137.         mesh.qface(2,8,7,13,mat,div).face(2,3,8,mat).qface(3,9,8,14,mat,div).face(3,4,9,mat);
  138.         mesh.qface(17,11,12,6,mat,div).face(17,16,11,mat).qface(16,10,11,5,mat,div).face(16,15,10,mat);
  139.         mesh.qface(15,14,10,9,mat,div).face(15,19,14,mat).qface(19,13,14,8,mat,div).face(19,18,13,mat);
  140.         mesh.qface(18,12,13,7,mat,div).face(18,17,12,mat).qface(16,18,15,19,mat,div).face(16,17,18,mat);
  141.         return mesh.updateFaces(true,179);
  142.     }
  143.     
  144.     static public function icosahedron(mesh:Mesh, size:Number, mat:int=0) : Mesh {
  145.         var a:Number=size*0.276393202, b:Number=size*0.447213595, c:Number=size*0.525731112
  146.             d:Number=size*0.723606798, e:Number=size*0.850650808;
  147.         mesh.vertices.push(0,size,00,b,b+b, e,b,a, c,b,-d, -c,b,-d, -e,b,a);
  148.         mesh.vertices.push(e,-b,-a, c,-b,d, -c,-b,d, -e,-b,-a, 0,-b,-b-b, 0,-size,0);
  149.         mesh.qface(0,2,1,7,mat).qface(0,3,2,6,mat).qface(0,4,3,10,mat).qface(0,5,4,9,mat).qface(0,1,5,8,mat);
  150.         mesh.qface(1,7,8,11,mat).qface(2,6,7,11,mat).qface(3,10,6,11,mat).qface(4,9,10,11,mat).qface(5,8,9,11,mat);
  151.         return mesh.updateFaces(true);
  152.     }
  153.     
  154.     static public function sphere(mesh:Mesh, size:Number, mat:int=0) : Mesh {
  155.         return icosahedron(mesh, size, mat);
  156.     }
  157. }
  158. // Structure Synth
  159. //----------------------------------------------------------------------------------------------------
  160. class StructureSynth {
  161.     private var _mesh:Mesh;
  162.     private var _rules:* = new Object();
  163.     private var _depthLimit:int, _objectsLimit:int;
  164.     private var _maxDepth:int, _maxObjects:int;
  165.     private var _depth:int, _objects:int;
  166.     private var _core:Render3D = new Render3D();
  167.     private var _rootSequence:SSRuleSequence = new SSRuleSequence(new Vector.<SSRuleCaller>());
  168.     static private var _rexContent:RegExp = /((\d+)[\s*]*)?\{(.*?)\}\s*|([^{},\s]+)\s*/g;
  169.     static private var _rexOption :RegExp = /([a-zA-Z]+|>)[\s=:()]*([\-\d.]+|\w+)/g;
  170.     static private var _rexRootOpt:RegExp = /(set)?[\s=:()]*([a-z]+)[\s=:()]*([\-\d.]+)/g;
  171.     static private var _rexOperate:RegExp = /(r?[x-z]|s)([\-\d.\s,:=()]*)/g;
  172.     
  173.     /** constructor. do nothing */
  174.     function StructureSynth(depthLimit:int=512, objectsLimit:int=4096) {
  175.         _depthLimit = depthLimit;
  176.         _objectsLimit = objectsLimit;
  177.     }
  178.     
  179.     /** register primitive */
  180.     public function primitive(name:String, mesh:Mesh) : StructureSynth {
  181.         if (!(name in _rules)) _rules[name] = new SSRule(name);
  182.         _rules[name].newMesh(mesh);
  183.         return this;
  184.     }
  185.     
  186.     /** register rule */
  187.     public function rule(name:String, option:String, content:String) : StructureSynth {
  188.         var opt:* = new Object(), res:*;
  189.         res = _rexOption.exec(option);
  190.         while (res) {
  191.             opt[res[1]] = res[2];
  192.             res = _rexOption.exec(option);
  193.         }
  194.         if (!(name in _rules)) _rules[name] = new SSRule(name);
  195.         _rules[name].newRule(parseContent(new Vector.<SSRuleCaller>(), content), opt);
  196.         return this;
  197.     }
  198.     
  199.     /** register root rule */
  200.     public function root(option:String, content:String, initialize:Boolean=true) : StructureSynth {
  201.         if (initialize) {
  202.             _rootSequence.callers.length = 0;
  203.             _maxDepth = _depthLimit;
  204.             _maxObjects = _objectsLimit;
  205.         }
  206.         var opt:* = new Object(), res:*;
  207.         res = _rexRootOpt.exec(option);
  208.         while (res) {
  209.             switch(res[2]) {
  210.             case "maxdepth":   case "md":   _maxDepth   = int(res[3]); break;
  211.             case "maxobjects"case "mo":   _maxObjects = int(res[3]); break;
  212.             case "background"case "seed":  break;
  213.             }
  214.             res = _rexRootOpt.exec(option);
  215.         }
  216.         _rootSequence.callers = parseContent(_rootSequence.callers, content);
  217.         return this;
  218.     }
  219.     /** execute */
  220.     public function exec(mesh:Mesh) : Mesh {
  221.         _mesh = mesh;
  222.         for each (var rule:SSRule in _rules) rule.init();
  223.         _depth = _objects = 0;
  224.         _core.id();
  225.         _exec(_rootSequence);
  226.         return mesh;
  227.     }
  228.     
  229.     /** parse contents of rule. */
  230.     static public function parseContent(rcList:Vector.<SSRuleCaller>, content:String) : Vector.<SSRuleCaller> {
  231.         var res:*, operations:Array = [];
  232.         res = _rexContent.exec(content);
  233.         while (res) {
  234.             if (res[3]) {
  235.                 operations.unshift(new SSOperation(res[2]||1, parseOperation(new Matrix3D(), res[3])));
  236.             } else if (res[4]) {
  237.                 rcList.push(new SSRuleCaller(res[4], operations));
  238.                 operations = [];
  239.             }
  240.             res = _rexContent.exec(content);
  241.         }
  242.         return rcList;
  243.     }
  244.     
  245.     /** parse matrix opreations. */
  246.     static public function parseOperation(matrix:Matrix3D, operation:String) : Matrix3D {
  247.         var res:*, param:Array, p0:Number, p1:Number, p2:Number;
  248.         res = _rexOperate.exec(operation);
  249.         while(res) {
  250.             param = res[2].match(/[\-\d.]+/g);
  251.             if (param) {
  252.                 p0 = Number(param[0]);
  253.                 switch (res[1]) {
  254.                 case 'x':  matrix.prependTranslation(p0,0,0); break;
  255.                 case 'y':  matrix.prependTranslation(0,p0,0); break;
  256.                 case 'z':  matrix.prependTranslation(0,0,p0); break;
  257.                 case 'rx': matrix.prependRotation(p0, Vector3D.X_AXIS); break;
  258.                 case 'ry': matrix.prependRotation(p0, Vector3D.Y_AXIS); break;
  259.                 case 'rz': matrix.prependRotation(p0, Vector3D.Z_AXIS); break;
  260.                 case 's':
  261.                     p1 = (param.length<2) ? p0 : Number(param[1]),
  262.                     p2 = (param.length<3) ? p1 : Number(param[2]);
  263.                     matrix.prependScale(p0, p1, p2);
  264.                     break;
  265.                 case 'm':
  266.                     if (param.length >= 9) {
  267.                         matrix.prepend(new Matrix3D(Vector.<Number>([
  268.                             Number(param[0]), Number(param[1]), Number(param[2]), 0,
  269.                             Number(param[3]), Number(param[4]), Number(param[5]), 0,
  270.                             Number(param[6]), Number(param[7]), Number(param[8]), 0,
  271.                             0,0,0,1
  272.                         ])));
  273.                     }
  274.                     break;
  275.                 }
  276.             }
  277.             res = _rexOperate.exec(operation);
  278.         }
  279.         return matrix;
  280.     }
  281.     
  282.     private function _exec(seq:SSRuleSequence) : void {
  283.         if (_depth < _maxDepth) {
  284.             _depth++;
  285.             if (seq.depth < seq.maxdepth) {
  286.                 seq.depth++;
  287.                 for each (var rc:SSRuleCaller in seq.callers) $s(rc, rc.operations.length-1);
  288.                 --seq.depth;
  289.             } else {
  290.                 if (seq.finalRuleName) $r(seq.finalRuleName);
  291.             }
  292.             --_depth;
  293.         }
  294.         function $s(rc:SSRuleCaller, index:int) : void {
  295.             var imax:int      = rc.operations[index].repeat, 
  296.                 mat :Matrix3D = rc.operations[index].matrix;
  297.             _core.push();
  298.             for (var i:int=0; i<imax; i++) {
  299.                 _core.mult(mat);
  300.                 if (index) $s(rc, index-1);
  301.                 else $r(rc.ruleName);
  302.             }
  303.             _core.pop();
  304.         }
  305.         function $r(ruleName:String) : void {
  306.             var rule:SSRule = _rules[ruleName];
  307.             if (rule.mesh) {
  308.                 if (++_objects == _maxObjects) _depth = int.MAX_VALUE;
  309.                 _core.project(rule.mesh);
  310.                 _mesh.put(rule.mesh);
  311.             } else {
  312.                 _exec(rule.getSequence());
  313.             }
  314.         }
  315.     }
  316. }
  317. class SSRule {
  318.     public var name:String;
  319.     public var mesh:ProjectionMesh = null;
  320.     private var _totalWeight:Number = 0;
  321.     private var _sequences:Vector.<SSRuleSequence> = new Vector.<SSRuleSequence>();
  322.     
  323.     function SSRule(name:String) { this.name = name; }
  324.     
  325.     public function newMesh(mesh:Mesh) : void {
  326.         this.mesh = new ProjectionMesh(mesh);
  327.     }
  328.     
  329.     public function newRule(callers:Vector.<SSRuleCaller>, option:*) : void {
  330.         var seq:SSRuleSequence = new SSRuleSequence(callers, option);
  331.         _sequences.push(seq);
  332.         _totalWeight += seq.weight;
  333.         mesh = null;
  334.     }
  335.     public function init() : void { 
  336.         for each (var seq:SSRuleSequence in _sequences) seq.depth = 0;
  337.     }
  338.     
  339.     public function getSequence() : SSRuleSequence {
  340.         var w:Number = 0, rand:Number = Math.random() * _totalWeight;
  341.         for each (var seq:SSRuleSequence in _sequences) {
  342.             w += seq.weight;
  343.             if (rand <= w) return seq;
  344.         }
  345.         throw new Error("no sequences in rule:" + name);
  346.     }
  347. }
  348. class SSRuleSequence {
  349.     public var callers:Vector.<SSRuleCaller>;
  350.     public var weight:Number;
  351.     public var maxdepth:int;
  352.     public var finalRuleName:String;
  353.     public var depth:int = 0;
  354.     
  355.     function SSRuleSequence(callers:Vector.<SSRuleCaller>, option:*=undefined) {
  356.         option = option || new Object();
  357.         this.callers = callers;
  358.         this.weight = option["w"] || option["weight"] || 1;
  359.         this.maxdepth = option["md"] || option["maxdepth"] || int.MAX_VALUE;
  360.         this.finalRuleName = option[">"] || null;
  361.     }
  362. }
  363. class SSRuleCaller {
  364.     public var ruleName:String, operations:Vector.<SSOperation>;
  365.     function SSRuleCaller(name:String, ope:Array) { 
  366.         ruleName = name;
  367.         if (ope.length == 0) ope = [new SSOperation(1new Matrix3D())];
  368.         operations = Vector.<SSOperation>(ope);
  369.     }
  370. }
  371. class SSOperation {
  372.     public var repeat:int, matrix:Matrix3D;
  373.     function SSOperation(rep:int, mat:Matrix3D) { repeat=rep; matrix=mat; }
  374. }
  375. // 3D Engine
  376. //----------------------------------------------------------------------------------------------------
  377. /** Core */
  378. class Render3D extends Shape {
  379.     /** model view matrix */
  380.     public var matrix:Matrix3D;
  381.     private var _projectionMatrix:Matrix3D;                              // projection matrix
  382.     private var _matrixStac:Vector.<Matrix3D> = new Vector.<Matrix3D>(); // matrix stac
  383.     private var _cmdWire:Vector.<int> = Vector.<int>([1,2]);             // commands to draw wire
  384.     private var _cmdTriangle:Vector.<int> = Vector.<int>([1,2,2]);       // commands to draw triangle
  385.     private var _cmdQuadrangle:Vector.<int> = Vector.<int>([1,2,2,2]);   // commands to draw quadrangle
  386.     private var _data:Vector.<Number> = new Vector.<Number>(8true);    // data to draw shape
  387.     private var _clippingZ:Number;                                       // clipping z value
  388.     private var _depthMap:BitmapData = new BitmapData(256256false);  // texture for depth buffer rendering
  389.     
  390.     /** constructor */
  391.     function Render3D(focus:Number=300, clippingZ:Number=-0.1) {
  392.         var projector:PerspectiveProjection = new PerspectiveProjection()
  393.         projector.focalLength = focus;
  394.         _projectionMatrix = projector.toMatrix3D();
  395.         _clippingZ = -clippingZ;
  396.         matrix = new Matrix3D();
  397.         _matrixStac.length = 1;
  398.         _matrixStac[0] = matrix;
  399.         var u:int, v:int;
  400.         for (v=0; v<256; v++) 
  401.             for (u=0; u<256; u++) 
  402.                 //_depthMap.setPixel(255-u, 255-v, (v<<8)|u);
  403.                 _depthMap.setPixel(255-u, 255-v, (u<<16)|(u<<8)|u);
  404.     }
  405.     // control matrix
  406.     //--------------------------------------------------
  407.     public function clear() : Render3D { matrix = _matrixStac[0]; _matrixStac.length = 1return this; }
  408.     public function push() : Render3D { _matrixStac.push(matrix.clone()); return this; }
  409.     public function pop() : Render3D { matrix = (_matrixStac.length == 1) ? matrix : _matrixStac.pop(); return this; }
  410.     public function id() : Render3D { matrix.identity(); return this; }
  411.     public function t(x:Number, y:Number, z:Number) : Render3D { matrix.prependTranslation(x, y, z); return this; }
  412.     public function tv(v:Vector3D) : Render3D { matrix.prependTranslation(v.x, v.y, v.z); return this; }
  413.     public function s(x:Number, y:Number, z:Number) : Render3D { matrix.prependScale(x, y, z); return this; }
  414.     public function sv(v:Vector3D) : Render3D { matrix.prependScale(v.x, v.y, v.z); return this; }
  415.     public function r(angle:Number, axis:Vector3D) : Render3D { matrix.prependRotation(angle, axis); return this; }
  416.     public function rv(v:Vector3D) : Render3D { matrix.prependRotation(v.w, v); return this; }
  417.     public function rx(angle:Number) : Render3D { matrix.prependRotation(angle, Vector3D.X_AXIS); return this; }
  418.     public function ry(angle:Number) : Render3D { matrix.prependRotation(angle, Vector3D.Y_AXIS); return this; }
  419.     public function rz(angle:Number) : Render3D { matrix.prependRotation(angle, Vector3D.Z_AXIS); return this; }
  420.     public function mult(mat:Matrix3D) : Render3D { matrix.prepend(mat); return this; }
  421.     
  422.     // projections
  423.     //--------------------------------------------------
  424.     /** project */
  425.     public function project(mesh:ProjectionMesh) : Render3D {
  426.         matrix.transformVectors(mesh.base.vertices, mesh.verticesOnWorld);
  427.         var fn:Vector3D, fnw:Vector3D, vs:Vector.<Number> = mesh.verticesOnWorld,
  428.             nearZ:Number = -Number.MAX_VALUE, farZ:Number = _clippingZ,
  429.             flist:Vector.<Face> = mesh.base.faces;
  430.         var m:Vector.<Number> = matrix.rawData, 
  431.             m00:Number = m[0], m01:Number = m[1], m02:Number = m[2], 
  432.             m10:Number = m[4], m11:Number = m[5], m12:Number = m[6], 
  433.             m20:Number = m[8], m21:Number = m[9], m22:Number = m[10];
  434.         mesh.facesProjected.length = 0;
  435.         for each (var f:Face in flist) {
  436.             var i0:int=(f.i0<<1)+f.i0, i1:int=(f.i1<<1)+f.i1, i2:int=(f.i2<<1)+f.i2,
  437.                 x0:Number=vs[i0++], x1:Number=vs[i1++], x2:Number=vs[i2++],
  438.                 y0:Number=vs[i0++], y1:Number=vs[i1++], y2:Number=vs[i2++],
  439.                 z0:Number=vs[i0],   z1:Number=vs[i1],   z2:Number=vs[i2];
  440.             if (z0<_clippingZ && z1<_clippingZ && z2<_clippingZ) {
  441.                 fn  = f.normal;
  442.                 fnw = mesh.normalsProjected[f.index];
  443.                 fnw.x = fn.x * m00 + fn.y * m10 + fn.z * m20;
  444.                 fnw.y = fn.x * m01 + fn.y * m11 + fn.z * m21;
  445.                 fnw.z = fn.x * m02 + fn.y * m12 + fn.z * m22;
  446.                 if (vs[f.gpi-2]*fnw.x + vs[f.gpi-1]*fnw.y + vs[f.gpi]*fnw.z <= 0) {
  447.                     if (nearZ < z0) nearZ = z0;
  448.                     if (nearZ < z1) nearZ = z1;
  449.                     if (nearZ < z2) nearZ = z2;
  450.                     if (farZ  > z0) farZ  = z0;
  451.                     if (farZ  > z1) farZ  = z1;
  452.                     if (farZ  > z2) farZ  = z2;
  453.                     mesh.facesProjected.push(f);
  454.                 }
  455.             }
  456.         }
  457.         mesh.nearZ = nearZ;
  458.         mesh.farZ  = farZ;
  459.         mesh.facesProjected.sort(function(f1:Face, f2:Face):Numberreturn vs[f1.gpi] - vs[f2.gpi]; });
  460.         mesh.indexDirty = true;
  461.         mesh.screenProjected = false;
  462.         return this;
  463.     }
  464.     
  465.     /** project slower than transformVectors() but Vector3D.w considerable. */
  466.     public function projectPoint3D(points:Vector.<Point3D>) : Render3D {
  467.         var m:Vector.<Number> = matrix.rawData, p:Point3D, 
  468.             m00:Number = m[0],  m01:Number = m[1],  m02:Number = m[2], 
  469.             m10:Number = m[4],  m11:Number = m[5],  m12:Number = m[6], 
  470.             m20:Number = m[8],  m21:Number = m[9],  m22:Number = m[10], 
  471.             m30:Number = m[12], m31:Number = m[13], m32:Number = m[14];
  472.         for each (p in points) {
  473.             p.world.x = p.x * m00 + p.y * m10 + p.z * m20 + p.w * m30;
  474.             p.world.y = p.x * m01 + p.y * m11 + p.z * m21 + p.w * m31;
  475.             p.world.z = p.x * m02 + p.y * m12 + p.z * m22 + p.w * m32;
  476.         }
  477.         return this;
  478.     }
  479.     // rendering
  480.     //--------------------------------------------------
  481.     /** render solid */
  482.     public function renderSolid(mesh:ProjectionMesh, light:Light) : Render3D {
  483.         var idx:int, mat:Material, materials:Vector.<Material> = mesh.base.materials,
  484.             vout:Vector.<Number> = mesh.verticesOnScreen;
  485.         if (!mesh.screenProjected) {
  486.             Utils3D.projectVectors(_projectionMatrix, mesh.verticesOnWorld, vout, mesh.base.texCoord);
  487.             mesh.screenProjected = true;
  488.         }
  489.         graphics.clear();
  490.         for each (var face:Face in mesh.facesProjected) {
  491.             mat = materials[face.mat];
  492.             graphics.beginFill(mat.getColor(light, mesh.normalsProjected[face.index]), mat.alpha);
  493.             idx = face.i0<<1;
  494.             _data[0] = vout[idx]; idx++;
  495.             _data[1] = vout[idx];
  496.             idx = face.i1<<1;
  497.             _data[2] = vout[idx]; idx++;
  498.             _data[3] = vout[idx];
  499.             idx = face.i2<<1;
  500.             _data[4] = vout[idx]; idx++;
  501.             _data[5] = vout[idx];
  502.             if (face.i3 == -1) {
  503.                 graphics.drawPath(_cmdTriangle, _data);
  504.             } else {
  505.                 idx = face.i3<<1;
  506.                 _data[6] = vout[idx]; idx++;
  507.                 _data[7] = vout[idx];
  508.                 graphics.drawPath(_cmdQuadrangle, _data);
  509.             }
  510.             graphics.endFill();
  511.         }
  512.         return this;
  513.     }
  514.     
  515.     /** render wireframe */
  516.     public function renderWire(mesh:ProjectionMesh, color:uint, alpha:Number=1, width:Number=1) : Render3D {
  517.         var idx:int, vout:Vector.<Number> = mesh.verticesOnScreen;
  518.         if (!mesh.screenProjected) {
  519.             Utils3D.projectVectors(_projectionMatrix, mesh.verticesOnWorld, vout, mesh.base.texCoord);
  520.             mesh.screenProjected = true;
  521.         }
  522.         graphics.clear();
  523.         graphics.lineStyle(width, color, alpha);
  524.         for each (var wire:Wire in mesh.base.wires) {
  525.             idx = wire.i0<<1;
  526.             _data[0] = vout[idx]; idx++;
  527.             _data[1] = vout[idx];
  528.             idx = wire.i1<<1;
  529.             _data[2] = vout[idx]; idx++;
  530.             _data[3] = vout[idx];
  531.             graphics.drawPath(_cmdWire, _data);
  532.         }
  533.         return this;
  534.     }
  535.     
  536.     /** render with texture */
  537.     public function renderTexture(mesh:ProjectionMesh, texture:BitmapData) : Render3D {
  538.         var vout:Vector.<Number> = mesh.verticesOnScreen;
  539.         if (!mesh.screenProjected) {
  540.             Utils3D.projectVectors(_projectionMatrix, mesh.verticesOnWorld, vout, mesh.base.texCoord);
  541.             mesh.screenProjected = true;
  542.         }
  543.         graphics.clear();
  544.         graphics.beginBitmapFill(texture, nullfalsetrue);
  545.         graphics.drawTriangles(vout, mesh.indicesProjected, mesh.base.texCoord);
  546.         graphics.endFill();
  547.         return this;
  548.     }
  549.     /** render depth buffer */
  550.     public function renderDepth(mesh:ProjectionMesh) : Render3D {
  551.         var i:int, imax:int = mesh.vertexImax, 
  552.             nearZ:Number = (_clippingZ < mesh.nearZ) ? _clippingZ : mesh.nearZ,
  553.             r:Number = 1/(mesh.farZ - nearZ), duvt:Vector.<Number> = _depthUVT;
  554.         duvt.length = 0;
  555.         for (i=2; i<imax; i+=3) duvt.push((mesh.verticesOnWorld[i]-nearZ)*r, 00);
  556.         Utils3D.projectVectors(_projectionMatrix, mesh.verticesOnWorld, mesh.verticesOnScreen, duvt);
  557.         graphics.clear();
  558.         graphics.beginBitmapFill(_depthMap, nullfalsetrue);
  559.         graphics.drawTriangles(mesh.verticesOnScreen, mesh.indicesProjected, duvt);
  560.         graphics.endFill();
  561.         return this;
  562.     }
  563.     private var _depthUVT:Vector.<Number> = new Vector.<Number>();
  564. }
  565. /** Point3D */
  566. class Point3D extends Vector3D {
  567.     public var world:Vector3D;
  568.     function Point3D(x:Number=0, y:Number=0, z:Number=0, w:Number=1) { super(x,y,z,w); world=clone(); }
  569. }
  570. /** Face */
  571. class Face {
  572.     public var index:int, i0:int, i1:int, i2:int, i3:int, gpi:int, mat:int, normal:Vector3D;
  573.     static private var _freeList:Vector.<Face> = new Vector.<Face>();
  574.     static public function free(face:Face) : void { _freeList.push(face); }
  575.     static public function alloc(index:int, i0:int, i1:int, i2:int, i3:int, mat:int) : Face { 
  576.         var f:Face = _freeList.pop() || new Face();
  577.         f.index=index; f.i0=i0; f.i1=i1; f.i2=i2; f.i3=i3; f.gpi=0; f.mat=mat;
  578.         return f;
  579.     }
  580. }
  581. /** Line */
  582. class Wire {
  583.     public var index:int, i0:int, i1:int;
  584.     static private var _freeList:Vector.<Wire> = new Vector.<Wire>();
  585.     static public function free(wire:Wire) : void { _freeList.push(wire); }
  586.     static public function alloc(index:int, i0:int, i1:int) : Wire { 
  587.         var w:Wire = _freeList.pop() || new Wire();
  588.         w.index=index; w.i0=i0; w.i1=i1;
  589.         return w;
  590.     }
  591. }
  592. /** Mesh */
  593. class Mesh {
  594.     public var materials:Vector.<Material>;                 // material list
  595.     public var vertices:Vector.<Number>;                    // vertex
  596.     public var verticesCount:int;                           // vertex count
  597.     public var texCoord:Vector.<Number>;                    // texture coordinate
  598.     public var faces:Vector.<Face> = new Vector.<Face>();   // face list
  599.     public var wires:Vector.<Wire> = new Vector.<Wire>();   // wireframe list
  600.     
  601.     /** constructor */
  602.     function Mesh(materials:Vector.<Material>=null) {
  603.         this.materials = materials;
  604.         this.vertices = new Vector.<Number>();
  605.         this.texCoord = new Vector.<Number>();
  606.         this.verticesCount = 0;
  607.     }
  608.     
  609.     /** clear all faces */
  610.     public function clear() : Mesh {
  611.         for each (var face:Face in faces) Face.free(face);
  612.         faces.length = 0;
  613.         return this;
  614.     }
  615.     
  616.     /** register face */
  617.     public function face(i0:int, i1:int, i2:int, mat:int=0) : Mesh {
  618.         faces.push(Face.alloc(faces.length, i0, i1, i2, -1, mat));
  619.         return this;
  620.     }
  621.     
  622.     /** register quadrangle face. set div=true to divide into 2 triangles. */
  623.     public function qface(i0:int, i1:int, i2:int, i3:int, mat:int=0, div:Boolean=true) : Mesh {
  624.         if (div) {
  625.             faces.push(Face.alloc(faces.length,   i0, i1, i2, -1, mat), 
  626.                        Face.alloc(faces.length+1, i3, i2, i1, -1, mat));
  627.         }
  628.         else faces.push(Face.alloc(faces.length, i0, i1, i3, i2, mat));
  629.         return this;
  630.     }
  631.     
  632.     /** register wire */
  633.     public function wire(i0:int, i1:int) : Mesh {
  634.         wires.push(Wire.alloc(wires.length, i0, i1));
  635.         return this;
  636.     }
  637.     
  638.     /** put mesh on world coordinate. */
  639.     public function put(src:ProjectionMesh, mat:int=-1) : Mesh {
  640.         var i0:int=vertices.length, imax:int=src.vertexImax, flist:Vector.<Face>=src.base.faces;
  641.         vertices.length += imax;
  642.         for (var i:int=0; i<imax; i++) vertices[i0+i] = src.verticesOnWorld[i];
  643.         i0 /= 3;
  644.         for each (var f:Face in flist) {
  645.             i = (mat == -1) ? f.mat : mat;
  646.             if (f.i3==-1) face (f.i0+i0, f.i1+i0, f.i2+i0, i);
  647.             else          qface(f.i0+i0, f.i1+i0, f.i3+i0, f.i2+i0, i, false);
  648.         }
  649.         return this;
  650.     }
  651.     
  652.     /** update face gravity point and normal. create fireframe lines when createWire==true */
  653.     public function updateFaces(createWire:Boolean = false, facetAngle:Number = 180) : Mesh {
  654.         verticesCount = vertices.length/3;
  655.         var vs:Vector.<Number> = vertices;
  656.         for each (var f:Face in faces) {
  657.             f.gpi = vs.length+2;
  658.             var i0:int=(f.i0<<1)+f.i0, i1:int=(f.i1<<1)+f.i1, i2:int=(f.i2<<1)+f.i2;
  659.             var x01:Number=vs[i1]-vs[i0], x02:Number=vs[i2]-vs[i0];
  660.             vs.push((vs[i0++] + vs[i1++] + vs[i2++]) * 0.333333333333);
  661.             var y01:Number=vs[i1]-vs[i0], y02:Number=vs[i2]-vs[i0];
  662.             vs.push((vs[i0++] + vs[i1++] + vs[i2++]) * 0.333333333333);
  663.             var z01:Number=vs[i1]-vs[i0], z02:Number=vs[i2]-vs[i0];
  664.             vs.push((vs[i0++] + vs[i1++] + vs[i2++]) * 0.333333333333);
  665.             f.normal = new Point3D(y02*z01-y01*z02, z02*x01-z01*x02, x02*y01-x01*y02, 0);
  666.             f.normal.normalize();
  667.             if (f.i3 != -1) {
  668.                 var i3:int = (f.i3<<1)+f.i3;
  669.                 vs[f.gpi-2] = vs[f.gpi-2]*0.75 + vs[i3++]*0.25;
  670.                 vs[f.gpi-1] = vs[f.gpi-1]*0.75 + vs[i3++]*0.25;
  671.                 vs[f.gpi]   = vs[f.gpi]  *0.75 + vs[i3]  *0.25;
  672.             }
  673.         }
  674.         if (createWire) {
  675.             var facetCos:Number = Math.cos((180-facetAngle)*57.29577951308232);
  676.             for each (var f0:Face in faces) {
  677.                 _wire(f0, f0.i0, f0.i1);
  678.                 _wire(f0, f0.i1, f0.i2);
  679.                 if (f0.i3==-1) _wire(f0, f0.i2, f0.i0);
  680.                 else { _wire(f0, f0.i2, f0.i3); _wire(f0, f0.i3, f0.i0); }
  681.             }
  682.         }
  683.         return this;
  684.         
  685.         function _wire(f0:Face, i0:int, i1:int) : void {
  686.             var f1:Face = _findFace(i0, i1);
  687.             if (f1==null || facetCos >= f0.normal.dotProduct(f1.normal)) {
  688.                 if (_findWire(i0, i1) == null) wire(i0, i1);
  689.             }
  690.         }
  691.         function _findFace(i0:int, i1:int) : Face {
  692.             for each (var f:Face in faces) {
  693.                 if ((f.i0==i0 && f.i1==i1) || (f.i0==i1 && f.i1==i0) ||
  694.                     (f.i1==i0 && f.i2==i1) || (f.i1==i1 && f.i2==i0)) return f;
  695.                 if (f.i3==-1if ((f.i2==i0 && f.i0==i1) || (f.i2==i1 && f.i0==i0)) return f;
  696.                 else if ((f.i2==i0 && f.i3==i1) || (f.i2==i1 && f.i3==i0) ||
  697.                          (f.i3==i0 && f.i0==i1) || (f.i3==i1 && f.i0==i0)) return f;
  698.             }
  699.             return null;
  700.         }
  701.         function _findWire(i0:int, i1:int) : Wire {
  702.             for each (var w:Wire in wires) {
  703.                 if ((w.i0==i0 && w.i1==i1) || (w.i0==i1 && w.i1==i0)) return w;
  704.             }
  705.             return null;
  706.         }
  707.     }
  708. }
  709. /** mesh for projection */
  710. class ProjectionMesh {
  711.     public var verticesOnWorld:Vector.<Number>;     // vertex on camera coordinate
  712.     public var verticesOnScreen:Vector.<Number>;    // vertex on screen
  713.     public var facesProjected:Vector.<Face>;        // projected face
  714.     public var normalsProjected:Vector.<Vector3D>;  // projected normals
  715.     public var vnormals:Vector.<Vector3D>;          // vertex normal
  716.     public var nearZ:Number, farZ:Number;           // z buffer range
  717.     public var screenProjected:Boolean = false;     // flag to projection on screen
  718.     private var _projectedFaceIndices:Vector.<int> = new Vector.<int>();
  719.     private var _base:Mesh;
  720.     
  721.     /** indices of projected faces */
  722.     public function get indicesProjected() : Vector.<int> {
  723.         var idx:Vector.<int> = _projectedFaceIndices;
  724.         if (idx.length == 0for each (var f:Face in facesProjected) idx.push(f.i0, f.i1, f.i2);
  725.         return idx;
  726.     }
  727.     
  728.     public function set indexDirty(b:Boolean) : void {
  729.         if (b) _projectedFaceIndices.length = 0;
  730.     }
  731.     public function get base() : Mesh { return _base; }
  732.     public function set base(m:Mesh) : void {
  733.         if (m && normalsProjected.length < m.faces.length) {
  734.             var i:int = normalsProjected.length, imax:int = m.faces.length;
  735.             normalsProjected.length = imax;
  736.             for (; i<imax; i++) normalsProjected[i] = new Vector3D();
  737.         }
  738.         _base = m;
  739.     }
  740.     
  741.     public function get vertexImax() : int { return (_base.verticesCount<<1) + _base.verticesCount; }
  742.     
  743.     /** constructor */
  744.     function ProjectionMesh(m:Mesh=null) {
  745.         this.verticesOnWorld = new Vector.<Number>();
  746.         this.verticesOnScreen = new Vector.<Number>();
  747.         this.facesProjected = new Vector.<Face>();
  748.         this.normalsProjected= new Vector.<Vector3D>();
  749.         this.vnormals = null;
  750.         this.base = m;
  751.     }
  752. }
  753. /** Light */
  754. class Light extends Point3D {
  755.     public var halfVector:Vector3D = new Vector3D();
  756.     
  757.     /** constructor (set position) */
  758.     function Light(x:Number=1, y:Number=1, z:Number=1) {
  759.         super(x, y, z, 0);
  760.         normalize();
  761.     }
  762.     /** projection */
  763.     public function transformBy(matrix:Matrix3D) : void {
  764.         world = matrix.deltaTransformVector(this);
  765.         halfVector.x = world.x;
  766.         halfVector.y = world.y;
  767.         halfVector.z = world.z + 1
  768.         halfVector.normalize();
  769.     }
  770. }
  771. /** Material */
  772. class Material extends BitmapData {
  773.     public var alpha:Number = 1;    // The alpha value is available for renderSolid()
  774.     public var doubleSided:int = 0// set doubleSided=-1 if double sided material
  775.     
  776.     /** constructor */
  777.     function Material(dif:int=128, spc:int=128) { super(dif, spc, false); }
  778.     
  779.     /** set color. */
  780.     public function setColor(col:uint, amb:int=64, dif:int=192, spc:int=0,  pow:Number=8) : Material {
  781.         fillRect(rect, col);
  782.         var lmap:LightMap = new LightMap(width, height);
  783.         draw(lmap.diffusion(amb, dif), nullnull"hardlight");
  784.         draw(lmap.specular (spc, pow), nullnull"add");
  785.         lmap.dispose();
  786.         return this;
  787.     }
  788.     
  789.     /** calculate color by light and normal vector. */
  790.     public function getColor(l:Light, n:Vector3D) : uint {
  791.         var dir:Vector3D = l.world, hv:Vector3D = l.halfVector;
  792.         var ln:int = int((dir.x * n.x + dir.y * n.y + dir.z * n.z) * (width-1)),
  793.             hn:int = int((hv.x  * n.x + hv.y  * n.y + hv.z  * n.z) * (height-1));
  794.         if (ln<0) ln = (-ln) & doubleSided;
  795.         if (hn<0) hn = (-hn) & doubleSided;
  796.         return getPixel(ln, hn);
  797.     }
  798. }
  799. class LightMap extends BitmapData {
  800.     function LightMap(dif:int, spc:int) { super(dif, spc, false); }
  801.     
  802.     public function diffusion(amb:int, dif:int) : BitmapData {
  803.         var col:int, rc:Rectangle = new Rectangle(001, height), ipk:Number = 1 / width;
  804.