package javaforce.gl;
/**
* Represents the frustum (viewable area of a perspective)
*
* @author pquiring
*/
public class GLFrustum {
private GLVector3 ntl, ntr, nbl, nbr, ftl, ftr, fbl, fbr;
private float nearD, farD;
private float nw, nh, fw, fh;
private GLPlane pl[];
private GLVector3 nc, fc, X, Y, Z;
private GLVector3 XX, YY, ZZ;
private GLVector3 _p, _l, _u; //pointers
public GLFrustum() {
ntl = new GLVector3();
ntr = new GLVector3();
nbl = new GLVector3();
nbr = new GLVector3();
ftl = new GLVector3();
ftr = new GLVector3();
fbl = new GLVector3();
fbr = new GLVector3();
nc = new GLVector3();
fc = new GLVector3();
X = new GLVector3();
Y = new GLVector3();
Z = new GLVector3();
XX = new GLVector3();
YY = new GLVector3();
ZZ = new GLVector3();
pl = new GLPlane[6];
for (int a = 0; a < 6; a++) {
pl[a] = new GLPlane();
}
}
private static final float ANG2RAD = (float) Math.PI / 180f;
public void setPerspecive(float angle, float ratio, float near, float far) {
nearD = near;
farD = far;
float tan = (float) Math.tan(angle * ANG2RAD * 0.5);
nh = nearD * tan;
nw = nh * ratio;
fh = farD * tan;
fw = fh * ratio;
}
private static final int TOP = 0;
private static final int BOTTOM = 1;
private static final int LEFT = 2;
private static final int RIGHT = 3;
private static final int NEARP = 4;
private static final int FARP = 5;
public void setPosition(GLVector3 p, GLVector3 l, GLVector3 u) {
_p = p;
_l = l;
_u = u;
Z.sub(p, l);
Z.normalize();
X.cross(u, Z);
X.normalize();
Y.cross(Z, X);
ZZ.set(Z);
ZZ.scale(nearD);
nc.sub(p, ZZ);
ZZ.set(Z);
ZZ.scale(farD);
fc.sub(p, ZZ);
// ntl = nc + Y * nh - X * nw;
// ntr = nc + Y * nh + X * nw;
// nbl = nc - Y * nh - X * nw;
// nbr = nc - Y * nh + X * nw;
YY.set(Y);
YY.scale(nh);
XX.set(X);
XX.scale(nw);
ntl.add(nc, YY);
ntl.sub(XX);
ntr.add(nc, YY);
ntr.add(XX);
nbl.sub(nc, YY);
nbl.sub(XX);
nbr.sub(nc, YY);
nbr.add(XX);
// ftl = fc + Y * fh - X * fw;
// ftr = fc + Y * fh + X * fw;
// fbl = fc - Y * fh - X * fw;
// fbr = fc - Y * fh + X * fw;
YY.set(Y);
YY.scale(fh);
XX.set(X);
XX.scale(fw);
ftl.add(fc, YY);
ftl.sub(XX);
ftr.add(fc, YY);
ftr.add(XX);
fbl.sub(fc, YY);
fbl.sub(XX);
fbr.sub(fc, YY);
fbr.add(XX);
pl[TOP].set3Points(ntr, ntl, ftl);
pl[BOTTOM].set3Points(nbl, nbr, fbr);
pl[LEFT].set3Points(ntl, nbl, fbl);
pl[RIGHT].set3Points(nbr, ntr, fbr);
pl[NEARP].set3Points(ntl, ntr, nbr);
pl[FARP].set3Points(ftr, ftl, fbl);
}
public static final int OUTSIDE = 0;
public static final int INTERSECT = 1;
public static final int INSIDE = 2;
public int pointInside(GLVector3 p) {
int result = INSIDE;
float d;
for(int i=0; i < 6; i++) {
d = pl[i].distance(p);
if (d < 0) return OUTSIDE;
if (d == 0f) result = INTERSECT;
}
return result;
}
/** Tests if sphere is within frustum.
* @param p = center if sphere
* @param size = size of sphere (radius or diameter?)
*/
public int sphereInside(GLVector3 p, float size) {
float distance;
int result = INSIDE;
for(int i=0; i < 6; i++) {
distance = pl[i].distance(p);
if (distance < -size) return OUTSIDE;
if (distance < size) result = INTERSECT;
}
return result;
}
/** Tests if box is within frustum.
* @param pts = 8 points of box
*/
public int boxInside(GLVector3 pts[]) {
int result = INSIDE, in, out;
for(int i=0; i < 6; i++) {
// reset counters for corners in and out
out=0;in=0;
// for each corner of the box do ...
// get out of the cycle as soon as a box as corners
// both inside and out of the frustum
for (int k = 0; k < 8 && (in==0 || out==0); k++) {
// is the corner outside or inside
if (pl[i].distance(pts[k]) < 0)
out++;
else
in++;
}
//if all corners are out
if (in == 0) return (OUTSIDE);
// if some corners are out and others are in
if (out > 0) result = INTERSECT;
}
return result;
}
public void print() {
System.out.println(String.format("GLFrustum:%7.3f,%7.3f,%7.3f,%7.3f", nw, nh, fw, fh));
System.out.println(String.format("GLFrustum:p:%7.3f,%7.3f,%7.3f", _p.v[0], _p.v[1], _p.v[2]));
System.out.println(String.format("GLFrustum:l:%7.3f,%7.3f,%7.3f", _l.v[0], _l.v[1], _l.v[2]));
System.out.println(String.format("GLFrustum:u:%7.3f,%7.3f,%7.3f", _u.v[0], _u.v[1], _u.v[2]));
for(int a=0;a<6;a++) {
pl[a].print();
}
}
}