/**
* Copyright mutantleg ( http://wonderfl.net/user/mutantleg )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/9rxy
*/
package {
import flash.text.TextField;
import flash.events.Event;
import flash.display.Sprite;
public class FlashTest extends Sprite {
public function FlashTest() {
frust.setPerspective(90, 1, 1, 500);
frust.setPoints(pos, ori, 0,0);
vecCutter[0].setPlane(frust.pa.x, frust.pa.y, frust.pa.z, frust.norma.x, frust.norma.y, frust.norma.z);
vecCutter[1].setPlane(frust.pb.x, frust.pb.y, frust.pb.z, frust.normb.x, frust.normb.y, frust.normb.z);
vecCutter[2].setPlane(frust.pc.x, frust.pc.y, frust.pc.z, frust.normc.x, frust.normc.y, frust.normc.z);
vecCutter[3].setPlane(frust.pd.x, frust.pd.y, frust.pd.z, frust.normd.x, frust.normd.y, frust.normd.z);
vecCutter[4].setPlane(frust.pe.x, frust.pe.y, frust.pe.z, frust.norme.x, frust.norme.y, frust.norme.z);
vecCutter[5].setPlane(frust.pf.x, frust.pf.y, frust.pf.z, frust.normf.x, frust.normf.y, frust.normf.z);
deb = new TextField();
deb.mouseEnabled = false;
deb.width = 320;
deb.height = 240;
addChild(deb);
stage.addEventListener(Event.ENTER_FRAME, onEnter);
}//ctor
public var ang:Number = 0;
public var myTri:xTri = new xTri();
public var deb:TextField;
public var mang:Number = 0;
public function onEnter(e:Event):void
{
graphics.clear();
graphics.lineStyle(2, 0);
deb.text = "";
mang += 0.01;
pos.z = -300 + (Math.cos(mang)*Math.sin(mang)) * 256;
frust.setPerspective(90, 1, 1, 1500);
frust.setPoints(pos, ori, 0,0);
vecCutter[0].setPlane(frust.pa.x, frust.pa.y, frust.pa.z, frust.norma.x, frust.norma.y, frust.norma.z);
vecCutter[1].setPlane(frust.pb.x, frust.pb.y, frust.pb.z, frust.normb.x, frust.normb.y, frust.normb.z);
vecCutter[2].setPlane(frust.pc.x, frust.pc.y, frust.pc.z, frust.normc.x, frust.normc.y, frust.normc.z);
vecCutter[3].setPlane(frust.pd.x, frust.pd.y, frust.pd.z, frust.normd.x, frust.normd.y, frust.normd.z);
vecCutter[4].setPlane(frust.pe.x, frust.pe.y, frust.pe.z, frust.norme.x, frust.norme.y, frust.norme.z);
vecCutter[5].setPlane(frust.pf.x, frust.pf.y, frust.pf.z, frust.normf.x, frust.normf.y, frust.normf.z);
setProjMat(proj, 90, 1, 1, 1500);
setViewMat(view, pos.x, pos.y, pos.z, ori.x, ori.y, ori.z, ori.w);
multMatrix(proj, view, projview);
ang += 0.0003;
myTri.a.setValue(200+Math.cos(ang-1.57)*200,200+Math.sin(ang-1.57)*200,100);
myTri.b.setValue(200+Math.cos(ang)*200,200+Math.sin(ang)*200,100);
myTri.c.setValue(200+Math.cos(ang+1.57)*200,200+Math.sin(ang+1.57)*200,100);
// renderTri(myTri);
drawCut(myTri, 0);
}//onenter
public var pos:xVec = new xVec();
public var ori:xQuat = new xQuat();
public var frust:xFrustum = new xFrustum();
public var vecCutter:Vector.<xCutter> = Vector.<xCutter>([new xCutter(), new xCutter(), new xCutter(), new xCutter(), new xCutter(), new xCutter()]);
public var projview:Vector.<Number> = new Vector.<Number>(16, false);
public var proj:Vector.<Number> = new Vector.<Number>(16, false);
public var view:Vector.<Number> = new Vector.<Number>(16, false);
public function drawCut(tri:xTri, d:int=0):void
{
var cut:xCutter;
var num:int;
if (d >= 6) { renderTri(tri); return; }
cut = vecCutter[d];
num = cut.cutTri(tri);
if (num < 0) { return; }
if (num == 0) { drawCut(tri, d+1); return; }
drawCut(cut.ret1, d+1);
if (num > 1) { drawCut(cut.ret2, d+1);}
}//drawtri
public function renderTri(tri:xTri):void
{
//deb.appendText(" tri ");
var mat:Vector.<Number>;
var w:Number;
var vx:Number;
var vy:Number;
var vz:Number;
var sx:Number;
var sy:Number;
var sx2:Number;
var sy2:Number;
var sx3:Number;
var sy3:Number;
mat = projview;
vx = tri.a.cx;
vy = tri.a.cy;
vz = tri.a.cz;
sx = vx * mat[0] + vy * mat[4] + vz * mat[8] + mat[12];
sy = vx * mat[1] + vy * mat[5] + vz * mat[9] + mat[13];
w = vx * mat[3] + vy * mat[7] + vz * mat[11] + mat[15];
if (w == 0) { w = 0.00001;}
sx /= w;
sy /= w;
vx = tri.b.cx;
vy = tri.b.cy;
vz = tri.b.cz;
sx2 = vx * mat[0] + vy * mat[4] + vz * mat[8] + mat[12];
sy2 = vx * mat[1] + vy * mat[5] + vz * mat[9] + mat[13];
w = vx * mat[3] + vy * mat[7] + vz * mat[11] + mat[15];
if (w == 0) { w = 0.00001;}
sx2 /= w;
sy2 /= w;
vx = tri.c.cx;
vy = tri.c.cy;
vz = tri.c.cz;
sx3 = vx * mat[0] + vy * mat[4] + vz * mat[8] + mat[12];
sy3 = vx * mat[1] + vy * mat[5] + vz * mat[9] + mat[13];
w = vx * mat[3] + vy * mat[7] + vz * mat[11] + mat[15];
if (w == 0) { w = 0.00001;}
sx3 /= w;
sy3 /= w;
sx *= 465;
sy *= 465;
sx2 *= 465;
sy2 *= 465;
sx3 *= 465;
sy3 *= 465;
graphics.beginFill(0, 0.5);
graphics.moveTo(sx, sy);
graphics.lineTo(sx2, sy2);
graphics.lineTo(sx3, sy3);
graphics.lineTo(sx, sy);
graphics.endFill();
/*
graphics.beginFill(0, 0.5);
graphics.moveTo(tri.a.cx+200, tri.a.cy+200);
graphics.lineTo(tri.b.cx+200, tri.b.cy+200);
graphics.lineTo(tri.c.cx+200, tri.c.cy+200);
graphics.lineTo(tri.a.cx+200, tri.a.cy+200);
graphics.endFill();
*/
}//rendertri
public function setProjMat(vec:Vector.<Number>, //m:Matrix3D,
fovdeg:Number = 60.0,
aspect:Number=1.0, nearp:Number = 1.0, farp:Number=1000.0):void
{
//var vec:Vector.<Number> = m.rawData;
var f:Number;
var i:int;
for (i = 0; i < 16; i++) { vec[i] = 0.0; }
f = 1.0 / Math.tan( (fovdeg * (3.1415 / 180.0)) * 0.5 );
if (nearp == 0) { nearp = 0.0001; }
if (farp == 0) { farp = 0.0001; }
vec[0] = f / aspect;
vec[5] = f;
vec[10] = (farp + nearp) / (nearp - farp);
vec[14] = (2.0 * farp * nearp) / (nearp - farp);
vec[11] = -1.0;
vec[15] = 0.0;
// m.rawData = vec;
}//projmatrix
public function setViewMat(vec:Vector.<Number>, //m:Matrix3D,
cx:Number, cy:Number, cz:Number, qx:Number, qy:Number, qz:Number, qw:Number):void
{
var forwx:Number; var forwy:Number; var forwz:Number;
var sidex:Number; var sidey:Number; var sidez:Number;
var upx:Number; var upy:Number; var upz:Number;
var i:int;
//var vec:Vector.<Number> = m.rawData;
for (i = 0; i < 16; i++) { vec[i] = 0.0; }
forwx = 2.0 * ( qx*qz + qy*qw );
forwy = 2.0 * ( qy*qz - qx*qw );
forwz = 1.0 - 2.0 * ( qx*qx + qy*qy );
upx = 2.0 * ( qx*qy - qz*qw );
upy = 1.0 - 2.0 * ( qx*qx + qz*qz );
upz = 2.0 * ( qy * qz + qx * qw );
sidex = 1.0 - 2.0 * ( qy*qy + qz*qz );
sidey = 2.0 * ( qx*qy + qz*qw );
sidez = 2.0 * ( qx * qz - qy * qw );
vec[0] = vec[5] = vec[10] = vec[15] = 1.0;
vec[0] = sidex; vec[4] = sidey; vec[8] = sidez;
vec[1] = upx; vec[5] = upy; vec[9] = upz;
vec[2] = -forwx; vec[6] = -forwy; vec[10] = -forwz;
vec[12] = (sidex *-cx) + (sidey * -cy) + (sidez * -cz);
vec[13] = (upx *-cx) + (upy * -cy) + (upz * -cz);
vec[14] = (-forwx *-cx) + (-forwy * -cy) + (-forwz * -cz);
//m.rawData = vec;
}//setlookat
//only works of 4x4 matrices
public function multMatrix(a:Vector.<Number>, b:Vector.<Number>, r:Vector.<Number>):void
{
var i:int;
for (i = 0; i < 16; i += 4)
{
r[i] = a[0] * b[i] + a[4] * b[i + 1] + a[8] * b[i + 2] + a[12] * b[i + 3];
r[i + 1] = a[1] * b[i] + a[5] * b[i + 1] + a[9] * b[i + 2] + a[13] * b[i + 3];
r[i + 2] = a[2] * b[i] + a[6] * b[i + 1] + a[10] * b[i + 2] + a[14] * b[i + 3];
r[i + 3] = a[3] * b[i] + a[7] * b[i + 1] + a[11] * b[i + 2] + a[15] * b[i + 3];
}//nexti
}//multmat
}//classend
}
internal class xVert
{
public var cx:Number = 0;
public var cy:Number = 0;
public var cz:Number = 0;
public function copyVert(b:xVert):void { cx = b.cx; cy = b.cy; cz = b.cz; }
public function setValue(vx:Number, vy:Number, vz:Number):void
{ cx = vx; cy = vy; cz = vz;}
}//xvert
internal class xTri
{
public var a:xVert = new xVert();
public var b:xVert = new xVert();
public var c:xVert = new xVert();
}//xtri
internal class xCutter
{
public var ret1:xTri = new xTri();
public var ret2:xTri = new xTri();
public var num:int = 0;
public var cx:Number = 0;
public var cy:Number = 0;
public var cz:Number = 0;
public var cnx:Number = 0;
public var cny:Number = 0;
public var cnz:Number = 0;
public function setPlane(x_:Number, y_:Number, z_:Number, nx_:Number, ny_:Number, nz_:Number):void
{
cx = x_;
cy = y_;
cz = z_;
cnx = nx_;
cny = ny_;
cnz = nz_;
}//setplane
public function isFront(tri:xTri):int
{
var ad:Number; var bd:Number; var cd:Number;
ad = (tri.a.cx - cx) *cnx + (tri.a.cy - cy) *cny +(tri.a.cz - cz) *cnz
bd = (tri.b.cx - cx) *cnx + (tri.b.cy - cy) *cny +(tri.b.cz - cz) *cnz
cd = (tri.c.cx - cx) *cnx + (tri.c.cy - cy) *cny +(tri.c.cz - cz) *cnz
if (ad > 0 && bd > 0 && cd > 0) { return 1; } //front of plane
if (ad < 0 && bd < 0 && cd < 0) { return -1; } //behind plane
return 0; //intersect
}//isfront
public function cutTri(tri:xTri):int
{
num = cutTriPlane(tri, cx, cy,cz, cnx, cny, cnz);
return num;
}//cut
public static var tempOut:Vector.<xVert> = Vector.<xVert>([new xVert(), new xVert(), new xVert(), new xVert()]);
public function cutTriPlane(tri:xTri,
px:Number, py:Number, pz:Number,
nx:Number, ny:Number, nz:Number):int
{
var vecOut:Vector.<xVert>;
var it:int;
var i:int;
var ad:Number; var bd:Number; var cd:Number;
var t:Number;
var va:xVert; var vs:xVert;
var da:Number; var ds:Number;
var dw:xVert;
vecOut = tempOut;
ad = (tri.a.cx - px) *nx + (tri.a.cy - py) *ny +(tri.a.cz - pz) *nz
bd = (tri.b.cx - px) *nx + (tri.b.cy - py) *ny +(tri.b.cz - pz) *nz
cd = (tri.c.cx - px) *nx + (tri.c.cy - py) *ny +(tri.c.cz - pz) *nz
if (ad > 0 && bd > 0 && cd > 0) { return 0; } //front of plane
it = 0;
//todo -- unroll later (and by unroll i mean no loop really needed here)
for (i = 0; i < 3; i++)
{
if (i == 0)
{
va = tri.a; vs = tri.c; da = ad; ds = cd;
} else if (i == 1)
{
va = tri.b; vs = tri.a; da = bd; ds = ad;
} else
{
va = tri.c; vs = tri.b; da = cd; ds = bd;
}
if (da > 0 && ds > 0)
{
vecOut[it].copyVert(va);
it += 1;
}
else if (da > 0 || ds > 0)
{
t = da / (nx * (va.cx - vs.cx) + ny * (va.cy - vs.cy) + nz * (va.cz - vs.cz) );
dw = vecOut[it];
dw.cx = va.cx + (vs.cx - va.cx) * t;
dw.cy = va.cy + (vs.cy - va.cy) * t;
dw.cz = va.cz + (vs.cz - va.cz) * t;
it += 1;
if (ds < 0)
{
vecOut[it].copyVert(va);
it += 1;
}
}//endif
}//nexti
if (it < 3) { return -1;}
ret1.a.copyVert(vecOut[0]);
ret1.b.copyVert(vecOut[1]);
ret1.c.copyVert(vecOut[2]);
if (it == 3) { return 1; }
ret2.a.copyVert(vecOut[0]);
ret2.b.copyVert(vecOut[2]);
ret2.c.copyVert(vecOut[3]);
return 2;
}//cuttriplane
}//xcutter
internal class xVec
{
public var x:Number = 0;
public var y:Number = 0;
public var z:Number = 0;
public function xVec(x_:Number = 0, y_:Number = 0, z_:Number = 0):void { x = x_; y = y_; z = z_; }
public function addVec(a:xVec):void { x += a.x; y += a.y; z += a.z; }
public function subVec(a:xVec):void { x -= a.x; y -= a.y; z -= a.z; }
public static function getVecMulNum(a:xVec, b:Number):xVec { return new xVec(a.x * b, a.y * b, a.z * b); }
public function copyVec(a:xVec):void { x = a.x; y = a.y; z = a.z; }
public function mulNum(b:Number):void { x *= b; y *= b; z *= b; }
}//xvec
internal class xQuat
{
public var x:Number = 0;
public var y:Number = 0;
public var z:Number = 0;
public var w:Number = 1;
//multiply by other quaternion
public function mul(b:xQuat):void
{
//temp values
var tx:Number; var ty:Number; var tz:Number; var tw:Number;
tx = (w*b.x + x*b.w + y*b.z - z*b.y),
ty = (w*b.y + y*b.w + z*b.x - x*b.z),
tz = (w*b.z + z*b.w + x*b.y - y*b.x),
tw = (w*b.w - x*b.x - y*b.y - z*b.z);
x = tx; y = ty; z = tz; w = tw;
}//mul
public function normalise():void
{
var mag:Number;
mag = (x * x) + (y * y) + (z * z) + (w * w);
if (mag == 1.0) return; //already normal
if (mag == 0) { x = 0; y = 0; z = 0; w = 1; return; }
mag = 1.0 / Math.sqrt(mag);
x *= mag; y *= mag; z *= mag; w *= mag;
}//norm
public function setVecSide(v:xVec):void
{ v.x = 1.0 - 2.0 * ( y*y + z*z ); v.y = 2.0 * ( x*y + z*w ); v.z = 2.0 * ( x*z - y*w ); }
public function setVecUp(v:xVec):void
{ v.x = 2.0 * ( x*y - z*w ); v.y = 1.0 - 2.0 * ( x*x + z*z ); v.z = 2.0 * ( y*z + x*w ); }
public function setVecFront(v:xVec):void
{ v.x = 2.0 * ( x*z + y*w ); v.y = 2.0 * ( y*z - x*w ); v.z = 1.0 - 2.0 * ( x*x + y*y ); }
}//xquat
internal class xFrustum
{
public function xFrustum()
{
//setPerspective(90, 465 / 465, 1, 500);
setPerspective(90, 1, 1, 500);
}//ctor
public var ftl:xVec=new xVec(), ftr:xVec=new xVec(), fbl:xVec=new xVec(), fbr:xVec=new xVec(); //front points
public var ntl:xVec=new xVec(), ntr:xVec=new xVec(), nbl:xVec=new xVec(), nbr:xVec=new xVec(); //near points
public var pa:xVec=new xVec(), pb:xVec=new xVec(), pc:xVec=new xVec(), pd:xVec=new xVec(), pe:xVec=new xVec(), pf:xVec=new xVec();
public var norma:xVec=new xVec(), normb:xVec=new xVec(), normc:xVec=new xVec(), normd:xVec=new xVec(), norme:xVec=new xVec(), normf:xVec=new xVec();
public var nearWidth:Number, nearHeight:Number;
public var farWidth:Number, farHeight:Number;
public var fov:Number;
public var aspect:Number;
public var nearDist:Number, farDist:Number;
public var ma:xVec = new xVec(), mb:xVec = new xVec();
public function setPerspective( fovdeg_:Number = 90, aspect_:Number=1.33, nearDist_:Number=1, farDist_:Number=300):void
{
//http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-implementation/
//tang = (float)tan(ANG2RAD * angle * 0.5) ;
fov = fovdeg_;
aspect = aspect_;
nearDist = nearDist_;
farDist = farDist_;
var tang:Number;
fov *= 3.1415 / 180.0; //torad
tang = Math.tan(fov * 0.5);
nearHeight = nearDist * tang;
nearWidth = nearHeight * aspect;
farHeight = farDist * tang;
farWidth = farHeight * aspect;
}//setpersp
//public var temp_pos:xVec = new xVec();
//sets the frustum points and planes
//based on a position and orientation
//todo: make mouse coord calculation seperate(?)
public function setPoints( pos:xVec, ori:xQuat, umx:Number=0, umy:Number=0):void
{
//todo .. replace new xVec with static ones
var side:xVec, up:xVec, front:xVec;
side = new xVec();
up = new xVec();
front = new xVec();
ori.setVecFront(front);
ori.setVecSide(side);
ori.setVecUp(up);
var fc:xVec, nc:xVec;
fc = new xVec();
nc = new xVec();
//dividing by two doesnt seem to work out ok
//not sure why they put that in the lighthouse3d tut
var nh:Number, nw:Number, fh:Number, fw:Number;
nh = nearHeight;// * 0.5f;
nw = nearWidth; //* 0.5f;
fh = farHeight; //* 0.5f;
fw = farWidth; //* 0.5f;
var farUp:xVec, farSide:xVec;
var nearUp:xVec, nearSide:xVec;
farUp = new xVec(); farSide = new xVec();
nearUp = new xVec(); nearSide = new xVec();
farUp.copyVec(up); farUp.mulNum(fh);
// farUp = up * fh;
farSide.copyVec(side); farSide.mulNum(fw);
// farSide = side * fw;
nearUp.copyVec(up); nearUp.mulNum(nh);
// nearUp = up * nh;
nearSide.copyVec(side); nearSide.mulNum(nw);
// nearSide = side * nw;
fc.copyVec(front); fc.mulNum(farDist); fc.addVec(pos);
//fc = pos + front * farDist;
ftl.copyVec(fc); ftl.addVec(farUp); ftl.subVec(farSide);
// ftl = fc + farUp - farSide;
ftr.copyVec(fc); ftr.addVec(farUp); ftr.addVec(farSide);
// ftr = fc + farUp + farSide;
fbl.copyVec(fc); fbl.subVec(farUp); fbl.subVec(farSide);
// fbl = fc - farUp - farSide;
fbr.copyVec(fc); fbr.subVec(farUp); fbr.addVec(farSide);
// fbr = fc - farUp + farSide;
nc.copyVec(front); nc.mulNum(nearDist); nc.addVec(pos);
//nc = pos + front * nearDist;
ntl.copyVec(nc); ntl.addVec(nearUp); ntl.subVec(nearSide);
// ntl = nc + nearUp - nearSide;
ntr.copyVec(nc); ntr.addVec(nearUp); ntr.addVec(nearSide);
// ntr = nc + nearUp + nearSide;
nbl.copyVec(nc); nbl.subVec(nearUp); nbl.subVec(nearSide);
// nbl = nc - nearUp - nearSide;
nbr.copyVec(nc); nbr.subVec(nearUp); nbr.addVec(nearSide);
// nbr = nc - nearUp + nearSide;
ma.copyVec(fc); ma.addVec( xVec.getVecMulNum(farUp, umy) ); ma.addVec( xVec.getVecMulNum(farSide, umx) );
//sa = fc + (farUp * umy) + (farSide * umx);
mb.copyVec(nc); mb.addVec( xVec.getVecMulNum(nearUp, umy) ); mb.addVec( xVec.getVecMulNum(nearSide, umx) );
//sb = nc + (nearUp * umy) + (nearSide * umx)
setNormals();
}//setpoints
//todo: i guess it would be enough to do in 2D (?)
public function isSphereInside2(px:Number, py:Number, pz:Number, r:Number):Boolean
{
var dist:Number;
var rad:Number;
rad = -r;
dist = (px-pa.x) * norma.x + (py-pa.y)*norma.y + (pz-pa.z)*norma.z;
if (dist < rad) return false;
dist = (px-pb.x) * normb.x + (py-pb.y)*normb.y + (pz-pb.z)*normb.z;
if (dist < rad) return false;
dist = (px-pc.x) * normc.x + (py-pc.y)*normc.y + (pz-pc.z)*normc.z;
if (dist < rad) return false;
dist = (px-pd.x) * normd.x + (py-pd.y)*normd.y + (pz-pd.z)*normd.z;
if (dist < rad) return false;
dist = (px-pe.x) * norme.x + (py-pe.y)*norme.y + (pz-pe.z)*norme.z;
if (dist < rad) return false;
dist = (px-pf.x) * normf.x + (py-pf.y)*normf.y + (pz-pf.z)*normf.z;
if (dist < rad) return false;
return true;
}//issphereinside
public function isSphereInside(p:xVec, rad:Number):Boolean
{
var dist:Number;
rad = -rad;
dist = (p.x-pa.x) * norma.x + (p.y-pa.y)*norma.y + (p.z-pa.z)*norma.z;
if (dist < rad) return false;
dist = (p.x-pb.x) * normb.x + (p.y-pb.y)*normb.y + (p.z-pb.z)*normb.z;
if (dist < rad) return false;
dist = (p.x-pc.x) * normc.x + (p.y-pc.y)*normc.y + (p.z-pc.z)*normc.z;
if (dist < rad) return false;
dist = (p.x-pd.x) * normd.x + (p.y-pd.y)*normd.y + (p.z-pd.z)*normd.z;
if (dist < rad) return false;
dist = (p.x-pe.x) * norme.x + (p.y-pe.y)*norme.y + (p.z-pe.z)*norme.z;
if (dist < rad) return false;
dist = (p.x-pf.x) * normf.x + (p.y-pf.y)*normf.y + (p.z-pf.z)*normf.z;
if (dist < rad) return false;
return true;
}//issphere_inside
public function isPointInside(p:xVec):Boolean
{
//todo -- opt
//dist variable is not really needed here
//so can jut put the calculations in the if
var dist:Number;
// check distance to planes
// distance = (object position - cam position) dot (plane normal)
//check point distance to near and far planes first
//if its behind any of them we know its outside the frustum
dist = (p.x-pa.x) * norma.x + (p.y-pa.y)*norma.y + (p.z-pa.z)*norma.z;
if (dist < 0) return false;
dist = (p.x-pb.x) * normb.x + (p.y-pb.y)*normb.y + (p.z-pb.z)*normb.z;
if (dist < 0) return false;
dist = (p.x-pc.x) * normc.x + (p.y-pc.y)*normc.y + (p.z-pc.z)*normc.z;
if (dist < 0) return false;
dist = (p.x-pd.x) * normd.x + (p.y-pd.y)*normd.y + (p.z-pd.z)*normd.z;
if (dist < 0) return false;
dist = (p.x-pe.x) * norme.x + (p.y-pe.y)*norme.y + (p.z-pe.z)*norme.z;
if (dist < 0) return false;
dist = (p.x-pf.x) * normf.x + (p.y-pf.y)*normf.y + (p.z-pf.z)*normf.z;
if (dist < 0) return false;
return true;
}//ispinside
public function calcNorm(norm:xVec, c:xVec, d:xVec, e:xVec, f:xVec):void
{
var ax:Number, ay:Number, az:Number;
var bx:Number, by:Number, bz:Number;
var cx:Number, cy:Number, cz:Number;
var dist:Number;
ax = c.x - d.x;
ay = c.y - d.y;
az = c.z - d.z;
bx = e.x - f.x;
by = e.y - f.y;
bz = e.z - f.z;
cx = (ay * bz) - (az * by);
cy = (az * bx) - (ax * bz);
cz = (ax * by) - (ay * bx);
dist = Math.sqrt( (cx * cx) + (cy * cy) + (cz * cz) );
if (dist == 0) { norm.x = 0; norm.y = 0; norm.z = 0; }
else
{
norm.x = cx / dist;
norm.y = cy / dist;
norm.z = cz / dist;
}//endif
}//calcplane
public function setNormals():void
{
//near
pa.x = (ntr.x + nbl.x) * 0.5;
pa.y = (ntr.y + nbl.y) * 0.5;
pa.z = (ntr.z + nbl.z) * 0.5;
calcNorm(norma, ntr, nbr, nbl, ntr);
//far
pb.x = (ftr.x + fbl.x) * 0.5;
pb.y = (ftr.y + fbl.y) * 0.5;
pb.z = (ftr.z + fbl.z) * 0.5;
calcNorm(normb, ftr, fbr, ftr, fbl);
//left
pc.x = (ftl.x + fbl.x + ntl.x + nbl.x) / 4;
pc.y = (ftl.y + fbl.y + ntl.y + nbl.y) / 4;
pc.z = (ftl.z + fbl.z + ntl.z + nbl.z) / 4;
calcNorm(normc, ftl, fbl, ftl, ntl);
//right
pd.x = (ftr.x + fbr.x + ntr.x + nbr.x) / 4;
pd.y = (ftr.y + fbr.y + ntr.y + nbr.y) / 4;
pd.z = (ftr.z + fbr.z + ntr.z + nbr.z) / 4;
calcNorm(normd, ftr, ntr, ftr, fbr);
//top
pe.x = (ftr.x + ftl.x + ntr.x + ntl.x) / 4;
pe.y = (ftr.y + ftl.y + ntr.y + ntl.y) / 4;
pe.z = (ftr.z + ftl.z + ntr.z + ntl.z) / 4;
calcNorm(norme, ftr, ftl, ftr, ntr);
//bottom
pf.x = (fbr.x + fbl.x + nbr.x + nbl.x) / 4;
pf.y = (fbr.y + fbl.y + nbr.y + nbl.y) / 4;
pf.z = (fbr.z + fbl.z + nbr.z + nbl.z) / 4;
calcNorm(normf, fbl, nbl, fbr, fbl);
}//setnormals
}//classend