// Copyright (C) 2015-2015 ChaosForge Ltd // http://chaosforge.org/ // // This file is part of Nova libraries. // For conditions of distribution and use, see copying.txt file in root folder. /** * @file mat4.hh * @author Kornel Kisielewicz epyon@chaosforge.org * @brief matrix 4x4 */ #ifndef NV_STL_MATH_MAT4_HH #define NV_STL_MATH_MAT4_HH #include namespace nv { namespace math { template struct tmat4 { typedef tvec4 column_type; typedef tvec4 row_type; typedef tmat4 this_type; typedef size_t size_type; typedef T value_type; static constexpr size_type SIZE = 4; inline constexpr size_type size() const { return 4; } private: column_type value[4]; public: inline tmat4() : value{ column_type( static_cast( 1 ), static_cast( 0 ), static_cast( 0 ), static_cast( 0 ) ), column_type( static_cast( 0 ), static_cast( 1 ), static_cast( 0 ), static_cast( 0 ) ), column_type( static_cast( 0 ), static_cast( 0 ), static_cast( 1 ), static_cast( 0 ) ), column_type( static_cast( 0 ), static_cast( 0 ), static_cast( 0 ), static_cast( 1 ) ) } {} inline tmat4( const tmat4 & m ) = default; inline tmat4( tmat4 && m ) = default; inline tmat4 & operator=( const tmat4 & m ) = default; inline tmat4 & operator=( tmat4 && m ) = default; inline explicit tmat4( T s ) : value{ column_type( static_cast( s ), static_cast( 0 ), static_cast( 0 ), static_cast( 0 ) ), column_type( static_cast( 0 ), static_cast( s ), static_cast( 0 ), static_cast( 0 ) ), column_type( static_cast( 0 ), static_cast( 0 ), static_cast( s ), static_cast( 0 ) ), column_type( static_cast( 0 ), static_cast( 0 ), static_cast( 0 ), static_cast( s ) ) } {} inline explicit tmat4( no_init_t ) : value{ column_type( no_init ), column_type( no_init ), column_type( no_init ), column_type( no_init ) } {} inline tmat4( T x0, T y0, T z0, T w0, T x1, T y1, T z1, T w1, T x2, T y2, T z2, T w2, T x3, T y3, T z3, T w3 ) : value{ column_type( x0, y0, z0, w0 ), column_type( x1, y1, z1, w1 ), column_type( x2, y2, z2, w2 ), column_type( x3, y3, z3, w3 ) } {} inline tmat4( const column_type & v0, const column_type & v1, const column_type & v2, const column_type & v3 ) : value{ v0, v1, v2, v3 } {} template inline explicit tmat4( const tmat4 & m ) : value{ column_type( m[0] ), column_type( m[1] ), column_type( m[2] ), column_type( m[3] ) } {} inline explicit tmat4( const tmat2 & m ) : value{ column_type( m[0], static_cast( 0 ), static_cast( 0 ) ), column_type( m[1], static_cast( 0 ), static_cast( 0 ) ), column_type( static_cast( 0 ), static_cast( 0 ), static_cast( 1 ), static_cast( 0 ) ), column_type( static_cast( 0 ), static_cast( 0 ), static_cast( 0 ), static_cast( 1 ) ) } {} inline explicit tmat4( const tmat3 & m ) : value{ column_type( m[0], static_cast( 0 ) ), column_type( m[1], static_cast( 0 ) ), column_type( m[2], static_cast( 0 ) ), column_type( static_cast( 0 ), static_cast( 0 ), static_cast( 0 ), static_cast( 1 ) ) } {} inline column_type & operator[]( size_type i ) { NV_ASSERT_DEBUG( i >= 0 && i < this->size(), "index out of range!" ); return this->value[i]; } inline const column_type& operator[]( size_type i ) const { NV_ASSERT_DEBUG( i >= 0 && i < this->size(), "index out of range!" ); return this->value[i]; } inline tmat4& operator+=( T s ) { this->value[0] += s; this->value[1] += s; this->value[2] += s; this->value[3] += s; return *this; } inline tmat4& operator+=( const tmat4 & m ) { this->value[0] += m[0]; this->value[1] += m[1]; this->value[2] += m[2]; this->value[3] += m[3]; return *this; } inline tmat4 & operator-=( T s ) { this->value[0] -= s; this->value[1] -= s; this->value[2] -= s; this->value[3] -= s; return *this; } inline tmat4 & operator-=( const tmat4 & m ) { this->value[0] -= m[0]; this->value[1] -= m[1]; this->value[2] -= m[2]; this->value[3] -= m[3]; return *this; } inline tmat4 & operator*=( T s ) { this->value[0] *= s; this->value[1] *= s; this->value[2] *= s; this->value[3] *= s; return *this; } inline tmat4 & operator*=( const tmat4 & m ) { return ( *this = *this * m ); } inline tmat4 & operator/=( T s ) { this->value[0] /= s; this->value[1] /= s; this->value[2] /= s; this->value[3] /= s; return *this; } inline tmat4 & operator/=( const tmat4 & m ) { return ( *this = *this * detail::compute_inverse( m ) ); } inline tmat4 & operator++() { ++this->value[0]; ++this->value[1]; ++this->value[2]; ++this->value[3]; return *this; } inline tmat4 & operator--() { --this->value[0]; --this->value[1]; --this->value[2]; --this->value[3]; return *this; } inline tmat4 operator++( int ) { tmat4 result( *this ); ++*this; return result; } inline tmat4 operator--( int ) { tmat4 result( *this ); --*this; return result; } }; namespace detail { template inline tmat4 compute_inverse( const tmat4 & m ) { T cf00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; T cf02 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; T cf03 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; T cf04 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; T cf06 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; T cf07 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; T cf08 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; T cf10 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; T cf11 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; T cf12 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; T cf14 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; T cf15 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; T cf16 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; T cf18 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; T cf19 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; T cf20 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; T cf22 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; T cf23 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; tvec4 f0( cf00, cf00, cf02, cf03 ); tvec4 f1( cf04, cf04, cf06, cf07 ); tvec4 f2( cf08, cf08, cf10, cf11 ); tvec4 f3( cf12, cf12, cf14, cf15 ); tvec4 f4( cf16, cf16, cf18, cf19 ); tvec4 f5( cf20, cf20, cf22, cf23 ); tvec4 v0( m[1][0], m[0][0], m[0][0], m[0][0] ); tvec4 v1( m[1][1], m[0][1], m[0][1], m[0][1] ); tvec4 v2( m[1][2], m[0][2], m[0][2], m[0][2] ); tvec4 v3( m[1][3], m[0][3], m[0][3], m[0][3] ); tvec4 i0( v1 * f0 - v2 * f1 + v3 * f2 ); tvec4 i1( v0 * f0 - v2 * f3 + v3 * f4 ); tvec4 i2( v0 * f1 - v1 * f3 + v3 * f5 ); tvec4 i3( v0 * f2 - v1 * f4 + v2 * f5 ); tvec4 sgn_a( +1, -1, +1, -1 ); tvec4 sgn_b( -1, +1, -1, +1 ); tmat4 inv( i0 * sgn_a, i1 * sgn_b, i2 * sgn_a, i3 * sgn_b ); tvec4 rz( inv[0][0], inv[1][0], inv[2][0], inv[3][0] ); tvec4 d0( m[0] * rz ); T d1 = ( d0.x + d0.y ) + ( d0.z + d0.w ); T one_over_det = static_cast( 1 ) / d1; return inv * one_over_det; } } template inline tmat4 const operator-( const tmat4 & m ) { return tmat4( -m[0], -m[1], -m[2], -m[3] ); } template inline tmat4 operator+( const tmat4 & m, T s ) { return tmat4( m[0] + s, m[1] + s, m[2] + s, m[3] + s ); } template inline tmat4 operator+( T s, const tmat4 & m ) { return tmat4( m[0] + s, m[1] + s, m[2] + s, m[3] + s ); } template inline tmat4 operator+( const tmat4 & m1, const tmat4 & m2 ) { return tmat4( m1[0] + m2[0], m1[1] + m2[1], m1[2] + m2[2], m1[3] + m2[3] ); } template inline tmat4 operator-( const tmat4 & m, T s ) { return tmat4( m[0] - s, m[1] - s, m[2] - s, m[3] - s ); } template inline tmat4 operator-( T s, const tmat4 & m ) { return tmat4( s - m[0], s - m[1], s - m[2], s - m[3] ); } template inline tmat4 operator-( const tmat4 & m1, const tmat4 & m2 ) { return tmat4( m1[0] - m2[0], m1[1] - m2[1], m1[2] - m2[2], m1[3] - m2[3] ); } template inline tmat4 operator*( const tmat4 & m, T s ) { return tmat4( m[0] * s, m[1] * s, m[2] * s, m[3] * s ); } template inline tmat4 operator*( T s, const tmat4 & m ) { return tmat4( m[0] * s, m[1] * s, m[2] * s, m[3] * s ); } template inline typename tmat4::column_type operator*( const tmat4 & m, const typename tmat4::row_type & v ) { typedef typename tmat4::column_type column_type; column_type u0 = m[0] * column_type( v[0] ); column_type u1 = m[1] * column_type( v[1] ); column_type u2 = m[2] * column_type( v[2] ); column_type u3 = m[3] * column_type( v[3] ); return ( u0 + u1 ) + ( u2 + u3 ); } template inline typename tmat4::row_type operator* ( const typename tmat4::column_type & v, const tmat4 & m ) { return typename tmat4::row_type( m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2] + m[0][3] * v[3], m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2] + m[1][3] * v[3], m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2] + m[2][3] * v[3], m[3][0] * v[0] + m[3][1] * v[1] + m[3][2] * v[2] + m[3][3] * v[3] ); } template inline tmat4 operator*( const tmat4 & m1, const tmat4 & m2 ) { typedef typename tmat4::column_type column_type; column_type m2_0 = m2[0]; column_type m2_1 = m2[1]; column_type m2_2 = m2[2]; column_type m2_3 = m2[3]; tmat4 result( no_init ); result[0] = m1[0] * m2_0[0] + m1[1] * m2_0[1] + m1[2] * m2_0[2] + m1[3] * m2_0[3]; result[1] = m1[0] * m2_1[0] + m1[1] * m2_1[1] + m1[2] * m2_1[2] + m1[3] * m2_1[3]; result[2] = m1[0] * m2_2[0] + m1[1] * m2_2[1] + m1[2] * m2_2[2] + m1[3] * m2_2[3]; result[3] = m1[0] * m2_3[0] + m1[1] * m2_3[1] + m1[2] * m2_3[2] + m1[3] * m2_3[3]; return result; } template inline tmat4 operator/( const tmat4 & m, T s ) { return tmat4( m[0] / s, m[1] / s, m[2] / s, m[3] / s ); } template inline tmat4 operator/( T s, const tmat4 & m ) { return tmat4( s / m[0], s / m[1], s / m[2], s / m[3] ); } template inline typename tmat4::column_type operator/( const tmat4 & m, typename tmat4::row_type const & v ) { return detail::compute_inverse( m ) * v; } template inline typename tmat4::row_type operator/( typename tmat4::column_type const & v, const tmat4 & m ) { return v * detail::compute_inverse( m ); } template inline tmat4 operator/( const tmat4 & m1, const tmat4 & m2 ) { tmat4 m1_copy( m1 ); return m1_copy /= m2; } template inline bool operator==( const tmat4 & m1, const tmat4 & m2 ) { return ( m1[0] == m2[0] ) && ( m1[1] == m2[1] ) && ( m1[2] == m2[2] ) && ( m1[3] == m2[3] ); } template inline bool operator!=( const tmat4 & m1, const tmat4 & m2 ) { return ( m1[0] != m2[0] ) || ( m1[1] != m2[1] ) || ( m1[2] != m2[2] ) || ( m1[3] != m2[3] ); } } } #endif // NV_STL_MATH_MAT4_HH