diff options
Diffstat (limited to 'indra/llmath/m4math.h')
-rw-r--r-- | indra/llmath/m4math.h | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h new file mode 100644 index 0000000000..4f26d875ff --- /dev/null +++ b/indra/llmath/m4math.h @@ -0,0 +1,365 @@ +/** + * @file m4math.h + * @brief LLMatrix3 class header file. + * + * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#ifndef LL_M4MATH_H +#define LL_M4MATH_H + +#include "v3math.h" + +class LLVector4; +class LLMatrix3; +class LLQuaternion; + +// NOTA BENE: Currently assuming a right-handed, x-forward, y-left, z-up universe + +// Us versus OpenGL: + +// Even though OpenGL uses column vectors and we use row vectors, we can plug our matrices +// directly into OpenGL. This is because OpenGL numbers its matrices going columnwise: +// +// OpenGL indexing: Our indexing: +// 0 4 8 12 [0][0] [0][1] [0][2] [0][3] +// 1 5 9 13 [1][0] [1][1] [1][2] [1][3] +// 2 6 10 14 [2][0] [2][1] [2][2] [2][3] +// 3 7 11 15 [3][0] [3][1] [3][2] [3][3] +// +// So when you're looking at OpenGL related matrices online, our matrices will be +// "transposed". But our matrices can be plugged directly into OpenGL and work fine! +// + +// We're using row vectors - [vx, vy, vz, vw] +// +// There are several different ways of thinking of matrices, if you mix them up, you'll get very confused. +// +// One way to think about it is a matrix that takes the origin frame A +// and rotates it into B': i.e. A*M = B +// +// Vectors: +// f - forward axis of B expressed in A +// l - left axis of B expressed in A +// u - up axis of B expressed in A +// +// | 0: fx 1: fy 2: fz 3:0 | +// M = | 4: lx 5: ly 6: lz 7:0 | +// | 8: ux 9: uy 10: uz 11:0 | +// | 12: 0 13: 0 14: 0 15:1 | +// +// +// +// +// Another way to think of matrices is matrix that takes a point p in frame A, and puts it into frame B: +// This is used most commonly for the modelview matrix. +// +// so p*M = p' +// +// Vectors: +// f - forward of frame B in frame A +// l - left of frame B in frame A +// u - up of frame B in frame A +// o - origin of frame frame B in frame A +// +// | 0: fx 1: lx 2: ux 3:0 | +// M = | 4: fy 5: ly 6: uy 7:0 | +// | 8: fz 9: lz 10: uz 11:0 | +// | 12:-of 13:-ol 14:-ou 15:1 | +// +// of, ol, and ou mean the component of the "global" origin o in the f axis, l axis, and u axis. +// + +static const U32 NUM_VALUES_IN_MAT4 = 4; + +#if LL_WINDOWS +__declspec(align(16)) +#endif +class LLMatrix4 +{ +public: + F32 mMatrix[NUM_VALUES_IN_MAT4][NUM_VALUES_IN_MAT4]; + + LLMatrix4(); // Initializes Matrix to identity matrix + explicit LLMatrix4(const F32 *mat); // Initializes Matrix to values in mat + explicit LLMatrix4(const LLMatrix3 &mat); // Initializes Matrix to valuee in mat and sets position to (0,0,0) + explicit LLMatrix4(const LLQuaternion &q); // Initializes Matrix with rotation q and sets position to (0,0,0) + + LLMatrix4(const LLMatrix3 &mat, const LLVector4 &pos); // Initializes Matrix to values in mat and pos + + // These are really, really, inefficient as implemented! - djs + LLMatrix4(const LLQuaternion &q, const LLVector4 &pos); // Initializes Matrix with rotation q and position pos + LLMatrix4(F32 angle, + const LLVector4 &vec, + const LLVector4 &pos); // Initializes Matrix with axis-angle and position + LLMatrix4(F32 angle, const LLVector4 &vec); // Initializes Matrix with axis-angle and sets position to (0,0,0) + LLMatrix4(const F32 roll, const F32 pitch, const F32 yaw, + const LLVector4 &pos); // Initializes Matrix with Euler angles + LLMatrix4(const F32 roll, const F32 pitch, const F32 yaw); // Initializes Matrix with Euler angles + + ~LLMatrix4(void); // Destructor + + + ////////////////////////////// + // + // Matrix initializers - these replace any existing values in the matrix + // + + void initRows(const LLVector4 &row0, + const LLVector4 &row1, + const LLVector4 &row2, + const LLVector4 &row3); + + // various useful matrix functions + const LLMatrix4& identity(); // Load identity matrix + const LLMatrix4& zero(); // Clears matrix to all zeros. + + const LLMatrix4& initRotation(const F32 angle, const F32 x, const F32 y, const F32 z); // Calculate rotation matrix by rotating angle radians about (x, y, z) + const LLMatrix4& initRotation(const F32 angle, const LLVector4 &axis); // Calculate rotation matrix for rotating angle radians about vec + const LLMatrix4& initRotation(const F32 roll, const F32 pitch, const F32 yaw); // Calculate rotation matrix from Euler angles + const LLMatrix4& initRotation(const LLQuaternion &q); // Set with Quaternion and position + + // Position Only + const LLMatrix4& initMatrix(const LLMatrix3 &mat); // + const LLMatrix4& initMatrix(const LLMatrix3 &mat, const LLVector4 &translation); + + // These operation create a matrix that will rotate and translate by the + // specified amounts. + const LLMatrix4& initRotTrans(const F32 angle, + const F32 rx, const F32 ry, const F32 rz, + const F32 px, const F32 py, const F32 pz); + + const LLMatrix4& initRotTrans(const F32 angle, const LLVector3 &axis, const LLVector3 &translation); // Rotation from axis angle + translation + const LLMatrix4& initRotTrans(const F32 roll, const F32 pitch, const F32 yaw, const LLVector4 &pos); // Rotation from Euler + translation + const LLMatrix4& initRotTrans(const LLQuaternion &q, const LLVector4 &pos); // Set with Quaternion and position + + + // Set all + const LLMatrix4& initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos); + + + /////////////////////////// + // + // Matrix setters - set some properties without modifying others + // + + const LLMatrix4& setTranslation(const F32 x, const F32 y, const F32 z); // Sets matrix to translate by (x,y,z) + + void setFwdRow(const LLVector3 &row); + void setLeftRow(const LLVector3 &row); + void setUpRow(const LLVector3 &row); + + void setFwdCol(const LLVector3 &col); + void setLeftCol(const LLVector3 &col); + void setUpCol(const LLVector3 &col); + + const LLMatrix4& setTranslation(const LLVector4 &translation); + const LLMatrix4& setTranslation(const LLVector3 &translation); + + /////////////////////////// + // + // Get properties of a matrix + // + + F32 determinant(void) const; // Return determinant + LLQuaternion quaternion(void) const; // Returns quaternion + + LLVector4 getFwdRow4() const; + LLVector4 getLeftRow4() const; + LLVector4 getUpRow4() const; + + LLMatrix3 getMat3() const; + + const LLVector3& getTranslation() const { return *(LLVector3*)&mMatrix[3][0]; } + + /////////////////////////// + // + // Operations on an existing matrix + // + + const LLMatrix4& transpose(); // Transpose LLMatrix4 + const LLMatrix4& invert(); // Invert LLMatrix4 + + // Rotate existing matrix + // These are really, really, inefficient as implemented! - djs + const LLMatrix4& rotate(const F32 angle, const F32 x, const F32 y, const F32 z); // Rotate matrix by rotating angle radians about (x, y, z) + const LLMatrix4& rotate(const F32 angle, const LLVector4 &vec); // Rotate matrix by rotating angle radians about vec + const LLMatrix4& rotate(const F32 roll, const F32 pitch, const F32 yaw); // Rotate matrix by Euler angles + const LLMatrix4& rotate(const LLQuaternion &q); // Rotate matrix by Quaternion + + + // Translate existing matrix + const LLMatrix4& translate(const LLVector3 &vec); // Translate matrix by (vec[VX], vec[VY], vec[VZ]) + + + + + /////////////////////// + // + // Operators + // + +// Not implemented to enforce code that agrees with symbolic syntax +// friend LLVector4 operator*(const LLMatrix4 &a, const LLVector4 &b); // Apply rotation a to vector b + +// friend inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b); // Return a * b + friend LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b); // Return transform of vector a by matrix b + friend LLVector3 operator*(const LLVector3 &a, const LLMatrix4 &b); // Return full transform of a by matrix b + friend LLVector4 rotate_vector(const LLVector4 &a, const LLMatrix4 &b); // Rotates a but does not translate + friend LLVector3 rotate_vector(const LLVector3 &a, const LLMatrix4 &b); // Rotates a but does not translate + + friend bool operator==(const LLMatrix4 &a, const LLMatrix4 &b); // Return a == b + friend bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b); // Return a != b + + friend const LLMatrix4& operator+=(LLMatrix4 &a, const LLMatrix4 &b); // Return a + b + friend const LLMatrix4& operator-=(LLMatrix4 &a, const LLMatrix4 &b); // Return a - b + friend const LLMatrix4& operator*=(LLMatrix4 &a, const LLMatrix4 &b); // Return a * b + friend const LLMatrix4& operator*=(LLMatrix4 &a, const F32 &b); // Return a * b + + friend std::ostream& operator<<(std::ostream& s, const LLMatrix4 &a); // Stream a +} +#if LL_DARWIN +__attribute__ ((aligned (16))) +#endif +; + + +inline LLMatrix4::LLMatrix4() +{ + identity(); +} + +inline const LLMatrix4& LLMatrix4::identity() +{ + mMatrix[0][0] = 1.f; + mMatrix[0][1] = 0.f; + mMatrix[0][2] = 0.f; + mMatrix[0][3] = 0.f; + + mMatrix[1][0] = 0.f; + mMatrix[1][1] = 1.f; + mMatrix[1][2] = 0.f; + mMatrix[1][3] = 0.f; + + mMatrix[2][0] = 0.f; + mMatrix[2][1] = 0.f; + mMatrix[2][2] = 1.f; + mMatrix[2][3] = 0.f; + + mMatrix[3][0] = 0.f; + mMatrix[3][1] = 0.f; + mMatrix[3][2] = 0.f; + mMatrix[3][3] = 1.f; + return (*this); +} + +inline LLVector3 operator*(const LLVector3 &a, const LLMatrix4 &b) +{ + // Converts a to LLVector4 and applies full transformation + // Operates "to the left" on row-vector a + LLVector3 vec; + vec.mV[VX] = a.mV[VX] * b.mMatrix[VX][VX] + + a.mV[VY] * b.mMatrix[VY][VX] + + a.mV[VZ] * b.mMatrix[VZ][VX] + + b.mMatrix[VW][VX]; + + vec.mV[VY] = a.mV[VX] * b.mMatrix[VX][VY] + + a.mV[VY] * b.mMatrix[VY][VY] + + a.mV[VZ] * b.mMatrix[VZ][VY] + + b.mMatrix[VW][VY]; + + vec.mV[VZ] = a.mV[VX] * b.mMatrix[VX][VZ] + + a.mV[VY] * b.mMatrix[VY][VZ] + + a.mV[VZ] * b.mMatrix[VZ][VZ] + + b.mMatrix[VW][VZ]; + return vec; +} + +/* +inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b) +{ + U32 i, j; + LLMatrix4 mat; + for (i = 0; i < NUM_VALUES_IN_MAT4; i++) + { + for (j = 0; j < NUM_VALUES_IN_MAT4; j++) + { + mat.mMatrix[j][i] = a.mMatrix[j][0] * b.mMatrix[0][i] + + a.mMatrix[j][1] * b.mMatrix[1][i] + + a.mMatrix[j][2] * b.mMatrix[2][i] + + a.mMatrix[j][3] * b.mMatrix[3][i]; + } + } + return mat; +} +*/ + + +inline const LLMatrix4& operator*=(LLMatrix4 &a, const LLMatrix4 &b) +{ + U32 i, j; + LLMatrix4 mat; + for (i = 0; i < NUM_VALUES_IN_MAT4; i++) + { + for (j = 0; j < NUM_VALUES_IN_MAT4; j++) + { + mat.mMatrix[j][i] = a.mMatrix[j][0] * b.mMatrix[0][i] + + a.mMatrix[j][1] * b.mMatrix[1][i] + + a.mMatrix[j][2] * b.mMatrix[2][i] + + a.mMatrix[j][3] * b.mMatrix[3][i]; + } + } + a = mat; + return a; +} + +inline const LLMatrix4& operator*=(LLMatrix4 &a, const F32 &b) +{ + U32 i, j; + LLMatrix4 mat; + for (i = 0; i < NUM_VALUES_IN_MAT4; i++) + { + for (j = 0; j < NUM_VALUES_IN_MAT4; j++) + { + mat.mMatrix[j][i] = a.mMatrix[j][i] * b; + } + } + a = mat; + return a; +} + +inline const LLMatrix4& operator+=(LLMatrix4 &a, const LLMatrix4 &b) +{ + LLMatrix4 mat; + U32 i, j; + for (i = 0; i < NUM_VALUES_IN_MAT4; i++) + { + for (j = 0; j < NUM_VALUES_IN_MAT4; j++) + { + mat.mMatrix[j][i] = a.mMatrix[j][i] + b.mMatrix[j][i]; + } + } + a = mat; + return a; +} + +inline const LLMatrix4& operator-=(LLMatrix4 &a, const LLMatrix4 &b) +{ + LLMatrix4 mat; + U32 i, j; + for (i = 0; i < NUM_VALUES_IN_MAT4; i++) + { + for (j = 0; j < NUM_VALUES_IN_MAT4; j++) + { + mat.mMatrix[j][i] = a.mMatrix[j][i] - b.mMatrix[j][i]; + } + } + a = mat; + return a; +} + +#endif + + + |