//-------------------------------------------------------------------------------------- // Copyright 2013 Intel Corporation // All Rights Reserved // // Permission is granted to use, copy, distribute and prepare derivative works of this // software for any purpose and without fee, provided, that the above copyright notice // and this statement appear in all copies. Intel makes no representations about the // suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS." // INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY, // INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE, // INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not // assume any responsibility for any errors which may appear in this software nor any // responsibility to update it. //-------------------------------------------------------------------------------------- #ifndef __CPUTMath_h__ #define __CPUTMath_h__ #include /* * Constants */ static const float kEpsilon = 0.00001f; static const float kPi = 3.14159265358979323846f; static const float k2Pi = kPi*2.0f; static const float kPiDiv2 = kPi/2.0f; static const float kInvPi = 1.0f/kPi; static const float kDegToRad = (kPi/180.0f); static const float kRadToDeg = (180.0f/kPi); static inline float DegToRad( float fDeg ) { return fDeg * kDegToRad; } static inline float RadToDeg( float fRad ) { return fRad * kRadToDeg; } template static inline void Swap(T &a, T &b) { T t = b; b = a; a = t; } static inline double InvSqrt(const double x) { return 1.0 / sqrt(x); } struct float2; struct float3; struct float4; /**************************************\ float2 \**************************************/ struct float2 { union { struct { float x; float y; }; float f[2]; }; /***************************************\ | Constructors | \***************************************/ float2() {} explicit float2(float f) : x(f), y(f) { } explicit float2(float _x, float _y) : x(_x), y(_y) { } explicit float2(float* f) : x(f[0]), y(f[1]) { } float2(const float2 &v) : x(v.x), y(v.y) { } const float2 &operator=(const float2 &v) { x = v.x; y = v.y; return *this; } /***************************************\ | Basic math operations | \***************************************/ float2 operator+(const float2 &r) const { return float2(x+r.x, y+r.y); } const float2 &operator+=(const float2 &r) { x += r.x; y += r.y; return *this; } float2 operator-(const float2 &r) const { return float2(x-r.x, y-r.y); } const float2 &operator-=(const float2 &r) { x -= r.x; y -= r.y; return *this; } /***************************************\ | Basic math operations with scalars | \***************************************/ float2 operator+(float f) const { return float2(x+f, y+f); } const float2 &operator+=(float f) { x += f; y += f; return *this; } float2 operator-(float f) const { return float2(x-f, y-f); } const float2 &operator-=(float f) { x -= f; y -= f; return *this; } float2 operator*(float f) const { return float2(x*f, y*f); } const float2 &operator*=(float f) { x *= f; y *= f; return *this; } float2 operator/(float f) const { return float2(x/f, y/f); } const float2 &operator/=(float f) { x /= f; y /= f; return *this; } /***************************************\ | Other math | \***************************************/ // Equality bool operator==(const float2 &r) const { return (x==r.x && y == r.y); } bool operator!=(const float2 &r) const { return !(*this == r); } // Hadd float hadd(void) const { return x + y; } // Length float lengthSq(void) const { return x*x + y*y; } float length(void) const { return sqrtf(lengthSq()); } void normalize(void) { *this /= length(); } }; inline float dot2(const float2 &l, const float2 &r) { return l.x*r.x + l.y*r.y; } inline float2 normalize(const float2 &v) { float length = v.length(); return v / length; } /**************************************\ float3 \**************************************/ struct float3 { union { struct { float x; float y; float z; }; float f[3]; }; static const float3 Left; static const float3 Right; static const float3 Up; static const float3 Down; static const float3 Forward; static const float3 Backward; static const float3 ZeroF; /***************************************\ | Constructors | \***************************************/ float3() {} explicit float3(float f) : x(f), y(f), z(f) { } explicit float3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) { } explicit float3(float* f) : x(f[0]), y(f[1]), z(f[2]) { } float3(const float3 &v) : x(v.x), y(v.y), z(v.z) { } float3(const float4 &v); const float3 &operator=(const float3 &v) { x = v.x; y = v.y; z = v.z; return *this; } /***************************************\ | Basic math operations | \***************************************/ float3 operator+(const float3 &r) const { return float3(x+r.x, y+r.y, z+r.z); } const float3 &operator+=(const float3 &r) { x += r.x; y += r.y; z += r.z; return *this; } float3 operator-(const float3 &r) const { return float3(x-r.x, y-r.y, z-r.z); } float operator[](const int index) const { return (&x)[index]; } float operator*(const float3 &a) const { return x * a.x + y * a.y + z * a.z; } float Dot(const float3 &a) const { return x * a.x + y * a.y + z * a.z; } static float Dot(const float3 &a, const float3 &b) { return a.x * b.x + a.y * b.y + a.z * b.z; } float &operator[](const int index) { return (&x)[index]; } const float3 &operator-=(const float3 &r) { x -= r.x; y -= r.y; z -= r.z; return *this; } float NormalizeFast() { float sqrLength, invLength; sqrLength = x * x + y * y + z * z; invLength = InvSqrt(sqrLength); x *= invLength; y *= invLength; z *= invLength; return invLength * sqrLength; } float3 operator*(float3 &r) { return float3(x*r.x, y*r.y, z*r.z); } float3 operator*(const float a) const { return float3(x * a, y * a, z * a); } friend float3 operator*(const float a, const float3 b) { return float3(b.x * a, b.y * a, b.z * a); } const float3 &operator*=(const float3 &r) { x *= r.x; y *= r.y; z *= r.z; return *this; } float3 &operator*=(float3 &r) { x *= r.x; y *= r.y; z *= r.z; return *this; } bool Compare(const float3 &a) const { return ((x == a.x) && (y == a.y) && (z == a.z)); } bool Compare(const float3 &a, const float epsilon) const { if (fabs(x - a.x) > epsilon) { return false; } if (fabs(y - a.y) > epsilon) { return false; } if (fabs(z - a.z) > epsilon) { return false; } return true; } float3 operator/(const float3 &r) const { return float3(x/r.x, y/r.y, z/r.z); } const float3 &operator/=(const float3 &r) { x /= r.x; y /= r.y; z /= r.z; return *this; } /***************************************\ | Basic math operations with scalars | \***************************************/ float3 operator+(float f) const { return float3(x+f, y+f, z+f); } const float3 &operator+=(float f) { x += f; y += f; z += f; return *this; } float3 operator-(float f) const { return float3(x-f, y-f, z-f); } const float3 &operator-=(float f) { x -= f; y -= f; z -= f; return *this; } const float3 &operator*=(float f) { x *= f; y *= f; z *= f; return *this; } float3 operator/(float f) const { return float3(x/f, y/f, z/f); } const float3 &operator/=(float f) { x /= f; y /= f; z /= f; return *this; } void Zero() { x = 0; y = 0; z = 0; } /***************************************\ | Other math | \***************************************/ // Equality bool operator==(const float3 &r) const { return x==r.x &&y == r.y &&z == r.z; } bool operator!=(const float3 &r) const { return !(*this == r); } // Hadd float hadd(void) const { return x + y + z; } // Length float lengthSq(void) const { return x*x + y*y + z*z; } float length(void) const { return sqrtf(lengthSq()); } float3 normalize(void) { return (*this /= length()); } float NormalizeSelf() { float sqrLength, invLength; sqrLength = x * x + y * y + z * z; invLength = InvSqrt(sqrLength); x *= invLength; y *= invLength; z *= invLength; return invLength * sqrLength; } float3 Cross(const float3 &a) const { return float3(y * a.z - z * a.y, z * a.x - x * a.z, x * a.y - y * a.x); } float3 &Cross(const float3 &a, const float3 &b) { x = a.y * b.z - a.z * b.y; y = a.z * b.x - a.x * b.z; z = a.x * b.y - a.y * b.x; return *this; } }; inline float dot3(const float3 &l, const float3 &r) { return l.x*r.x + l.y*r.y + l.z*r.z; } inline float3 cross3(const float3 &l, const float3 &r) { return float3( l.y*r.z-l.z*r.y, l.z*r.x-l.x*r.z, l.x*r.y-l.y*r.x); } inline float3 normalize(const float3 &v) { float length = v.length(); return v / length; } inline float3 abs3( const float3 &l ) { float3 tmp; tmp.x = fabs(l.x); tmp.y = fabs(l.y); tmp.z = fabs(l.z); return tmp; } /**************************************\ float4 \**************************************/ __declspec(align(16)) struct float4 { union { struct { float x; float y; float z; float w; }; float f[4]; }; /***************************************\ | Constructors | \***************************************/ float4() {} explicit float4(float f) : x(f), y(f), z(f), w(f) { } explicit float4(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) { } explicit float4(float* f) : x(f[0]), y(f[1]), z(f[2]), w(f[3]) { } float4(const float4 &v) : x(v.x), y(v.y), z(v.z), w(v.w) { } float4(const float3 &v, float _w) : x(v.x), y(v.y), z(v.z), w(_w) { } const float4 &operator=(const float4 &v) { x = v.x; y = v.y; z = v.z; w = v.w; return *this; } /***************************************\ | Basic math operations | \***************************************/ float4 operator+(const float4 &r) const { return float4(x+r.x, y+r.y, z+r.z, w+r.w); } const float4 &operator+=(const float4 &r) { x += r.x; y += r.y; z += r.z; w += r.w; return *this; } float4 operator-(const float4 &r) const { return float4(x-r.x, y-r.y, z-r.z, w-r.w); } const float4 &operator-=(const float4 &r) { x -= r.x; y -= r.y; z -= r.z; w -= r.w; return *this; } float4 operator*(const float4 &r) const { return float4(x*r.x, y*r.y, z*r.z, w*r.w); } const float4 &operator*=(const float4 &r) { x *= r.x; y *= r.y; z *= r.z; w *= r.w; return *this; } float4 operator/(const float4 &r) const { return float4(x/r.x, y/r.y, z/r.z, w/r.w); } const float4 &operator/=(const float4 &r) { x /= r.x; y /= r.y; z /= r.z; w /= r.w; return *this; } /***************************************\ | Basic math operations with scalars | \***************************************/ float4 operator+(float f) const { return float4(x+f, y+f, z+f, w+f); } const float4 &operator+=(float f) { x += f; y += f; z += f; return *this; } float4 operator-(float f) const { return float4(x-f, y-f, z-f, w-f); } const float4 &operator-=(float f) { x -= f; y -= f; z -= f; w -= f; return *this; } float4 operator*(float f) const { return float4(x*f, y*f, z*f, w*f); } const float4 &operator*=(float f) { x *= f; y *= f; z *= f; w *= f; return *this; } float4 operator/(float f) const { return float4(x/f, y/f, z/f, w/f); } const float4 &operator/=(float f) { x /= f; y /= f; z /= f; w /= f; return *this; } /***************************************\ | Other math | \***************************************/ // Equality bool operator==(const float4 &r) const { return x==r.x && y == r.y && z == r.z && w == r.w; } bool operator!=(const float4 &r) const { return !(*this == r); } // Hadd float hadd(void) const { return x + y + z + w; } // Length float lengthSq(void) const { return x*x + y*y + z*z + w*w; } float length(void) const { return sqrtf(lengthSq()); } void normalize(void) { *this /= length(); } }; inline float dot4(const float4 &l, const float4 &r) { return l.x*r.x + l.y*r.y + l.z*r.z + l.w*r.w; } inline float4 normalize(const float4 &v) { float length = v.length(); return v / length; } inline float3::float3(const float4 &v) : x(v.x), y(v.y), z(v.z) { } /**************************************\ float3x3 \**************************************/ struct float4x4; struct float3x3 { struct { float3 r0; float3 r1; float3 r2; }; /***************************************\ | Constructors | \***************************************/ float3x3() {} explicit float3x3(float f) : r0(f), r1(f), r2(f) { } explicit float3x3(float* f) : r0(f+0), r1(f+3), r2(f+6) { } float3x3(const float3 &_r0, const float3 &_r1, const float3 &_r2) : r0(_r0), r1(_r1), r2(_r2) { } float3x3(float _m00, float _m01, float _m02, float _m10, float _m11, float _m12, float _m20, float _m21, float _m22) : r0(_m00,_m01,_m02) , r1(_m10,_m11,_m12) , r2(_m20,_m21,_m22) { } float3x3(const float4x4 &m); const float3x3 &operator=(const float3x3 &m) { r0 = m.r0; r1 = m.r1; r2 = m.r2; return *this; } /***************************************\ | Basic math operations | \***************************************/ #define MTX3_INDEX(f,r,c) ((f)[(r*3)+c]) inline float3x3 operator*(const float3x3 &r) const { float3x3 m(1,0,0,0,1,0,0,0,1); const float* left = (const float*)&this->r0; const float* right = (const float*)&r.r0; float* result = (float*)&m; int ii, jj, kk; for(ii=0; ii<3; ++ii) /* row */ { for(jj=0; jj<3; ++jj) /* column */ { float sum = MTX3_INDEX(left,ii,0)*MTX3_INDEX(right,0,jj); for(kk=1; kk<3; ++kk) { sum += (MTX3_INDEX(left,ii,kk)*MTX3_INDEX(right,kk,jj)); } MTX3_INDEX(result,ii,jj) = sum; } } return m; } #undef MTX3_INDEX inline float3 operator*(const float3 &v) const { float3 a; a.x = (r0*v); a.y = (r1*v); a.z = (r2*v); return a; } /***************************************\ | Basic math operations with scalars | \***************************************/ float3x3 operator+(float f) const { return float3x3(r0+f, r1+f, r2+f); } float3 const &operator[](int index) const { //assert( ( index >= 0 ) && ( index < 3 ) ); return (&r0)[index]; } float3 &operator[](int index) { //assert( ( index >= 0 ) && ( index < 3 ) ); return (&r0)[index]; } const float3x3 &operator+=(float f) { r0 += f; r1 += f; r2 += f; return *this; } friend float3 operator*(const float3 &vec, const float3x3 &mat) { return mat * vec; } friend float3x3 operator*(const float a, const float3x3 &mat) { return mat * a; } friend float3 &operator*=(float3 &vec, const float3x3 &mat) { float x = mat[0].x * vec.x + mat[1].x * vec.y + mat[2].x * vec.z; float y = mat[0].y * vec.x + mat[1].y * vec.y + mat[2].y * vec.z; vec.z = mat[0].z * vec.x + mat[1].z * vec.y + mat[2].z * vec.z; vec.x = x; vec.y = y; return vec; } float3x3 &operator*=(const float3x3 &a) { int i, j; const float *m2Ptr; float *m1Ptr, dst[3]; m1Ptr = reinterpret_cast(this); m2Ptr = reinterpret_cast(&a); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { dst[j] = m1Ptr[0] * m2Ptr[0 * 3 + j] + m1Ptr[1] * m2Ptr[1 * 3 + j] + m1Ptr[2] * m2Ptr[2 * 3 + j]; } m1Ptr[0] = dst[0]; m1Ptr[1] = dst[1]; m1Ptr[2] = dst[2]; m1Ptr += 3; } return *this; } float3x3 operator-(float f) const { return float3x3(r0-f, r1-f, r2-f); } bool Compare(const float3x3 &a) const { if (r0.Compare(a[0]) && r1.Compare(a[1]) && r2.Compare(a[2])) { return true; } return false; } bool Compare(const float3x3 &a, const float epsilon) const { if (r0.Compare(a[0], epsilon) && r1.Compare(a[1], epsilon) && r2.Compare(a[2], epsilon)) { return true; } return false; } const float3x3 &operator-=(float f) { r0 -= f; r1 -= f; r2 -= f; return *this; } float3x3 operator*(float f) const { return float3x3(r0*f, r1*f, r2*f); } const float3x3 &operator*=(float f) { r0 *= f; r1 *= f; r2 *= f; return *this; } float3x3 operator/(float f) const { return float3x3(r0/f, r1/f, r2/f); } const float3x3 &operator/=(float f) { r0 /= f; r1 /= f; r2 /= f; return *this; } /***************************************\ | Other math | \***************************************/ // Equality bool operator==(const float3x3 &r) const { return r0 == r.r0 && r1 == r.r1 && r2 == r.r2; } bool operator!=(const float3x3 &r) const { return !(*this == r); } float determinant() const { float f0 = r0.x * (r1.y*r2.z-r2.y*r1.z); float f1 = r0.y * -(r1.x*r2.z-r2.x*r1.z); float f2 = r0.z * (r1.x*r2.y-r2.x*r1.y); return f0 + f1 + f2; } void transpose(void) { Swap(r0.y, r1.x); Swap(r0.z, r2.x); Swap(r1.z, r2.y); } void invert(void) { float det = determinant(); float3x3 inv; inv.r0.x = (r1.y*r2.z) - (r1.z*r2.y); inv.r0.y = -((r1.x*r2.z) - (r1.z*r2.x)); inv.r0.z = (r1.x*r2.y) - (r1.y*r2.x); inv.r1.x = -((r0.y*r2.z) - (r0.z*r2.y)); inv.r1.y = (r0.x*r2.z) - (r0.z*r2.x); inv.r1.z = -((r0.x*r2.y) - (r0.y*r2.x)); inv.r2.x = (r0.y*r1.z) - (r0.z*r1.y); inv.r2.y = -((r0.x*r1.z) - (r0.z*r1.x)); inv.r2.z = (r0.x*r1.y) - (r0.y*r1.x); inv.transpose(); inv /= det; *this = inv; } }; inline float3x3 float3x3Identity(void) { return float3x3(1,0,0, 0,1,0, 0,0,1); } inline float determinant(const float3x3&m) { return m.determinant(); } inline float3x3 transpose(const float3x3 &m) { float3x3 ret = m; ret.transpose(); return ret; } inline float3x3 inverse(const float3x3 &m) { float3x3 ret = m; ret.invert(); return ret; } inline float3x3 float3x3RotationX(float rad) { float c = cosf( rad ); float s = sinf( rad ); float3x3 m( 1.0f, 0.0f, 0.0f, 0.0f, c, s, 0.0f, -s, c ); return m; } inline float3x3 float3x3RotationY(float rad) { float c = cosf( rad ); float s = sinf( rad ); float3x3 m( c, 0.0f, -s, 0.0f, 1.0f, 0.0f, s, 0.0f, c ); return m; } inline float3x3 float3x3RotationZ(float rad) { float c = cosf( rad ); float s = sinf( rad ); float3x3 m( c, s, 0.0f, -s, c, 0.0f, 0.0f, 0.0f, 1.0f ); return m; } inline float3x3 float3x3RotationAxis(const float3 &axis, float rad ) { float3 normAxis = normalize(axis); float c = cosf(rad); float s = sinf(rad); float t = 1 - c; float x = normAxis.x; float y = normAxis.y; float z = normAxis.z; float3x3 m; m.r0.x = (t * x * x) + c; m.r0.y = (t * x * y) + s * z; m.r0.z = (t * x * z) - s * y; m.r1.x = (t * x * y) - (s * z); m.r1.y = (t * y * y) + c; m.r1.z = (t * y * z) + (s * x); m.r2.x = (t * x * z) + (s * y); m.r2.y = (t * y * z) - (s * x); m.r2.z = (t * z * z) + c; return m; } inline float3x3 float3x3Scale(float x, float y, float z) { return float3x3(x,0,0, 0,y,0, 0,0,z); } /**************************************\ float4x4 \**************************************/ struct float4x4 { struct { float4 r0; float4 r1; float4 r2; float4 r3; }; /***************************************\ | Constructors | \***************************************/ float4x4() {} explicit float4x4(float f) : r0(f), r1(f), r2(f), r3(f) { } explicit float4x4(float* f) : r0(f+0), r1(f+4), r2(f+8), r3(f+12) { } float4x4(const float4 &_r0, const float4 &_r1, const float4 &_r2, const float4 &_r3) : r0(_r0), r1(_r1), r2(_r2), r3(_r3) { } float4x4(float _m00, float _m01, float _m02, float _m03, float _m10, float _m11, float _m12, float _m13, float _m20, float _m21, float _m22, float _m23, float _m30, float _m31, float _m32, float _m33) : r0(_m00,_m01,_m02,_m03) , r1(_m10,_m11,_m12,_m13) , r2(_m20,_m21,_m22,_m23) , r3(_m30,_m31,_m32,_m33) { } float4x4(const float3x3 &m) : r0(m.r0, 0.0f) , r1(m.r1, 0.0f) , r2(m.r2, 0.0f) , r3(0.0f, 0.0f, 0.0f, 1.0f) { } const float4x4 &operator=(const float4x4 &m) { r0 = m.r0; r1 = m.r1; r2 = m.r2; r3 = m.r3; return *this; } /***************************************\ | Basic math operations | \***************************************/ #define MTX4_INDEX(f,r,c) ((f)[(r*4)+c]) inline float4x4 operator*(const float4x4 &r) const { float4x4 m(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1); const float* right = (const float*)&this->r0; const float* left = (const float*)&r.r0; float* result = (float*)&m; int ii, jj, kk; for(ii=0; ii<4; ++ii) /* row */ { for(jj=0; jj<4; ++jj) /* column */ { float sum = MTX4_INDEX(left,ii,0)*MTX4_INDEX(right,0,jj); for(kk=1; kk<4; ++kk) { sum += (MTX4_INDEX(left,ii,kk)*MTX4_INDEX(right,kk,jj)); } MTX4_INDEX(result,ii,jj) = sum; } } return m; } #undef MTX4_INDEX inline float4 operator*(const float4 &v) const { float4 a; a.x = (r0*v).hadd(); a.y = (r1*v).hadd(); a.z = (r2*v).hadd(); a.w = (r3*v).hadd(); return a; } /***************************************\ | Basic math operations with scalars | \***************************************/ float4x4 operator+(float f) const { return float4x4(r0+f, r1+f, r2+f, r3+f); } const float4x4 &operator+=(float f) { r0 += f; r1 += f; r2 += f; r3 += f; return *this; } float4x4 operator-(float f) const { return float4x4(r0-f, r1-f, r2-f, r3-f); } const float4x4 &operator-=(float f) { r0 -= f; r1 -= f; r2 -= f; r3 -= f; return *this; } float4x4 operator*(float f) const { return float4x4(r0*f, r1*f, r2*f, r3*f); } const float4x4 &operator*=(float f) { r0 *= f; r1 *= f; r2 *= f; r3 *= f; return *this; } float4x4 operator/(float f) const { return float4x4(r0/f, r1/f, r2/f, r3/f); } const float4x4 &operator/=(float f) { r0 /= f; r1 /= f; r2 /= f; r3 /= f; return *this; } /***************************************\ | Other math | \***************************************/ // Equality bool operator==(const float4x4 &r) const { return r0 == r.r0 && r1 == r.r1 && r2 == r.r2 && r3 == r.r3; } bool operator!=(const float4x4 &r) const { return !(*this == r); } float determinant() const { float det = 0.0f; float3x3 a( r1.y,r1.z,r1.w, r2.y,r2.z,r2.w, r3.y,r3.z,r3.w); float3x3 b( r1.x,r1.z,r1.w, r2.x,r2.z,r2.w, r3.x,r3.z,r3.w); float3x3 c( r1.x,r1.y,r1.w, r2.x,r2.y,r2.w, r3.x,r3.y,r3.w); float3x3 d( r1.x,r1.y,r1.z, r2.x,r2.y,r2.z, r3.x,r3.y,r3.z); det += r0.x * a.determinant(); det -= r0.y * b.determinant(); det += r0.z * c.determinant(); det -= r0.w * d.determinant(); return det; } void transpose(void) { Swap(r0.y, r1.x); Swap(r0.z, r2.x); Swap(r0.w, r3.x); Swap(r1.z, r2.y); Swap(r1.w, r3.y); Swap(r2.w, r3.z); } void invert(void) { float4x4 ret; float recip; /* temp matrices */ /* row 1 */ float3x3 a( r1.y,r1.z,r1.w, r2.y,r2.z,r2.w, r3.y,r3.z,r3.w); float3x3 b( r1.x,r1.z,r1.w, r2.x,r2.z,r2.w, r3.x,r3.z,r3.w); float3x3 c( r1.x,r1.y,r1.w, r2.x,r2.y,r2.w, r3.x,r3.y,r3.w); float3x3 d( r1.x,r1.y,r1.z, r2.x,r2.y,r2.z, r3.x,r3.y,r3.z); /* row 2 */ float3x3 e( r0.y,r0.z,r0.w, r2.y,r2.z,r2.w, r3.y,r3.z,r3.w); float3x3 f( r0.x,r0.z,r0.w, r2.x,r2.z,r2.w, r3.x,r3.z,r3.w); float3x3 g( r0.x,r0.y,r0.w, r2.x,r2.y,r2.w, r3.x,r3.y,r3.w); float3x3 h( r0.x,r0.y,r0.z, r2.x,r2.y,r2.z, r3.x,r3.y,r3.z); /* row 3 */ float3x3 i( r0.y,r0.z,r0.w, r1.y,r1.z,r1.w, r3.y,r3.z,r3.w); float3x3 j( r0.x,r0.z,r0.w, r1.x,r1.z,r1.w, r3.x,r3.z,r3.w); float3x3 k( r0.x,r0.y,r0.w, r1.x,r1.y,r1.w, r3.x,r3.y,r3.w); float3x3 l( r0.x,r0.y,r0.z, r1.x,r1.y,r1.z, r3.x,r3.y,r3.z); /* row 4 */ float3x3 m( r0.y, r0.z, r0.w, r1.y, r1.z, r1.w, r2.y, r2.z, r2.w); float3x3 n( r0.x, r0.z, r0.w, r1.x, r1.z, r1.w, r2.x, r2.z, r2.w); float3x3 o( r0.x,r0.y,r0.w, r1.x,r1.y,r1.w, r2.x,r2.y,r2.w); float3x3 p( r0.x,r0.y,r0.z, r1.x,r1.y,r1.z, r2.x,r2.y,r2.z); /* row 1 */ ret.r0.x = a.determinant(); ret.r0.y = -b.determinant(); ret.r0.z = c.determinant(); ret.r0.w = -d.determinant(); /* row 2 */ ret.r1.x = -e.determinant(); ret.r1.y = f.determinant(); ret.r1.z = -g.determinant(); ret.r1.w = h.determinant(); /* row 3 */ ret.r2.x = i.determinant(); ret.r2.y = -j.determinant(); ret.r2.z = k.determinant(); ret.r2.w = -l.determinant(); /* row 4 */ ret.r3.x = -m.determinant(); ret.r3.y = n.determinant(); ret.r3.z = -o.determinant(); ret.r3.w = p.determinant(); ret.transpose(); recip = 1.0f/determinant(); ret *= recip; *this = ret; } // Axis access float3 getXAxis(void) const { return r0; } float3 getYAxis(void) const { return r1; } float3 getZAxis(void) const { return r2; } float3 getPosition(void) const { return float3(r3); } void orthonormalize(void) { float3 x = getXAxis(); float3 y = getYAxis(); float3 z; x.normalize(); z = normalize(cross3(x, y)); y = normalize(cross3(z, x)); r0 = float4(x, 0.0f); r1 = float4(y, 0.0f); r2 = float4(z, 0.0f); } }; inline float3x3::float3x3(const float4x4 &m) : r0(m.r0) , r1(m.r1) , r2(m.r2) { } inline float determinant(const float4x4&m) { return m.determinant(); } inline float4x4 float4x4Identity(void) { return float4x4(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1); } inline float4x4 transpose(const float4x4 &m) { float4x4 ret = m; ret.transpose(); return ret; } inline float4x4 inverse(const float4x4 &m) { float4x4 ret = m; ret.invert(); return ret; } inline float4x4 float4x4RotationX(float rad) { float c = cosf( rad ); float s = sinf( rad ); float4x4 m( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, c, s, 0.0f, 0.0f, -s, c, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); return m; } inline float4x4 float4x4RotationY(float rad) { float c = cosf( rad ); float s = sinf( rad ); float4x4 m( c, 0.0f, -s, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, s, 0.0f, c, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); return m; } inline float4x4 float4x4RotationZ(float rad) { float c = cosf( rad ); float s = sinf( rad ); float4x4 m( c, s, 0.0f, 0.0f, -s, c, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); return m; } inline float4x4 float4x4RotationAxis(const float3 &axis, float rad ) { float3 normAxis = normalize(axis); float c = cosf(rad); float s = sinf(rad); float t = 1 - c; float x = normAxis.x; float y = normAxis.y; float z = normAxis.z; float4x4 m = float4x4Identity(); m.r0.x = (t * x * x) + c; m.r0.y = (t * x * y) + s * z; m.r0.z = (t * x * z) - s * y; m.r1.x = (t * x * y) - (s * z); m.r1.y = (t * y * y) + c; m.r1.z = (t * y * z) + (s * x); m.r2.x = (t * x * z) + (s * y); m.r2.y = (t * y * z) - (s * x); m.r2.z = (t * z * z) + c; return m; } inline float4x4 float4x4Scale(float x, float y, float z) { return float4x4(x,0,0,0, 0,y,0,0, 0,0,z,0, 0,0,0,1); } inline float4x4 float4x4Translation(float x, float y, float z) { float4x4 m = float4x4Identity(); m.r3.x = x; m.r3.y = y; m.r3.z = z; return m; } inline float4x4 float4x4Translation(const float3 &v) { return float4x4Translation(v.x, v.y, v.z); } inline float4x4 float4x4PerspectiveFovLH(float fov, float aspect, float nearPlane, float farPlane) { float width = tanf(fov * 0.5f); float height = width / aspect; float diff = farPlane-nearPlane; float div = farPlane / diff; float4x4 m( 1.0f/width, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f/height, 0.0f, 0.0f, 0.0f, 0.0f, div, 1.0f, 0.0f, 0.0f, -nearPlane*div, 0.0f ); return m; } inline float4x4 float4x4PerspectiveFovRH(float fov, float aspect, float nearPlane, float farPlane) { float4x4 m = float4x4Identity(); float f = tanf(kPiDiv2 - (fov/2.0f)); float diff = nearPlane-farPlane; float div = farPlane / diff; m.r0.x = f/aspect; m.r1.y = f; m.r2.z = div; m.r2.w = -1; m.r3.z = nearPlane * div; m.r3.w = 0; return m; } inline float4x4 float4x4PerspectiveLH(float width, float height, float nearPlane, float farPlane) { float4x4 m = float4x4Identity(); m.r0.x = 2*nearPlane/width; m.r1.y = 2*nearPlane/height; m.r2.z = farPlane/(farPlane-nearPlane); m.r2.w = 1; m.r3.z = nearPlane*farPlane/(nearPlane-farPlane); m.r3.w = 0; return m; } inline float4x4 float4x4PerspectiveRH(float width, float height, float nearPlane, float farPlane) { float4x4 m = float4x4Identity(); m.r0.x = 2*nearPlane/width; m.r1.y = 2*nearPlane/height; m.r2.z = farPlane/(nearPlane-farPlane); m.r2.w = -1; m.r3.z = nearPlane*farPlane/(nearPlane-farPlane); m.r3.w = 0; return m; } inline float4x4 float4x4OrthographicOffCenterLH(float left, float right, float top, float bottom, float nearPlane, float farPlane) { float4x4 m = float4x4Identity(); float diff = farPlane-nearPlane; m.r0.x = 2.0f/(right-left); m.r1.y = 2.0f/(top-bottom); m.r2.z = 1.0f/diff; m.r3.x = -((left+right)/(right-left)); m.r3.y = -((top+bottom)/(top-bottom)); m.r3.z = -nearPlane/diff; return m; } inline float4x4 float4x4OrthographicOffCenterRH(float left, float right, float top, float bottom, float nearPlane, float farPlane) { float4x4 m = float4x4Identity(); float diff = nearPlane-farPlane; m.r0.x = 2.0f/(right-left); m.r1.y = 2.0f/(top-bottom); m.r2.z = 1.0f/diff; m.r3.x = -((left+right)/(right-left)); m.r3.y = -((top+bottom)/(top-bottom)); m.r3.z = nearPlane/diff; return m; } inline float4x4 float4x4OrthographicLH(float width, float height, float nearPlane, float farPlane) { float halfWidth = width/2.0f; float halfHeight = height/2.0f; return float4x4OrthographicOffCenterLH(-halfWidth, halfWidth, halfHeight, -halfHeight, nearPlane, farPlane); } inline float4x4 float4x4OrthographicRH(float width, float height, float nearPlane, float farPlane) { float halfWidth = width/2.0f; float halfHeight = height/2.0f; return float4x4OrthographicOffCenterRH(-halfWidth, halfWidth, halfHeight, -halfHeight, nearPlane, farPlane); } /**************************************\ Quaternion \**************************************/ struct quaternion : public float4 { /***************************************\ | Constructors | \***************************************/ quaternion() {} explicit quaternion(float f) : float4(f) { } explicit quaternion(float _x, float _y, float _z, float _w) : float4(_x,_y,_z,_w) { } explicit quaternion(float* f) : float4(f) { } quaternion(const quaternion &v) : float4(v) { } quaternion(const float3 &v, float _w) { float3 norm = ::normalize(v); float a = _w*0.5f; float s = sinf(a); x = norm.x*s; y = norm.y*s; z = norm.z*s; w = cosf(a); } const quaternion &operator=(const quaternion &v) { x = v.x; y = v.y; z = v.z; w = v.w; return *this; } /* Methods */ float3 getXAxis(void) const { float3 ret( 1-2*(y*y+z*z), 2*(x*y+w*z), 2*(x*z-y*w)); return ret; } float3 getYAxis(void) const { float3 ret( 2*(x*y-z*w), 1-2*(x*x+z*z), 2*(y*z+x*w)); return ret; } float3 getZAxis(void) const { float3 ret( 2*(x*z+y*w), 2*(y*z-x*w), 1-2*(x*x+y*y)); return ret; } float3x3 getMatrix(void) const { quaternion q = *this; q.normalize(); float xx = q.x * q.x; float yy = q.y * q.y; float zz = q.z * q.z; float xy = q.x * q.y; float zw = q.z * q.w; float xz = q.x * q.z; float yw = q.y * q.w; float yz = q.y * q.z; float xw = q.x * q.w; float3x3 ret(1 - 2*(yy+zz), 2*(xy+zw), 2*(xz-yw), 2*(xy-zw), 1 - 2*(xx+zz), 2*(yz+xw), 2*(xz+yw), 2*(yz-xw), 1 - 2*(xx+yy) ); return ret; } quaternion conjugate(void) const { return quaternion(-x, -y, -z, w); } quaternion inverse(void) const { // Note: Only normalized quaternions are supportted at the moment quaternion q = *this; q.normalize(); return q.conjugate(); } }; inline quaternion quaternionMultiply(const quaternion &l, const quaternion &r) { quaternion q( r.w*l.x + r.x*l.w + r.y*l.z - r.z*l.y, r.w*l.y + r.y*l.w + r.z*l.x - r.x*l.z, r.w*l.z + r.z*l.w + r.x*l.y - r.y*l.x, r.w*l.w - r.x*l.x - r.y*l.y - r.z*l.z ); return q; } inline quaternion quaternionIdentity(void) { return quaternion(0.0f, 0.0f, 0.0f, 1.0f); } inline float3 Min( float3 &v0, float3 &v1 ) { float3 result; result.x = v0.x < v1.x ? v0.x : v1.x; result.y = v0.y < v1.y ? v0.y : v1.y; result.z = v0.z < v1.z ? v0.z : v1.z; return result; } inline float3 Max( float3 &v0, float3 &v1 ) { float3 result; result.x = v0.x > v1.x ? v0.x : v1.x; result.y = v0.y > v1.y ? v0.y : v1.y; result.z = v0.z > v1.z ? v0.z : v1.z; return result; } inline float4 Min( float4 &v0, float4 &v1 ) { float4 result; result.x = v0.x < v1.x ? v0.x : v1.x; result.y = v0.y < v1.y ? v0.y : v1.y; result.z = v0.z < v1.z ? v0.z : v1.z; result.w = v0.w < v1.w ? v0.w : v1.w; return result; } inline float4 Max( float4 &v0, float4 &v1 ) { float4 result; result.x = v0.x > v1.x ? v0.x : v1.x; result.y = v0.y > v1.y ? v0.y : v1.y; result.z = v0.z > v1.z ? v0.z : v1.z; result.w = v0.w > v1.w ? v0.w : v1.w; return result; } inline float4 operator*(const float4 &v, const float4x4 &m) { float4 result; result = m.r0 * v.x; result += m.r1 * v.y; result += m.r2 * v.z; result += m.r3 * v.w; return result; } /* ============================ CreateLookAtMatrix ============================ */ inline float4x4 CreateLookAtMatrix(float3 cameraPosition, float3 cameraTarget, float3 cameraUpVector) { float3 vector3_1 = (cameraPosition - cameraTarget).normalize(); float3 vector3_2; vector3_2.Cross(cameraUpVector, vector3_1); vector3_2.NormalizeSelf(); float3 vector1; vector1.Cross(vector3_1, vector3_2); float4x4 matrix; matrix.r0.x = vector3_2.x; matrix.r0.y = vector1.x; matrix.r0.z = vector3_1.x; matrix.r0.w = 0.0f; matrix.r1.x = vector3_2.y; matrix.r1.y = vector1.y; matrix.r1.z = vector3_1.y; matrix.r1.w = 0.0f; matrix.r2.x = vector3_2.z; matrix.r2.y = vector1.z; matrix.r2.z = vector3_1.z; matrix.r2.w = 0.0f; matrix.r3.x = -float3::Dot(vector3_2, cameraPosition); matrix.r3.y = -float3::Dot(vector1, cameraPosition); matrix.r3.z = -float3::Dot(vector3_1, cameraPosition); matrix.r3.w = 1.0f; return matrix; } __inline float3 abs(const float3 xyz) { float3 result(fabs(xyz.x), fabs(xyz.y), fabs(xyz.z)); return result; } __inline float4 abs(const float4 xyz) { float4 result(fabs(xyz.x), fabs(xyz.y), fabs(xyz.z), fabs(xyz.w)); return result; } __inline float3 fabs(const float3 xyz) { float3 result(fabs(xyz.x), fabs(xyz.y), fabs(xyz.z)); return result; } __inline float4 fabs(const float4 xyz) { float4 result(fabs(xyz.x), fabs(xyz.y), fabs(xyz.z), fabs(xyz.w)); return result; } static const float Identity[16] = { 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 }; __inline void _math_matrix_rotate(float4x4 &matrix, float angle, float x, float y, float z) { float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c, s, c; float m[16]; bool optimized; #define M_PI 3.14159265358979323846 s = sinf(angle * M_PI / 180.0); c = cosf(angle * M_PI / 180.0); memcpy(m, Identity, sizeof(Identity)); optimized = false; #define M(row,col) m[col*4+row] if (x == 0.0F) { if (y == 0.0F) { if (z != 0.0F) { optimized = true; /* rotate only around z-axis */ M(0, 0) = c; M(1, 1) = c; if (z < 0.0F) { M(0, 1) = s; M(1, 0) = -s; } else { M(0, 1) = -s; M(1, 0) = s; } } } else if (z == 0.0F) { optimized = true; /* rotate only around y-axis */ M(0, 0) = c; M(2, 2) = c; if (y < 0.0F) { M(0, 2) = -s; M(2, 0) = s; } else { M(0, 2) = s; M(2, 0) = -s; } } } else if (y == 0.0F) { if (z == 0.0F) { optimized = true; /* rotate only around x-axis */ M(1, 1) = c; M(2, 2) = c; if (x < 0.0F) { M(1, 2) = s; M(2, 1) = -s; } else { M(1, 2) = -s; M(2, 1) = s; } } } if (!optimized) { const float mag = sqrtf(x * x + y * y + z * z); if (mag <= 1.0e-4F) { /* no rotation, leave mat as-is */ return; } x /= mag; y /= mag; z /= mag; /* * Arbitrary axis rotation matrix. * * This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied * like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation * (which is about the X-axis), and the two composite transforms * Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary * from the arbitrary axis to the X-axis then back. They are * all elementary rotations. * * Rz' is a rotation about the Z-axis, to bring the axis vector * into the x-z plane. Then Ry' is applied, rotating about the * Y-axis to bring the axis vector parallel with the X-axis. The * rotation about the X-axis is then performed. Ry and Rz are * simply the respective inverse transforms to bring the arbitrary * axis back to its original orientation. The first transforms * Rz' and Ry' are considered inverses, since the data from the * arbitrary axis gives you info on how to get to it, not how * to get away from it, and an inverse must be applied. * * The basic calculation used is to recognize that the arbitrary * axis vector (x, y, z), since it is of unit length, actually * represents the sines and cosines of the angles to rotate the * X-axis to the same orientation, with theta being the angle about * Z and phi the angle about Y (in the order described above) * as follows: * * cos ( theta ) = x / sqrt ( 1 - z^2 ) * sin ( theta ) = y / sqrt ( 1 - z^2 ) * * cos ( phi ) = sqrt ( 1 - z^2 ) * sin ( phi ) = z * * Note that cos ( phi ) can further be inserted to the above * formulas: * * cos ( theta ) = x / cos ( phi ) * sin ( theta ) = y / sin ( phi ) * * ...etc. Because of those relations and the standard trigonometric * relations, it is pssible to reduce the transforms down to what * is used below. It may be that any primary axis chosen will give the * same results (modulo a sign convention) using thie method. * * Particularly nice is to notice that all divisions that might * have caused trouble when parallel to certain planes or * axis go away with care paid to reducing the expressions. * After checking, it does perform correctly under all cases, since * in all the cases of division where the denominator would have * been zero, the numerator would have been zero as well, giving * the expected result. */ xx = x * x; yy = y * y; zz = z * z; xy = x * y; yz = y * z; zx = z * x; xs = x * s; ys = y * s; zs = z * s; one_c = 1.0F - c; /* We already hold the identity-matrix so we can skip some statements */ M(0, 0) = (one_c * xx) + c; M(0, 1) = (one_c * xy) - zs; M(0, 2) = (one_c * zx) + ys; /* M(0,3) = 0.0F; */ M(1, 0) = (one_c * xy) + zs; M(1, 1) = (one_c * yy) + c; M(1, 2) = (one_c * yz) - xs; /* M(1,3) = 0.0F; */ M(2, 0) = (one_c * zx) - ys; M(2, 1) = (one_c * yz) + xs; M(2, 2) = (one_c * zz) + c; /* M(2,3) = 0.0F; */ /* M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = 0.0F; M(3,3) = 1.0F; */ } #undef M float4x4 _internalMatrix(&m[0]); //_internalMatrix.r[0] = XMVectorSet(m[0], m[1], m[2], m[3]); //_internalMatrix.r[1] = XMVectorSet(m[4], m[5], m[6], m[7]); //_internalMatrix.r[2] = XMVectorSet(m[8], m[9], m[10], m[11]); //_internalMatrix.r[3] = XMVectorSet(m[12], m[13], m[14], m[15]); float4x4 temp = matrix * _internalMatrix; matrix = temp; //matmul4(mat, mat, m); //matrix_multf(mat, m, MAT_FLAG_ROTATION); } static void glhFrustumf2(float *matrix, float left, float right, float bottom, float top, float znear, float zfar) { float temp, temp2, temp3, temp4; temp = 2.0 * znear; temp2 = right - left; temp3 = top - bottom; temp4 = zfar - znear; matrix[0] = temp / temp2; matrix[1] = 0.0; matrix[2] = 0.0; matrix[3] = 0.0; matrix[4] = 0.0; matrix[5] = temp / temp3; matrix[6] = 0.0; matrix[7] = 0.0; matrix[8] = (right + left) / temp2; matrix[9] = (top + bottom) / temp3; matrix[10] = (-zfar - znear) / temp4; matrix[11] = -1.0; matrix[12] = 0.0; matrix[13] = 0.0; matrix[14] = (-temp * zfar) / temp4; matrix[15] = 0.0; } static void glhPerspectivef2(float *matrix, float fovyInDegrees, float aspectRatio, float znear, float zfar) { float ymax, xmax; float temp, temp2, temp3, temp4; ymax = znear * tanf(fovyInDegrees * M_PI / 360.0); //ymin = -ymax; //xmin = -ymax * aspectRatio; xmax = ymax * aspectRatio; glhFrustumf2(matrix, -xmax, xmax, -ymax, ymax, znear, zfar); } #endif // #ifndef __CPUTMath_h__