Forked from: saharan's Texture Mapping(Soft3D 4) diff:12 [wonderfl] Filthy Brown Bricks Texture Mapping gya forked:0favorite:3lines:1346license : MIT License modified : 2011-10-29 03:12:59 Embed Tweet package { import flash.display.*; import flash.events.*; import flash.text.*; //import net.hires.debug.*; import flash.system.Security; [SWF(frameRate = "60", width="465", height="465")] /** * Software rendering in ActionScript3.0 #4 * @author saharan */ public class Main extends Sprite { private var r:Renderer; private var count:uint; private var box:Model; private var t:Texture; public static var debug:TextField; public function Main() { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null):void { Security.loadPolicyFile("http://geffrotin.com/crossdomain.xml"); //Security.loadPolicyFile("http://localhost/crossdomain.xml"); removeEventListener(Event.ADDED_TO_STAGE, init); r = new Renderer(465, 465); t = new Texture(); t.load("http://geffrotin.com/yann/flash/%5Bwonderfl%5D%20texture%20mapping/src/Filthy%20Brown%20Bricks.jpg"); //t.load("http://localhost/yann/flash/%5Bwonderfl%5D%20texture%20mapping/src/Filthy%20Brown%20Bricks.jpg"); // dirx, diry, dirz, red, green, blue // r.light(0).directional(0, 0, 1, 1, 1, 1); r.light(0).directional(2, 0, 1, 0.6, 0.3, 0.3); r.light(1).directional(-2, 0, 1, 0.3, 0.6, 0.3); r.light(2).directional(0, -2, 1, 0.3, 0.3, 0.6); addChild(r.image); // debug = new TextField(); // debug.x = 200; // debug.textColor = 0xffffff; // addChild(debug); // addChild(new Stats()); box = new Model(); box.toBox(1, 1, 1); addEventListener(Event.ENTER_FRAME, frame); } private function frame(e:Event = null):void { count++; r.beginScene(0xffffff); r.material(0.8, 0.8, 1, 20, 0, 1, 1, 1); r.texture(t); r.push(); r.rotateX(count / 70); r.rotateY(count / 75); r.rotateZ(count / 80); r.scale(6, 12, 12); box.render(r); r.pop(); r.push(); r.rotateX(count / 50); r.rotateY(count / 55); r.rotateZ(count / 60); r.scale(12, 12, 6); box.render(r); r.pop(); r.endScene(); } } } import flash.events.*; import flash.display.*; import flash.net.*; import flash.system.*; class Renderer { private var img:BitmapData; private var fBuffer:Vector.<uint>; private var zBuffer:Vector.<Number>; private var bitmap:Bitmap; private var texel:Vector.<uint>; private var texUse:Boolean; private var texWidth:uint; private var texHeight:uint; private var texSize:uint; private var texShift:uint; private var width:uint; private var height:uint; private var aspect:Number; private var width2:uint; private var height2:uint; private var size:uint; private var near:uint; private var far:uint; private var cameraPosition:Vec3D; private var cameraTarget:Vec3D; private var cameraUp:Vec3D; private var worldMatrix:Mat4x4; private var viewMatrix:Mat4x4; private var projectionMatrix:Mat4x4; private var numStacks:int; private var stack:Vector.<Mat4x4>; private var color:Vector.<uint>; private var amb:Number; private var dif:Number; private var spc:Number; private var shn:Number; private var emi:Number; private var r:Number; private var g:Number; private var b:Number; private var lights:Vector.<Light>; private var ambr:Number; private var ambg:Number; private var ambb:Number; private var vtop:RVtx; // for recycle object private var vleft:RVtx; private var vright:RVtx; public function Renderer(width:uint, height:uint) { img = new BitmapData(width, height, false, 0); bitmap = new Bitmap(img); this.width = width; this.height = height; aspect = height / width; size = width * height; width2 = width >> 1; height2 = height >> 1; numStacks = 0; texUse = false; zBuffer = new Vector.<Number>(size, true); fBuffer = new Vector.<uint>(size, true); lights = new Vector.<Light>(8, true); for (var i:int = 0; i < 8; i++) lights[i] = new Light(); stack = new Vector.<Mat4x4>(64, true); worldMatrix = new Mat4x4(); viewMatrix = new Mat4x4(); projectionMatrix = new Mat4x4(); // system initialization lookAt(new Vec3D(0, 0, 50), new Vec3D(0, 0, 0), new Vec3D(0, 1, 0)); perspective(60 * Math.PI / 180, 5, 5000); ambient(0.2, 0.2, 0.2); light(0).directional(0, 0, 1, 1, 1, 1); material(0.8, 0.8, 0, 0, 0, 1, 1, 1); vtop = new RVtx(); vleft = new RVtx(); vright = new RVtx(); color = new Vector.<uint>(9, true); } public function get image():Bitmap { return bitmap; } public function push():void { if(numStacks < 32) { stack[numStacks] = new Mat4x4( worldMatrix.e00, worldMatrix.e01, worldMatrix.e02, worldMatrix.e03, worldMatrix.e10, worldMatrix.e11, worldMatrix.e12, worldMatrix.e13, worldMatrix.e20, worldMatrix.e21, worldMatrix.e22, worldMatrix.e23, worldMatrix.e30, worldMatrix.e31, worldMatrix.e32, worldMatrix.e33); numStacks++; } } public function pop():void { if (numStacks > 0) { numStacks--; worldMatrix = stack[numStacks]; } } public function rotateX(theta:Number):void { var temp:Mat4x4 = new Mat4x4(); temp.rotateX(theta); temp.mulEqualMatrix(worldMatrix); worldMatrix = temp; } public function rotateY(theta:Number):void { var temp:Mat4x4 = new Mat4x4(); temp.rotateY(theta); temp.mulEqualMatrix(worldMatrix); worldMatrix = temp; } public function rotateZ(theta:Number):void { var temp:Mat4x4 = new Mat4x4(); temp.rotateZ(theta); temp.mulEqualMatrix(worldMatrix); worldMatrix = temp; } public function scale(sx:Number, sy:Number, sz:Number):void { var temp:Mat4x4 = new Mat4x4(); temp.scale(sx, sy, sz); temp.mulEqualMatrix(worldMatrix); worldMatrix = temp; } public function translate(tx:Number, ty:Number, tz:Number):void { var temp:Mat4x4 = new Mat4x4(); temp.translate(tx, ty, tz); temp.mulEqualMatrix(worldMatrix); worldMatrix = temp; } public function beginScene(background:uint):void { for (var i:int = 0; i < size; i++) { fBuffer[i] = background; zBuffer[i] = 0; } worldMatrix.identity(); } public function renderPolygon(v1:Vertex, v2:Vertex, v3:Vertex):void { v1.worldPos.setVector(v1.pos.x, v1.pos.y, v1.pos.z); worldMatrix.mulEqualVector(v1.worldPos); v2.worldPos.setVector(v2.pos.x, v2.pos.y, v2.pos.z); worldMatrix.mulEqualVector(v2.worldPos); v3.worldPos.setVector(v3.pos.x, v3.pos.y, v3.pos.z); worldMatrix.mulEqualVector(v3.worldPos); lighting(v1, v2, v3); v1.viewPos.setVector(v1.worldPos.x, v1.worldPos.y, v1.worldPos.z); viewMatrix.mulEqualVector(v1.viewPos); v2.viewPos.setVector(v2.worldPos.x, v2.worldPos.y, v2.worldPos.z); viewMatrix.mulEqualVector(v2.viewPos); v3.viewPos.setVector(v3.worldPos.x, v3.worldPos.y, v3.worldPos.z); viewMatrix.mulEqualVector(v3.viewPos); clipPolygonDepth(v1, v2, v3, 0); } public function light(id:uint):Light { return lights[id]; } public function ambient(r:Number, g:Number, b:Number):void { ambr = r; ambg = g; ambb = b; } public function material(ambient:Number, diffuse:Number, specular:Number, shininess:Number, emission:Number, r:Number, g:Number, b:Number):void { amb = ambient; dif = diffuse; spc = specular; shn = shininess; emi = emission; this.r = r; this.g = g; this.b = b; } public function texture(tex:Texture):void { if (!tex.loaded) { texUse = false; return; } texWidth = tex.width; texHeight = tex.height; texSize = tex.size; texel = tex.texel; texShift = tex.shift; texUse = true; } private function lighting(v1:Vertex, v2:Vertex, v3:Vertex):void { // simple lighting var cr:Number = amb * ambr * r; var cg:Number = amb * ambg * g; var cb:Number = amb * ambb * b; var sr:Number = 0; var sg:Number = 0; var sb:Number = 0; const nor:Vec3D = v2.worldPos.sub(v1.worldPos).cross(v3.worldPos.sub(v2.worldPos)); nor.normalize(); const view:Vec3D = cameraTarget.sub(cameraPosition); view.normalize(); const ref:Vec3D = new Vec3D(); for (var i:int = 0; i < 8; i++) { const light:Light = lights[i]; if (light.type == Light.DISABLED) continue; const lr:Number = light.r; const lg:Number = light.g; const lb:Number = light.b; switch(light.type) { case Light.DIRECTIONAL: // directional light const dot:Number = light.dir.dot(nor) * dif; if (dot > 0) { cr += r * lr * dot; cg += g * lg * dot; cb += b * lb * dot; } if (spc > 0) { // calc reflection vector and specular // ref = vec - 2 * (nor * vec) * nor var dots:Number = 2 * nor.dot(view); ref.setVector(view.x - nor.x * dots, view.y - nor.y * dots, view.z - nor.z * dots); dots = light.dir.dot(ref); if (dots > 0) { dots = Math.pow(dots, shn) * spc; sr += lr * dots; sg += lg * dots; sb += lb * dots; } } break; } } if (cr > 1) cr = 1; if (cg > 1) cg = 1; if (cb > 1) cb = 1; if (sr > 1) sr = 1; if (sg > 1) sg = 1; if (sb > 1) sb = 1; color[0] = cr * 0xff; color[1] = cg * 0xff; color[2] = cb * 0xff; color[3] = sr * 0xff; color[4] = sg * 0xff; color[5] = sb * 0xff; cr += sr; cg += sg; cb += sb; if (cr > 1) cr = 1; if (cg > 1) cg = 1; if (cb > 1) cb = 1; color[6] = cr * 0xff; color[7] = cg * 0xff; color[8] = cb * 0xff; } private function clipPolygonDepth(v1:Vertex, v2:Vertex, v3:Vertex, step:int):void { var flag:int; var c1:Vertex; var c2:Vertex; switch(step) { case 0:// near flag = 0; if (v1.viewPos.z < near) flag |= 1; if (v2.viewPos.z < near) flag |= 2; if (v3.viewPos.z < near) flag |= 4; if (flag != 0) { switch (flag) { case 1:// 1 c1 = interpolate(v1, v2, (near - v1.viewPos.z) / (v2.viewPos.z - v1.viewPos.z), false); c2 = interpolate(v1, v3, (near - v1.viewPos.z) / (v3.viewPos.z - v1.viewPos.z), false); c1.viewPos.z = near; c2.viewPos.z = near; clipPolygonDepth(c1, v2, v3, 1); clipPolygonDepth(c1, v3, c2, 1); return; case 2:// 2 c1 = interpolate(v2, v3, (near - v2.viewPos.z) / (v3.viewPos.z - v2.viewPos.z), false); c2 = interpolate(v2, v1, (near - v2.viewPos.z) / (v1.viewPos.z - v2.viewPos.z), false); c1.viewPos.z = near; c2.viewPos.z = near; clipPolygonDepth(c1, v3, v1, 1); clipPolygonDepth(c1, v1, c2, 1); return; case 3:// 1 2 c1 = interpolate(v1, v3, (near - v1.viewPos.z) / (v3.viewPos.z - v1.viewPos.z), false); c2 = interpolate(v2, v3, (near - v2.viewPos.z) / (v3.viewPos.z - v2.viewPos.z), false); c1.viewPos.z = near; c2.viewPos.z = near; clipPolygonDepth(c1, c2, v3, 1); return; case 4:// 3 c1 = interpolate(v3, v1, (near - v3.viewPos.z) / (v1.viewPos.z - v3.viewPos.z), false); c2 = interpolate(v3, v2, (near - v3.viewPos.z) / (v2.viewPos.z - v3.viewPos.z), false); c1.viewPos.z = near; c2.viewPos.z = near; clipPolygonDepth(c1, v1, v2, 1); clipPolygonDepth(c1, v2, c2, 1); return; case 5:// 3 1 c1 = interpolate(v3, v2, (near - v3.viewPos.z) / (v2.viewPos.z - v3.viewPos.z), false); c2 = interpolate(v1, v2, (near - v1.viewPos.z) / (v2.viewPos.z - v1.viewPos.z), false); c1.viewPos.z = near; c2.viewPos.z = near; clipPolygonDepth(c1, c2, v2, 1); return; case 6:// 2 3 c1 = interpolate(v2, v1, (near - v2.viewPos.z) / (v1.viewPos.z - v2.viewPos.z), false); c2 = interpolate(v3, v1, (near - v3.viewPos.z) / (v1.viewPos.z - v3.viewPos.z), false); c1.viewPos.z = near; c2.viewPos.z = near; clipPolygonDepth(c1, c2, v1, 1); return; case 7:// 1 2 3 return; } } case 1:// far flag = 0; if (v1.viewPos.z > far) flag |= 1; if (v2.viewPos.z > far) flag |= 2; if (v3.viewPos.z > far) flag |= 4; if (flag != 0) { switch (flag) { case 1:// 1 c1 = interpolate(v1, v2, (far - v1.viewPos.z) / (v2.viewPos.z - v1.viewPos.z), false); c2 = interpolate(v1, v3, (far - v1.viewPos.z) / (v3.viewPos.z - v1.viewPos.z), false); c1.viewPos.z = far; c2.viewPos.z = far; clipPolygonScreen(c1, v2, v3, 0); clipPolygonScreen(c1, v3, c2, 0); return; case 2:// 2 c1 = interpolate(v2, v3, (far - v2.viewPos.z) / (v3.viewPos.z - v2.viewPos.z), false); c2 = interpolate(v2, v1, (far - v2.viewPos.z) / (v1.viewPos.z - v2.viewPos.z), false); c1.viewPos.z = far; c2.viewPos.z = far; clipPolygonScreen(c1, v3, v1, 0); clipPolygonScreen(c1, v1, c2, 0); return; case 3:// 1 2 c1 = interpolate(v1, v3, (far - v1.viewPos.z) / (v3.viewPos.z - v1.viewPos.z), false); c2 = interpolate(v2, v3, (far - v2.viewPos.z) / (v3.viewPos.z - v2.viewPos.z), false); c1.viewPos.z = far; c2.viewPos.z = far; clipPolygonScreen(c1, c2, v3, 0); return; case 4:// 3 c1 = interpolate(v3, v1, (far - v3.viewPos.z) / (v1.viewPos.z - v3.viewPos.z), false); c2 = interpolate(v3, v2, (far - v3.viewPos.z) / (v2.viewPos.z - v3.viewPos.z), false); c1.viewPos.z = far; c2.viewPos.z = far; clipPolygonScreen(c1, v1, v2, 0); clipPolygonScreen(c1, v2, c2, 0); return; case 5:// 3 1 c1 = interpolate(v3, v2, (far - v3.viewPos.z) / (v2.viewPos.z - v3.viewPos.z), false); c2 = interpolate(v1, v2, (far - v1.viewPos.z) / (v2.viewPos.z - v1.viewPos.z), false); c1.viewPos.z = far; c2.viewPos.z = far; clipPolygonScreen(c1, c2, v2, 0); return; case 6:// 2 3 c1 = interpolate(v2, v1, (far - v2.viewPos.z) / (v1.viewPos.z - v2.viewPos.z), false); c2 = interpolate(v3, v1, (far - v3.viewPos.z) / (v1.viewPos.z - v3.viewPos.z), false); c1.viewPos.z = far; c2.viewPos.z = far; clipPolygonScreen(c1, c2, v1, 0); return; case 7:// 1 2 3 return; } } } clipPolygonScreen(v1, v2, v3, 0); } private function clipPolygonScreen(v1:Vertex, v2:Vertex, v3:Vertex, step:int):void { var flag:int; var c1:Vertex; var c2:Vertex; switch(step) { case 0:// left { // transform var invW:Number; v1.projPos.setVector(v1.viewPos.x, v1.viewPos.y, v1.viewPos.z, 1); projectionMatrix.mulEqualVector(v1.projPos); invW = 1 / v1.projPos.w; v1.projPos.x *= invW; v1.projPos.y *= invW; v1.projPos.z = invW; v1.projPos.x = width2 + v1.projPos.x * width2 >> 0; v1.projPos.y = height2 + v1.projPos.y * height2 >> 0; v2.projPos.setVector(v2.viewPos.x, v2.viewPos.y, v2.viewPos.z); projectionMatrix.mulEqualVector(v2.projPos); invW = 1 / v2.projPos.w; v2.projPos.x *= invW; v2.projPos.y *= invW; v2.projPos.z = invW; v2.projPos.x = width2 + v2.projPos.x * width2 >> 0; v2.projPos.y = height2 + v2.projPos.y * height2 >> 0; v3.projPos.setVector(v3.viewPos.x, v3.viewPos.y, v3.viewPos.z); projectionMatrix.mulEqualVector(v3.projPos); invW = 1 / v3.projPos.w; v3.projPos.x *= invW; v3.projPos.y *= invW; v3.projPos.z = invW; v3.projPos.x = width2 + v3.projPos.x * width2 >> 0; v3.projPos.y = height2 + v3.projPos.y * height2 >> 0; if (texUse) { v1.tu = v1.u * texWidth; v1.tv = v1.v * texHeight; v2.tu = v2.u * texWidth; v2.tv = v2.v * texHeight; v3.tu = v3.u * texWidth; v3.tv = v3.v * texHeight; } // culling if ((v3.projPos.x - v1.projPos.x) * (v2.projPos.y - v1.projPos.y) - (v3.projPos.y - v1.projPos.y) * (v2.projPos.x - v1.projPos.x) < 0) return; } flag = 0; if (v1.projPos.x < 0) flag |= 1; if (v2.projPos.x < 0) flag |= 2; if (v3.projPos.x < 0) flag |= 4; if (flag != 0) { switch (flag) { case 1:// 1 c1 = interpolate(v1, v2, -v1.projPos.x / (v2.projPos.x - v1.projPos.x), true); c2 = interpolate(v1, v3, -v1.projPos.x / (v3.projPos.x - v1.projPos.x), true); c1.projPos.x = 0; c2.projPos.x = 0; clipPolygonScreen(c1, v2, v3, 1); clipPolygonScreen(c1, v3, c2, 1); return; case 2:// 2 c1 = interpolate(v2, v3, -v2.projPos.x / (v3.projPos.x - v2.projPos.x), true); c2 = interpolate(v2, v1, -v2.projPos.x / (v1.projPos.x - v2.projPos.x), true); c1.projPos.x = 0; c2.projPos.x = 0; clipPolygonScreen(c1, v3, v1, 1); clipPolygonScreen(c1, v1, c2, 1); return; case 3:// 1 2 c1 = interpolate(v1, v3, -v1.projPos.x / (v3.projPos.x - v1.projPos.x), true); c2 = interpolate(v2, v3, -v2.projPos.x / (v3.projPos.x - v2.projPos.x), true); c1.projPos.x = 0; c2.projPos.x = 0; clipPolygonScreen(c1, c2, v3, 1); return; case 4:// 3 c1 = interpolate(v3, v1, -v3.projPos.x / (v1.projPos.x - v3.projPos.x), true); c2 = interpolate(v3, v2, -v3.projPos.x / (v2.projPos.x - v3.projPos.x), true); c1.projPos.x = 0; c2.projPos.x = 0; clipPolygonScreen(c1, v1, v2, 1); clipPolygonScreen(c1, v2, c2, 1); return; case 5:// 3 1 c1 = interpolate(v3, v2, -v3.projPos.x / (v2.projPos.x - v3.projPos.x), true); c2 = interpolate(v1, v2, -v1.projPos.x / (v2.projPos.x - v1.projPos.x), true); c1.projPos.x = 0; c2.projPos.x = 0; clipPolygonScreen(c1, c2, v2, 1); return; case 6:// 2 3 c1 = interpolate(v2, v1, -v2.projPos.x / (v1.projPos.x - v2.projPos.x), true); c2 = interpolate(v3, v1, -v3.projPos.x / (v1.projPos.x - v3.projPos.x), true); c1.projPos.x = 0; c2.projPos.x = 0; clipPolygonScreen(c1, c2, v1, 1); return; case 7:// 1 2 3 return; } } case 1:// right flag = 0; if (v1.projPos.x > width) flag |= 1; if (v2.projPos.x > width) flag |= 2; if (v3.projPos.x > width) flag |= 4; if (flag != 0) { switch (flag) { case 1:// 1 c1 = interpolate(v1, v2, (width - v1.projPos.x) / (v2.projPos.x - v1.projPos.x), true); c2 = interpolate(v1, v3, (width - v1.projPos.x) / (v3.projPos.x - v1.projPos.x), true); c1.projPos.x = width; c2.projPos.x = width; clipPolygonScreen(c1, v2, v3, 2); clipPolygonScreen(c1, v3, c2, 2); return; case 2:// 2 c1 = interpolate(v2, v3, (width - v2.projPos.x) / (v3.projPos.x - v2.projPos.x), true); c2 = interpolate(v2, v1, (width - v2.projPos.x) / (v1.projPos.x - v2.projPos.x), true); c1.projPos.x = width; c2.projPos.x = width; clipPolygonScreen(c1, v3, v1, 2); clipPolygonScreen(c1, v1, c2, 2); return; case 3:// 1 2 c1 = interpolate(v1, v3, (width - v1.projPos.x) / (v3.projPos.x - v1.projPos.x), true); c2 = interpolate(v2, v3, (width - v2.projPos.x) / (v3.projPos.x - v2.projPos.x), true); c1.projPos.x = width; c2.projPos.x = width; clipPolygonScreen(c1, c2, v3, 2); return; case 4:// 3 c1 = interpolate(v3, v1, (width - v3.projPos.x) / (v1.projPos.x - v3.projPos.x), true); c2 = interpolate(v3, v2, (width - v3.projPos.x) / (v2.projPos.x - v3.projPos.x), true); c1.projPos.x = width; c2.projPos.x = width; clipPolygonScreen(c1, v1, v2, 2); clipPolygonScreen(c1, v2, c2, 2); return; case 5:// 3 1 c1 = interpolate(v3, v2, (width - v3.projPos.x) / (v2.projPos.x - v3.projPos.x), true); c2 = interpolate(v1, v2, (width - v1.projPos.x) / (v2.projPos.x - v1.projPos.x), true); c1.projPos.x = width; c2.projPos.x = width; clipPolygonScreen(c1, c2, v2, 2); return; case 6:// 2 3 c1 = interpolate(v2, v1, (width - v2.projPos.x) / (v1.projPos.x - v2.projPos.x), true); c2 = interpolate(v3, v1, (width - v3.projPos.x) / (v1.projPos.x - v3.projPos.x), true); c1.projPos.x = width; c2.projPos.x = width; clipPolygonScreen(c1, c2, v1, 2); return; case 7:// 1 2 3 return; } } case 2:// top flag = 0; if (v1.projPos.y < 0) flag |= 1; if (v2.projPos.y < 0) flag |= 2; if (v3.projPos.y < 0) flag |= 4; if (flag != 0) { switch (flag) { case 1:// 1 c1 = interpolate(v1, v2, -v1.projPos.y / (v2.projPos.y - v1.projPos.y), true); c2 = interpolate(v1, v3, -v1.projPos.y / (v3.projPos.y - v1.projPos.y), true); c1.projPos.y = 0; c2.projPos.y = 0; clipPolygonScreen(c1, v2, v3, 3); clipPolygonScreen(c1, v3, c2, 3); return; case 2:// 2 c1 = interpolate(v2, v3, -v2.projPos.y / (v3.projPos.y - v2.projPos.y), true); c2 = interpolate(v2, v1, -v2.projPos.y / (v1.projPos.y - v2.projPos.y), true); c1.projPos.y = 0; c2.projPos.y = 0; clipPolygonScreen(c1, v3, v1, 3); clipPolygonScreen(c1, v1, c2, 3); return; case 3:// 1 2 c1 = interpolate(v1, v3, -v1.projPos.y / (v3.projPos.y - v1.projPos.y), true); c2 = interpolate(v2, v3, -v2.projPos.y / (v3.projPos.y - v2.projPos.y), true); c1.projPos.y = 0; c2.projPos.y = 0; clipPolygonScreen(c1, c2, v3, 3); return; case 4:// 3 c1 = interpolate(v3, v1, -v3.projPos.y / (v1.projPos.y - v3.projPos.y), true); c2 = interpolate(v3, v2, -v3.projPos.y / (v2.projPos.y - v3.projPos.y), true); c1.projPos.y = 0; c2.projPos.y = 0; clipPolygonScreen(c1, v1, v2, 3); clipPolygonScreen(c1, v2, c2, 3); return; case 5:// 3 1 c1 = interpolate(v3, v2, -v3.projPos.y / (v2.projPos.y - v3.projPos.y), true); c2 = interpolate(v1, v2, -v1.projPos.y / (v2.projPos.y - v1.projPos.y), true); c1.projPos.y = 0; c2.projPos.y = 0; clipPolygonScreen(c1, c2, v2, 3); return; case 6:// 2 3 c1 = interpolate(v2, v1, -v2.projPos.y / (v1.projPos.y - v2.projPos.y), true); c2 = interpolate(v3, v1, -v3.projPos.y / (v1.projPos.y - v3.projPos.y), true); c1.projPos.y = 0; c2.projPos.y = 0; clipPolygonScreen(c1, c2, v1, 3); return; case 7:// 1 2 3 return; } } case 3:// bottom flag = 0; if (v1.projPos.y > height) flag |= 1; if (v2.projPos.y > height) flag |= 2; if (v3.projPos.y > height) flag |= 4; if (flag != 0) { switch (flag) { case 1:// 1 c1 = interpolate(v1, v2, (height - v1.projPos.y) / (v2.projPos.y - v1.projPos.y), true); c2 = interpolate(v1, v3, (height - v1.projPos.y) / (v3.projPos.y - v1.projPos.y), true); c1.projPos.y = height; c2.projPos.y = height; renderTriangle(c1, v2, v3); renderTriangle(c1, v3, c2); return; case 2:// 2 c1 = interpolate(v2, v3, (height - v2.projPos.y) / (v3.projPos.y - v2.projPos.y), true); c2 = interpolate(v2, v1, (height - v2.projPos.y) / (v1.projPos.y - v2.projPos.y), true); c1.projPos.y = height; c2.projPos.y = height; renderTriangle(c1, v3, v1); renderTriangle(c1, v1, c2); return; case 3:// 1 2 c1 = interpolate(v1, v3, (height - v1.projPos.y) / (v3.projPos.y - v1.projPos.y), true); c2 = interpolate(v2, v3, (height - v2.projPos.y) / (v3.projPos.y - v2.projPos.y), true); c1.projPos.y = height; c2.projPos.y = height; renderTriangle(c1, c2, v3); return; case 4:// 3 c1 = interpolate(v3, v1, (height - v3.projPos.y) / (v1.projPos.y - v3.projPos.y), true); c2 = interpolate(v3, v2, (height - v3.projPos.y) / (v2.projPos.y - v3.projPos.y), true); c1.projPos.y = height; c2.projPos.y = height; renderTriangle(c1, v1, v2); renderTriangle(c1, v2, c2); return; case 5:// 3 1 c1 = interpolate(v3, v2, (height - v3.projPos.y) / (v2.projPos.y - v3.projPos.y), true); c2 = interpolate(v1, v2, (height - v1.projPos.y) / (v2.projPos.y - v1.projPos.y), true); c1.projPos.y = height; c2.projPos.y = height; renderTriangle(c1, c2, v2); return; case 6:// 2 3 c1 = interpolate(v2, v1, (height - v2.projPos.y) / (v1.projPos.y - v2.projPos.y), true); c2 = interpolate(v3, v1, (height - v3.projPos.y) / (v1.projPos.y - v3.projPos.y), true); c1.projPos.y = height; c2.projPos.y = height; renderTriangle(c1, c2, v1); return; case 7:// 1 2 3 return; } } } renderTriangle(v1, v2, v3); } private function interpolate(v1:Vertex, v2:Vertex, t:Number, screen:Boolean):Vertex { var v3:Vertex = new Vertex(); // v3.worldPos.x = v1.worldPos.x + (v2.worldPos.x - v1.worldPos.x) * t; // v3.worldPos.y = v1.worldPos.y + (v2.worldPos.y - v1.worldPos.y) * t; // v3.worldPos.z = v1.worldPos.z + (v2.worldPos.z - v1.worldPos.z) * t; if(screen) { v3.projPos.x = (v1.projPos.x + (v2.projPos.x - v1.projPos.x) * t) >> 0; v3.projPos.y = (v1.projPos.y + (v2.projPos.y - v1.projPos.y) * t) >> 0; v3.projPos.z = v1.projPos.z + (v2.projPos.z - v1.projPos.z) * t; v3.tu = v1.tu + (v2.tu - v1.tu) * t; v3.tv = v1.tv + (v2.tv - v1.tv) * t; } else { v3.viewPos.x = v1.viewPos.x + (v2.viewPos.x - v1.viewPos.x) * t; v3.viewPos.y = v1.viewPos.y + (v2.viewPos.y - v1.viewPos.y) * t; v3.viewPos.z = v1.viewPos.z + (v2.viewPos.z - v1.viewPos.z) * t; v3.u = v1.u + (v2.u - v1.u) * t; v3.v = v1.v + (v2.v - v1.v) * t; } return v3; } private function renderTriangle(v1:Vertex, v2:Vertex, v3:Vertex):void { if (v1.projPos.y < v2.projPos.y) { if (v2.projPos.y < v3.projPos.y) { vtop.reset(v1.projPos.x, v1.projPos.y, v1.projPos.z, v1.tu, v1.tv); vleft.reset(v2.projPos.x, v2.projPos.y, v2.projPos.z, v2.tu, v2.tv); vright.reset(v3.projPos.x, v3.projPos.y, v3.projPos.z, v3.tu, v3.tv); } else if (v1.projPos.y < v3.projPos.y) { vtop.reset(v1.projPos.x, v1.projPos.y, v1.projPos.z, v1.tu, v1.tv); vleft.reset(v3.projPos.x, v3.projPos.y, v3.projPos.z, v3.tu, v3.tv); vright.reset(v2.projPos.x, v2.projPos.y, v2.projPos.z, v2.tu, v2.tv); } else { vtop.reset(v3.projPos.x, v3.projPos.y, v3.projPos.z, v3.tu, v3.tv); vleft.reset(v1.projPos.x, v1.projPos.y, v1.projPos.z, v1.tu, v1.tv); vright.reset(v2.projPos.x, v2.projPos.y, v2.projPos.z, v2.tu, v2.tv); } } else { if (v2.projPos.y > v3.projPos.y) { vtop.reset(v3.projPos.x, v3.projPos.y, v3.projPos.z, v3.tu, v3.tv); vleft.reset(v2.projPos.x, v2.projPos.y, v2.projPos.z, v2.tu, v2.tv); vright.reset(v1.projPos.x, v1.projPos.y, v1.projPos.z, v1.tu, v1.tv); } else if (v1.projPos.y > v3.projPos.y) { vtop.reset(v2.projPos.x, v2.projPos.y, v2.projPos.z, v2.tu, v2.tv); vleft.reset(v3.projPos.x, v3.projPos.y, v3.projPos.z, v3.tu, v3.tv); vright.reset(v1.projPos.x, v1.projPos.y, v1.projPos.z, v1.tu, v1.tv); } else { vtop.reset(v2.projPos.x, v2.projPos.y, v2.projPos.z, v2.tu, v2.tv); vleft.reset(v1.projPos.x, v1.projPos.y, v1.projPos.z, v1.tu, v1.tv); vright.reset(v3.projPos.x, v3.projPos.y, v3.projPos.z, v3.tu, v3.tv); } } var min:int = vtop.y + 0.5; var mid:int = vleft.y + 0.5; var max:int = vright.y + 0.5; if ((vleft.x - vtop.x) / (vleft.y - vtop.y) > (vright.x - vtop.x) / (vright.y - vtop.y)) { var temp:RVtx = vleft; vleft = vright; vright = temp; } if (min == max) return; if (texUse) renderFlatTexture(vtop, vleft, vright, min, mid, max); else renderFlat(vtop, vleft, vright, min, mid, max); } private function renderFlat(top:RVtx, left:RVtx, right:RVtx, min:int, mid:int, max:int):void { var invLength:Number; const zBuffer:Vector.<Number> = this.zBuffer; const fBuffer:Vector.<uint> = this.fBuffer; var colorRGB:uint = color[6] << 16 | color[7] << 8 | color[8]; // thickness var t:Number = (right.x - top.x) * (left.y - top.y) - (left.x - top.x) * (right.y - top.y); if (t == 0) return; t = 1 / t; // in scanline var lLength:int = left.y - top.y; var rLength:int = right.y - top.y; var lineZ:Number; const addLineZ:Number = ((right.z - top.z) * lLength - (left.z - top.z) * rLength) * t * 0xffffff; // left data var lY:int = left.y; invLength = 1 / lLength; var lX:Number = top.x; var lAddX:Number = (left.x - top.x) * invLength; var lZ:Number = top.z; var lAddZ:Number = (left.z - top.z) * invLength; // right data var rY:int = right.y; invLength = 1 / rLength; var rX:Number = top.x; var rAddX:Number = (right.x - top.x) * invLength; var rZ:Number = top.z; var rAddZ:Number = (right.z - top.z) * invLength; var y:int = min; var offset:int = min * width; while (y < max) { if (y == mid) { // flip left and right if (lY == rY) return; if (y == lY) { lLength = right.y - left.y; invLength = 1 / lLength; lX = left.x; lAddX = (right.x - left.x) * invLength; lZ = left.z; lAddZ = (right.z - left.z) * invLength; } if (y == rY) { rLength = left.y - right.y; invLength = 1 / rLength; rX = right.x; rAddX = (left.x - right.x) * invLength; rZ = right.z; rAddZ = (left.z - right.z) * invLength; } } const ilx:int = lX; const irx:int = rX; if (irx - ilx > 0) { lineZ = lZ * 0xffffff; var pix:int = offset + ilx; const end:int = offset + irx; while (pix < end) { if (zBuffer[pix] < lineZ) { fBuffer[pix] = colorRGB; zBuffer[pix] = lineZ; } pix++; lineZ += addLineZ; } } lX += lAddX; rX += rAddX; lZ += lAddZ; rZ += rAddZ; offset += width; y++; } } private function renderFlatTexture(top:RVtx, left:RVtx, right:RVtx, min:int, mid:int, max:int):void { var invLength:Number; const zBuffer:Vector.<Number> = this.zBuffer; const fBuffer:Vector.<uint> = this.fBuffer; const texel:Vector.<uint> = this.texel; const maskU:uint = texWidth - 1; const maskV:uint = texHeight - 1; const shift:uint = texShift; const cr:uint = color[0] + 1; // + 1 はビット演算のため const cg:uint = color[1] + 1; const cb:uint = color[2] + 1; const spc:uint = color[3] << 16 | color[4] << 8 | color[5]; // thickness var t:Number = (right.x - top.x) * (left.y - top.y) - (left.x - top.x) * (right.y - top.y); if (t == 0) return; t = 1 / t; // in scanline var lLength:int = left.y - top.y; var rLength:int = right.y - top.y; var lineZ:Number; var lineU:Number; var lineV:Number; const addLineZ:Number = ((right.z - top.z) * lLength - (left.z - top.z) * rLength) * t * 0xffffff; const addLineU:Number = ((right.u - top.u) * lLength - (left.u - top.u) * rLength) * t * 0xffff; const addLineV:Number = ((right.v - top.v) * lLength - (left.v - top.v) * rLength) * t * 0xffff; // left data var lY:int = left.y; invLength = 1 / lLength; var lX:Number = top.x; var lAddX:Number = (left.x - top.x) * invLength; var lZ:Number = top.z; var lAddZ:Number = (left.z - top.z) * invLength; var lU:Number = top.u; var lAddU:Number = (left.u - top.u) * invLength; var lV:Number = top.v; var lAddV:Number = (left.v - top.v) * invLength; // right data var rY:int = right.y; invLength = 1 / rLength; var rX:Number = top.x; var rAddX:Number = (right.x - top.x) * invLength; var rZ:Number = top.z; var rAddZ:Number = (right.z - top.z) * invLength; var rU:Number = top.u; var rAddU:Number = (right.u - top.u) * invLength; var rV:Number = top.u; var rAddV:Number = (right.v - top.v) * invLength; var y:int = min; var offset:int = min * width; while (y < max) { if (y == mid) { // flip left and right if (lY == rY) return; if (y == lY) { lLength = right.y - left.y; invLength = 1 / lLength; lX = left.x; lAddX = (right.x - left.x) * invLength; lZ = left.z; lAddZ = (right.z - left.z) * invLength; lU = left.u; lAddU = (right.u - left.u) * invLength; lV = left.v; lAddV = (right.v - left.v) * invLength; } if (y == rY) { rLength = left.y - right.y; invLength = 1 / rLength; rX = right.x; rAddX = (left.x - right.x) * invLength; rZ = right.z; rAddZ = (left.z - right.z) * invLength; rU = right.u; rAddU = (left.u - right.u) * invLength; rV = right.v; rAddV = (left.v - right.v) * invLength; } } const ilx:int = lX; const irx:int = rX; if (irx - ilx > 0) { lineZ = lZ * 0xffffff; lineU = lU * 0xffff; lineV = lV * 0xffff; var pix:int = offset + ilx; const end:int = offset + irx; while (pix < end) { if (zBuffer[pix] < lineZ) { var col:uint = texel[lineU >> 16 & maskU | (lineV >> 16 & maskV) << shift]; col = (col & 0xff0000) * cr >> 8 & 0xff0000 | (col & 0xff00) * cg >> 8 & 0xff00 | (col & 0xff) * cb >> 8 & 0xff; var temp:uint = (col & spc) + ((col ^ spc) >> 1 & 0x7f7f7f) & 0x808080; var mask:uint = (temp << 1) - (temp >> 7); fBuffer[pix] = col + spc - mask | mask; zBuffer[pix] = lineZ; } pix++; lineZ += addLineZ; lineU += addLineU; lineV += addLineV; } } lX += lAddX; rX += rAddX; lU += lAddU; rU += rAddU; lV += lAddV; rV += rAddV; lZ += lAddZ; rZ += rAddZ; offset += width; y++; } } public function renderPoint(vertex:Vec3D):void { worldMatrix.mulEqualVector(vertex); viewMatrix.mulEqualVector(vertex); projectionMatrix.mulEqualVector(vertex); var invW:Number = 1 / vertex.w; vertex.x *= invW; vertex.y *= invW; vertex.z *= invW; vertex.x = (width2 + vertex.x * width2) >> 0; vertex.y = (height2 + vertex.y * height2) >> 0; if (vertex.x >= 0 && vertex.x < width && vertex.y >= 0 && vertex.y < height) { var index:uint = vertex.y * width + vertex.x; fBuffer[index] = 0xffffff; } } public function endScene():void { img.setVector(img.rect, fBuffer); } public function lookAt(position:Vec3D, target:Vec3D, up:Vec3D):void { cameraPosition = position; cameraTarget = target; cameraUp = up; var axisZ:Vec3D = cameraTarget.sub(cameraPosition); axisZ.normalize(); var axisX:Vec3D = cameraUp.cross(axisZ); axisX.normalize(); var axisY:Vec3D = axisZ.cross(axisX); viewMatrix.e00 = axisX.x; viewMatrix.e01 = axisY.x; viewMatrix.e02 = axisZ.x; viewMatrix.e03 = 0; viewMatrix.e10 = axisX.y; viewMatrix.e11 = axisY.y; viewMatrix.e12 = axisZ.y; viewMatrix.e13 = 0; viewMatrix.e20 = axisX.z; viewMatrix.e21 = axisY.z; viewMatrix.e22 = axisZ.z; viewMatrix.e23 = 0; viewMatrix.e30 = -axisX.dot(cameraPosition); viewMatrix.e31 = -axisY.dot(cameraPosition); viewMatrix.e32 = -axisZ.dot(cameraPosition); viewMatrix.e33 = 1; } public function perspective(fovY:Number, near:Number, far:Number):void { this.near = near; this.far = far; var h:Number = Math.cos(fovY * 0.5) / Math.sin(fovY * 0.5); var w:Number = h * aspect; var ffn:Number = far / (far - near); projectionMatrix.e00 = w; projectionMatrix.e01 = 0; projectionMatrix.e02 = 0; projectionMatrix.e03 = 0; projectionMatrix.e10 = 0; projectionMatrix.e11 = h; projectionMatrix.e12 = 0; projectionMatrix.e13 = 0; projectionMatrix.e20 = 0; projectionMatrix.e21 = 0; projectionMatrix.e22 = ffn; projectionMatrix.e23 = 1; projectionMatrix.e30 = 0; projectionMatrix.e31 = 0; projectionMatrix.e32 = -near * ffn; projectionMatrix.e33 = 0; } } class Light { public static const DISABLED:uint = 0; public static const DIRECTIONAL:uint = 1; public var dir:Vec3D; public var pos:Vec3D; public var r:Number; public var g:Number; public var b:Number; public var type:uint; public function Light() { type = DISABLED; dir = new Vec3D(); pos = new Vec3D(); } public function directional(dx:Number, dy:Number, dz:Number, r:Number, g:Number, b:Number):void { type = DIRECTIONAL; dir.setVector(dx, dy, dz); dir.normalize(); this.r = r; this.g = g; this.b = b; } public function disable():void { type = DISABLED; } } class Model { public var vertices:Vector.<Vertex>; public var faces:Vector.<Vector.<uint>>; public var uvs:Vector.<Vector.<uint>>; public function Model() { vertices = new Vector.<Vertex>(); faces = new Vector.<Vector.<uint>>(); uvs = new Vector.<Vector.<uint>>(); } public function toBox(w:Number, h:Number, d:Number):void { vertices[0] = new Vertex(-w, -h, -d); vertices[1] = new Vertex(w, -h, -d); vertices[2] = new Vertex(w, -h, d); vertices[3] = new Vertex(-w, -h, d); vertices[4] = new Vertex(-w, h, -d); vertices[5] = new Vertex(w, h, -d); vertices[6] = new Vertex(w, h, d); vertices[7] = new Vertex( -w, h, d); for (var i:int = 0; i < 12; i++) initFace(i); setFace(0, 0, 1, 2, 0, 0, 1, 0, 1, 1); setFace(1, 0, 2, 3, 0, 0, 1, 1, 0, 1); setFace(2, 7, 6, 5, 0, 0, 1, 0, 1, 1); setFace(3, 7, 5, 4, 0, 0, 1, 1, 0, 1); setFace(4, 4, 5, 1, 0, 0, 1, 0, 1, 1); setFace(5, 4, 1, 0, 0, 0, 1, 1, 0, 1); setFace(6, 6, 7, 3, 0, 0, 1, 0, 1, 1); setFace(7, 6, 3, 2, 0, 0, 1, 1, 0, 1); setFace(8, 5, 6, 2, 0, 0, 1, 0, 1, 1); setFace(9, 5, 2, 1, 0, 0, 1, 1, 0, 1); setFace(10, 7, 4, 0, 0, 0, 1, 0, 1, 1); setFace(11, 7, 0, 3, 0, 0, 1, 1, 0, 1); } public function initFace(id:uint):void { faces[id] = new Vector.<uint>(3, true); uvs[id] = new Vector.<uint>(6, true); } public function setFace(id:uint, vtx1:uint, vtx2:uint, vtx3:uint, u1:uint = -1, v1:uint = -1, u2:uint = -1, v2:uint = -1, u3:uint = -1, v3:uint = -1):void { faces[id][0] = vtx1; faces[id][1] = vtx2; faces[id][2] = vtx3; uvs[id][0] = u1; uvs[id][1] = v1; uvs[id][2] = u2; uvs[id][3] = v2; uvs[id][4] = u3; uvs[id][5] = v3; } public function render(renderer:Renderer):void { for (var i:int = 0; i < faces.length; i++) { const v1:Vertex = vertices[faces[i][0]]; const v2:Vertex = vertices[faces[i][1]]; const v3:Vertex = vertices[faces[i][2]]; if (uvs[i][0] != -1) { v1.u = uvs[i][0]; v1.v = uvs[i][1]; v2.u = uvs[i][2]; v2.v = uvs[i][3]; v3.u = uvs[i][4]; v3.v = uvs[i][5]; } renderer.renderPolygon(v1, v2, v3); } } } class Vertex { public var pos:Vec3D; public var worldPos:Vec3D; public var viewPos:Vec3D; public var projPos:Vec3D; public var u:Number; public var v:Number; public var tu:Number; public var tv:Number; public function Vertex(x:Number = 0, y:Number = 0, z:Number = 0):void { pos = new Vec3D(x, y, z); worldPos = new Vec3D(); viewPos = new Vec3D(); projPos = new Vec3D(); } } class RVtx { public var x:int; public var y:int; public var z:Number; public var u:Number; public var v:Number; public function RVtx():void { } public function reset(x:Number, y:Number, z:Number, u:Number, v:Number):void { this.x = x; this.y = y; this.z = z; this.u = u; this.v = v; } } class Texture { public var texel:Vector.<uint>; public var width:uint; public var height:uint; public var shift:uint; public var size:uint; public var loaded:Boolean; public function Texture() { loaded = false; } public function load(url:String):void { loaded = false; var bmd:BitmapData = null; var loader:Loader = new Loader(); loader.load(new URLRequest(url), new LoaderContext(true)); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event = null):void { bmd = Bitmap(loader.content).bitmapData; width = bmd.width; height = bmd.height; size = width * height; shift = 0; var i:int; for (i = 0; i < 16; i++) if (((width - 1) & (1 << i)) != 0) shift++; var pix:Vector.<uint> = bmd.getVector(bmd.rect); texel = new Vector.<uint>(size, true); for (i = 0; i < size; i++) texel[i] = pix[i]; loaded = true; }); } } class Vec3D { /* * [x y z w] */ public var x:Number; public var y:Number; public var z:Number; public var w:Number; public function Vec3D(x:Number = 0, y:Number = 0, z:Number = 0, w:Number = 0) { setVector(x, y, z, w); } public function setVector(x:Number = 0, y:Number = 0, z:Number = 0, w:Number = 0):void { this.x = x; this.y = y; this.z = z; this.w = w; } public function add(v:Vec3D):Vec3D { return new Vec3D(x + v.x, y + v.y, z + v.z); } public function addEqual(v:Vec3D):void { x += v.x; y += v.y; z += v.z; } public function sub(v:Vec3D):Vec3D { return new Vec3D(x - v.x, y - v.y, z - v.z); } public function subEqual(v:Vec3D):void { x -= v.x; y -= v.y; z -= v.z; } public function mul(s:Number):Vec3D { return new Vec3D(x * s, y * s, z * s); } public function mulEqual(s:Number):void { x *= s; y *= s; z *= s; } public function dot(v:Vec3D):Number { return x * v.x + y * v.y + z * v.z; } public function cross(v:Vec3D):Vec3D { return new Vec3D(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); } public function length():Number { return Math.sqrt(x * x + y * y + z * z); } public function normalize():void { var length:Number = length(); if (length != 0 && length != 1) { length = 1 / length; x *= length; y *= length; z *= length; } } } class Mat4x4 { /* * [e00 e01 e02 e03] * [e10 e11 e12 e13] * [e20 e21 e22 e23] * [e30 e31 e32 e33] */ public var e00:Number; public var e01:Number; public var e02:Number; public var e03:Number; public var e10:Number; public var e11:Number; public var e12:Number; public var e13:Number; public var e20:Number; public var e21:Number; public var e22:Number; public var e23:Number; public var e30:Number; public var e31:Number; public var e32:Number; public var e33:Number; public function Mat4x4(e00:Number = 1, e01:Number = 0, e02:Number = 0, e03:Number = 0, e10:Number = 0, e11:Number = 1, e12:Number = 0, e13:Number = 0, e20:Number = 0, e21:Number = 0, e22:Number = 1, e23:Number = 0, e30:Number = 0, e31:Number = 0, e32:Number = 0, e33:Number = 1) { setMatrix(e00, e01, e02, e03, e10, e11, e12, e13, e20, e21, e22, e23, e30, e31, e32, e33); } public function identity():void { setMatrix(); } public function setMatrix(e00:Number = 1, e01:Number = 0, e02:Number = 0, e03:Number = 0, e10:Number = 0, e11:Number = 1, e12:Number = 0, e13:Number = 0, e20:Number = 0, e21:Number = 0, e22:Number = 1, e23:Number = 0, e30:Number = 0, e31:Number = 0, e32:Number = 0, e33:Number = 1):void { this.e00 = e00; this.e01 = e01; this.e02 = e02; this.e03 = e03; this.e10 = e10; this.e11 = e11; this.e12 = e12; this.e13 = e13; this.e20 = e20; this.e21 = e21; this.e22 = e22; this.e23 = e23; this.e30 = e30; this.e31 = e31; this.e32 = e32; this.e33 = e33; } public function rotateX(theta:Number):void { var sin:Number = Math.sin(theta); var cos:Number = Math.cos(theta); var m:Mat4x4 = new Mat4x4(); m.e11 = cos; m.e12 = sin; m.e21 = -sin; m.e22 = cos; mulEqualMatrix(m); } public function rotateY(theta:Number):void { var sin:Number = Math.sin(theta); var cos:Number = Math.cos(theta); var m:Mat4x4 = new Mat4x4(); m.e00 = cos; m.e02 = sin; m.e20 = -sin; m.e22 = cos; mulEqualMatrix(m); } public function rotateZ(theta:Number):void { var sin:Number = Math.sin(theta); var cos:Number = Math.cos(theta); var m:Mat4x4 = new Mat4x4(); m.e00 = cos; m.e01 = -sin; m.e10 = sin; m.e11 = cos; mulEqualMatrix(m); } public function translate(tx:Number, ty:Number, tz:Number):void { var m:Mat4x4 = new Mat4x4(); m.e30 = tx; m.e31 = ty; m.e32 = tz; mulEqualMatrix(m); } public function scale(sx:Number, sy:Number, sz:Number):void { var m:Mat4x4 = new Mat4x4(); m.e00 = sx; m.e11 = sy; m.e22 = sz; mulEqualMatrix(m); } public function mulMatrix(m:Mat4x4):Mat4x4 { var t11:Number = e00 * m.e00 + e01 * m.e10 + e02 * m.e20 + e03 * m.e30; var t12:Number = e00 * m.e01 + e01 * m.e11 + e02 * m.e21 + e03 * m.e31; var t13:Number = e00 * m.e02 + e01 * m.e12 + e02 * m.e22 + e03 * m.e32; var t14:Number = e00 * m.e03 + e01 * m.e13 + e02 * m.e23 + e03 * m.e33; var t21:Number = e10 * m.e00 + e11 * m.e10 + e12 * m.e20 + e13 * m.e30; var t22:Number = e10 * m.e01 + e11 * m.e11 + e12 * m.e21 + e13 * m.e31; var t23:Number = e10 * m.e02 + e11 * m.e12 + e12 * m.e22 + e13 * m.e32; var t24:Number = e10 * m.e03 + e11 * m.e13 + e12 * m.e23 + e13 * m.e33; var t31:Number = e20 * m.e00 + e21 * m.e10 + e22 * m.e20 + e23 * m.e30; var t32:Number = e20 * m.e01 + e21 * m.e11 + e22 * m.e21 + e23 * m.e31; var t33:Number = e20 * m.e02 + e21 * m.e12 + e22 * m.e22 + e23 * m.e32; var t34:Number = e20 * m.e03 + e21 * m.e13 + e22 * m.e23 + e23 * m.e33; var t41:Number = e30 * m.e00 + e31 * m.e10 + e32 * m.e20 + e33 * m.e30; var t42:Number = e30 * m.e01 + e31 * m.e11 + e32 * m.e21 + e33 * m.e31; var t43:Number = e30 * m.e02 + e31 * m.e12 + e32 * m.e22 + e33 * m.e32; var t44:Number = e30 * m.e03 + e31 * m.e13 + e32 * m.e23 + e33 * m.e33; return new Mat4x4(t11, t12, t13, t14, t21, t22, t23, t24, t31, t32, t33, t34, t41, t42, t43, t44); } public function mulEqualMatrix(m:Mat4x4):void { var t11:Number = e00 * m.e00 + e01 * m.e10 + e02 * m.e20 + e03 * m.e30; var t12:Number = e00 * m.e01 + e01 * m.e11 + e02 * m.e21 + e03 * m.e31; var t13:Number = e00 * m.e02 + e01 * m.e12 + e02 * m.e22 + e03 * m.e32; var t14:Number = e00 * m.e03 + e01 * m.e13 + e02 * m.e23 + e03 * m.e33; var t21:Number = e10 * m.e00 + e11 * m.e10 + e12 * m.e20 + e13 * m.e30; var t22:Number = e10 * m.e01 + e11 * m.e11 + e12 * m.e21 + e13 * m.e31; var t23:Number = e10 * m.e02 + e11 * m.e12 + e12 * m.e22 + e13 * m.e32; var t24:Number = e10 * m.e03 + e11 * m.e13 + e12 * m.e23 + e13 * m.e33; var t31:Number = e20 * m.e00 + e21 * m.e10 + e22 * m.e20 + e23 * m.e30; var t32:Number = e20 * m.e01 + e21 * m.e11 + e22 * m.e21 + e23 * m.e31; var t33:Number = e20 * m.e02 + e21 * m.e12 + e22 * m.e22 + e23 * m.e32; var t34:Number = e20 * m.e03 + e21 * m.e13 + e22 * m.e23 + e23 * m.e33; var t41:Number = e30 * m.e00 + e31 * m.e10 + e32 * m.e20 + e33 * m.e30; var t42:Number = e30 * m.e01 + e31 * m.e11 + e32 * m.e21 + e33 * m.e31; var t43:Number = e30 * m.e02 + e31 * m.e12 + e32 * m.e22 + e33 * m.e32; var t44:Number = e30 * m.e03 + e31 * m.e13 + e32 * m.e23 + e33 * m.e33; setMatrix(t11, t12, t13, t14, t21, t22, t23, t24, t31, t32, t33, t34, t41, t42, t43, t44); } public function mulVector(v:Vec3D):Vec3D { return new Vec3D(e00 * v.x + e10 * v.y + e20 * v.z + e30, e01 * v.x + e11 * v.y + e21 * v.z + e31, e02 * v.x + e12 * v.y + e22 * v.z + e32, e03 * v.x + e13 * v.y + e23 * v.z + e33); } public function mulEqualVector(v:Vec3D):void { v.setVector(e00 * v.x + e10 * v.y + e20 * v.z + e30, e01 * v.x + e11 * v.y + e21 * v.z + e31, e02 * v.x + e12 * v.y + e22 * v.z + e32, e03 * v.x + e13 * v.y + e23 * v.z + e33); } } Code Fullscreen Preview Fullscreen alexnotkin zmaxlin andrewexex88.. Mapping Security Texture vertices color size shift Math.min mask Math.max Math.cos position background Math.sin frame url Vector type target getVector Bitmap index setVector