// ************************************************************************************************* // // Horde3D // Next-Generation Graphics Engine // -------------------------------------- // Copyright (C) 2006-2008 Nicolas Schulz // // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // // ************************************************************************************************* // ------------------------------------------------------------------------------------------------- // // Math library // // Conventions: // // - Coordinate system is right-handed with positive y as up axis // - All rotation angles are counter-clockwise when looking from the positive end of the rotation // axis towards the origin // - An unrotated view vector points along the negative z-axis // // ------------------------------------------------------------------------------------------------- #ifndef _utMath_H_ #define _utMath_H_ #include #include // Constants namespace Math { const unsigned int MaxUInt32 = 0xFFFFFFFF; const int MinInt32 = 0x80000000; const int MaxInt32 = 0x7FFFFFFF; const float MaxFloat = FLT_MAX; const float Pi = 3.1415926f; const float TwoPi = Pi * 2; const float PiHalf = Pi / 2; const float Epsilon = 0.000001f; const float NaN = *(float *)&MaxUInt32; }; // ------------------------------------------------------------------------------------------------- // General // ------------------------------------------------------------------------------------------------- inline float degToRad( float f ) { return f * (Math::Pi / 180.0f); } inline float radToDeg( float f ) { return f * (180.0f / Math::Pi); } inline float clamp( float f, float min, float max ) { if( f < min ) f = min; if( f > max ) f = max; return f; } inline float minf( float a, float b ) { return a < b ? a : b; } inline float maxf( float a, float b ) { return a > b ? a : b; } // ------------------------------------------------------------------------------------------------- // Vector // ------------------------------------------------------------------------------------------------- class Vec3f { public: float x, y, z; // ------------ // Constructors // ------------ Vec3f() : x( 0.0f ), y( 0.0f ), z( 0.0f ) { } explicit Vec3f( const float x, const float y, const float z ) : x( x ), y( y ), z( z ) { } // ----------- // Comparisons // ----------- bool operator==( const Vec3f &v ) const { return (x > v.x - Math::Epsilon && x < v.x + Math::Epsilon && y > v.y - Math::Epsilon && y < v.y + Math::Epsilon && z > v.z - Math::Epsilon && z < v.z + Math::Epsilon); } bool operator!=( const Vec3f &v ) const { return (x < v.x - Math::Epsilon || x > v.x + Math::Epsilon || y < v.y - Math::Epsilon || y > v.y + Math::Epsilon || z < v.z - Math::Epsilon || z > v.z + Math::Epsilon); } // --------------------- // Artitmetic operations // --------------------- Vec3f operator-() const { return Vec3f( -x, -y, -z ); } Vec3f operator+( const Vec3f &v ) const { return Vec3f( x + v.x, y + v.y, z + v.z ); } Vec3f &operator+=( const Vec3f &v ) { return *this = *this + v; } Vec3f operator-( const Vec3f &v ) const { return Vec3f( x - v.x, y - v.y, z - v.z ); } Vec3f &operator-=( const Vec3f &v ) { return *this = *this - v; } Vec3f operator*( const float f ) const { return Vec3f( x * f, y * f, z * f ); } Vec3f &operator*=( const float f ) { return *this = *this * f; } Vec3f operator/( const float f ) const { return Vec3f( x / f, y / f, z / f ); } Vec3f &operator/=( const float f ) { return *this = *this / f; } // ----------- // Dot product // ----------- float operator*( const Vec3f &v ) const { return ( x * v.x + y * v.y + z * v.z ); } // ------------- // Cross Product // ------------- Vec3f crossProduct( const Vec3f &v ) const { return Vec3f( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x ); } // ---------------- // Other operations // ---------------- float length() const { return sqrtf( *this * *this ); } Vec3f normalized() const { float l = length(); if( l != 0 ) return Vec3f( x / l, y / l, z / l ); else return Vec3f( 0, 0, 0 ); } /*void fromRotation( float angleX, float angleY ) { x = cosf( angleX ) * sinf( angleY ); y = -sinf( angleX ); z = cosf( angleX ) * cosf( angleY ); }*/ Vec3f toRotation() const { // Assumes that the unrotated view vector is (0, 0, -1) Vec3f v; if( y != 0 ) v.x = atan2( y, sqrtf( x*x + z*z ) ); if( z != 0 ) v.y = atan2( -x, -z ); return v; } Vec3f lerp( const Vec3f &v, float f ) const { return Vec3f( x + (v.x - x) * f, y + (v.y - y) * f, z + (v.z - z) * f ); } }; class Vec4f { public: float x, y, z, w; Vec4f() : x( 0 ), y( 0 ), z( 0 ), w( 0 ) { } explicit Vec4f( const float x, const float y, const float z, const float w ) : x( x ), y( y ), z( z ), w( w ) { } explicit Vec4f( Vec3f v ) : x( v.x ), y( v.y ), z( v.z ), w( 1.0f ) { } Vec4f& operator/=( const float value) { x /= value; y /= value; z /= value; w /= value; return *this; } }; // ------------------------------------------------------------------------------------------------- // Quaternion // ------------------------------------------------------------------------------------------------- class Quaternion { public: float x, y, z, w; // ------------ // Constructors // ------------ Quaternion() : x( 0.0f ), y( 0.0f ), z( 0.0f ), w( 0.0f ) { } explicit Quaternion( const float x, const float y, const float z, const float w ) : x( x ), y( y ), z( z ), w( w ) { } Quaternion( const float eulerX, const float eulerY, const float eulerZ ) { Quaternion roll( sinf( eulerX / 2 ), 0, 0, cosf( eulerX / 2 ) ); Quaternion pitch( 0, sinf( eulerY / 2 ), 0, cosf( eulerY / 2 ) ); Quaternion yaw( 0, 0, sinf( eulerZ / 2 ), cosf( eulerZ / 2 ) ); // Order: y * x * z *this = pitch * roll * yaw; } // --------------------- // Artitmetic operations // --------------------- Quaternion operator*( const Quaternion &q ) const { return Quaternion( y * q.z - z * q.y + q.x * w + x * q.w, z * q.x - x * q.z + q.y * w + y * q.w, x * q.y - y * q.x + q.z * w + z * q.w, w * q.w - (x * q.x + y * q.y + z * q.z) ); } Quaternion &operator*=( const Quaternion &q ) { return *this = *this * q; } // ---------------- // Other operations // ---------------- Quaternion slerp( const Quaternion &q, const float t ) const { float omega, cosom, sinom, scale0, scale1; Quaternion q1 = q, res; // Calc cosine cosom = x * q.x + y * q.y + z * q.z + w * q.w; // Adjust signs (if necessary) if( cosom < 0 ) { cosom = -cosom; q1.x = -q.x; q1.y = -q.y; q1.z = -q.z; q1.w = -q.w; } // Calculate coefficients if( (1 - cosom) > Math::Epsilon ) { // Standard case (Slerp) omega = acosf( cosom ); sinom = sinf( omega ); scale0 = sinf( (1 - t) * omega ) / sinom; scale1 = sinf( t * omega ) / sinom; } else { // Quaternions very close, so do linear interpolation scale0 = 1 - t; scale1 = t; } // Calculate final values res.x = x * scale0 + q1.x * scale1; res.y = y * scale0 + q1.y * scale1; res.z = z * scale0 + q1.z * scale1; res.w = w * scale0 + q1.w * scale1; return res; } Quaternion inverted() const { float len = x * x + y * y + z * z + w * w; if( len > 0 ) { float invLen = 1.0f / len; return Quaternion( -x * invLen, -y * invLen, -z * invLen, w * invLen ); } else return Quaternion(); } }; // ------------------------------------------------------------------------------------------------- // Matrix // ------------------------------------------------------------------------------------------------- class Matrix4f { private: Matrix4f( bool ) { // Don't initialize the matrix } public: union { float c[4][4]; // Column major order for OpenGL: c[column][row] float x[16]; }; // -------------- // Static methods // -------------- static Matrix4f TransMat( float x, float y, float z ) { Matrix4f m; m.c[3][0] = x; m.c[3][1] = y; m.c[3][2] = z; return m; } static Matrix4f ScaleMat( float x, float y, float z ) { Matrix4f m; m.c[0][0] = x; m.c[1][1] = y; m.c[2][2] = z; return m; } static Matrix4f RotMat( float x, float y, float z ) { // Rotation order: YXZ [* Vector] return Matrix4f( Quaternion( x, y, z ) ); } static Matrix4f RotMat( Vec3f axis, float angle ) { axis = axis * sinf( angle / 2 ); return Matrix4f( Quaternion( axis.x, axis.y, axis.z, cosf( angle / 2 ) ) ); } // ------------ // Constructors // ------------ Matrix4f() { c[0][0] = 1; c[1][0] = 0; c[2][0] = 0; c[3][0] = 0; c[0][1] = 0; c[1][1] = 1; c[2][1] = 0; c[3][1] = 0; c[0][2] = 0; c[1][2] = 0; c[2][2] = 1; c[3][2] = 0; c[0][3] = 0; c[1][3] = 0; c[2][3] = 0; c[3][3] = 1; } Matrix4f( const float *floatArray16 ) { for( unsigned int i = 0; i < 4; ++i ) { for( unsigned int j = 0; j < 4; ++j ) { c[i][j] = floatArray16[i * 4 + j]; } } } Matrix4f( const Quaternion &q ) { float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2; // Calculate coefficients x2 = q.x + q.x; y2 = q.y + q.y; z2 = q.z + q.z; xx = q.x * x2; xy = q.x * y2; xz = q.x * z2; yy = q.y * y2; yz = q.y * z2; zz = q.z * z2; wx = q.w * x2; wy = q.w * y2; wz = q.w * z2; c[0][0] = 1 - (yy + zz); c[1][0] = xy - wz; c[2][0] = xz + wy; c[3][0] = 0; c[0][1] = xy + wz; c[1][1] = 1 - (xx + zz); c[2][1] = yz - wx; c[3][1] = 0; c[0][2] = xz - wy; c[1][2] = yz + wx; c[2][2] = 1 - (xx + yy); c[3][2] = 0; c[0][3] = 0; c[1][3] = 0; c[2][3] = 0; c[3][3] = 1; } // ---------- // Matrix sum // ---------- Matrix4f operator+( const Matrix4f &m ) const { Matrix4f mf( false ); mf.x[0] = x[0] + m.x[0]; mf.x[1] = x[1] + m.x[1]; mf.x[2] = x[2] + m.x[2]; mf.x[3] = x[3] + m.x[3]; mf.x[4] = x[4] + m.x[4]; mf.x[5] = x[5] + m.x[5]; mf.x[6] = x[6] + m.x[6]; mf.x[7] = x[7] + m.x[7]; mf.x[8] = x[8] + m.x[8]; mf.x[9] = x[9] + m.x[9]; mf.x[10] = x[10] + m.x[10]; mf.x[11] = x[11] + m.x[11]; mf.x[12] = x[12] + m.x[12]; mf.x[13] = x[13] + m.x[13]; mf.x[14] = x[14] + m.x[14]; mf.x[15] = x[15] + m.x[15]; return mf; } Matrix4f &operator+=( const Matrix4f &m ) { return *this = *this + m; } // --------------------- // Matrix multiplication // --------------------- Matrix4f operator*( const Matrix4f &m ) const { Matrix4f mf( false ); mf.x[0] = x[0] * m.x[0] + x[4] * m.x[1] + x[8] * m.x[2] + x[12] * m.x[3]; mf.x[1] = x[1] * m.x[0] + x[5] * m.x[1] + x[9] * m.x[2] + x[13] * m.x[3]; mf.x[2] = x[2] * m.x[0] + x[6] * m.x[1] + x[10] * m.x[2] + x[14] * m.x[3]; mf.x[3] = x[3] * m.x[0] + x[7] * m.x[1] + x[11] * m.x[2] + x[15] * m.x[3]; mf.x[4] = x[0] * m.x[4] + x[4] * m.x[5] + x[8] * m.x[6] + x[12] * m.x[7]; mf.x[5] = x[1] * m.x[4] + x[5] * m.x[5] + x[9] * m.x[6] + x[13] * m.x[7]; mf.x[6] = x[2] * m.x[4] + x[6] * m.x[5] + x[10] * m.x[6] + x[14] * m.x[7]; mf.x[7] = x[3] * m.x[4] + x[7] * m.x[5] + x[11] * m.x[6] + x[15] * m.x[7]; mf.x[8] = x[0] * m.x[8] + x[4] * m.x[9] + x[8] * m.x[10] + x[12] * m.x[11]; mf.x[9] = x[1] * m.x[8] + x[5] * m.x[9] + x[9] * m.x[10] + x[13] * m.x[11]; mf.x[10] = x[2] * m.x[8] + x[6] * m.x[9] + x[10] * m.x[10] + x[14] * m.x[11]; mf.x[11] = x[3] * m.x[8] + x[7] * m.x[9] + x[11] * m.x[10] + x[15] * m.x[11]; mf.x[12] = x[0] * m.x[12] + x[4] * m.x[13] + x[8] * m.x[14] + x[12] * m.x[15]; mf.x[13] = x[1] * m.x[12] + x[5] * m.x[13] + x[9] * m.x[14] + x[13] * m.x[15]; mf.x[14] = x[2] * m.x[12] + x[6] * m.x[13] + x[10] * m.x[14] + x[14] * m.x[15]; mf.x[15] = x[3] * m.x[12] + x[7] * m.x[13] + x[11] * m.x[14] + x[15] * m.x[15]; return mf; } void fastMult( const Matrix4f &m1, const Matrix4f &m2 ) { x[0] = m1.x[0] * m2.x[0] + m1.x[4] * m2.x[1] + m1.x[8] * m2.x[2] + m1.x[12] * m2.x[3]; x[1] = m1.x[1] * m2.x[0] + m1.x[5] * m2.x[1] + m1.x[9] * m2.x[2] + m1.x[13] * m2.x[3]; x[2] = m1.x[2] * m2.x[0] + m1.x[6] * m2.x[1] + m1.x[10] * m2.x[2] + m1.x[14] * m2.x[3]; x[3] = m1.x[3] * m2.x[0] + m1.x[7] * m2.x[1] + m1.x[11] * m2.x[2] + m1.x[15] * m2.x[3]; x[4] = m1.x[0] * m2.x[4] + m1.x[4] * m2.x[5] + m1.x[8] * m2.x[6] + m1.x[12] * m2.x[7]; x[5] = m1.x[1] * m2.x[4] + m1.x[5] * m2.x[5] + m1.x[9] * m2.x[6] + m1.x[13] * m2.x[7]; x[6] = m1.x[2] * m2.x[4] + m1.x[6] * m2.x[5] + m1.x[10] * m2.x[6] + m1.x[14] * m2.x[7]; x[7] = m1.x[3] * m2.x[4] + m1.x[7] * m2.x[5] + m1.x[11] * m2.x[6] + m1.x[15] * m2.x[7]; x[8] = m1.x[0] * m2.x[8] + m1.x[4] * m2.x[9] + m1.x[8] * m2.x[10] + m1.x[12] * m2.x[11]; x[9] = m1.x[1] * m2.x[8] + m1.x[5] * m2.x[9] + m1.x[9] * m2.x[10] + m1.x[13] * m2.x[11]; x[10] = m1.x[2] * m2.x[8] + m1.x[6] * m2.x[9] + m1.x[10] * m2.x[10] + m1.x[14] * m2.x[11]; x[11] = m1.x[3] * m2.x[8] + m1.x[7] * m2.x[9] + m1.x[11] * m2.x[10] + m1.x[15] * m2.x[11]; x[12] = m1.x[0] * m2.x[12] + m1.x[4] * m2.x[13] + m1.x[8] * m2.x[14] + m1.x[12] * m2.x[15]; x[13] = m1.x[1] * m2.x[12] + m1.x[5] * m2.x[13] + m1.x[9] * m2.x[14] + m1.x[13] * m2.x[15]; x[14] = m1.x[2] * m2.x[12] + m1.x[6] * m2.x[13] + m1.x[10] * m2.x[14] + m1.x[14] * m2.x[15]; x[15] = m1.x[3] * m2.x[12] + m1.x[7] * m2.x[13] + m1.x[11] * m2.x[14] + m1.x[15] * m2.x[15]; } Matrix4f operator*( const float f ) const { Matrix4f m( *this ); for( unsigned int y = 0; y < 4; ++y ) { for( unsigned int x = 0; x < 4; ++x ) { m.c[x][y] *= f; } } return m; } // ---------------------------- // Vector-Matrix multiplication // ---------------------------- Vec3f operator*( const Vec3f &v ) const { return Vec3f( v.x * c[0][0] + v.y * c[1][0] + v.z * c[2][0] + c[3][0], v.x * c[0][1] + v.y * c[1][1] + v.z * c[2][1] + c[3][1], v.x * c[0][2] + v.y * c[1][2] + v.z * c[2][2] + c[3][2] ); } Vec4f operator*( const Vec4f &v ) const { return Vec4f( v.x * c[0][0] + v.y * c[1][0] + v.z * c[2][0] + c[3][0], v.x * c[0][1] + v.y * c[1][1] + v.z * c[2][1] + c[3][1], v.x * c[0][2] + v.y * c[1][2] + v.z * c[2][2] + c[3][2], v.x * c[0][3] + v.y * c[1][3] + v.z * c[2][3] + c[3][3] ); } // --------------- // Transformations // --------------- void translate( const float x, const float y, const float z ) { *this = TransMat( x, y, z ) * *this; } void scale( const float x, const float y, const float z ) { *this = ScaleMat( x, y, z ) * *this; } void rotate( const float x, const float y, const float z ) { *this = RotMat( x, y, z ) * *this; } // --------------- // Other // --------------- Matrix4f transposed() const { Matrix4f m( *this ); for( unsigned int y = 0; y < 4; ++y ) { for( unsigned int x = y + 1; x < 4; ++x ) { float tmp = m.c[x][y]; m.c[x][y] = m.c[y][x]; m.c[y][x] = tmp; } } return m; } float determinant() const { return c[0][3]*c[1][2]*c[2][1]*c[3][0] - c[0][2]*c[1][3]*c[2][1]*c[3][0] - c[0][3]*c[1][1]*c[2][2]*c[3][0] + c[0][1]*c[1][3]*c[2][2]*c[3][0] + c[0][2]*c[1][1]*c[2][3]*c[3][0] - c[0][1]*c[1][2]*c[2][3]*c[3][0] - c[0][3]*c[1][2]*c[2][0]*c[3][1] + c[0][2]*c[1][3]*c[2][0]*c[3][1] + c[0][3]*c[1][0]*c[2][2]*c[3][1] - c[0][0]*c[1][3]*c[2][2]*c[3][1] - c[0][2]*c[1][0]*c[2][3]*c[3][1] + c[0][0]*c[1][2]*c[2][3]*c[3][1] + c[0][3]*c[1][1]*c[2][0]*c[3][2] - c[0][1]*c[1][3]*c[2][0]*c[3][2] - c[0][3]*c[1][0]*c[2][1]*c[3][2] + c[0][0]*c[1][3]*c[2][1]*c[3][2] + c[0][1]*c[1][0]*c[2][3]*c[3][2] - c[0][0]*c[1][1]*c[2][3]*c[3][2] - c[0][2]*c[1][1]*c[2][0]*c[3][3] + c[0][1]*c[1][2]*c[2][0]*c[3][3] + c[0][2]*c[1][0]*c[2][1]*c[3][3] - c[0][0]*c[1][2]*c[2][1]*c[3][3] - c[0][1]*c[1][0]*c[2][2]*c[3][3] + c[0][0]*c[1][1]*c[2][2]*c[3][3]; } Matrix4f inverted() const { Matrix4f m( false ); float d = determinant(); if( d == 0 ) return m; d = 1 / d; m.c[0][0] = d * (c[1][2]*c[2][3]*c[3][1] - c[1][3]*c[2][2]*c[3][1] + c[1][3]*c[2][1]*c[3][2] - c[1][1]*c[2][3]*c[3][2] - c[1][2]*c[2][1]*c[3][3] + c[1][1]*c[2][2]*c[3][3]); m.c[0][1] = d * (c[0][3]*c[2][2]*c[3][1] - c[0][2]*c[2][3]*c[3][1] - c[0][3]*c[2][1]*c[3][2] + c[0][1]*c[2][3]*c[3][2] + c[0][2]*c[2][1]*c[3][3] - c[0][1]*c[2][2]*c[3][3]); m.c[0][2] = d * (c[0][2]*c[1][3]*c[3][1] - c[0][3]*c[1][2]*c[3][1] + c[0][3]*c[1][1]*c[3][2] - c[0][1]*c[1][3]*c[3][2] - c[0][2]*c[1][1]*c[3][3] + c[0][1]*c[1][2]*c[3][3]); m.c[0][3] = d * (c[0][3]*c[1][2]*c[2][1] - c[0][2]*c[1][3]*c[2][1] - c[0][3]*c[1][1]*c[2][2] + c[0][1]*c[1][3]*c[2][2] + c[0][2]*c[1][1]*c[2][3] - c[0][1]*c[1][2]*c[2][3]); m.c[1][0] = d * (c[1][3]*c[2][2]*c[3][0] - c[1][2]*c[2][3]*c[3][0] - c[1][3]*c[2][0]*c[3][2] + c[1][0]*c[2][3]*c[3][2] + c[1][2]*c[2][0]*c[3][3] - c[1][0]*c[2][2]*c[3][3]); m.c[1][1] = d * (c[0][2]*c[2][3]*c[3][0] - c[0][3]*c[2][2]*c[3][0] + c[0][3]*c[2][0]*c[3][2] - c[0][0]*c[2][3]*c[3][2] - c[0][2]*c[2][0]*c[3][3] + c[0][0]*c[2][2]*c[3][3]); m.c[1][2] = d * (c[0][3]*c[1][2]*c[3][0] - c[0][2]*c[1][3]*c[3][0] - c[0][3]*c[1][0]*c[3][2] + c[0][0]*c[1][3]*c[3][2] + c[0][2]*c[1][0]*c[3][3] - c[0][0]*c[1][2]*c[3][3]); m.c[1][3] = d * (c[0][2]*c[1][3]*c[2][0] - c[0][3]*c[1][2]*c[2][0] + c[0][3]*c[1][0]*c[2][2] - c[0][0]*c[1][3]*c[2][2] - c[0][2]*c[1][0]*c[2][3] + c[0][0]*c[1][2]*c[2][3]); m.c[2][0] = d * (c[1][1]*c[2][3]*c[3][0] - c[1][3]*c[2][1]*c[3][0] + c[1][3]*c[2][0]*c[3][1] - c[1][0]*c[2][3]*c[3][1] - c[1][1]*c[2][0]*c[3][3] + c[1][0]*c[2][1]*c[3][3]); m.c[2][1] = d * (c[0][3]*c[2][1]*c[3][0] - c[0][1]*c[2][3]*c[3][0] - c[0][3]*c[2][0]*c[3][1] + c[0][0]*c[2][3]*c[3][1] + c[0][1]*c[2][0]*c[3][3] - c[0][0]*c[2][1]*c[3][3]); m.c[2][2] = d * (c[0][1]*c[1][3]*c[3][0] - c[0][3]*c[1][1]*c[3][0] + c[0][3]*c[1][0]*c[3][1] - c[0][0]*c[1][3]*c[3][1] - c[0][1]*c[1][0]*c[3][3] + c[0][0]*c[1][1]*c[3][3]); m.c[2][3] = d * (c[0][3]*c[1][1]*c[2][0] - c[0][1]*c[1][3]*c[2][0] - c[0][3]*c[1][0]*c[2][1] + c[0][0]*c[1][3]*c[2][1] + c[0][1]*c[1][0]*c[2][3] - c[0][0]*c[1][1]*c[2][3]); m.c[3][0] = d * (c[1][2]*c[2][1]*c[3][0] - c[1][1]*c[2][2]*c[3][0] - c[1][2]*c[2][0]*c[3][1] + c[1][0]*c[2][2]*c[3][1] + c[1][1]*c[2][0]*c[3][2] - c[1][0]*c[2][1]*c[3][2]); m.c[3][1] = d * (c[0][1]*c[2][2]*c[3][0] - c[0][2]*c[2][1]*c[3][0] + c[0][2]*c[2][0]*c[3][1] - c[0][0]*c[2][2]*c[3][1] - c[0][1]*c[2][0]*c[3][2] + c[0][0]*c[2][1]*c[3][2]); m.c[3][2] = d * (c[0][2]*c[1][1]*c[3][0] - c[0][1]*c[1][2]*c[3][0] - c[0][2]*c[1][0]*c[3][1] + c[0][0]*c[1][2]*c[3][1] + c[0][1]*c[1][0]*c[3][2] - c[0][0]*c[1][1]*c[3][2]); m.c[3][3] = d * (c[0][1]*c[1][2]*c[2][0] - c[0][2]*c[1][1]*c[2][0] + c[0][2]*c[1][0]*c[2][1] - c[0][0]*c[1][2]*c[2][1] - c[0][1]*c[1][0]*c[2][2] + c[0][0]*c[1][1]*c[2][2]); return m; } void decompose( Vec3f &trans, Vec3f &rot, Vec3f &scale ) const { // Getting translation is trivial trans = Vec3f( c[3][0], c[3][1], c[3][2] ); // Scale is length of columns scale.x = sqrt( c[0][0] * c[0][0] + c[0][1] * c[0][1] + c[0][2] * c[0][2] ); scale.y = sqrt( c[1][0] * c[1][0] + c[1][1] * c[1][1] + c[1][2] * c[1][2] ); scale.z = sqrt( c[2][0] * c[2][0] + c[2][1] * c[2][1] + c[2][2] * c[2][2] ); if( scale.x == 0 || scale.y == 0 || scale.z == 0 ) return; // Detect negative scale with determinant and flip one arbitrary axis if( determinant() < 0 ) scale.x = -scale.x; // Combined rotation matrix YXZ // // Cos[y]*Cos[z]+Sin[x]*Sin[y]*Sin[z] Cos[z]*Sin[x]*Sin[y]-Cos[y]*Sin[z] Cos[x]*Sin[y] // Cos[x]*Sin[z] Cos[x]*Cos[z] -Sin[x] // -Cos[z]*Sin[y]+Cos[y]*Sin[x]*Sin[z] Cos[y]*Cos[z]*Sin[x]+Sin[y]*Sin[z] Cos[x]*Cos[y] rot.x = asinf( -c[2][1] / scale.z ); // Special case: Cos[x] == 0 (when Sin[x] is +/-1) float f = fabsf( c[2][1] / scale.z ); if( f > 0.999f && f < 1.001f ) { // Pin arbitrarily one of y or z to zero // Mathematical equivalent of gimbal lock rot.y = 0; // Now: Cos[x] = 0, Sin[x] = +/-1, Cos[y] = 1, Sin[y] = 0 // => m[0][0] = Cos[z] and m[1][0] = Sin[z] rot.z = atan2f( -c[1][0] / scale.y, c[0][0] / scale.x ); } // Standard case else { rot.y = atan2f( c[2][0] / scale.z, c[2][2] / scale.z ); rot.z = atan2f( c[0][1] / scale.x, c[1][1] / scale.y ); } } Vec4f getCol( unsigned int col ) const { return Vec4f( x[col * 4 + 0], x[col * 4 + 1], x[col * 4 + 2], x[col * 4 + 3] ); } Vec4f getRow( unsigned int row ) const { return Vec4f( x[row + 0], x[row + 4], x[row + 8], x[row + 12] ); } Vec3f getScale() { Vec3f scale; // Scale is length of columns scale.x = sqrt( c[0][0] * c[0][0] + c[0][1] * c[0][1] + c[0][2] * c[0][2] ); scale.y = sqrt( c[1][0] * c[1][0] + c[1][1] * c[1][1] + c[1][2] * c[1][2] ); scale.z = sqrt( c[2][0] * c[2][0] + c[2][1] * c[2][1] + c[2][2] * c[2][2] ); return scale; } }; // ------------------------------------------------------------------------------------------------- // Plane // ------------------------------------------------------------------------------------------------- class Plane { public: Vec3f normal; float dist; // ------------ // Constructors // ------------ Plane() { normal.x = 0; normal.y = 0; normal.z = 0; dist = 0; }; explicit Plane( const float a, const float b, const float c, const float d ) { normal = Vec3f( a, b, c ); float len = normal.length(); normal /= len; // Normalize dist = d / len; } Plane( const Vec3f &v0, const Vec3f &v1, const Vec3f &v2 ) { normal = v1 - v0; normal = normal.crossProduct( v2 - v0 ).normalized(); dist = -(normal * v0); } // ---------------- // Other operations // ---------------- float distToPoint( const Vec3f &v ) const { return (normal * v) + dist; } }; // ------------------------------------------------------------------------------------------------- // Intersection // ------------------------------------------------------------------------------------------------- inline bool rayTriangleIntersection( const Vec3f &rayOrig, const Vec3f &rayDir, const Vec3f &vert0, const Vec3f &vert1, const Vec3f &vert2, Vec3f &intsPoint ) { // Idea: Tomas Moeller and Ben Trumbore // in Fast, Minimum Storage Ray/Triangle Intersection // Find vectors for two edges sharing vert0 Vec3f edge1 = vert1 - vert0; Vec3f edge2 = vert2 - vert0; // Begin calculating determinant - also used to calculate U parameter Vec3f pvec = rayDir.crossProduct( edge2 ); // If determinant is near zero, ray lies in plane of triangle float det = edge1 * pvec; // *** Culling branch *** /*if( det < Math::Epsilon )return false; // Calculate distance from vert0 to ray origin Vec3f tvec = rayOrig - vert0; // Calculate U parameter and test bounds float u = tvec * pvec; if (u < 0 || u > det ) return false; // Prepare to test V parameter Vec3f qvec = tvec.crossProduct( edge1 ); // Calculate V parameter and test bounds float v = rayDir * qvec; if (v < 0 || u + v > det ) return false; // Calculate t, scale parameters, ray intersects triangle float t = (edge2 * qvec) / det;*/ // *** Non-culling branch *** if( det > -Math::Epsilon && det < Math::Epsilon ) return 0; float inv_det = 1.0f / det; // Calculate distance from vert0 to ray origin Vec3f tvec = rayOrig - vert0; // Calculate U parameter and test bounds float u = (tvec * pvec) * inv_det; if( u < 0.0f || u > 1.0f ) return 0; // Prepare to test V parameter Vec3f qvec = tvec.crossProduct( edge1 ); // Calculate V parameter and test bounds float v = (rayDir * qvec) * inv_det; if( v < 0.0f || u + v > 1.0f ) return 0; // Calculate t, ray intersects triangle float t = (edge2 * qvec) * inv_det; // Calculate intersection point and test ray length and direction intsPoint = rayOrig + rayDir * t; Vec3f vec = intsPoint - rayOrig; if( vec * rayDir < 0 || vec.length() > rayDir.length() ) return false; return true; } inline bool rayAABBIntersection( const Vec3f &rayOrig, const Vec3f &rayDir, const Vec3f &mins, const Vec3f &maxs ) { // SLAB based optimized ray/AABB intersection routine // Idea taken from http://ompf.org/ray/ float l1 = (mins.x - rayOrig.x) / rayDir.x; float l2 = (maxs.x - rayOrig.x) / rayDir.x; float lmin = minf( l1, l2 ); float lmax = maxf( l1, l2 ); l1 = (mins.y - rayOrig.y) / rayDir.y; l2 = (maxs.y - rayOrig.y) / rayDir.y; lmin = maxf( minf( l1, l2 ), lmin ); lmax = minf( maxf( l1, l2 ), lmax ); l1 = (mins.z - rayOrig.z) / rayDir.z; l2 = (maxs.z - rayOrig.z) / rayDir.z; lmin = maxf( minf( l1, l2 ), lmin ); lmax = minf( maxf( l1, l2 ), lmax ); if( (lmax >= 0.0f) & (lmax >= lmin) ) { // Consider length const Vec3f rayDest = rayOrig + rayDir; Vec3f rayMins( minf( rayDest.x, rayOrig.x), minf( rayDest.y, rayOrig.y ), minf( rayDest.z, rayOrig.z ) ); Vec3f rayMaxs( maxf( rayDest.x, rayOrig.x), maxf( rayDest.y, rayOrig.y ), maxf( rayDest.z, rayOrig.z ) ); return (rayMins.x < maxs.x) && (rayMaxs.x > mins.x) && (rayMins.y < maxs.y) && (rayMaxs.y > mins.y) && (rayMins.z < maxs.z) && (rayMaxs.z > mins.z); } else return false; } inline float nearestDistToAABB( const Vec3f &pos, const Vec3f &mins, const Vec3f &maxs ) { const Vec3f center = (mins + maxs) / 2.0f; const Vec3f extent = (maxs - mins) / 2.0f; Vec3f nearestVec; nearestVec.x = maxf( 0, fabsf( pos.x - center.x ) - extent.x ); nearestVec.y = maxf( 0, fabsf( pos.y - center.y ) - extent.y ); nearestVec.z = maxf( 0, fabsf( pos.z - center.z ) - extent.z ); return nearestVec.length(); } #endif // _utMath_H_