summaryrefslogtreecommitdiffstats
path: root/lib/glfrustum.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/glfrustum.h')
-rw-r--r--lib/glfrustum.h217
1 files changed, 217 insertions, 0 deletions
diff --git a/lib/glfrustum.h b/lib/glfrustum.h
new file mode 100644
index 0000000..03a3827
--- /dev/null
+++ b/lib/glfrustum.h
@@ -0,0 +1,217 @@
+// GLFrustum.h
+// Code by Richard S. Wright Jr.
+// Encapsulates a frustum... works in conjunction
+// with GLFrame
+
+#include "math3d.h"
+#include "glframe.h"
+
+#ifndef __GL_FRAME_CLASS
+#define __GL_FRAME_CLASS
+
+class GLFrustum
+{
+ public:
+ // Set some Reasonable Defaults
+ GLFrustum(void)
+ { Set(30.0f, 1.0, 1.0, 10.0); }
+
+ // Set the View Frustum
+ GLFrustum(float fFov, float fAspect, float fNear, float fFar)
+ { Set(fFov, fAspect, fNear, fFar); }
+
+ // Calculates the corners of the Frustum and sets the projection matrix.
+ // Switches to projection matrix before returning
+ void Set(float fFov, float fAspect, float fNear, float fFar)
+ {
+ float xmin, xmax, ymin, ymax; // Dimensions of near clipping plane
+ float xFmin, xFmax, yFmin, yFmax; // Dimensions of far clipping plane
+
+ // Do the Math for the near clipping plane
+ ymax = fNear * float(tan( fFov * M3D_PI / 360.0 ));
+ ymin = -ymax;
+ xmin = ymin * fAspect;
+ xmax = -xmin;
+
+ // Do the Math for the far clipping plane
+ yFmax = fFar * float(tan(fFov * M3D_PI / 360.0));
+ yFmin = -yFmax;
+ xFmin = yFmin * fAspect;
+ xFmax = -xFmin;
+
+ // Do the GL
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum( xmin, xmax, ymin, ymax, fNear, fFar );
+ glMatrixMode(GL_MODELVIEW);
+
+ // Fill in values for untransformed Frustum corners
+ // Near Upper Left
+ nearUL[0] = xmin; nearUL[1] = ymax; nearUL[2] = -fNear; nearUL[3] = 1.0f;
+
+ // Near Lower Left
+ nearLL[0] = xmin; nearLL[1] = ymin; nearLL[2] = -fNear; nearLL[3] = 1.0f;
+
+ // Near Upper Right
+ nearUR[0] = xmax; nearUR[1] = ymax; nearUR[2] = -fNear; nearUR[3] = 1.0f;
+
+ // Near Lower Right
+ nearLR[0] = xmax; nearLR[1] = ymin; nearLR[2] = -fNear; nearLR[3] = 1.0f;
+
+ // Far Upper Left
+ farUL[0] = xFmin; farUL[1] = yFmax; farUL[2] = -fFar; farUL[3] = 1.0f;
+
+ // Far Lower Left
+ farLL[0] = xFmin; farLL[1] = yFmin; farLL[2] = -fFar; farLL[3] = 1.0f;
+
+ // Far Upper Right
+ farUR[0] = xFmax; farUR[1] = yFmax; farUR[2] = -fFar; farUR[3] = 1.0f;
+
+ // Far Lower Right
+ farLR[0] = xFmax; farLR[1] = yFmin; farLR[2] = -fFar; farLR[3] = 1.0f;
+ }
+
+ // Builds a transformation matrix and transforms the corners of the Frustum,
+ // then derives the plane equations
+ void Transform(GLFrame& Camera)
+ {
+ // Workspace
+ M3DMatrix44f rotMat;
+ M3DVector3f vForward, vUp, vCross;
+ M3DVector3f vOrigin;
+
+ ///////////////////////////////////////////////////////////////////
+ // Create the transformation matrix. This was the trickiest part
+ // for me. The default view from OpenGL is down the negative Z
+ // axis. However, building a transformation axis from these
+ // directional vectors points the frustum the wrong direction. So
+ // You must reverse them here, or build the initial frustum
+ // backwards - which to do is purely a matter of taste. I chose to
+ // compensate here to allow better operability with some of my other
+ // legacy code and projects. RSW
+ Camera.GetForwardVector(vForward);
+ vForward[0] = -vForward[0];
+ vForward[1] = -vForward[1];
+ vForward[2] = -vForward[2];
+
+ Camera.GetUpVector(vUp);
+ Camera.GetOrigin(vOrigin);
+
+ // Calculate the right side (x) vector
+ m3dCrossProduct(vCross, vUp, vForward);
+
+ // The Matrix
+ // X Column
+ memcpy(rotMat, vCross, sizeof(float)*3);
+ rotMat[3] = 0.0f;
+
+ // Y Column
+ memcpy(&rotMat[4], vUp, sizeof(float)*3);
+ rotMat[7] = 0.0f;
+
+ // Z Column
+ memcpy(&rotMat[8], vForward, sizeof(float)*3);
+ rotMat[11] = 0.0f;
+
+ // Translation
+ rotMat[12] = vOrigin[0];
+ rotMat[13] = vOrigin[1];
+ rotMat[14] = vOrigin[2];
+ rotMat[15] = 1.0f;
+
+ ////////////////////////////////////////////////////
+ // Transform the frustum corners
+ m3dTransformVector4(nearULT, rotMat, nearUL);
+ m3dTransformVector4(nearLLT, rotMat, nearLL);
+ m3dTransformVector4(nearURT, rotMat, nearUR);
+ m3dTransformVector4(nearLRT, rotMat, nearLR);
+ m3dTransformVector4(farULT, rotMat, farUL);
+ m3dTransformVector4(farLLT, rotMat, farLL);
+ m3dTransformVector4(farURT, rotMat, farUR);
+ m3dTransformVector4(farLRT, rotMat, farLR);
+
+ ////////////////////////////////////////////////////
+ // Derive Plane Equations from points... Points given in
+ // counter clockwise order to make normals point inside
+ // the Frustum
+ // Near and Far Planes
+ m3dGetPlaneEquation(nearPlane, nearULT, nearLLT, nearLRT);
+ m3dGetPlaneEquation(farPlane, farULT, farURT, farLRT);
+
+ // Top and Bottom Planes
+ m3dGetPlaneEquation(topPlane, nearULT, nearURT, farURT);
+ m3dGetPlaneEquation(bottomPlane, nearLLT, farLLT, farLRT);
+
+ // Left and right planes
+ m3dGetPlaneEquation(leftPlane, nearLLT, nearULT, farULT);
+ m3dGetPlaneEquation(rightPlane, nearLRT, farLRT, farURT);
+ }
+
+ // Allow expanded version of sphere test
+ bool TestSphere(float x, float y, float z, float fRadius)
+ {
+ M3DVector3f vPoint;
+ vPoint[0] = x;
+ vPoint[1] = y;
+ vPoint[2] = z;
+
+ return TestSphere(vPoint, fRadius);
+ }
+
+ // Test a point against all frustum planes. A negative distance for any
+ // single plane means it is outside the frustum. The radius value allows
+ // to test for a point (radius = 0), or a sphere. Possibly there might
+ // be some gain in an alternative function that saves the addition of
+ // zero in this case.
+ // Returns false if it is not in the frustum, true if it intersects
+ // the Frustum.
+ bool TestSphere(M3DVector3f vPoint, float fRadius)
+ {
+ float fDist;
+
+ // Near Plane - See if it is behind me
+ fDist = m3dGetDistanceToPlane(vPoint, nearPlane);
+ if(fDist + fRadius <= 0.0)
+ return false;
+
+ // Distance to far plane
+ fDist = m3dGetDistanceToPlane(vPoint, farPlane);
+ if(fDist + fRadius <= 0.0)
+ return false;
+
+ fDist = m3dGetDistanceToPlane(vPoint, leftPlane);
+ if(fDist + fRadius <= 0.0)
+ return false;
+
+ fDist = m3dGetDistanceToPlane(vPoint, rightPlane);
+ if(fDist + fRadius <= 0.0)
+ return false;
+
+ fDist = m3dGetDistanceToPlane(vPoint, bottomPlane);
+ if(fDist + fRadius <= 0.0)
+ return false;
+
+ fDist = m3dGetDistanceToPlane(vPoint, topPlane);
+ if(fDist + fRadius <= 0.0)
+ return false;
+
+ return true;
+ }
+
+ protected:
+ // Untransformed corners of the frustum
+ M3DVector4f nearUL, nearLL, nearUR, nearLR;
+ M3DVector4f farUL, farLL, farUR, farLR;
+
+ // Transformed corners of Frustum
+ M3DVector4f nearULT, nearLLT, nearURT, nearLRT;
+ M3DVector4f farULT, farLLT, farURT, farLRT;
+
+ // Base and Transformed plane equations
+ M3DVector4f nearPlane, farPlane, leftPlane, rightPlane;
+ M3DVector4f topPlane, bottomPlane;
+};
+
+
+#endif
+