// OldSchool Tunnel-class for Flash 10 // Petri Leskinen, leskinen[dot]petri[at]luukku.com // August 2008, Espoo, Finland // update September 2nd 2008 // added PerspectiveProjection, Utils3D etc. package { import flash.display.Sprite; import flash.display.BitmapData; import flash.display.GraphicsPathCommand; import flash.display.TriangleCulling; import flash.geom.Vector3D; import flash.geom.PerspectiveProjection; import flash.geom.Matrix3D; import flash.geom.Utils3D; public class Tunnel extends Sprite { public var n:int =20; // divisions in z-depth public var m:int =20; // circular tube is in fact a regular m-polygon public var w:Number = 800; public var h:Number = 600; public var xBending:Number = 0.02; public var yBending:Number = -0.03; public var bitmapData:BitmapData = new BitmapData(1,1,true,0xFFFFFFFF); private var msk:Sprite; private var radius:Number; private var vertices:Vector.; private var indices:Vector.; private var uvtData:Vector.; private var coords3D:Vector.; private var projectedVerts:Vector.; private var bendedVerts:Vector.; private var projectionMatrix:Matrix3D; private var i:int; private var j:int; private static const doublePi:Number = 2.0*Math.PI; // 6.28... public function Tunnel(bmp:BitmapData, _w:Number = 800, _h:Number = 600, _n:int =20, _m:int=20) { bitmapData = bmp; this.w = _w; this.h = _h; this.n = _n; this.m = _m; // minor radius of a polygon // r = R cos(PI/m); radius = 0.5*Math.sqrt(w*w+h*h) / Math.cos(Math.PI/(m-1)); var perspective:PerspectiveProjection= new PerspectiveProjection(); perspective.fieldOfView = 70.0; // camera angle, in degrees projectionMatrix = perspective.toMatrix3D(); // Defining the correct radius for the cone, // so that it fills the rectangle (w,h) on the screen // point (1,0,1) must not be closer to the center that half the diameter var check3D:Vector3D = Utils3D.projectVector( projectionMatrix, new Vector3D(1.0,0.0,1.0) ); radius /= check3D.x; init(); update(); } private function init():void { vertices = new Vector.(); indices = new Vector.(); uvtData = new Vector.(); coords3D = new Vector.(); var x:Number; var y:Number; var z:Number; var w:Number =0.0; var a:Number; var tmp:Number; for (i=0 ; i!=n; i++) { // z starts from the farest end of the tunnel // so there's no need for sorting the 3d-faces in depth z = n-i; tmp = radius*i/(n-1.0); for (j=0; j!=m; j++) { // x,y coordinates, initialize vector size vertices.push(0.0, 0.0); // Texture mapping coordinates // u and v; between 0,0 and 1,1 // w for correcting the perspective projection // (here w=0.0, only to allocate the vector, // where rendered the correct w-values // are counted by Utils3D.projectVectors ) uvtData.push(i/(n-1.0),j/(m-1.0), w); // coords3D: precount the xyz-coordinates // of a cone looking up the z-axis // with radius of 'radius' at bottom, 0.0 at top. // No bending or projection yet a = j/(m-1.0)*doublePi; x = Math.sin(a) *tmp; y = -Math.cos(a) *tmp; coords3D.push(x,y,z); } } // // indices for two triangles, CCW // // ii-----ii+1 // |\ | // | \ | // | \ | // | \| // ii+n---ii+n+1 var ii:int =0; for (i=0 ; i!=n-1; i++) { for (j=0 ; j!=m-1; j++) { indices.push(ii,ii+m+1,ii+1); indices.push(ii+m,ii+m+1,ii++); } ii++; } projectedVerts = new Vector.(vertices.length); bendedVerts = new Vector.(coords3D.length); addMask(); } // 'moving' in tunnel is done by altering the uv-coordinates of the projection // 'we' don't move forward, bitmap moves towards the origin // that's why it's a subtraction for x // adding to y rotates around the axis // // usual values for addX seem very small, // remember that addX = 1.0/bitmapData.width moves 1 pixel forward public function step(addX:Number, addY:Number=0.0):void { for (var i=0; i