engine/engine/inc/uf/utils/math/matrix/pod.inl

701 lines
22 KiB
C++

#if !__clang__ && __GNUC__
#pragma GCC push_options
#pragma GCC optimize ("unroll-loops")
#endif
// Overloaded ops
// Accessing via subscripts
template<typename T, size_t R, size_t C>
inline T& pod::Matrix<T,R,C>::operator[](uint_fast8_t i) {
// static T null = 0.0/0.0;
// if ( i >= R*C ) return null;
return this->components[i];
}
template<typename T, size_t R, size_t C>
inline const T& pod::Matrix<T,R,C>::operator[](uint_fast8_t i) const {
// static T null = 0.0/0.0;
// if ( i >= R*C ) return null;
return this->components[i];
}
template<typename T, size_t R, size_t C>
pod::Matrix<T,R,C> pod::Matrix<T,R,C>::operator()() const {
pod::Matrix<T,R,C> matrix;
#pragma unroll // GCC unroll C
for ( uint_fast8_t c = 0; c < C; ++c )
#pragma unroll // GCC unroll R
for ( uint_fast8_t r = 0; r < R; ++r )
matrix[r+c*C] = (r == c ? 1 : 0);
return matrix;
}
template<typename T, size_t R, size_t C>
inline T& pod::Matrix<T,R,C>::operator()(uint_fast8_t r, uint_fast8_t c) {
return this->components[r+c*C];
}
template<typename T, size_t R, size_t C>
inline const T& pod::Matrix<T,R,C>::operator()(uint_fast8_t r, uint_fast8_t c) const {
return this->components[r+c*C];
}
/*
template<typename T, size_t R, size_t C>
T* pod::Matrix<T,R,C>::operator[](size_t i) {
return this->components[i];
}
template<typename T, size_t R, size_t C>
const T* pod::Matrix<T,R,C>::operator[](size_t i) const {
return this->components[i];
}
*/
template<typename T>
pod::Matrix4t<T> /*UF_API*/ uf::matrix::identity() {
ALIGN16 pod::Matrix4t<T> matrix;
#pragma unroll // GCC unroll 4
for ( uint_fast8_t c = 0; c < 4; ++c )
#pragma unroll // GCC unroll 4
for ( uint_fast8_t r = 0; r < 4; ++r )
matrix[r+c*4] = (r == c ? 1 : 0);
return matrix;
}
template<typename T>
pod::Matrix4t<T> /*UF_API*/ uf::matrix::initialize( const T* list ) {
ALIGN16 pod::Matrix4t<T> matrix;
// memcpy(&matrix[0], list, sizeof(matrix));
#pragma unroll // GCC unroll 16
for ( uint_fast8_t i = 0; i < 16; ++i )
matrix.components[i] = list[i];
/*
for ( uint_fast8_t r = 0; r < 4; ++r )
for ( uint_fast8_t c = 0; c < 4; ++c )
matrix[r+c*4] = list[r+c*4];
*/
return matrix;
}
template<typename T>
pod::Matrix4t<T> /*UF_API*/ uf::matrix::initialize( const uf::stl::vector<T>& list ) {
ALIGN16 pod::Matrix4t<T> matrix;
if ( list.size() != 16 ) return matrix;
// memcpy(&matrix[0], &list[0], sizeof(matrix));
#pragma unroll // GCC unroll 16
for ( uint_fast8_t i = 0; i < 16; ++i )
matrix.components[i] = list[i];
/*
#pragma unroll // GCC unroll 4
for ( uint_fast8_t r = 0; r < 4; ++r )
#pragma unroll // GCC unroll 4
for ( uint_fast8_t c = 0; c < 4; ++c )
matrix[r+c*4] = list[r+c*4];
*/
return matrix;
}
template<typename T> pod::Matrix<typename T::type_t, T::columns, T::columns> uf::matrix::identityi(){
ALIGN16 pod::Matrix<typename T::type_t, T::columns, T::columns> matrix;
#pragma unroll // GCC unroll T::columns
for ( uint_fast8_t c = 0; c < T::columns; ++c )
#pragma unroll // GCC unroll T::rows
for ( uint_fast8_t r = 0; r < T::rows; ++r )
matrix[r+c*T::columns] = (r == c ? 1 : 0);
return matrix;
}
// Arithmetic
// Negation
template<typename T, size_t R, size_t C>
inline pod::Matrix<T,R,C> pod::Matrix<T,R,C>::operator-() const {
return uf::matrix::inverse(*this);
}
// Multiplication between two matrices
template<typename T, size_t R, size_t C>
inline pod::Matrix<T,R,C> pod::Matrix<T,R,C>::operator*( const Matrix<T,R,C>& matrix ) const {
return uf::matrix::multiply(*this, matrix);
}
// Multiplication between two matrices
template<typename T, size_t R, size_t C>
inline pod::Matrix<T,R,C> pod::Matrix<T,R,C>::operator*( T scalar ) const {
return uf::matrix::multiplyAll(*this, scalar);
}
// Multiplication between two matrices
template<typename T, size_t R, size_t C>
inline pod::Matrix<T,R,C> pod::Matrix<T,R,C>::operator+( const Matrix<T,R,C>& matrix ) const {
return uf::matrix::add(*this, matrix);
}
// Multiplication set between two matrices
template<typename T, size_t R, size_t C>
inline pod::Matrix<T,R,C>& pod::Matrix<T,R,C>::operator *=( const Matrix<T,R,C>& matrix ) {
return uf::matrix::multiply(*this, matrix);
}
// Equality check between two matrices (equals)
template<typename T, size_t R, size_t C>
inline bool pod::Matrix<T,R,C>::operator==( const Matrix<T,R,C>& matrix ) const {
return uf::matrix::equals( *this, matrix );
}
// Equality check between two matrices (not equals)
template<typename T, size_t R, size_t C>
inline bool pod::Matrix<T,R,C>::operator!=( const Matrix<T,R,C>& matrix ) const {
return !uf::matrix::equals( *this, matrix );
}
// Equality checking
// Equality check between two matrices (less than)
template<typename T> int uf::matrix::compareTo( const T& left, const T& right ) {
return memcmp( &left[0], &right[0], sizeof(left) );
}
// Equality check between two matrices (equals)
template<typename T> bool uf::matrix::equals( const T& left, const T& right ) {
return uf::matrix::compareTo(left, right) == 0;
}
template<typename T> bool uf::matrix::equals( const T& left, const T& right, float eps ) {
bool equals = true;
for ( size_t i = 0; i < 16; ++i ) {
if ( abs(left[i] - right[i]) <= eps ) continue;
equals = false;
break;
}
return equals;
}
// Basic arithmetic
// Multiplies two matrices of same type and size together
template<typename T> pod::Matrix<T,4,4> uf::matrix::multiply( const pod::Matrix<T,4,4>& left, const pod::Matrix<T,4,4>& right ) {
ALIGN16 pod::Matrix<T,4,4> res;
#if UF_USE_SIMD
auto row1 = uf::simd::load(&left[0]);
auto row2 = uf::simd::load(&left[4]);
auto row3 = uf::simd::load(&left[8]);
auto row4 = uf::simd::load(&left[12]);
#pragma unroll // GCC unroll 4
for( uint_fast8_t i = 0; i < 4; i++) {
auto brod1 = uf::simd::set(right[4*i + 0]);
auto brod2 = uf::simd::set(right[4*i + 1]);
auto brod3 = uf::simd::set(right[4*i + 2]);
auto brod4 = uf::simd::set(right[4*i + 3]);
auto row = uf::simd::add(
uf::simd::add(
uf::simd::mul(brod1, row1),
uf::simd::mul(brod2, row2)),
uf::simd::add(
uf::simd::mul(brod3, row3),
uf::simd::mul(brod4, row4)));
uf::simd::store(row, &res[4*i]);
}
return res;
#elif UF_ENV_DREAMCAST
// kallistios has dedicated SH4 asm for these or something
mat_load( (matrix_t*) &left[0] );
mat_apply( (matrix_t*) &right[0] );
mat_store( (matrix_t*) &res[0]);
// gives very wrong output, not sure why
// MATH_Load_Matrix_Product( (ALL_FLOATS_STRUCT*) &left[0], (ALL_FLOATS_STRUCT*) &right[0] );
// MATH_Store_XMTRX( (ALL_FLOATS_STRUCT*) &res[0]);
return res;
#elif 0
//
float* dstPtr = &res[0];
const float* leftPtr = &right[0];
#pragma unroll // GCC unroll 4
for (uint_fast8_t i = 0; i < 4; ++i) {
#pragma unroll // GCC unroll 4
for (uint_fast8_t j = 0; j < 4; ++j) {
const float* rightPtr = &left[0] + j;
float sum = leftPtr[0] * rightPtr[0];
#pragma unroll // GCC unroll 3
for (uint_fast8_t n = 1; n < 4; ++n) {
rightPtr += 4;
sum += leftPtr[n] * rightPtr[0];
}
*dstPtr++ = sum;
}
leftPtr += 4;
}
return res;
#elif 0
// don't know if it's more performant than below
uint_fast8_t i = 0;
#pragma unroll // GCC unroll 4
for ( uint_fast8_t c = 0; c < 4; c++ ) {
#pragma unroll // GCC unroll 4
for ( uint_fast8_t r = 0; r < 4; r++ ) {
res[i++] = uf::vector::dot( { right[0+c*4], right[1+c*4], right[2+c*4], right[3+c*4] }, { left[r+0*4], left[r+1*4], left[r+2*4], left[r+3*4] } );
}
}
return res;
#else
// it works
const pod::Vector<T,4>& srcA0 = *((pod::Vector<T,4>*) &left[0]);
const pod::Vector<T,4>& srcA1 = *((pod::Vector<T,4>*) &left[4]);
const pod::Vector<T,4>& srcA2 = *((pod::Vector<T,4>*) &left[8]);
const pod::Vector<T,4>& srcA3 = *((pod::Vector<T,4>*) &left[12]);
const pod::Vector<T,4>& srcB0 = *((pod::Vector<T,4>*) &right[0]);
const pod::Vector<T,4>& srcB1 = *((pod::Vector<T,4>*) &right[4]);
const pod::Vector<T,4>& srcB2 = *((pod::Vector<T,4>*) &right[8]);
const pod::Vector<T,4>& srcB3 = *((pod::Vector<T,4>*) &right[12]);
pod::Vector<T,4>& dst0 = *((pod::Vector<T,4>*) &res[0]);
pod::Vector<T,4>& dst1 = *((pod::Vector<T,4>*) &res[4]);
pod::Vector<T,4>& dst2 = *((pod::Vector<T,4>*) &res[8]);
pod::Vector<T,4>& dst3 = *((pod::Vector<T,4>*) &res[12]);
dst0 = srcA0 * srcB0[0] + srcA1 * srcB0[1] + srcA2 * srcB0[2] + srcA3 * srcB0[3];
dst1 = srcA0 * srcB1[0] + srcA1 * srcB1[1] + srcA2 * srcB1[2] + srcA3 * srcB1[3];
dst2 = srcA0 * srcB2[0] + srcA1 * srcB2[1] + srcA2 * srcB2[2] + srcA3 * srcB2[3];
dst3 = srcA0 * srcB3[0] + srcA1 * srcB3[1] + srcA2 * srcB3[2] + srcA3 * srcB3[3];
return res;
#endif
}
template<typename T, typename U> pod::Matrix<typename T::type_t, T::columns, T::columns> uf::matrix::multiply( const T& left, const U& right ) {
ALIGN16 pod::Matrix<typename T::type_t,T::rows,T::columns> res;
#if 1
float* dstPtr = &res[0];
const float* leftPtr = &right[0];
#pragma unroll // GCC unroll T::rows
for (uint_fast8_t i = 0; i < T::rows; ++i) {
#pragma unroll // GCC unroll T::columns
for (uint_fast8_t j = 0; j < T::columns; ++j) {
const float* rightPtr = &left[0] + j;
float sum = leftPtr[0] * rightPtr[0];
#pragma unroll // GCC unroll T::columns - 1
for (uint_fast8_t n = 1; n < T::columns; ++n) {
rightPtr += T::columns;
sum += leftPtr[n] * rightPtr[0];
}
*dstPtr++ = sum;
}
leftPtr += T::columns;
}
#else
uint_fast8_t i = 0;
#pragma unroll // GCC unroll
for ( uint_fast8_t col = 0; col < R; col++ ) {
#pragma unroll // GCC unroll
for ( uint_fast8_t row = 0; row < C; row++ ) {
auto& sum = res[i++];
#pragma unroll // GCC unroll
for ( uint_fast8_t i = 0; i < C; i++ )
sum += right[i + col * C] * left[row + i * R];
}
}
#endif
return res;
}
template<typename T> T /*UF_API*/ uf::matrix::multiplyAll( const T& m, typename T::type_t scalar ) {
ALIGN16 T matrix;
#pragma unroll // GCC unroll T::rows * T::columns
for ( uint_fast8_t i = 0; i < T::rows * T::columns; ++i )
matrix[i] = m[i] * scalar;
return matrix;
}
template<typename T> T /*UF_API*/ uf::matrix::add( const T& lhs, const T& rhs ) {
ALIGN16 T matrix;
#pragma unroll // GCC unroll T::rows * T::columns
for ( uint_fast8_t i = 0; i < T::rows * T::columns; ++i )
matrix[i] = lhs[i] + rhs[i];
return matrix;
}
// Transpose matrix
template<typename T> T uf::matrix::transpose( const T& matrix ) {
ALIGN16 T transpose;
#pragma unroll // GCC unroll T::rows
for ( typename T::type_t r = 0; r < T::rows; ++r )
#pragma unroll // GCC unroll T::columns
for ( typename T::type_t c = 0; c < T::columns; ++c )
transpose[c * T::rows + r] = matrix[r * T::columns + c];
return transpose;
}
// Flip sign of all components
template<typename T> T uf::matrix::inverse( const T& matrix ) {
if ( T::rows != 4 || T::columns != 4 ) return matrix;
const typename T::type_t* m = &matrix[0];
ALIGN16 typename T::type_t inv[16];
typename T::type_t det;
uint_fast8_t i;
inv[0] = m[5] * m[10] * m[15] -
m[5] * m[11] * m[14] -
m[9] * m[6] * m[15] +
m[9] * m[7] * m[14] +
m[13] * m[6] * m[11] -
m[13] * m[7] * m[10];
inv[4] = -m[4] * m[10] * m[15] +
m[4] * m[11] * m[14] +
m[8] * m[6] * m[15] -
m[8] * m[7] * m[14] -
m[12] * m[6] * m[11] +
m[12] * m[7] * m[10];
inv[8] = m[4] * m[9] * m[15] -
m[4] * m[11] * m[13] -
m[8] * m[5] * m[15] +
m[8] * m[7] * m[13] +
m[12] * m[5] * m[11] -
m[12] * m[7] * m[9];
inv[12] = -m[4] * m[9] * m[14] +
m[4] * m[10] * m[13] +
m[8] * m[5] * m[14] -
m[8] * m[6] * m[13] -
m[12] * m[5] * m[10] +
m[12] * m[6] * m[9];
inv[1] = -m[1] * m[10] * m[15] +
m[1] * m[11] * m[14] +
m[9] * m[2] * m[15] -
m[9] * m[3] * m[14] -
m[13] * m[2] * m[11] +
m[13] * m[3] * m[10];
inv[5] = m[0] * m[10] * m[15] -
m[0] * m[11] * m[14] -
m[8] * m[2] * m[15] +
m[8] * m[3] * m[14] +
m[12] * m[2] * m[11] -
m[12] * m[3] * m[10];
inv[9] = -m[0] * m[9] * m[15] +
m[0] * m[11] * m[13] +
m[8] * m[1] * m[15] -
m[8] * m[3] * m[13] -
m[12] * m[1] * m[11] +
m[12] * m[3] * m[9];
inv[13] = m[0] * m[9] * m[14] -
m[0] * m[10] * m[13] -
m[8] * m[1] * m[14] +
m[8] * m[2] * m[13] +
m[12] * m[1] * m[10] -
m[12] * m[2] * m[9];
inv[2] = m[1] * m[6] * m[15] -
m[1] * m[7] * m[14] -
m[5] * m[2] * m[15] +
m[5] * m[3] * m[14] +
m[13] * m[2] * m[7] -
m[13] * m[3] * m[6];
inv[6] = -m[0] * m[6] * m[15] +
m[0] * m[7] * m[14] +
m[4] * m[2] * m[15] -
m[4] * m[3] * m[14] -
m[12] * m[2] * m[7] +
m[12] * m[3] * m[6];
inv[10] = m[0] * m[5] * m[15] -
m[0] * m[7] * m[13] -
m[4] * m[1] * m[15] +
m[4] * m[3] * m[13] +
m[12] * m[1] * m[7] -
m[12] * m[3] * m[5];
inv[14] = -m[0] * m[5] * m[14] +
m[0] * m[6] * m[13] +
m[4] * m[1] * m[14] -
m[4] * m[2] * m[13] -
m[12] * m[1] * m[6] +
m[12] * m[2] * m[5];
inv[3] = -m[1] * m[6] * m[11] +
m[1] * m[7] * m[10] +
m[5] * m[2] * m[11] -
m[5] * m[3] * m[10] -
m[9] * m[2] * m[7] +
m[9] * m[3] * m[6];
inv[7] = m[0] * m[6] * m[11] -
m[0] * m[7] * m[10] -
m[4] * m[2] * m[11] +
m[4] * m[3] * m[10] +
m[8] * m[2] * m[7] -
m[8] * m[3] * m[6];
inv[11] = -m[0] * m[5] * m[11] +
m[0] * m[7] * m[9] +
m[4] * m[1] * m[11] -
m[4] * m[3] * m[9] -
m[8] * m[1] * m[7] +
m[8] * m[3] * m[5];
inv[15] = m[0] * m[5] * m[10] -
m[0] * m[6] * m[9] -
m[4] * m[1] * m[10] +
m[4] * m[2] * m[9] +
m[8] * m[1] * m[6] -
m[8] * m[2] * m[5];
det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
if (det == 0) return matrix;
det = 1.0 / det;
ALIGN16 T inverted;
#pragma unroll // GCC unroll 16
for ( i = 0; i < 16; ++i )
inverted[i] = inv[i] * det;
return inverted;
}
template<typename T> pod::Vector3t<T> uf::matrix::multiply( const pod::Matrix4t<T>& mat, const pod::Vector3t<T>& vector, T w, bool div ) {
return uf::matrix::multiply( mat, pod::Vector4t<T>{ vector[0], vector[1], vector[2], w }, div );
}
template<typename T> pod::Vector4t<T> uf::matrix::multiply( const pod::Matrix4t<T>& mat, const pod::Vector4t<T>& vector, bool div ) {
#if UF_ENV_DREAMCAST
MATH_Load_XMTRX( (ALL_FLOATS_STRUCT*) &mat[0] );
auto t = MATH_Matrix_Transform( vector[0], vector[1], vector[2], vector[3] );
auto res = *((pod::Vector4t<T>*) &t);
if ( div && res.w > 0 ) res /= res.w;
return res;
#else
ALIGN16 auto res = pod::Vector4t<T>{
vector[0] * mat[0] + vector[1] * mat[4] + vector[2] * mat[8] + vector[3] * mat[12],
vector[0] * mat[1] + vector[1] * mat[5] + vector[2] * mat[9] + vector[3] * mat[13],
vector[0] * mat[2] + vector[1] * mat[6] + vector[2] * mat[10] + vector[3] * mat[14],
vector[0] * mat[3] + vector[1] * mat[7] + vector[2] * mat[11] + vector[3] * mat[15]
};
if ( div && res.w > 0 ) res /= res.w;
return res;
#endif
}
// Writes to first value
// Multiplies two matrices of same type and size together
// Flip sign of all components
template<typename T> T& uf::matrix::invert( T& matrix ) {
return matrix = uf::matrix::inverse((const T&) matrix);
}
template<typename T> pod::Matrix<typename T::type_t, T::columns, T::columns> uf::matrix::multiply_( T& left, const T& right ) {
return left = uf::matrix::multiply((const T&) left, right);
}
template<typename T> T& uf::matrix::translate_( T& matrix, const pod::Vector3t<typename T::type_t>& vector ) {
matrix[12] = vector.x;
matrix[13] = vector.y;
matrix[14] = vector.z;
return matrix;
}
template<typename T> T& uf::matrix::rotate_( T& matrix, const pod::Vector3t<typename T::type_t>& vector ) {
if ( vector.x != 0 ) {
matrix[5] = cos( vector.x );
matrix[6] = sin( vector.x );
matrix[9] = -1 * sin( vector.x );
matrix[10] = cos( vector.x );
}
if ( vector.y != 0 ) {
matrix[0] = cos( vector.y );
matrix[2] = -1 * sin( vector.y );
matrix[8] = sin( vector.y );
matrix[10] = cos( vector.y );
}
if ( vector.z != 0 ) {
matrix[0] = cos( vector.z );
matrix[1] = sin( vector.z );
matrix[4] = -1 * sin( vector.z );
matrix[5] = cos( vector.z );
}
return matrix;
}
template<typename T> T& uf::matrix::scale_( T& matrix, const pod::Vector3t<typename T::type_t>& vector ) {
matrix[0] = vector.x;
matrix[5] = vector.y;
matrix[10] = vector.z;
return matrix;
}
// Complex arithmetic
template<typename T> T uf::matrix::translate( const T& matrix, const pod::Vector3t<typename T::type_t>& vector ) {
ALIGN16 T res = matrix;
res[12] = vector.x;
res[13] = vector.y;
res[14] = vector.z;
return res;
}
template<typename T> T uf::matrix::rotate( const T& matrix, const pod::Vector3t<typename T::type_t>& vector ) {
ALIGN16 T res = matrix;
if ( vector.x != 0 ) {
res[5] = cos( vector.x );
res[6] = sin( vector.x );
res[9] = -1 * sin( vector.x );
res[10] = cos( vector.x );
}
if ( vector.y != 0 ) {
res[0] = cos( vector.y );
res[2] = -1 * sin( vector.y );
res[8] = sin( vector.y );
res[10] = cos( vector.y );
}
if ( vector.z != 0 ) {
res[0] = cos( vector.z );
res[1] = sin( vector.z );
res[4] = -1 * sin( vector.z );
res[5] = cos( vector.z );
}
return res;
}
template<typename T> T uf::matrix::scale( const T& matrix, const pod::Vector3t<typename T::type_t>& vector ) {
ALIGN16 T res = matrix;
res[0] = vector.x;
res[5] = vector.y;
res[10] = vector.z;
return res;
}
template<typename T>
pod::Matrix4t<T> /*UF_API*/ uf::matrix::orthographic( T l, T r, T b, T t, T f, T n ) {
ALIGN16 pod::Matrix4t<T> m = uf::matrix::identity();
m[0*4+0] = 2 / (r - l);
m[1*4+1] = 2 / (t - b);
m[2*4+2] = - 2 / (f - n);
m[3*4+0] = - (r + l) / (r - l);
m[3*4+1] = - (t + b) / (t - b);
m[3*4+2] = - (f + n) / (f - n);
return m;
/*
uf::stl::vector<T> m = {
2 / (r - l), 0, 0, 0,
0, 2 / (t - b), 0, 0,
0, 0, -2 / (f - n), 0,
-(r + l) / (r - l), -(t + b) / (t - b), -(f + n) / (f - n), 1,
};
return uf::matrix::initialize(m);
*/
}
template<typename T>
pod::Matrix4t<T> /*UF_API*/ uf::matrix::orthographic( T l, T r, T b, T t ) {
return pod::Matrix4t<T>({
2 / (r - l), 0, 0, 0,
0, 2 / (t - b), 0, 0,
0, 0, 1, 0,
-(r + l) / (r - l), -(t+b)/(t-b), 0, 1
});
}
template<typename T>
pod::Matrix4t<T> /*UF_API*/ uf::matrix::perspective( T fov, T raidou, T znear, T zfar ) {
if ( uf::matrix::reverseInfiniteProjection ) {
T f = static_cast<T>(1) / tan( static_cast<T>(0.5) * fov );
#if UF_USE_OPENGL
return pod::Matrix4t<T>({
f / raidou, 0, 0, 0,
0, f, 0, 0,
0, 0, 0, 1,
0, 0, znear, 0
});
#elif UF_USE_VULKAN
return pod::Matrix4t<T>({
f / raidou, 0, 0, 0,
0, -f, 0, 0,
0, 0, 0, 1,
0, 0, znear, 0
});
#endif
} else {
T range = znear - zfar;
T f = tan( static_cast<T>(0.5) * fov );
T Sx = static_cast<T>(1) / (f * raidou);
T Sy = static_cast<T>(1) / f;
T Sz = (-znear - zfar) / range;
T Pz = static_cast<T>(2) * zfar * znear / range;
#if UF_USE_VULKAN
Sy = -Sy;
#endif
return pod::Matrix4t<T>({
Sx, 0, 0, 0,
0, Sy, 0, 0,
0, 0, Sz, 1,
0, 0, Pz, 0
});
}
}
template<typename T> T& uf::matrix::copy( T& destination, const T& source ) {
#pragma unroll // GCC unroll 16
for ( uint_fast8_t i = 0; i < 16; ++i )
destination[i] = source[i];
return destination;
}
template<typename T> T& uf::matrix::copy( T& destination, typename T::type_t* const source ) {
#pragma unroll // GCC unroll 16
for ( uint_fast8_t i = 0; i < 16; ++i )
destination[i] = source[i];
return destination;
}
template<typename T> pod::Vector3t<typename T::type_t> /*UF_API*/ uf::matrix::eulerAngles( const T& M ) {
typename T::type_t T1 = atan2(M[2*4+1], M[2*4+2]);
typename T::type_t C2 = sqrt(M[0*4+0]*M[0*4+0] + M[1*4+0]*M[1*4+0]);
typename T::type_t T2 = atan2(-M[2*4+0], C2);
typename T::type_t S1 = sin(T1);
typename T::type_t C1 = cos(T1);
typename T::type_t T3 = atan2(S1*M[0*4+2] - C1*M[0*4+1], C1*M[1*4+1] - S1*M[1*4+2 ]);
return pod::Vector3t<typename T::type_t>{-T1, -T2, -T3};
}
template<typename T, size_t R, size_t C>
ext::json::Value /*UF_API*/ uf::matrix::encode( const pod::Matrix<T,R,C>& m, const ext::json::EncodingSettings& settings ) {
ext::json::Value json;
if ( settings.quantize )
#pragma unroll // GCC unroll R*C
for ( uint_fast8_t i = 0; i < R*C; ++i )
json[i] = uf::math::quantizeShort( m[i] );
else
#pragma unroll // GCC unroll R*C
for ( uint_fast8_t i = 0; i < R*C; ++i )
json[i] = m[i];
return json;
}
template<typename T, size_t R, size_t C>
pod::Matrix<T,R,C>& /*UF_API*/ uf::matrix::decode( const ext::json::Value& json, pod::Matrix<T,R,C>& m ) {
if ( ext::json::isArray(json) )
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < R*C; ++i )
m[i] = json[i].as<T>(m[i]);
else if ( ext::json::isObject(json) ) {
uint_fast8_t i = 0;
ext::json::forEach(json, [&](const ext::json::Value& c){
if ( i >= R*C ) return;
m[i] = c.as<T>(m[i]);
++i;
});
}
return m;
}
template<typename T, size_t R, size_t C>
pod::Matrix<T,R,C> /*UF_API*/ uf::matrix::decode( const ext::json::Value& json, const pod::Matrix<T,R,C>& _m ) {
ALIGN16 pod::Matrix<T,R,C> m = _m;
if ( ext::json::isArray(json) )
#pragma unroll // GCC unroll T::size
for ( uint_fast8_t i = 0; i < R*C; ++i )
m[i] = json[i].as<T>(_m[i]);
else if ( ext::json::isObject(json) ) {
uint_fast8_t i = 0;
ext::json::forEach(json, [&](const ext::json::Value& c){
if ( i >= R*C ) return;
m[i] = c.as<T>(_m[i]);
++i;
});
}
return m;
}
template<typename T, size_t R, size_t C>
uf::stl::string /*UF_API*/ uf::matrix::toString( const pod::Matrix<T,R,C>& m ) {
uf::stl::stringstream ss;
ss << "Matrix(\n\t";
#pragma unroll // GCC unroll C
for ( uint_fast8_t c = 0; c < C; ++c ) {
#pragma unroll // GCC unroll R
for ( uint_fast8_t r = 0; r < R; ++r ) {
ss << m[r+c*C] << ", ";
}
if ( c + 1 < C ) ss << "\n\t";
}
ss << "\n)";
return ss.str();
}
#if !__clang__ && __GNUC__
#pragma GCC pop_options
#endif