summaryrefslogtreecommitdiffstats
path: root/lib/glframe.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/glframe.h')
-rw-r--r--lib/glframe.h412
1 files changed, 412 insertions, 0 deletions
diff --git a/lib/glframe.h b/lib/glframe.h
new file mode 100644
index 0000000..356d630
--- /dev/null
+++ b/lib/glframe.h
@@ -0,0 +1,412 @@
+// Frame.h
+// Implementation of the GLFrame Class
+// Richard S. Wright Jr.
+// Code by Richard S. Wright Jr.
+
+#include "math3d.h"
+#include "gltools.h"
+
+#ifndef _ORTHO_FRAME_
+#define _ORTHO_FRAME_
+
+// The GLFrame (OrthonormalFrame) class. Possibly the most useful little piece of 3D graphics
+// code for OpenGL immersive environments.
+// Richard S. Wright Jr.
+class GLFrame
+{
+ protected:
+ M3DVector3f vOrigin; // Where am I?
+ M3DVector3f vForward; // Where am I going?
+ M3DVector3f vUp; // Which way is up?
+
+ public:
+ // Default position and orientation. At the origin, looking
+ // down the positive Z axis (right handed coordinate system).
+ GLFrame(void) {
+ // At origin
+ vOrigin[0] = 0.0f; vOrigin[1] = 0.0f; vOrigin[2] = 0.0f;
+
+ // Up is up (+Y)
+ vUp[0] = 0.0f; vUp[1] = 1.0f; vUp[2] = 0.0f;
+
+ // Forward is -Z (default OpenGL)
+ vForward[0] = 0.0f; vForward[1] = 0.0f; vForward[2] = -1.0f;
+ }
+
+ /////////////////////////////////////////////////////////////
+ // Set Location
+ inline void SetOrigin(const M3DVector3f vPoint) {
+ m3dCopyVector3(vOrigin, vPoint); }
+
+ inline void SetOrigin(float x, float y, float z) {
+ vOrigin[0] = x; vOrigin[1] = y; vOrigin[2] = z; }
+
+ inline void GetOrigin(M3DVector3f vPoint) {
+ m3dCopyVector3(vPoint, vOrigin); }
+
+ inline float GetOriginX(void) { return vOrigin[0]; }
+ inline float GetOriginY(void) { return vOrigin[1]; }
+ inline float GetOriginZ(void) { return vOrigin[2]; }
+
+ /////////////////////////////////////////////////////////////
+ // Set Forward Direction
+ inline void SetForwardVector(const M3DVector3f vDirection) {
+ m3dCopyVector3(vForward, vDirection); }
+
+ inline void SetForwardVector(float x, float y, float z)
+ { vForward[0] = x; vForward[1] = y; vForward[2] = z; }
+
+ inline void GetForwardVector(M3DVector3f vVector) { m3dCopyVector3(vVector, vForward); }
+
+ /////////////////////////////////////////////////////////////
+ // Set Up Direction
+ inline void SetUpVector(const M3DVector3f vDirection) {
+ m3dCopyVector3(vUp, vDirection); }
+
+ inline void SetUpVector(float x, float y, float z)
+ { vUp[0] = x; vUp[1] = y; vUp[2] = z; }
+
+ inline void GetUpVector(M3DVector3f vVector) { m3dCopyVector3(vVector, vUp); }
+
+ /////////////////////////////////////////////////////////////
+ // Get Axes
+ inline void GetZAxis(M3DVector3f vVector) { GetForwardVector(vVector); }
+ inline void GetYAxis(M3DVector3f vVector) { GetUpVector(vVector); }
+ inline void GetXAxis(M3DVector3f vVector) { m3dCrossProduct(vVector, vUp, vForward); }
+
+ /////////////////////////////////////////////////////////////
+ // Translate along orthonormal axis... world or local
+ inline void TranslateWorld(float x, float y, float z)
+ { vOrigin[0] += x; vOrigin[1] += y; vOrigin[2] += z; }
+
+ inline void TranslateLocal(float x, float y, float z)
+ { MoveForward(z); MoveUp(y); MoveRight(x);}
+
+ /////////////////////////////////////////////////////////////
+ // Move Forward (along Z axis)
+ inline void MoveForward(float fDelta)
+ {
+ // Move along direction of front direction
+ vOrigin[0] += vForward[0] * fDelta;
+ vOrigin[1] += vForward[1] * fDelta;
+ vOrigin[2] += vForward[2] * fDelta;
+ }
+
+ // Move along Y axis
+ inline void MoveUp(float fDelta)
+ {
+ // Move along direction of up direction
+ vOrigin[0] += vUp[0] * fDelta;
+ vOrigin[1] += vUp[1] * fDelta;
+ vOrigin[2] += vUp[2] * fDelta;
+ }
+
+ // Move along X axis
+ inline void MoveRight(float fDelta)
+ {
+ // Move along direction of right vector
+ M3DVector3f vCross;
+ m3dCrossProduct(vCross, vUp, vForward);
+
+ vOrigin[0] += vCross[0] * fDelta;
+ vOrigin[1] += vCross[1] * fDelta;
+ vOrigin[2] += vCross[2] * fDelta;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // Just assemble the matrix
+ void GetMatrix(M3DMatrix44f matrix, bool bRotationOnly = false)
+ {
+ // Calculate the right side (x) vector, drop it right into the matrix
+ M3DVector3f vXAxis;
+ m3dCrossProduct(vXAxis, vUp, vForward);
+
+ // Set matrix column does not fill in the fourth value...
+ m3dSetMatrixColumn44(matrix, vXAxis, 0);
+ matrix[3] = 0.0f;
+
+ // Y Column
+ m3dSetMatrixColumn44(matrix, vUp, 1);
+ matrix[7] = 0.0f;
+
+ // Z Column
+ m3dSetMatrixColumn44(matrix, vForward, 2);
+ matrix[11] = 0.0f;
+
+ // Translation (already done)
+ if (bRotationOnly == true)
+ {
+ matrix[12] = 0.0f;
+ matrix[13] = 0.0f;
+ matrix[14] = 0.0f;
+ }
+ else
+ m3dSetMatrixColumn44(matrix, vOrigin, 3);
+
+ matrix[15] = 1.0f;
+ }
+
+ /////////////////////////////////////////////////////////////
+ // Get a 4x4 transformation matrix that describes the ccamera
+ // orientation.
+ inline void GetCameraOrientation(M3DMatrix44f m)
+ {
+ M3DVector3f x, z;
+
+ // Make rotation matrix
+ // Z vector is reversed
+ z[0] = -vForward[0];
+ z[1] = -vForward[1];
+ z[2] = -vForward[2];
+
+ // X vector = Y cross Z
+ m3dCrossProduct(x, vUp, z);
+
+ // Matrix has no translation information and is
+ // transposed.... (rows instead of columns)
+ #define M(row,col) m[col*4+row]
+ M(0, 0) = x[0];
+ M(0, 1) = x[1];
+ M(0, 2) = x[2];
+ M(0, 3) = 0.0;
+ M(1, 0) = vUp[0];
+ M(1, 1) = vUp[1];
+ M(1, 2) = vUp[2];
+ M(1, 3) = 0.0;
+ M(2, 0) = z[0];
+ M(2, 1) = z[1];
+ M(2, 2) = z[2];
+ M(2, 3) = 0.0;
+ M(3, 0) = 0.0;
+ M(3, 1) = 0.0;
+ M(3, 2) = 0.0;
+ M(3, 3) = 1.0;
+ #undef M
+ }
+
+ /////////////////////////////////////////////////////////////
+ // Perform viewing or modeling transformations
+ // Position as the camera (for viewing). Apply this transformation
+ // first as your viewing transformation
+ // The default implementation of gluLookAt can be considerably sped up
+ // since it uses doubles for everything... then again profile before you
+ // tune... ;-) You might get a boost form page fault reduction too... if
+ // no other glu routines are used...
+ // This will get called once per frame.... go ahead and inline
+ inline void ApplyCameraTransform(bool bRotOnly = false)
+ {
+ M3DMatrix44f m;
+
+ GetCameraOrientation(m);
+
+ // Camera Transform
+ glMultMatrixf(m);
+
+ // If Rotation only, then do not do the translation
+ if (!bRotOnly)
+ glTranslatef(-vOrigin[0], -vOrigin[1], -vOrigin[2]);
+
+ /*gluLookAt(vOrigin[0], vOrigin[1], vOrigin[2],
+ vOrigin[0] + vForward[0],
+ vOrigin[1] + vForward[1],
+ vOrigin[2] + vForward[2],
+ vUp[0], vUp[1], vUp[2]);
+ */
+ }
+
+ // Position as an object in the scene. This places and orients a
+ // coordinate frame for other objects (besides the camera)
+ // There is ample room for optimization here...
+ // This is going to be called alot... don't inline
+ // Add flag to perform actor rotation only and not the translation
+ void ApplyActorTransform(bool bRotationOnly = false)
+ {
+ M3DMatrix44f rotMat;
+ GetMatrix(rotMat, bRotationOnly);
+
+ // Apply rotation to the current matrix
+ glMultMatrixf(rotMat);
+ }
+
+ // Rotate around local X Axes - Note all rotations are in radians
+ void RotateLocalX(float fAngle)
+ {
+ M3DMatrix44f rotMat;
+ M3DVector3f vCross;
+ m3dCrossProduct(vCross, vUp, vForward);
+ m3dRotationMatrix44(rotMat, fAngle,
+ vCross[0], vCross[1], vCross[2]);
+
+ M3DVector3f newVect;
+ // Inline 3x3 matrix multiply for rotation only
+ newVect[0] = rotMat[0] * vForward[0] + rotMat[4] * vForward[1] + rotMat[8] * vForward[2];
+ newVect[1] = rotMat[1] * vForward[0] + rotMat[5] * vForward[1] + rotMat[9] * vForward[2];
+ newVect[2] = rotMat[2] * vForward[0] + rotMat[6] * vForward[1] + rotMat[10] * vForward[2];
+ m3dCopyVector3(vForward, newVect);
+
+ // Update pointing up vector
+ newVect[0] = rotMat[0] * vUp[0] + rotMat[4] * vUp[1] + rotMat[8] * vUp[2];
+ newVect[1] = rotMat[1] * vUp[0] + rotMat[5] * vUp[1] + rotMat[9] * vUp[2];
+ newVect[2] = rotMat[2] * vUp[0] + rotMat[6] * vUp[1] + rotMat[10] * vUp[2];
+ m3dCopyVector3(vUp, newVect);
+ }
+
+ // Rotate around local Y
+ void RotateLocalY(float fAngle)
+ {
+ M3DMatrix44f rotMat;
+
+ // Just Rotate around the up vector
+ // Create a rotation matrix around my Up (Y) vector
+ m3dRotationMatrix44(rotMat, fAngle,
+ vUp[0], vUp[1], vUp[2]);
+
+ M3DVector3f newVect;
+
+ // Rotate forward pointing vector (inlined 3x3 transform)
+ newVect[0] = rotMat[0] * vForward[0] + rotMat[4] * vForward[1] + rotMat[8] * vForward[2];
+ newVect[1] = rotMat[1] * vForward[0] + rotMat[5] * vForward[1] + rotMat[9] * vForward[2];
+ newVect[2] = rotMat[2] * vForward[0] + rotMat[6] * vForward[1] + rotMat[10] * vForward[2];
+ m3dCopyVector3(vForward, newVect);
+ }
+
+ // Rotate around local Z
+ void RotateLocalZ(float fAngle)
+ {
+ M3DMatrix44f rotMat;
+
+ // Only the up vector needs to be rotated
+ m3dRotationMatrix44(rotMat, fAngle,
+ vForward[0], vForward[1], vForward[2]);
+
+ M3DVector3f newVect;
+ newVect[0] = rotMat[0] * vUp[0] + rotMat[4] * vUp[1] + rotMat[8] * vUp[2];
+ newVect[1] = rotMat[1] * vUp[0] + rotMat[5] * vUp[1] + rotMat[9] * vUp[2];
+ newVect[2] = rotMat[2] * vUp[0] + rotMat[6] * vUp[1] + rotMat[10] * vUp[2];
+ m3dCopyVector3(vUp, newVect);
+ }
+
+ // Reset axes to make sure they are orthonormal. This should be called on occasion
+ // if the matrix is long-lived and frequently transformed.
+ void Normalize(void)
+ {
+ M3DVector3f vCross;
+
+ // Calculate cross product of up and forward vectors
+ m3dCrossProduct(vCross, vUp, vForward);
+
+ // Use result to recalculate forward vector
+ m3dCrossProduct(vForward, vCross, vUp);
+
+ // Also check for unit length...
+ m3dNormalizeVector(vUp);
+ m3dNormalizeVector(vForward);
+ }
+
+ // Rotate in world coordinates...
+ void RotateWorld(float fAngle, float x, float y, float z)
+ {
+ M3DMatrix44f rotMat;
+
+ // Create the Rotation matrix
+ m3dRotationMatrix44(rotMat, fAngle, x, y, z);
+
+ M3DVector3f newVect;
+
+ // Transform the up axis (inlined 3x3 rotation)
+ newVect[0] = rotMat[0] * vUp[0] + rotMat[4] * vUp[1] + rotMat[8] * vUp[2];
+ newVect[1] = rotMat[1] * vUp[0] + rotMat[5] * vUp[1] + rotMat[9] * vUp[2];
+ newVect[2] = rotMat[2] * vUp[0] + rotMat[6] * vUp[1] + rotMat[10] * vUp[2];
+ m3dCopyVector3(vUp, newVect);
+
+ // Transform the forward axis
+ newVect[0] = rotMat[0] * vForward[0] + rotMat[4] * vForward[1] + rotMat[8] * vForward[2];
+ newVect[1] = rotMat[1] * vForward[0] + rotMat[5] * vForward[1] + rotMat[9] * vForward[2];
+ newVect[2] = rotMat[2] * vForward[0] + rotMat[6] * vForward[1] + rotMat[10] * vForward[2];
+ m3dCopyVector3(vForward, newVect);
+ }
+
+ // Rotate around a local axis
+ void RotateLocal(float fAngle, float x, float y, float z)
+ {
+ M3DVector3f vWorldVect;
+ M3DVector3f vLocalVect;
+ m3dLoadVector3(vLocalVect, x, y, z);
+
+ LocalToWorld(vLocalVect, vWorldVect);
+ RotateWorld(fAngle, vWorldVect[0], vWorldVect[1], vWorldVect[2]);
+ }
+
+ // Convert Coordinate Systems
+ // This is pretty much, do the transformation represented by the rotation
+ // and position on the point
+ // Is it better to stick to the convention that the destination always comes
+ // first, or use the conventions that "sounds" like the function...
+ void LocalToWorld(const M3DVector3f vLocal, M3DVector3f vWorld)
+ {
+ // Create the rotation matrix based on the vectors
+ M3DMatrix44f rotMat;
+
+ GetMatrix(rotMat, true);
+
+ // Do the rotation (inline it, and remove 4th column...)
+ vWorld[0] = rotMat[0] * vLocal[0] + rotMat[4] * vLocal[1] + rotMat[8] * vLocal[2];
+ vWorld[1] = rotMat[1] * vLocal[0] + rotMat[5] * vLocal[1] + rotMat[9] * vLocal[2];
+ vWorld[2] = rotMat[2] * vLocal[0] + rotMat[6] * vLocal[1] + rotMat[10] * vLocal[2];
+
+ // Translate the point
+ vWorld[0] += vOrigin[0];
+ vWorld[1] += vOrigin[1];
+ vWorld[2] += vOrigin[2];
+ }
+
+ // Change world coordinates into "local" coordinates
+ void WorldToLocal(const M3DVector3f vWorld, M3DVector3f vLocal)
+ {
+ ////////////////////////////////////////////////
+ // Translate the origin
+ M3DVector3f vNewWorld;
+ vNewWorld[0] = vWorld[0] - vOrigin[0];
+ vNewWorld[1] = vWorld[1] - vOrigin[1];
+ vNewWorld[2] = vWorld[2] - vOrigin[2];
+
+ // Create the rotation matrix based on the vectors
+ M3DMatrix44f rotMat;
+ M3DMatrix44f invMat;
+ GetMatrix(rotMat, true);
+
+ // Do the rotation based on inverted matrix
+ m3dInvertMatrix44(invMat, rotMat);
+
+ vLocal[0] = invMat[0] * vNewWorld[0] + invMat[4] * vNewWorld[1] + invMat[8] * vNewWorld[2];
+ vLocal[1] = invMat[1] * vNewWorld[0] + invMat[5] * vNewWorld[1] + invMat[9] * vNewWorld[2];
+ vLocal[2] = invMat[2] * vNewWorld[0] + invMat[6] * vNewWorld[1] + invMat[10] * vNewWorld[2];
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Transform a point by frame matrix
+ void TransformPoint(M3DVector3f vPointSrc, M3DVector3f vPointDst)
+ {
+ M3DMatrix44f m;
+ GetMatrix(m, false); // Rotate and translate
+ vPointDst[0] = m[0] * vPointSrc[0] + m[4] * vPointSrc[1] + m[8] * vPointSrc[2] + m[12];// * v[3];
+ vPointDst[1] = m[1] * vPointSrc[0] + m[5] * vPointSrc[1] + m[9] * vPointSrc[2] + m[13];// * v[3];
+ vPointDst[2] = m[2] * vPointSrc[0] + m[6] * vPointSrc[1] + m[10] * vPointSrc[2] + m[14];// * v[3];
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Rotate a vector by frame matrix
+ void RotateVector(M3DVector3f vVectorSrc, M3DVector3f vVectorDst)
+ {
+ M3DMatrix44f m;
+ GetMatrix(m, true); // Rotate only
+
+ vVectorDst[0] = m[0] * vVectorSrc[0] + m[4] * vVectorSrc[1] + m[8] * vVectorSrc[2];
+ vVectorDst[1] = m[1] * vVectorSrc[0] + m[5] * vVectorSrc[1] + m[9] * vVectorSrc[2];
+ vVectorDst[2] = m[2] * vVectorSrc[0] + m[6] * vVectorSrc[1] + m[10] * vVectorSrc[2];
+ }
+ };
+
+
+#endif
+