Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
MathMatrices.inl
Go to the documentation of this file.
1/*
2Copyright (c) 2018 DIVIDE-Studio
3Copyright (c) 2009 Ionut Cava
4
5This file is part of DIVIDE Framework.
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software
9and associated documentation files (the "Software"), to deal in the Software
10without restriction,
11including without limitation the rights to use, copy, modify, merge, publish,
12distribute, sublicense,
13and/or sell copies of the Software, and to permit persons to whom the
14Software is furnished to do so,
15subject to the following conditions:
16
17The above copyright notice and this permission notice shall be included in
18all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED,
22INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
23PARTICULAR PURPOSE AND NONINFRINGEMENT.
24IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
25DAMAGES OR OTHER LIABILITY,
26WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
27IN CONNECTION WITH THE SOFTWARE
28OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30*/
31
32#ifndef DVD_MATH_MATRICES_INL_
33#define DVD_MATH_MATRICES_INL_
34namespace Divide
35{
36
37# define MakeShuffleMask(x,y,z,w) (x | y << 2 | z << 4 | w << 6)
38
39 // vec(0, 1, 2, 3) -> (vec[x], vec[y], vec[z], vec[w])
40# define VecSwizzle(vec, x,y,z,w) _mm_shuffle_ps(vec, vec, MakeShuffleMask(x,y,z,w))
41# define VecSwizzle1(vec, x) _mm_shuffle_ps(vec, vec, MakeShuffleMask(x,x,x,x))
42 // special swizzle
43# define VecSwizzle_0101(vec) _mm_movelh_ps(vec, vec)
44# define VecSwizzle_2323(vec) _mm_movehl_ps(vec, vec)
45# define VecSwizzle_0022(vec) _mm_moveldup_ps(vec)
46# define VecSwizzle_1133(vec) _mm_movehdup_ps(vec)
47
48 // return (vec1[x], vec1[y], vec2[z], vec2[w])
49# define VecShuffle(vec1, vec2, x,y,z,w) _mm_shuffle_ps(vec1, vec2, MakeShuffleMask(x,y,z,w))
50 // special shuffle
51# define VecShuffle_0101(vec1, vec2) _mm_movelh_ps(vec1, vec2)
52# define VecShuffle_2323(vec1, vec2) _mm_movehl_ps(vec2, vec1)
53
54 namespace AVX
55 {
56 //Ref: http://stackoverflow.com/questions/18499971/efficient-4x4-matrix-multiplication-c-vs-assembly
57 FORCE_INLINE void M4x4_SSE( const F32* A, const F32* B, F32* C ) noexcept
58 {
59 const __m128 row1 = _mm_load_ps( &B[0] );
60 const __m128 row2 = _mm_load_ps( &B[4] );
61 const __m128 row3 = _mm_load_ps( &B[8] );
62 const __m128 row4 = _mm_load_ps( &B[12] );
63 for ( U8 i = 0u; i < 4u; ++i )
64 {
65 const __m128 brod1 = _mm_set1_ps( A[4 * i + 0] );
66 const __m128 brod2 = _mm_set1_ps( A[4 * i + 1] );
67 const __m128 brod3 = _mm_set1_ps( A[4 * i + 2] );
68 const __m128 brod4 = _mm_set1_ps( A[4 * i + 3] );
69 const __m128 row = _mm_add_ps( _mm_add_ps( _mm_mul_ps( brod1, row1 ),
70 _mm_mul_ps( brod2, row2 ) ),
71 _mm_add_ps( _mm_mul_ps( brod3, row3 ),
72 _mm_mul_ps( brod4, row4 ) ) );
73 _mm_store_ps( &C[4 * i], row );
74 }
75 }
76
77#if defined(HAS_AVX2)
78 // another linear combination, using AVX instructions on XMM regs
79 static FORCE_INLINE __m128 lincomb_AVX_4mem( const F32* a, const mat4<F32>& B ) noexcept
80 {
81 const auto& bReg = B._reg;
82 __m128 result = _mm_mul_ps( _mm_broadcast_ss( &a[0] ), bReg[0]._reg );
83 result = _mm_add_ps( result, _mm_mul_ps( _mm_broadcast_ss( &a[1] ), bReg[1]._reg ) );
84 result = _mm_add_ps( result, _mm_mul_ps( _mm_broadcast_ss( &a[2] ), bReg[2]._reg ) );
85 result = _mm_add_ps( result, _mm_mul_ps( _mm_broadcast_ss( &a[3] ), bReg[3]._reg ) );
86 return result;
87 }
88#else //HAS_AVX2
89 // ref: https://gist.github.com/rygorous/4172889
90 // linear combination:
91 // a[0] * B.row[0] + a[1] * B.row[1] + a[2] * B.row[2] + a[3] * B.row[3]
92 static FORCE_INLINE __m128 lincomb_SSE( const __m128& a, const mat4<F32>& B )
93 {
94 const auto& bReg = B._reg;
95 __m128 result = _mm_mul_ps( _mm_shuffle_ps( a, a, 0x00 ), bReg[0]._reg );
96 result = _mm_add_ps( result, _mm_mul_ps( _mm_shuffle_ps( a, a, 0x55 ), bReg[1]._reg ) );
97 result = _mm_add_ps( result, _mm_mul_ps( _mm_shuffle_ps( a, a, 0xaa ), bReg[2]._reg ) );
98 result = _mm_add_ps( result, _mm_mul_ps( _mm_shuffle_ps( a, a, 0xff ), bReg[3]._reg ) );
99
100 return result;
101 }
102#endif //HAS_AVX2
103
104 //ref: https://lxjk.github.io/2017/09/03/Fast-4x4-Matrix-Inverse-with-SSE-SIMD-Explained.html
106 {
107 // transpose 3x3, we know m03 = m13 = m23 = 0
108 const __m128 t0 = VecShuffle_0101( inM._reg[0]._reg, inM._reg[1]._reg ); // 00, 01, 10, 11
109 const __m128 t1 = VecShuffle_2323( inM._reg[0]._reg, inM._reg[1]._reg ); // 02, 03, 12, 13
110 r._reg[0] = SimdVector<F32>( VecShuffle( t0, inM._reg[2]._reg, 0, 2, 0, 3 ) ); // 00, 10, 20, 23(=0)
111 r._reg[1] = SimdVector<F32>( VecShuffle( t0, inM._reg[2]._reg, 1, 3, 1, 3 ) ); // 01, 11, 21, 23(=0)
112 r._reg[2] = SimdVector<F32>( VecShuffle( t1, inM._reg[2]._reg, 0, 2, 2, 3 ) ); // 02, 12, 22, 23(=0)
113
114 // last line
115 r._reg[3] = SimdVector<F32>( _mm_mul_ps( r._reg[0]._reg, VecSwizzle1( inM._reg[3]._reg, 0 ) ) );
116 r._reg[3] = SimdVector<F32>( _mm_add_ps( r._reg[3]._reg, _mm_mul_ps( r._reg[1]._reg, VecSwizzle1( inM._reg[3]._reg, 1 ) ) ) );
117 r._reg[3] = SimdVector<F32>( _mm_add_ps( r._reg[3]._reg, _mm_mul_ps( r._reg[2]._reg, VecSwizzle1( inM._reg[3]._reg, 2 ) ) ) );
118 r._reg[3] = SimdVector<F32>( _mm_sub_ps( _mm_setr_ps( 0.f, 0.f, 0.f, 1.f ), r._reg[3]._reg ) );
119 }
120
121 // for column major matrix
122 // we use __m128 to represent 2x2 matrix as A = | A0 A2 |
123 // | A1 A3 |
124 // 2x2 column major Matrix multiply A*B
125 FORCE_INLINE __m128 Mat2Mul( const __m128 vec1, const __m128 vec2 ) noexcept
126 {
127 return _mm_add_ps( _mm_mul_ps( vec1, VecSwizzle( vec2, 0, 0, 3, 3 ) ),
128 _mm_mul_ps( VecSwizzle( vec1, 2, 3, 0, 1 ), VecSwizzle( vec2, 1, 1, 2, 2 ) ) );
129 }
130 // 2x2 column major Matrix adjugate multiply (A#)*B
131 FORCE_INLINE __m128 Mat2AdjMul( const __m128 vec1, const __m128 vec2 ) noexcept
132 {
133 return _mm_sub_ps( _mm_mul_ps( VecSwizzle( vec1, 3, 0, 3, 0 ), vec2 ),
134 _mm_mul_ps( VecSwizzle( vec1, 2, 1, 2, 1 ), VecSwizzle( vec2, 1, 0, 3, 2 ) ) );
135
136 }
137 // 2x2 column major Matrix multiply adjugate A*(B#)
138 FORCE_INLINE __m128 Mat2MulAdj( const __m128 vec1, const __m128 vec2 ) noexcept
139 {
140 return _mm_sub_ps( _mm_mul_ps( vec1, VecSwizzle( vec2, 3, 3, 0, 0 ) ),
141 _mm_mul_ps( VecSwizzle( vec1, 2, 3, 0, 1 ), VecSwizzle( vec2, 1, 1, 2, 2 ) ) );
142 }
143
144 // Requires this matrix to be transform matrix
145 FORCE_INLINE void GetTransformInverse( const mat4<F32>& inM, mat4<F32>& r ) noexcept
146 {
147 // transpose 3x3, we know m03 = m13 = m23 = 0
148 const __m128 t0 = VecShuffle_0101( inM._reg[0]._reg, inM._reg[1]._reg ); // 00, 01, 10, 11
149 const __m128 t1 = VecShuffle_2323( inM._reg[0]._reg, inM._reg[1]._reg ); // 02, 03, 12, 13
150 r._reg[0]._reg = VecShuffle( t0, inM._reg[2]._reg, 0, 2, 0, 3 ); // 00, 10, 20, 23(=0)
151 r._reg[1]._reg = VecShuffle( t0, inM._reg[2]._reg, 1, 3, 1, 3 ); // 01, 11, 21, 23(=0)
152 r._reg[2]._reg = VecShuffle( t1, inM._reg[2]._reg, 0, 2, 2, 3 ); // 02, 12, 22, 23(=0)
153
154 __m128 sizeSqr = _mm_mul_ps( r._reg[0]._reg, r._reg[0]._reg );
155 sizeSqr = _mm_add_ps( sizeSqr, _mm_mul_ps( r._reg[1]._reg, r._reg[1]._reg ) );
156 sizeSqr = _mm_add_ps( sizeSqr, _mm_mul_ps( r._reg[2]._reg, r._reg[2]._reg ) );
157
158 // optional test to avoid divide by 0
159 const __m128 one = _mm_set1_ps( 1.f );
160 // for each component, if(sizeSqr < epsilon) sizeSqr = 1;
161 const __m128 rSizeSqr = _mm_blendv_ps(
162 _mm_div_ps( one, sizeSqr ),
163 one,
164 _mm_cmplt_ps( sizeSqr, _mm_set1_ps( std::numeric_limits<F32>::epsilon() ) )
165 );
166
167 r._reg[0] = SimdVector<F32>( _mm_mul_ps( r._reg[0]._reg, rSizeSqr ) );
168 r._reg[1] = SimdVector<F32>( _mm_mul_ps( r._reg[1]._reg, rSizeSqr ) );
169 r._reg[2] = SimdVector<F32>( _mm_mul_ps( r._reg[2]._reg, rSizeSqr ) );
170
171 // last line
172 r._reg[3] = SimdVector<F32>( _mm_mul_ps( r._reg[0]._reg, VecSwizzle1( inM._reg[3]._reg, 0 ) ) );
173 r._reg[3] = SimdVector<F32>( _mm_add_ps( r._reg[3]._reg, _mm_mul_ps( r._reg[1]._reg, VecSwizzle1( inM._reg[3]._reg, 1 ) ) ) );
174 r._reg[3] = SimdVector<F32>( _mm_add_ps( r._reg[3]._reg, _mm_mul_ps( r._reg[2]._reg, VecSwizzle1( inM._reg[3]._reg, 2 ) ) ) );
175 r._reg[3] = SimdVector<F32>( _mm_sub_ps( _mm_setr_ps( 0.f, 0.f, 0.f, 1.f ), r._reg[3]._reg ) );
176 }
177
178 // Inverse function is the same no matter column major or row major this version treats it as column major
179 FORCE_INLINE void GetInverse( const mat4<F32>& inM, mat4<F32>& r ) noexcept
180 {
181 // use block matrix method
182 // A is a matrix, then i(A) or iA means inverse of A, A# (or A_ in code) means adjugate of A, |A| (or detA in code) is determinant, tr(A) is trace
183
184 // sub matrices
185 const __m128 A = VecShuffle_0101( inM._reg[0]._reg, inM._reg[1]._reg );
186 const __m128 C = VecShuffle_2323( inM._reg[0]._reg, inM._reg[1]._reg );
187 const __m128 B = VecShuffle_0101( inM._reg[2]._reg, inM._reg[3]._reg );
188 const __m128 D = VecShuffle_2323( inM._reg[2]._reg, inM._reg[3]._reg );
189
190 const __m128 detA = _mm_set1_ps( inM.m[0][0] * inM.m[1][1] - inM.m[0][1] * inM.m[1][0] );
191 const __m128 detC = _mm_set1_ps( inM.m[0][2] * inM.m[1][3] - inM.m[0][3] * inM.m[1][2] );
192 const __m128 detB = _mm_set1_ps( inM.m[2][0] * inM.m[3][1] - inM.m[2][1] * inM.m[3][0] );
193 const __m128 detD = _mm_set1_ps( inM.m[2][2] * inM.m[3][3] - inM.m[2][3] * inM.m[3][2] );
194
195#if 0 // for determinant, float version is faster
196 // determinant as (|A| |C| |B| |D|)
197 __m128 detSub = _mm_sub_ps(
198 _mm_mul_ps( VecShuffle( inM._reg[0]._reg, inM._reg[2]._reg, 0, 2, 0, 2 ), VecShuffle( inM._reg[1]._reg, inM._reg[3]._reg, 1, 3, 1, 3 ) ),
199 _mm_mul_ps( VecShuffle( inM._reg[0]._reg, inM._reg[2]._reg, 1, 3, 1, 3 ), VecShuffle( inM._reg[1]._reg, inM._reg[3]._reg, 0, 2, 0, 2 ) )
200 );
201 __m128 detA = VecSwizzle1( detSub, 0 );
202 __m128 detC = VecSwizzle1( detSub, 1 );
203 __m128 detB = VecSwizzle1( detSub, 2 );
204 __m128 detD = VecSwizzle1( detSub, 3 );
205#endif
206
207 // let iM = 1/|M| * | X Y |
208 // | Z W |
209
210 // D#C
211 const __m128 D_C = Mat2AdjMul( D, C );
212 // A#B
213 const __m128 A_B = Mat2AdjMul( A, B );
214 // X# = |D|A - B(D#C)
215 __m128 X_ = _mm_sub_ps( _mm_mul_ps( detD, A ), Mat2Mul( B, D_C ) );
216 // W# = |A|D - C(A#B)
217 __m128 W_ = _mm_sub_ps( _mm_mul_ps( detA, D ), Mat2Mul( C, A_B ) );
218
219 // |M| = |A|*|D| + ... (continue later)
220 __m128 detM = _mm_mul_ps( detA, detD );
221
222 // Y# = |B|C - D(A#B)#
223 __m128 Y_ = _mm_sub_ps( _mm_mul_ps( detB, C ), Mat2MulAdj( D, A_B ) );
224 // Z# = |C|B - A(D#C)#
225 __m128 Z_ = _mm_sub_ps( _mm_mul_ps( detC, B ), Mat2MulAdj( A, D_C ) );
226
227 // |M| = |A|*|D| + |B|*|C| ... (continue later)
228 detM = _mm_add_ps( detM, _mm_mul_ps( detB, detC ) );
229
230 // tr((A#B)(D#C))
231 __m128 tr = _mm_mul_ps( A_B, VecSwizzle( D_C, 0, 2, 1, 3 ) );
232 tr = _mm_hadd_ps( tr, tr );
233 tr = _mm_hadd_ps( tr, tr );
234 // |M| = |A|*|D| + |B|*|C| - tr((A#B)(D#C))
235 detM = _mm_sub_ps( detM, tr );
236
237 const __m128 adjSignMask = _mm_setr_ps( 1.f, -1.f, -1.f, 1.f );
238 // (1/|M|, -1/|M|, -1/|M|, 1/|M|)
239 const __m128 rDetM = _mm_div_ps( adjSignMask, detM );
240
241 X_ = _mm_mul_ps( X_, rDetM );
242 Y_ = _mm_mul_ps( Y_, rDetM );
243 Z_ = _mm_mul_ps( Z_, rDetM );
244 W_ = _mm_mul_ps( W_, rDetM );
245
246 // apply adjugate and store, here we combine adjugate shuffle and store shuffle
247 r._reg[0]._reg = VecShuffle( X_, Z_, 3, 1, 3, 1 );
248 r._reg[1]._reg = VecShuffle( X_, Z_, 2, 0, 2, 0 );
249 r._reg[2]._reg = VecShuffle( Y_, W_, 3, 1, 3, 1 );
250 r._reg[3]._reg = VecShuffle( Y_, W_, 2, 0, 2, 0 );
251 }
252 }
253
254 template<typename T>
255 void GetInverse( const mat4<T>& inM, mat4<T>& r ) noexcept
256 {
257 inM.getInverse( r );
258 }
259
260 template<>
261 inline void GetInverse( const mat4<F32>& inM, mat4<F32>& r ) noexcept
262 {
263 AVX::GetInverse( inM, r );
264 }
265
266 template<typename T>
267 mat4<T> GetInverse( const mat4<T>& inM ) noexcept
268 {
269 return inM.getInverse();
270 }
271
272 template<>
273 inline mat4<F32> GetInverse( const mat4<F32>& inM ) noexcept
274 {
275 mat4<F32> r;
276 AVX::GetInverse( inM, r );
277 return r;
278 }
279
280 /*********************************
281 * mat2
282 *********************************/
283 template<typename T>
284 mat2<T>::mat2() noexcept
285 : mat2( 1, 0,
286 0, 1 )
287 {
288 }
289
290 template<typename T>
291 template<typename U>
292 mat2<T>::mat2( U m ) noexcept
293 : mat{ static_cast<T>(m), static_cast<T>(m),
294 static_cast<T>(m), static_cast<T>(m) }
295 {
296 }
297
298 template<typename T>
299 template<typename U>
300 mat2<T>::mat2( U m0, U m1,
301 U m2, U m3 ) noexcept
302 : mat{ static_cast<T>(m0), static_cast<T>(m1),
303 static_cast<T>(m2), static_cast<T>(m3) }
304 {
305 }
306
307 template<typename T>
308 template<typename U>
309 mat2<T>::mat2( const U* values ) noexcept
310 : mat2( values[0], values[1],
311 values[2], values[3] )
312 {
313 }
314
315 template<typename T>
316 mat2<T>::mat2( const mat2& B ) noexcept
317 : mat2( B.mat )
318 {
319 }
320
321 template<typename T>
322 template<typename U>
323 mat2<T>::mat2( const mat2<U>& B ) noexcept
324 : mat2( B.mat )
325 {
326 }
327
328 template<typename T>
329 template<typename U>
330 mat2<T>::mat2( const mat3<U>& B ) noexcept
331 : mat2( B[0], B[1],
332 B[3], B[4] )
333 {
334 }
335
336 template<typename T>
337 template<typename U>
338 mat2<T>::mat2( const mat4<U>& B ) noexcept
339 : mat2( B[0], B[1],
340 B[4], B[5] )
341 {
342 }
343
344 template<typename T>
345 template<typename U>
346 vec2<T> mat2<T>::operator*( const vec2<U> v ) const noexcept
347 {
348 return { mat[0] * v[0] + mat[1] * v[1],
349 mat[2] * v[0] + mat[3] * v[1] };
350 }
351
352 template<typename T>
353 template<typename U>
354 vec3<T> mat2<T>::operator*( const vec3<U>& v ) const noexcept
355 {
356 return { mat[0] * v[0] + mat[1] * v[1],
357 mat[2] * v[0] + mat[3] * v[1],
358 v[2] };
359 }
360
361 template<typename T>
362 template<typename U>
363 vec4<T> mat2<T>::operator*( const vec4<U>& v ) const noexcept
364 {
365 return { mat[0] * v[0] + mat[1] * v[1],
366 mat[2] * v[0] + mat[3] * v[1],
367 v[2],
368 v[3] };
369 }
370
371 template<typename T>
372 template<typename U>
373 mat2<T> mat2<T>::operator*( const mat2<U>& B ) const noexcept
374 {
375 return mat2( mat[0] * B.mat[0] + mat[1] * B.mat[2], mat[0] * B.mat[1] + mat[1] * B.mat[3],
376 mat[2] * B.mat[0] + mat[3] * B.mat[2], mat[2] * B.mat[1] + mat[3] * B.mat[3] );
377 }
378
379 template<typename T>
380 template<typename U>
381 mat2<T> mat2<T>::operator/( const mat2<U>& B ) const noexcept
382 {
383 return this * B.getInverse();
384 }
385
386 template<typename T>
387 template<typename U>
388 mat2<T> mat2<T>::operator+( const mat2<U>& B ) const noexcept
389 {
390 return mat2( mat[0] + B[0], mat[1] + B[1],
391 mat[2] + B[2], mat[3] + B[3] );
392 }
393
394 template<typename T>
395 template<typename U>
396 mat2<T> mat2<T>::operator-( const mat2<U>& B ) const noexcept
397 {
398 return mat2( mat[0] - B[0], mat[1] - B[1],
399 mat[2] - B[2], mat[3] - B[3] );
400 }
401
402 template<typename T>
403 template<typename U>
404 mat2<T>& mat2<T>::operator*=( const mat2<U>& B ) noexcept
405 {
406 return *this = *this * B;
407 }
408
409 template<typename T>
410 template<typename U>
411 mat2<T>& mat2<T>::operator/=( const mat2<U>& B ) noexcept
412 {
413 return *this = *this * B;
414 }
415
416 template<typename T>
417 template<typename U>
418 mat2<T>& mat2<T>::operator+=( const mat2<U>& B ) noexcept
419 {
420 return *this = *this + B;
421 }
422
423 template<typename T>
424 template<typename U>
425 mat2<T>& mat2<T>::operator-=( const mat2<U>& B ) noexcept
426 {
427 return *this = *this - B;
428 }
429
430 template<typename T>
431 template<typename U>
432 mat2<T> mat2<T>::operator*( U f ) const noexcept
433 {
434 return mat2( *this ) *= f;
435 }
436
437 template<typename T>
438 template<typename U>
439 mat2<T> mat2<T>::operator/( U f ) const noexcept
440 {
441 return mat2( *this ) /= f;
442 }
443
444 template<typename T>
445 template<typename U>
446 mat2<T> mat2<T>::operator+( U f ) const noexcept
447 {
448 return mat2( *this ) += f;
449 }
450
451 template<typename T>
452 template<typename U>
453 mat2<T> mat2<T>::operator-( U f ) const noexcept
454 {
455 return mat2( *this ) -= f;
456 }
457
458 template<typename T>
459 template<typename U>
461 {
462 for ( auto& val : _vec )
463 {
464 val *= f;
465 }
466 return *this;
467 }
468
469 template<typename T>
470 template<typename U>
472 {
473 for ( auto& val : _vec )
474 {
475 val /= f;
477 return *this;
478 }
479
480 template<typename T>
481 template<typename U>
484 for ( auto& val : _vec )
486 val += f;
488 return *this;
489 }
491 template<typename T>
492 template<typename U>
495 for ( auto& val : _vec )
497 val -= f;
499 return *this;
501
502 template<typename T>
503 bool mat2<T>::operator==( const mat2& B ) const noexcept
505 for ( U8 i = 0; i < 4; ++i )
506 {
507 if ( !COMPARE( mat[i], B.mat[i] ) )
508 {
509 return false;
510 }
511 }
512 return true;
513 }
514
515 template<typename T>
516 bool mat2<T>::operator!=( const mat2& B ) const noexcept
517 {
518 for ( U8 i = 0; i < 4; ++i )
519 {
520 if ( !COMPARE( mat[i], B.mat[i] ) )
521 {
522 return true;
523 }
524 }
525 return false;
526 }
527
528 template<typename T>
529 template<typename U>
530 bool mat2<T>::operator==( const mat2<U>& B ) const noexcept
531 {
532 for ( U8 i = 0; i < 4; ++i )
533 {
534 if ( !COMPARE( mat[i], B.mat[i] ) )
535 {
536 return false;
537 }
538 }
539 return true;
540 }
541
542 template<typename T>
543 template<typename U>
544 bool mat2<T>::operator!=( const mat2<U>& B ) const noexcept
545 {
546 for ( U8 i = 0; i < 4; ++i )
547 {
548 if ( !COMPARE( mat[i], B.mat[i] ) )
550 return true;
551 }
553 return false;
555
556 template<typename T>
557 bool mat2<T>::compare( const mat2& B, F32 epsilon ) const noexcept
558 {
559 for ( U8 i = 0; i < 4; ++i )
561 if ( !COMPARE_TOLERANCE( mat[i], B.mat[i], epsilon ) )
562 {
563 return false;
565 }
566 return true;
568
569 template<typename T>
570 template<typename U>
571 bool mat2<T>::compare( const mat2<U>& B, F32 epsilon ) const noexcept
572 {
573 for ( U8 i = 0; i < 4; ++i )
574 {
575 if ( !COMPARE_TOLERANCE( mat[i], B.mat[i], epsilon ) )
576 {
577 return false;
578 }
579 }
580 return true;
581 }
582
583 template<typename T>
585 {
586 return mat;
587 }
588
589 template<typename T>
590 mat2<T>::operator const T* () const
591 {
592 return mat;
593 }
594
595 template<typename T>
597 {
598 return mat[i];
599 }
601 template<typename T>
604 return mat[i];
606
607 template<typename T>
608 T& mat2<T>::element( const U8 row, const U8 column ) noexcept
610 return m[row][column];
613 template<typename T>
614 const T& mat2<T>::element( const U8 row, const U8 column ) const noexcept
616 return m[row][column];
617 }
619 template<typename T>
620 template<typename U>
621 void mat2<T>::set( U m0, U m1, U m2, U m3 ) noexcept
623 mat[0] = static_cast<T>(m0);
624 mat[3] = static_cast<T>(m3);
625 mat[1] = static_cast<T>(m1);
626 mat[2] = static_cast<T>(m2);
627 }
629 template<typename T>
630 template<typename U>
631 void mat2<T>::set( const U* matrix ) noexcept
632 {
633 if constexpr ( sizeof( T ) == sizeof( U ) )
634 {
635 std::memcpy( mat, matrix, sizeof( U ) * 4 );
636 }
637 else
638 {
639 set( matrix[0], matrix[1],
640 matrix[2], matrix[3] );
641 }
642 }
643
644 template<typename T>
645 template<typename U>
646 void mat2<T>::set( const mat2<U>& matrix ) noexcept
648 set( matrix.mat );
649 }
651 template<typename T>
652 template<typename U>
653 void mat2<T>::set( const mat3<U>& matrix ) noexcept
655 set( matrix[0], matrix[1], matrix[3], matrix[4] );
656 }
658 template<typename T>
659 template<typename U>
660 void mat2<T>::set( const mat4<U>& matrix ) noexcept
662 set( matrix[0], matrix[1], matrix[4], matrix[5] );
663 }
664
665 template<typename T>
666 template<typename U>
667 void mat2<T>::setRow( const I32 index, const U value ) noexcept
668 {
669 _vec[index].set( value );
670 }
671
672 template<typename T>
673 template<typename U>
674 void mat2<T>::setRow( const I32 index, const vec2<U> value ) noexcept
675 {
676 _vec[index].set( value );
677 }
679 template<typename T>
680 template<typename U>
681 void mat2<T>::setRow( const I32 index, const U x, const U y ) noexcept
682 {
683 _vec[index].set( x, y );
684 }
685
686 template<typename T>
687 vec2<T> mat2<T>::getRow( const I32 index ) const noexcept
688 {
689 return _vec[index];
690 }
691
692 template<typename T>
693 template<typename U>
694 void mat2<T>::setCol( const I32 index, const vec2<U> value ) noexcept
696 m[0][index] = static_cast<T>(value.x);
697 m[1][index] = static_cast<T>(value.y);
699
700 template<typename T>
701 template<typename U>
702 void mat2<T>::setCol( const I32 index, const U value ) noexcept
703 {
704 m[0][index] = static_cast<T>(value);
705 m[1][index] = static_cast<T>(value);
706 }
707
708 template<typename T>
709 template<typename U>
710 void mat2<T>::setCol( const I32 index, const U x, const U y ) noexcept
711 {
712 m[0][index] = static_cast<T>(x);
713 m[1][index] = static_cast<T>(y);
714 }
715
716 template<typename T>
717 vec2<T> mat2<T>::getCol( const I32 index ) const noexcept
718 {
719 return {
720 m[0][index],
721 m[1][index]
722 };
723 }
724
725 template<typename T>
726 void mat2<T>::zero() noexcept
727 {
728 memset( mat, 0, 4 * sizeof( T ) );
729 }
730
731 template<typename T>
732 void mat2<T>::identity() noexcept
733 {
734 mat[0] = static_cast<T>(1);
735 mat[1] = static_cast<T>(0);
736 mat[2] = static_cast<T>(0);
737 mat[3] = static_cast<T>(1);
738 }
739
740 template<typename T>
741 bool mat2<T>::isIdentity() const noexcept
742 {
743 return COMPARE( mat[0], 1 ) && IS_ZERO( mat[1] ) &&
744 IS_ZERO( mat[2] ) && COMPARE( mat[3], 1 );
745 }
746
747 template<typename T>
748 void mat2<T>::swap( mat2& B ) noexcept
749 {
750 std::swap( m[0][0], B.m[0][0] );
751 std::swap( m[0][1], B.m[0][1] );
752
753 std::swap( m[1][0], B.m[1][0] );
754 std::swap( m[1][1], B.m[1][1] );
755 }
756
757 template<typename T>
758 T mat2<T>::det() const noexcept
759 {
760 return mat[0] * mat[3] - mat[1] * mat[2];
761 }
762
763 template<typename T>
764 T mat2<T>::elementSum() const noexcept
765 {
766 return mat[0] + mat[1] + mat[2] + mat[3];
767 }
768
769 template<typename T>
770 void mat2<T>::inverse() noexcept
771 {
772 F32 idet = static_cast<F32>(det());
773 assert( !IS_ZERO( idet ) );
774 idet = 1 / idet;
775
776 set( mat[3] * idet, -mat[1] * idet,
777 -mat[2] * idet, mat[0] * idet );
778 }
779
780 template<typename T>
781 void mat2<T>::transpose() noexcept
782 {
783 set( mat[0], mat[2],
784 mat[1], mat[3] );
785 }
786
787 template<typename T>
789 {
790 inverse();
791 transpose();
792 }
793
794 template<typename T>
796 {
797 mat2<T> ret( mat );
798 ret.inverse();
799 return ret;
800 }
801
802 template<typename T>
803 void mat2<T>::getInverse( mat2<T>& ret ) const noexcept
804 {
805 ret.set( mat );
806 ret.inverse();
807 }
808
809 template<typename T>
811 {
812 mat2 ret( mat );
813 ret.transpose();
814 return ret;
815 }
816
817 template<typename T>
818 void mat2<T>::getTranspose( mat2& ret ) const noexcept
819 {
820 ret.set( mat );
821 ret.transpose();
822 }
823
824 template<typename T>
826 {
827 mat2 ret;
828 getInverse( ret );
829 ret.transpose();
830 return ret;
831 }
832
833 template<typename T>
834 void mat2<T>::getInverseTranspose( mat2& ret ) const noexcept
835 {
836 getInverse( ret );
837 ret.transpose();
838 }
839
840
841 /*********************************
842 * mat3
843 *********************************/
844
845 template<typename T>
846 mat3<T>::mat3() noexcept
847 : mat3( 1, 0, 0,
848 0, 1, 0,
849 0, 0, 1 )
850 {
851 }
852
853 template<typename T>
854 template<typename U>
855 mat3<T>::mat3( U m ) noexcept
856 : mat{ static_cast<T>(m), static_cast<T>(m), static_cast<T>(m),
857 static_cast<T>(m), static_cast<T>(m), static_cast<T>(m),
858 static_cast<T>(m), static_cast<T>(m), static_cast<T>(m) }
859 {
860 }
861
862 template<typename T>
863 template<typename U>
864 mat3<T>::mat3( U m0, U m1, U m2,
865 U m3, U m4, U m5,
866 U m6, U m7, U m8 ) noexcept
867 : mat{ static_cast<T>(m0), static_cast<T>(m1), static_cast<T>(m2),
868 static_cast<T>(m3), static_cast<T>(m4), static_cast<T>(m5),
869 static_cast<T>(m6), static_cast<T>(m7), static_cast<T>(m8) }
870 {
871 }
872
873 template<typename T>
874 template<typename U>
875 mat3<T>::mat3( const U* values ) noexcept
876 : mat3( values[0], values[1], values[2],
877 values[3], values[4], values[5],
878 values[6], values[7], values[8] )
879 {
880 }
881
882 template<typename T>
883 template<typename U>
884 mat3<T>::mat3( const mat2<U>& B, const bool zeroFill ) noexcept
885 : mat3( B[0], B[1], 0,
886 B[2], B[3], 0,
887 0, 0, zeroFill ? 0 : 1 )
888 {
889 }
890
891 template<typename T>
892 mat3<T>::mat3( const mat3& B ) noexcept
893 : mat3( B.mat )
894 {
895 }
896
897 template<typename T>
898 template<typename U>
899 mat3<T>::mat3( const mat3<U>& B ) noexcept
900 : mat3( B.mat )
901 {
902 }
903
904 template<typename T>
905 template<typename U>
906 mat3<T>::mat3( const mat4<U>& B ) noexcept
907 : mat3( B[0], B[1], B[2],
908 B[4], B[5], B[6],
909 B[8], B[9], B[10] )
910 {
911 }
912
913 //ref: http://iquilezles.org/www/articles/noacos/noacos.htm
914 template<typename T>
915 template<typename U>
916 mat3<T>::mat3( const vec3<U>& rotStart, const vec3<U>& rotEnd ) noexcept
917 {
918 const vec3<U>& d = rotStart;
919 const vec3<U>& z = rotEnd;
920
921 const vec3<U> v = cross( z, d );
922 const F32 c = dot( z, d );
923 const F32 k = 1.0f / (1.0f + c);
924
925 set( v.x * v.x * k + c, v.y * v.x * k - v.z, v.z * v.x * k + v.y,
926 v.x * v.y * k + v.z, v.y * v.y * k + c, v.z * v.y * k - v.x,
927 v.x * v.z * k - v.y, v.y * v.z * k + v.x, v.z * v.z * k + c );
928 }
929
930 template<typename T>
931 template<typename U>
932 mat3<T>::mat3( const vec3<U>& scale ) noexcept
933 {
934 setScale( scale );
935 }
936
937 template<typename T>
938 template<typename U>
939 vec2<U> mat3<T>::operator*( const vec2<U> v ) const noexcept
940 {
941 return *this * vec3<U>( v );
942 }
943
944 template<typename T>
945 template<typename U>
946 vec3<U> mat3<T>::operator*( const vec3<U>& v ) const noexcept
947 {
948 return vec3<U>( mat[0] * v[0] + mat[3] * v[1] + mat[6] * v[2],
949 mat[1] * v[0] + mat[4] * v[1] + mat[7] * v[2],
950 mat[2] * v[0] + mat[5] * v[1] + mat[8] * v[2] );
951 }
952
953 template<typename T>
954 template<typename U>
955 vec4<U> mat3<T>::operator*( const vec4<U>& v ) const noexcept
956 {
957 return vec4<U>( mat[0] * v[0] + mat[3] * v[1] + mat[6] * v[2],
958 mat[1] * v[0] + mat[4] * v[1] + mat[7] * v[2],
959 mat[2] * v[0] + mat[5] * v[1] + mat[8] * v[2],
960 v[3] );
961 }
962
963 template<typename T>
964 template<typename U>
965 mat3<T> mat3<T>::operator*( const mat3<U>& B ) const noexcept
966 {
967 return mat3( B.m[0][0] * m[0][0] + B.m[1][0] * m[0][1] + B.m[2][0] * m[0][2], B.m[0][1] * m[0][0] + B.m[1][1] * m[0][1] + B.m[2][1] * m[0][2], B.m[0][2] * m[0][0] + B.m[1][2] * m[0][1] + B.m[2][2] * m[0][2],
968 B.m[0][0] * m[1][0] + B.m[1][0] * m[1][1] + B.m[2][0] * m[1][2], B.m[0][1] * m[1][0] + B.m[1][1] * m[1][1] + B.m[2][1] * m[1][2], B.m[0][2] * m[1][0] + B.m[1][2] * m[1][1] + B.m[2][2] * m[1][2],
969 B.m[0][0] * m[2][0] + B.m[1][0] * m[2][1] + B.m[2][0] * m[2][2], B.m[0][1] * m[2][0] + B.m[1][1] * m[2][1] + B.m[2][1] * m[2][2], B.m[0][2] * m[2][0] + B.m[1][2] * m[2][1] + B.m[2][2] * m[2][2] );
970 }
971
972 template<typename T>
973 template<typename U>
974 mat3<T> mat3<T>::operator/( const mat3<U>& B ) const noexcept
975 {
976 return *this * B.getInverse();
977 }
978
979 template<typename T>
980 template<typename U>
981 mat3<T> mat3<T>::operator+( const mat3<U>& B ) const noexcept
982 {
983 return mat3( mat[0] + B[0], mat[1] + B[1], mat[2] + B[2],
984 mat[3] + B[3], mat[4] + B[4], mat[5] + B[5],
985 mat[6] + B[6], mat[7] + B[7], mat[8] + B[8] );
986 }
987
988 template<typename T>
989 template<typename U>
990 mat3<T> mat3<T>::operator-( const mat3<U>& B ) const noexcept
991 {
992 return mat3( mat[0] - B[0], mat[1] - B[1], mat[2] - B[2],
993 mat[3] - B[3], mat[4] - B[4], mat[5] - B[5],
994 mat[6] - B[6], mat[7] - B[7], mat[8] - B[8] );
995 }
996
997 template<typename T>
998 template<typename U>
999 mat3<T>& mat3<T>::operator*=( const mat3<U>& B ) noexcept
1000 {
1001 return *this = *this * B;
1002 }
1003
1004 template<typename T>
1005 template<typename U>
1007 {
1008 return *this = *this / B;
1009 }
1010
1011 template<typename T>
1012 template<typename U>
1014 {
1015 return *this = *this + B;
1016 }
1017
1018 template<typename T>
1019 template<typename U>
1021 {
1022 return *this = *this - B;
1023 }
1024
1025 template<typename T>
1026 template<typename U>
1027 mat3<T> mat3<T>::operator*( U f ) const noexcept
1028 {
1029 return mat3( *this ) *= f;
1030 }
1031
1032 template<typename T>
1033 template<typename U>
1034 mat3<T> mat3<T>::operator/( U f ) const noexcept
1035 {
1036 return mat3( *this ) /= f;
1037 }
1038
1039 template<typename T>
1040 template<typename U>
1041 mat3<T> mat3<T>::operator+( U f ) const noexcept
1042 {
1043 return mat3( *this ) += f;
1044 }
1045
1046 template<typename T>
1047 template<typename U>
1048 mat3<T> mat3<T>::operator-( U f ) const noexcept
1049 {
1050 return mat3( *this ) -= f;
1051 }
1052
1053 template<typename T>
1054 template<typename U>
1056 {
1057 for ( auto& val : _vec )
1058 {
1059 val *= f;
1060 }
1061 return *this;
1062 }
1063
1064 template<typename T>
1065 template<typename U>
1067 {
1068 for ( auto& val : _vec )
1069 {
1070 val /= f;
1071 }
1072 return *this;
1073 }
1074
1075 template<typename T>
1076 template<typename U>
1078 {
1079 for ( auto& val : _vec )
1080 {
1081 val += f;
1082 }
1083 return *this;
1084 }
1085
1086 template<typename T>
1087 template<typename U>
1089 {
1090 for ( auto& val : _vec )
1091 {
1092 val -= f;
1093 }
1094 return *this;
1095 }
1096
1097 template<typename T>
1098 bool mat3<T>::operator==( const mat3& B ) const noexcept
1099 {
1100 for ( U8 i = 0; i < 9; ++i )
1101 {
1102 if ( !COMPARE( mat[i], B.mat[i] ) )
1103 {
1104 return false;
1105 }
1106 }
1107
1108 return true;
1109 }
1110
1111 template<typename T>
1112 template<typename U>
1113 bool mat3<T>::operator==( const mat3<U>& B ) const noexcept
1114 {
1115 for ( U8 i = 0; i < 9; ++i )
1116 {
1117 if ( !COMPARE( mat[i], B.mat[i] ) )
1118 {
1119 return false;
1120 }
1121 }
1122
1123 return true;
1124 }
1125
1126 template<typename T>
1127 template<typename U>
1128 bool mat3<T>::operator!=( const mat3<U>& B ) const noexcept
1129 {
1130 for ( U8 i = 0; i < 9; ++i )
1131 {
1132 if ( !COMPARE( mat[i], B.mat[i] ) )
1133 {
1134 return true;
1135 }
1136 }
1137
1138 return false;
1139 }
1140
1141 template<typename T>
1142 bool mat3<T>::operator!=( const mat3& B ) const noexcept
1143 {
1144 for ( U8 i = 0; i < 9; ++i )
1145 {
1146 if ( !COMPARE( mat[i], B.mat[i] ) )
1147 {
1148 return true;
1149 }
1150 }
1151
1152 return false;
1153 }
1154
1155 template<typename T>
1156 bool mat3<T>::compare( const mat3& B, F32 epsilon ) const noexcept
1157 {
1158 for ( U8 i = 0; i < 9; ++i )
1159 {
1160 if ( !COMPARE_TOLERANCE( mat[i], B.mat[i], epsilon ) )
1161 {
1162 return false;
1163 }
1164 }
1165
1166 return true;
1167 }
1168
1169 template<typename T>
1170 template<typename U>
1171 bool mat3<T>::compare( const mat3<U>& B, F32 epsilon ) const noexcept
1172 {
1173 for ( U8 i = 0; i < 9; ++i )
1174 {
1175 if ( !COMPARE_TOLERANCE( mat[i], B.mat[i], epsilon ) )
1176 {
1177 return false;
1178 }
1179 }
1180
1181 return true;
1182 }
1183
1184 template<typename T>
1185 mat3<T>::operator T* () noexcept
1186 {
1187 return mat;
1188 }
1189
1190 template<typename T>
1191 mat3<T>::operator const T* () const noexcept
1192 {
1193 return mat;
1194 }
1195
1196 template<typename T>
1197 T& mat3<T>::operator[]( I32 i ) noexcept
1198 {
1199 return mat[i];
1200 }
1201
1202 template<typename T>
1203 T mat3<T>::operator[]( I32 i ) const noexcept
1204 {
1205 return mat[i];
1206 }
1207
1208 template<typename T>
1209 T& mat3<T>::element( const U8 row, const U8 column ) noexcept
1210 {
1211 return m[row][column];
1212 }
1213
1214 template<typename T>
1215 const T& mat3<T>::element( const U8 row, const U8 column ) const noexcept
1216 {
1217 return m[row][column];
1218 }
1219
1220 template<typename T>
1221 template<typename U>
1222 void mat3<T>::set( U m0, U m1, U m2, U m3, U m4, U m5, U m6, U m7, U m8 ) noexcept
1223 {
1224 mat[0] = static_cast<T>(m0); mat[1] = static_cast<T>(m1); mat[3] = static_cast<T>(m3);
1225 mat[2] = static_cast<T>(m2); mat[4] = static_cast<T>(m4); mat[5] = static_cast<T>(m5);
1226 mat[6] = static_cast<T>(m6); mat[7] = static_cast<T>(m7); mat[8] = static_cast<T>(m8);
1227 }
1228
1229 template<typename T>
1230 template<typename U>
1231 void mat3<T>::set( const U* matrix ) noexcept
1232 {
1233 if ( sizeof( T ) == sizeof( U ) )
1234 {
1235 memcpy( mat, matrix, sizeof( U ) * 9 );
1236 }
1237 else
1238 {
1239 set( matrix[0], matrix[1], matrix[2],
1240 matrix[3], matrix[4], matrix[5],
1241 matrix[6], matrix[7], matrix[8] );
1242 }
1243 }
1244
1245 template<typename T>
1246 template<typename U>
1247 void mat3<T>::set( const mat2<U>& matrix ) noexcept
1248 {
1249 const U zero = static_cast<U>(0);
1250 set( matrix[0], matrix[1], zero,
1251 matrix[2], matrix[3], zero,
1252 zero, zero, zero ); //maybe mat[8] should be 1?
1253 }
1254
1255 template<typename T>
1256 template<typename U>
1257 void mat3<T>::set( const mat3<U>& matrix ) noexcept
1258 {
1259 set( matrix.mat );
1260 }
1261
1262 template<typename T>
1263 template<typename U>
1264 void mat3<T>::set( const mat4<U>& matrix ) noexcept
1265 {
1266 set( matrix[0], matrix[1], matrix[2],
1267 matrix[4], matrix[5], matrix[6],
1268 matrix[8], matrix[9], matrix[10] );
1269 }
1270
1271 template<typename T>
1272 template<typename U>
1273 void mat3<T>::setRow( const I32 index, const U value ) noexcept
1274 {
1275 _vec[index].set( value );
1276 }
1277
1278 template<typename T>
1279 template<typename U>
1280 void mat3<T>::setRow( const I32 index, const vec3<U>& value ) noexcept
1281 {
1282 _vec[index].set( value );
1283 }
1284
1285 template<typename T>
1286 template<typename U>
1287 void mat3<T>::setRow( const I32 index, const U x, const U y, const U z ) noexcept
1288 {
1289 _vec[index].set( x, y, z );
1290 }
1291
1292 template<typename T>
1293 const vec3<T>& mat3<T>::getRow( const I32 index ) const noexcept
1294 {
1295 return _vec[index];
1296 }
1297
1298 template<typename T>
1299 template<typename U>
1300 void mat3<T>::setCol( const I32 index, const vec3<U>& value ) noexcept
1301 {
1302 m[0][index] = static_cast<T>(value.x);
1303 m[1][index] = static_cast<T>(value.y);
1304 m[2][index] = static_cast<T>(value.z);
1305 }
1306
1307 template<typename T>
1308 template<typename U>
1309 void mat3<T>::setCol( const I32 index, const U value ) noexcept
1310 {
1311 m[0][index] = static_cast<T>(value);
1312 m[1][index] = static_cast<T>(value);
1313 m[2][index] = static_cast<T>(value);
1314 }
1315
1316 template<typename T>
1317 template<typename U>
1318 void mat3<T>::setCol( const I32 index, const U x, const U y, const U z ) noexcept
1319 {
1320 m[0][index] = static_cast<T>(x);
1321 m[1][index] = static_cast<T>(y);
1322 m[2][index] = static_cast<T>(z);
1323 }
1324
1325 template<typename T>
1326 FORCE_INLINE vec3<T> mat3<T>::getCol( const I32 index ) const noexcept
1327 {
1328 return {
1329 m[0][index],
1330 m[1][index],
1331 m[2][index]
1332 };
1333 }
1334
1335 template<typename T>
1336 void mat3<T>::zero() noexcept
1337 {
1338 memset( mat, 0, 9 * sizeof( T ) );
1339 }
1340
1341 template<typename T>
1342 void mat3<T>::identity() noexcept
1343 {
1344 constexpr T zero = static_cast<T>(0);
1345 constexpr T one = static_cast<T>(1);
1346 mat[0] = one; mat[1] = zero; mat[2] = zero;
1347 mat[3] = zero; mat[4] = one; mat[5] = zero;
1348 mat[6] = zero; mat[7] = zero; mat[8] = one;
1349 }
1350
1351 template<typename T>
1352 bool mat3<T>::isIdentity() const noexcept
1353 {
1354 return COMPARE( mat[0], 1 ) && IS_ZERO( mat[1] ) && IS_ZERO( mat[2] ) &&
1355 IS_ZERO( mat[3] ) && COMPARE( mat[4], 1 ) && IS_ZERO( mat[5] ) &&
1356 IS_ZERO( mat[6] ) && IS_ZERO( mat[7] ) && COMPARE( mat[8], 1 );
1357 }
1358
1359 template<typename T>
1360 FORCE_INLINE bool mat3<T>::isUniformScale( const F32 tolerance ) const noexcept
1361 {
1362 return isColOrthogonal() && getScaleSq().isUniform( tolerance );
1363 }
1364
1365 template<typename T>
1367 {
1368 const vec3<F32> col0 = getCol( 0 );
1369 const vec3<F32> col1 = getCol( 1 );
1370 const vec3<F32> col2 = getCol( 2 );
1371
1372 return AreOrthogonal( col0, col1 ) &&
1373 AreOrthogonal( col0, col2 ) &&
1374 AreOrthogonal( col1, col2 );
1375 }
1376
1377 template<typename T>
1378 void mat3<T>::swap( mat3& B ) noexcept
1379 {
1380 std::swap( m[0][0], B.m[0][0] );
1381 std::swap( m[0][1], B.m[0][1] );
1382 std::swap( m[0][2], B.m[0][2] );
1383
1384 std::swap( m[1][0], B.m[1][0] );
1385 std::swap( m[1][1], B.m[1][1] );
1386 std::swap( m[1][2], B.m[1][2] );
1387
1388 std::swap( m[2][0], B.m[2][0] );
1389 std::swap( m[2][1], B.m[2][1] );
1390 std::swap( m[2][2], B.m[2][2] );
1391 }
1392
1393 template<typename T>
1394 T mat3<T>::det() const noexcept
1395 {
1396 return mat[0] * mat[4] * mat[8] +
1397 mat[3] * mat[7] * mat[2] +
1398 mat[6] * mat[1] * mat[5] -
1399 mat[6] * mat[4] * mat[2] -
1400 mat[3] * mat[1] * mat[8] -
1401 mat[0] * mat[7] * mat[5];
1402 }
1403
1404 template<typename T>
1405 T mat3<T>::elementSum() const noexcept
1406 {
1407 return mat[0] + mat[1] + mat[2] +
1408 mat[3] + mat[4] + mat[5] +
1409 mat[6] + mat[7] + mat[8];
1410 }
1411
1412 template<typename T>
1413 void mat3<T>::inverse() noexcept
1414 {
1415 F32 idet = det();
1416 if ( IS_ZERO( idet ) ) [[unlikely]]
1417 {
1418 return;
1419 }
1420
1421 idet = 1 / idet;
1422
1423 set( (mat[4] * mat[8] - mat[7] * mat[5]) * idet,
1424 -(mat[1] * mat[8] - mat[7] * mat[2]) * idet,
1425 (mat[1] * mat[5] - mat[4] * mat[2]) * idet,
1426 -(mat[3] * mat[8] - mat[6] * mat[5]) * idet,
1427 (mat[0] * mat[8] - mat[6] * mat[2]) * idet,
1428 -(mat[0] * mat[5] - mat[3] * mat[2]) * idet,
1429 (mat[3] * mat[7] - mat[6] * mat[4]) * idet,
1430 -(mat[0] * mat[7] - mat[6] * mat[1]) * idet,
1431 (mat[0] * mat[4] - mat[3] * mat[1]) * idet );
1432 }
1433
1434 template<typename T>
1435 void mat3<T>::transpose() noexcept
1436 {
1437 set( mat[0], mat[3], mat[6],
1438 mat[1], mat[4], mat[7],
1439 mat[2], mat[5], mat[8] );
1440 }
1441
1442 template<typename T>
1444 {
1445 inverse();
1446 transpose();
1447 }
1448
1449 template<typename T>
1451 {
1452 mat3<T> ret( mat );
1453 ret.inverse();
1454 return ret;
1455 }
1456
1457 template<typename T>
1458 void mat3<T>::getInverse( mat3<T>& ret ) const noexcept
1459 {
1460 ret.set( mat );
1461 ret.inverse();
1462 }
1463
1464 template<typename T>
1466 {
1467 mat3<T> ret( mat );
1468 ret.transpose();
1469 return ret;
1470 }
1471
1472 template<typename T>
1473 void mat3<T>::getTranspose( mat3<T>& ret ) const noexcept
1474 {
1475 ret.set( mat );
1476 ret.transpose();
1477 }
1478
1479 template<typename T>
1481 {
1482 mat3<T> ret( getInverse() );
1483 ret.transpose();
1484 return ret;
1485 }
1486
1487 template<typename T>
1488 void mat3<T>::getInverseTranspose( mat3<T>& ret ) const noexcept
1489 {
1490 ret.set( this );
1491 ret.inverseTranspose();
1492 }
1493
1494 template<typename T>
1495 template<typename U>
1497 {
1498 fromRotation( v.x, v.y, v.z, angle );
1499 }
1500
1501 template<typename T>
1502 template<typename U>
1503 void mat3<T>::fromRotation( U x, U y, U z, Angle::RADIANS<U> angle )
1504 {
1505 const U c = std::cos( angle );
1506 const U s = std::sin( angle );
1507 U l = static_cast<U>(Sqrt( static_cast<D64>(x * x + y * y + z * z) ));
1508
1509 l = l < EPSILON_F32 ? 1 : 1 / l;
1510 x *= l;
1511 y *= l;
1512 z *= l;
1513
1514 const U xy = x * y;
1515 const U yz = y * z;
1516 const U zx = z * x;
1517 const U xs = x * s;
1518 const U ys = y * s;
1519 const U zs = z * s;
1520 const U c1 = 1 - c;
1521
1522 set( c1 * x * x + c, c1 * xy + zs, c1 * zx - ys,
1523 c1 * xy - zs, c1 * y * y + c, c1 * yz + xs,
1524 c1 * zx + ys, c1 * yz - xs, c1 * z * z + c );
1525 }
1526
1527 template<typename T>
1528 template<typename U>
1530 {
1531 constexpr U zero = static_cast<U>(0);
1532 constexpr U one = static_cast<U>(1);
1533 const U c = std::cos( angle );
1534 const U s = std::sin( angle );
1535
1536 set( one, zero, zero,
1537 zero, c, s,
1538 zero, -s, c);
1539 }
1540
1541 template<typename T>
1542 template<typename U>
1544 {
1545 constexpr U zero = static_cast<U>(0);
1546 constexpr U one = static_cast<U>(1);
1547
1548 const U c = std::cos( angle );
1549 const U s = std::sin( angle );
1550
1551 set( c, zero, -s,
1552 zero, one, zero,
1553 s, zero, c );
1554 }
1555
1556 template<typename T>
1557 template<typename U>
1559 {
1560 constexpr U zero = static_cast<U>(0);
1561 constexpr U one = static_cast<U>(1);
1562
1563 const U c = std::cos( angle );
1564 const U s = std::sin( angle );
1565
1566 set( c, s, zero,
1567 -s, c, zero,
1568 zero, zero, one );
1569 }
1570
1571 // setScale replaces the main diagonal!
1572 template<typename T>
1573 template<typename U>
1574 void mat3<T>::setScale( U x, U y, U z ) noexcept
1575 {
1576 mat[0] = static_cast<T>(x);
1577 mat[4] = static_cast<T>(y);
1578 mat[8] = static_cast<T>(z);
1579 }
1580
1581 template<typename T>
1582 template<typename U>
1583 void mat3<T>::setScale( const vec3<U>& v ) noexcept
1584 {
1585 setScale( v.x, v.y, v.z );
1586 }
1587
1588 template<typename T>
1590 {
1591 return {
1592 getRow( 0 ).length(),
1593 getRow( 1 ).length(),
1594 getRow( 2 ).length()
1595 };
1596 }
1597
1598 template<typename T>
1600 {
1601 return {
1602 getRow( 0 ).lengthSquared(),
1603 getRow( 1 ).lengthSquared(),
1604 getRow( 2 ).lengthSquared()
1605 };
1606 }
1607
1608 template<typename T>
1610 {
1611 return getCol( 0 );
1612 }
1613
1614 template<typename T>
1616 {
1617 return getCol( 1 );
1618 }
1619
1620 template<typename T>
1622 {
1623 // FWD = WORLD_NEG_Z_AXIS
1624 return -getCol( 2 );
1625 }
1626
1627 template<typename T>
1629 {
1630 return Normalized( getRightVec() );
1631 }
1632
1633 template<typename T>
1635 {
1636 return Normalized( getUpVec() );
1637 }
1638
1639 template<typename T>
1641 {
1642 // FWD = WORLD_NEG_Z_AXIS
1643 return -Normalized( -getForwardVec() );
1644 }
1645
1646 template<typename T>
1648 {
1649 vec3<T> x( mat[0], mat[1], mat[2] );
1650 x.normalize();
1651 vec3<T> y( mat[3], mat[4], mat[5] );
1652 vec3<T> z( cross( x, y ) );
1653 z.normalize();
1654 y.cross( z, x );
1655 y.normalize();
1656
1657 set( x.x, x.y, x.z,
1658 y.x, y.y, y.z,
1659 z.x, z.y, z.z );
1660 }
1661
1662 /***************
1663 * mat4
1664 ***************/
1665
1666 template<typename T>
1667 mat4<T>::mat4() noexcept
1668 : mat{ 1, 0, 0, 0,
1669 0, 1, 0, 0,
1670 0, 0, 1, 0,
1671 0, 0, 0, 1 }
1672 {
1673 }
1674
1675 template<typename T>
1676 template<typename U>
1677 mat4<T>::mat4( U value ) noexcept
1678 : mat{ static_cast<T>(value), static_cast<T>(value), static_cast<T>(value), static_cast<T>(value),
1679 static_cast<T>(value), static_cast<T>(value), static_cast<T>(value), static_cast<T>(value),
1680 static_cast<T>(value), static_cast<T>(value), static_cast<T>(value), static_cast<T>(value),
1681 static_cast<T>(value), static_cast<T>(value), static_cast<T>(value), static_cast<T>(value) }
1682 {
1683 }
1684
1685 template<typename T>
1686 template<typename U>
1687 mat4<T>::mat4(U m0, U m1, U m2, U m3,
1688 U m4, U m5, U m6, U m7,
1689 U m8, U m9, U m10, U m11,
1690 U m12, U m13, U m14, U m15 ) noexcept
1691 : mat{ static_cast<T>(m0), static_cast<T>(m1), static_cast<T>(m2), static_cast<T>(m3),
1692 static_cast<T>(m4), static_cast<T>(m5), static_cast<T>(m6), static_cast<T>(m7),
1693 static_cast<T>(m8), static_cast<T>(m9), static_cast<T>(m10), static_cast<T>(m11),
1694 static_cast<T>(m12), static_cast<T>(m13), static_cast<T>(m14), static_cast<T>(m15) }
1695 {
1696 }
1697
1698 template<typename T>
1699 template<typename U>
1700 mat4<T>::mat4( const U* values ) noexcept
1701 : mat{ static_cast<T>(values[0]), static_cast<T>(values[1]), static_cast<T>(values[2]), static_cast<T>(values[3]),
1702 static_cast<T>(values[4]), static_cast<T>(values[5]), static_cast<T>(values[6]), static_cast<T>(values[7]),
1703 static_cast<T>(values[8]), static_cast<T>(values[9]), static_cast<T>(values[10]), static_cast<T>(values[11]),
1704 static_cast<T>(values[12]), static_cast<T>(values[13]), static_cast<T>(values[14]), static_cast<T>(values[15]) }
1705 {
1706 }
1707
1708 template<typename T>
1709 template<typename U>
1710 mat4<T>::mat4( const mat2<U>& B, const bool zeroFill ) noexcept
1711 : mat4( { B[0], B[1], static_cast<U>(0), static_cast<U>(0),
1712 B[2], B[3], static_cast<U>(0), static_cast<U>(0),
1713 static_cast<U>(0), static_cast<U>(0), static_cast<U>(zeroFill ? 0 : 1), static_cast<U>(0),
1714 static_cast<U>(0), static_cast<U>(0), static_cast<U>(0), static_cast<U>(zeroFill ? 0 : 1) } )
1715 {
1716 }
1717
1718 template<typename T>
1719 template<typename U>
1720 mat4<T>::mat4( const mat3<U>& B, const bool zeroFill ) noexcept
1721 : mat4( { B[0], B[1], B[2], static_cast<U>(0),
1722 B[3], B[4], B[5], static_cast<U>(0),
1723 B[6], B[7], B[8], static_cast<U>(0),
1724 static_cast<U>(0), static_cast<U>(0), static_cast<U>(0), static_cast<U>(zeroFill ? 0 : 1) } )
1725 {
1726 }
1727
1728 template<typename T>
1729 mat4<T>::mat4( const mat4& B ) noexcept
1730 : mat4( B.mat )
1731 {
1732 }
1733
1734 template<typename T>
1735 template<typename U>
1736 mat4<T>::mat4( const mat4<U>& B ) noexcept
1737 : mat4( B.mat )
1738 {
1739 }
1740
1741 template<typename T>
1742 template<typename U>
1743 mat4<T>::mat4( const vec3<U>& translation, const vec3<U>& scale ) noexcept
1744 : mat4( { scale.x, static_cast<U>(0), static_cast<U>(0), static_cast<U>(0),
1745 static_cast<U>(0), scale.y, static_cast<U>(0), static_cast<U>(0),
1746 static_cast<U>(0), static_cast<U>(0), scale.z, static_cast<U>(0),
1747 translation.x, translation.y, translation.z, static_cast<U>(1) } )
1748 {
1749 }
1750
1751 template<typename T>
1752 template<typename U>
1753 mat4<T>::mat4( const vec3<U>& translation, const vec3<U>& scale, const mat3<U>& rotation ) noexcept
1754 : mat4( { scale.x, static_cast<U>(0), static_cast<U>(0), static_cast<U>(0),
1755 static_cast<U>(0), scale.y, static_cast<U>(0), static_cast<U>(0),
1756 static_cast<U>(0), static_cast<U>(0), scale.z, static_cast<U>(0),
1757 static_cast<U>(0), static_cast<U>(0), static_cast<U>(0), static_cast<U>(1) } )
1758 {
1759 // Rotate around origin then move!
1760 set( *this * mat4<U>( rotation, false ) );
1761 setTranslation( translation );
1762 }
1763
1764 template<typename T>
1765 template<typename U>
1766 mat4<T>::mat4( const vec3<U>& translation ) noexcept
1767 : mat4( translation.x, translation.y, translation.z )
1768 {
1769 }
1770
1771 template<typename T>
1772 template<typename U>
1773 mat4<T>::mat4( U translationX, U translationY, U translationZ ) noexcept
1774 : mat4( { static_cast<U>(1), static_cast<U>(0), static_cast<U>(0), static_cast<U>(0),
1775 static_cast<U>(0), static_cast<U>(1), static_cast<U>(0), static_cast<U>(0),
1776 static_cast<U>(0), static_cast<U>(0), static_cast<U>(1), static_cast<U>(0),
1777 translationX, translationY, translationZ, static_cast<U>(1) } )
1778 {
1779 }
1780
1781 template<typename T>
1782 template<typename U>
1783 mat4<T>::mat4( const vec3<U>& axis, Angle::RADIANS<U> angle ) noexcept
1784 : mat4( axis.x, axis.y, axis.z, angle )
1785 {
1786 }
1787
1788 template<typename T>
1789 template<typename U>
1790 mat4<T>::mat4( U x, U y, U z, Angle::RADIANS<U> angle ) noexcept
1791 : mat4()
1792 {
1793 fromRotation( x, y, z, angle );
1794 }
1795
1796 template<typename T>
1797 template<typename U>
1798 mat4<T>::mat4( const Plane<U>& reflectionPlane ) noexcept
1799 : mat4()
1800 {
1801 reflect( reflectionPlane );
1802 }
1803
1804 template<typename T>
1805 template<typename U>
1807 {
1808 return *this * vec4<U>( v );
1809 }
1810
1811 template<typename T>
1812 template<typename U>
1814 {
1815 return *this * vec4<U>( v );
1816 }
1817
1818 template<typename T>
1819 template<typename U>
1821 {
1822 return { mat[0] * v.x + mat[4] * v.y + mat[8] * v.z + mat[12] * v.w,
1823 mat[1] * v.x + mat[5] * v.y + mat[9] * v.z + mat[13] * v.w,
1824 mat[2] * v.x + mat[6] * v.y + mat[10] * v.z + mat[14] * v.w,
1825 mat[3] * v.x + mat[7] * v.y + mat[11] * v.z + mat[15] * v.w };
1826 }
1827
1828 template<typename T>
1829 template<typename U>
1830 mat4<T> mat4<T>::operator*( const mat4<U>& matrix ) const noexcept
1831 {
1832 mat4<T> retValue;
1833 Multiply( matrix, *this, retValue );
1834 return retValue;
1835 }
1836
1837 template<typename T>
1838 template<typename U>
1839 mat4<T> mat4<T>::operator/( const mat4<U>& matrix ) const noexcept
1840 {
1841 mat4<T> retValue;
1842 Multiply( matrix.getInverse(), *this, retValue );
1843 return retValue;
1844 }
1845
1846 template<typename T>
1847 template<typename U>
1848 mat4<T> mat4<T>::operator+( const mat4<U>& matrix ) const noexcept
1849 {
1850 return mat4( *this ) += matrix;
1851 }
1852
1853 template<typename T>
1854 template<typename U>
1855 mat4<T> mat4<T>::operator-( const mat4<U>& matrix ) const noexcept
1856 {
1857 return mat4( *this ) -= matrix;
1858 }
1859
1860 template<typename T>
1861 template<typename U>
1863 {
1864 Multiply( matrix, *this, *this );
1865 return *this;
1866 }
1867
1868 template<typename T>
1869 template<typename U>
1871 {
1872 Multiply( matrix.getInverse(), *this, *this );
1873 return *this;
1874 }
1875
1876 template<typename T>
1877 template<typename U>
1879 {
1880 for ( U8 i = 0u; i < 4u; ++i )
1881 {
1882 _vec[i] += matrix._vec[i];
1883 }
1884 return *this;
1885 }
1886
1887 template<typename T>
1888 template<typename U>
1890 {
1891 for ( U8 i = 0u; i < 4u; ++i )
1892 {
1893 _vec[i] -= matrix._vec[i];
1894 }
1895
1896 return *this;
1897 }
1898
1899 template<typename T>
1900 template<typename U>
1901 FORCE_INLINE mat4<T> mat4<T>::operator*( const U f ) const noexcept
1902 {
1903 return mat4( *this ) *= f;
1904 }
1905
1906 template<typename T>
1907 template<typename U>
1908 FORCE_INLINE mat4<T> mat4<T>::operator/( const U f ) const noexcept
1909 {
1910 return mat4( *this ) /= f;
1911 }
1912
1913 template<typename T>
1914 template<typename U>
1915 FORCE_INLINE mat4<T> mat4<T>::operator+( const U f ) const noexcept
1916 {
1917 return mat4( *this ) += f;
1918 }
1919
1920 template<typename T>
1921 template<typename U>
1922 FORCE_INLINE mat4<T> mat4<T>::operator-( const U f ) const noexcept
1923 {
1924 return mat4( *this ) -= f;
1925 }
1926
1927 template<typename T>
1928 template<typename U>
1930 {
1931 for ( U8 i = 0u; i < 4u; ++i )
1932 {
1933 _vec[i] *= f;
1934 }
1935
1936 return *this;
1937 }
1938
1939 template<typename T>
1940 template<typename U>
1942 {
1943 for ( U8 i = 0u; i < 4u; ++i )
1944 {
1945 _vec[i] /= f;
1946 }
1947
1948 return *this;
1949 }
1950
1951 template<typename T>
1952 template<typename U>
1954 {
1955 for ( U8 i = 0u; i < 4u; ++i )
1956 {
1957 _vec[i] += f;
1958 }
1959
1960 return *this;
1961 }
1962
1963 template<typename T>
1964 template<typename U>
1966 {
1967 for ( U8 i = 0u; i < 4u; ++i )
1968 {
1969 _vec[i] -= f;
1970 }
1971
1972 return *this;
1973 }
1974
1975 template<typename T>
1976 bool mat4<T>::operator==( const mat4& B ) const noexcept
1977 {
1978 for ( U8 i = 0u; i < 4u; ++i )
1979 {
1980 if ( _reg[i] != B._reg[i] )
1981 {
1982 return false;
1983 }
1984 }
1985
1986 return true;
1987 }
1988
1989 template<typename T>
1990 bool mat4<T>::operator!=( const mat4& B ) const noexcept
1991 {
1992 for ( U8 i = 0u; i < 4u; ++i )
1993 {
1994 if ( _reg[i] != B._reg[i] )
1995 {
1996 return true;
1997 }
1998 }
1999
2000 return false;
2001 }
2002
2003 template<typename T>
2004 template<typename U>
2005 bool mat4<T>::operator==( const mat4<U>& B ) const noexcept
2006 {
2007 /*
2008 // Add a small epsilon value to avoid 0.0 != 0.0
2009 if (!COMPARE(elementSum() + EPSILON_F32,
2010 B.elementSum() + EPSILON_F32)) {
2011 return false;
2012 }
2013 */
2014 for ( U8 i = 0u; i < 16u; ++i )
2015 {
2016 if ( !COMPARE( mat[i], B.mat[i] ) )
2017 {
2018 return false;
2019 }
2020 }
2021
2022 return true;
2023 }
2024
2025 template<typename T>
2026 template<typename U>
2027 bool mat4<T>::operator!=( const mat4<U>& B ) const noexcept
2028 {
2029 /*
2030 // Add a small epsilon value to avoid 0.0 != 0.0
2031 if (!COMPARE(elementSum() + EPSILON_F32,
2032 B.elementSum() + EPSILON_F32)) {
2033 return true;
2034 }
2035 */
2036 for ( U8 i = 0u; i < 16u; ++i )
2037 {
2038 if ( !COMPARE( mat[i], B.mat[i] ) )
2039 {
2040 return true;
2041 }
2042 }
2043
2044 return false;
2045 }
2046
2047 template<typename T>
2048 FORCE_INLINE bool mat4<T>::compare( const mat4& B, F32 epsilon ) const noexcept
2049 {
2050 for ( U8 i = 0u; i < 16u; ++i )
2051 {
2052 if ( !COMPARE_TOLERANCE( mat[i], B.mat[i], epsilon ) )
2053 {
2054 return false;
2055 }
2056 }
2057
2058 return true;
2059 }
2060
2061 template<typename T>
2062 template<typename U>
2063 FORCE_INLINE bool mat4<T>::compare( const mat4<U>& B, F32 epsilon ) const noexcept
2064 {
2065 for ( U8 i = 0u; i < 16u; ++i )
2066 {
2067 if ( !COMPARE_TOLERANCE( mat[i], B.mat[i], epsilon ) )
2068 {
2069 return false;
2070 }
2071 }
2072
2073 return true;
2074 }
2075
2076 template<typename T>
2078 {
2079 return mat;
2080 }
2081
2082 template<typename T>
2083 FORCE_INLINE mat4<T>::operator const T* () const noexcept
2084 {
2085 return mat;
2086 }
2087
2088 template<typename T>
2090 {
2091 return mat[i];
2092 }
2093
2094 template<typename T>
2095 FORCE_INLINE const T& mat4<T>::operator[]( I32 i ) const noexcept
2096 {
2097 return mat[i];
2098 }
2099
2100 template<typename T>
2101 FORCE_INLINE T& mat4<T>::element( const U8 row, const U8 column ) noexcept
2102 {
2103 return m[row][column];
2104 }
2105
2106 template<typename T>
2107 FORCE_INLINE const T& mat4<T>::element( const U8 row, const U8 column ) const noexcept
2108 {
2109 return m[row][column];
2110 }
2111
2112 template<typename T>
2113 FORCE_INLINE void mat4<T>::set( std::initializer_list<T> matrix ) noexcept
2114 {
2115 set( matrix.begin() );
2116 }
2117
2118 template<typename T>
2119 template<typename U>
2120 FORCE_INLINE void mat4<T>::set( U const* matrix ) noexcept
2121 {
2122 if constexpr ( std::is_same<T, U>::value )
2123 {
2124 std::memcpy( mat, matrix, sizeof( T ) * 16 );
2125 }
2126 else
2127 {
2128 for ( U8 i = 0u; i < 16u; ++i )
2129 {
2130 mat[i] = static_cast<T>(matrix[i]);
2131 }
2132 }
2133 }
2134
2135 template<typename T>
2136 template<typename U>
2137 FORCE_INLINE void mat4<T>::set( const mat2<U>& matrix ) noexcept
2138 {
2139 zero();
2140
2141 mat[0] = matrix[0]; mat[1] = matrix[1];
2142 mat[4] = matrix[2]; mat[5] = matrix[3];
2143 }
2144
2145 template<typename T>
2146 template<typename U>
2147 FORCE_INLINE void mat4<T>::set( const mat3<U>& matrix ) noexcept
2148 {
2149 zero();
2150
2151 mat[0] = matrix[0]; mat[1] = matrix[1]; mat[2] = matrix[2];
2152 mat[4] = matrix[3]; mat[5] = matrix[4]; mat[6] = matrix[5];
2153 mat[8] = matrix[6]; mat[9] = matrix[7]; mat[10] = matrix[8];
2154 mat[15] = 1.f;
2155 }
2156
2157 template<typename T>
2158 template<typename U>
2159 FORCE_INLINE void mat4<T>::set( const mat4<U>& matrix ) noexcept
2160 {
2161 set( matrix.mat );
2162 }
2163
2164 template<typename T>
2165 template<typename U>
2166 void mat4<T>::set( const vec3<U>& translation, const vec3<U>& scale, const mat4<U>& rotation ) noexcept
2167 {
2168 set( scale.x, static_cast<U>(0), static_cast<U>(0), static_cast<U>(0),
2169 static_cast<U>(0), scale.y, static_cast<U>(0), static_cast<U>(0),
2170 static_cast<U>(0), static_cast<U>(0), scale.z, static_cast<U>(0),
2171 static_cast<U>(0), static_cast<U>(0), static_cast<U>(0), static_cast<U>(1) );
2172
2173 set( *this * rotation );
2174
2175 setTranslation( translation );
2176 }
2177
2178 template<typename T>
2179 template<typename U>
2180 FORCE_INLINE void mat4<T>::setRow( I32 index, const U value ) noexcept
2181 {
2182 _vec[index].set( value );
2183 }
2184
2185 template<typename T>
2186 template<typename U>
2187 FORCE_INLINE void mat4<T>::setRow( I32 index, const vec4<U>& value ) noexcept
2188 {
2189 _vec[index].set( value );
2190 }
2191
2192 template<typename T>
2193 template<typename U>
2194 FORCE_INLINE void mat4<T>::setRow( I32 index, const U x, const U y, const U z, const U w ) noexcept
2195 {
2196 _vec[index].set( x, y, z, w );
2197 }
2198
2199 template<typename T>
2200 FORCE_INLINE const vec4<T>& mat4<T>::getRow( I32 index ) const noexcept
2201 {
2202 return _vec[index];
2203 }
2204
2205 template<typename T>
2206 template<typename U>
2207 FORCE_INLINE void mat4<T>::setCol( I32 index, const vec4<U>& value ) noexcept
2208 {
2209 setCol( index, value.x, value.y, value.z, value.w );
2210 }
2211
2212 template<typename T>
2213 template<typename U>
2214 FORCE_INLINE void mat4<T>::setCol( I32 index, const U value ) noexcept
2215 {
2216 m[0][index] = static_cast<T>(value);
2217 m[1][index] = static_cast<T>(value);
2218 m[2][index] = static_cast<T>(value);
2219 m[3][index] = static_cast<T>(value);
2220 }
2221
2222 template<typename T>
2223 template<typename U>
2224 FORCE_INLINE void mat4<T>::setCol( I32 index, const U x, const U y, const U z, const U w ) noexcept
2225 {
2226 m[0][index] = static_cast<T>(x);
2227 m[1][index] = static_cast<T>(y);
2228 m[2][index] = static_cast<T>(z);
2229 m[3][index] = static_cast<T>(w);
2230 }
2231
2232 template<typename T>
2233 FORCE_INLINE vec4<T> mat4<T>::getCol( const I32 index ) const noexcept
2234 {
2235 return {
2236 m[0][index],
2237 m[1][index],
2238 m[2][index],
2239 m[3][index]
2240 };
2241 }
2242
2243 template<typename T>
2245 {
2246 memset( mat, 0, sizeof( T ) * 16 );
2247 }
2248
2249 template<typename T>
2251 {
2252 zero();
2253
2254 m[0][0] = m[1][1] = m[2][2] = m[3][3] = static_cast<T>(1);
2255 }
2256
2257 template<typename T>
2258 FORCE_INLINE bool mat4<T>::isIdentity() const noexcept
2259 {
2260 return *this == MAT4_IDENTITY;
2261 }
2262
2263 template<typename T>
2264 FORCE_INLINE bool mat4<T>::isUniformScale( const F32 tolerance ) const noexcept
2265 {
2266 return isColOrthogonal() && getScaleSq().isUniform( tolerance );
2267 }
2268
2269 template<typename T>
2270 bool mat4<T>::isColOrthogonal() const noexcept
2271 {
2272 const vec3<F32> col0 = getCol( 0 ).xyz;
2273 const vec3<F32> col1 = getCol( 1 ).xyz;
2274 const vec3<F32> col2 = getCol( 2 ).xyz;
2275
2276 return AreOrthogonal( col0, col1 ) &&
2277 AreOrthogonal( col0, col2 ) &&
2278 AreOrthogonal( col1, col2 );
2279 }
2280
2281 template<typename T>
2282 void mat4<T>::swap( mat4& B ) noexcept
2283 {
2284 for ( U8 i = 0u; i < 16u; ++i )
2285 {
2286 std::swap( mat[i], B.mat[i] );
2287 }
2288 }
2289
2290 template<typename T>
2291 FORCE_INLINE T mat4<T>::det() const noexcept
2292 {
2293 return mat[0] * mat[5] * mat[10] + mat[4] * mat[9] * mat[2] +
2294 mat[8] * mat[1] * mat[6] - mat[8] * mat[5] * mat[2] -
2295 mat[4] * mat[1] * mat[10] - mat[0] * mat[9] * mat[6];
2296 }
2297
2298 template<typename T>
2300 {
2301 return mat[0] + mat[1] + mat[2] + mat[3] +
2302 mat[4] + mat[5] + mat[6] + mat[7] +
2303 mat[8] + mat[9] + mat[10] + mat[11] +
2304 mat[12] + mat[13] + mat[14] + mat[15];
2305 }
2306
2307 template<typename T>
2309 {
2310 _vec[0].normalize(); //right
2311 _vec[1].normalize(); //up
2312 _vec[2].normalize(); //dir
2313 }
2314
2315 template<typename T>
2317 {
2318 Inverse( mat, mat );
2319 }
2320
2321 template<>
2322 inline void mat4<F32>::inverse() noexcept
2323 {
2324 mat4<F32> ret;
2325 AVX::GetInverse( *this, ret );
2326 *this = ret;
2327 }
2328
2329 template<typename T>
2331 {
2332 set( {
2333 mat[0], mat[4], mat[8], mat[12],
2334 mat[1], mat[5], mat[9], mat[13],
2335 mat[2], mat[6], mat[10], mat[14],
2336 mat[3], mat[7], mat[11], mat[15]
2337 } );
2338 }
2339
2340 template<typename T>
2342 {
2343 mat4<F32> r;
2344 GetInverse( *this, r );
2345 r.getTranspose( *this );
2346 }
2347
2348 template<typename T>
2350 {
2351 set( { mat[0], mat[4], mat[8], mat[3],
2352 mat[1], mat[5], mat[9], mat[7],
2353 mat[2], mat[6], mat[10], mat[11],
2354 mat[12], mat[13], mat[14], mat[15]
2355 } );
2356
2357 return *this;
2358 }
2359
2360 template<typename T>
2362 {
2363 mat4 ret;
2364 Inverse( mat, ret.mat );
2365 return ret;
2366 }
2367
2368 template<>
2369 inline mat4<F32> mat4<F32>::getInverse() const noexcept
2370 {
2371 mat4<F32> ret;
2372 AVX::GetInverse( *this, ret );
2373 return ret;
2374 }
2375
2376 template<typename T>
2377 FORCE_INLINE void mat4<T>::getInverse( mat4& ret ) const noexcept
2378 {
2379 Inverse( mat, ret.mat );
2380 }
2381
2382 template<>
2384 {
2385 AVX::GetInverse( *this, ret );
2386 }
2387
2388 template<typename T>
2390 {
2391 return mat4( { mat[0], mat[4], mat[8], mat[12],
2392 mat[1], mat[5], mat[9], mat[13],
2393 mat[2], mat[6], mat[10], mat[14],
2394 mat[3], mat[7], mat[11], mat[15] } );
2395 }
2396
2397 template<typename T>
2398 FORCE_INLINE void mat4<T>::getTranspose( mat4& out ) const noexcept
2399 {
2400 out.set( { mat[0], mat[4], mat[8], mat[12],
2401 mat[1], mat[5], mat[9], mat[13],
2402 mat[2], mat[6], mat[10], mat[14],
2403 mat[3], mat[7], mat[11], mat[15] } );
2404 }
2405
2406 template<typename T>
2408 {
2409 mat4 ret;
2410 Inverse( mat, ret.mat );
2411 ret.transpose();
2412 return ret;
2413 }
2414
2415 template<>
2417 {
2418 mat4<F32> ret;
2419 AVX::GetInverse( *this, ret );
2420 ret.transpose();
2421 return ret;
2422 }
2423
2424 template<typename T>
2426 {
2427 Inverse( mat, ret.mat );
2428 ret.transpose();
2429 }
2430
2431 template<>
2433 {
2434 AVX::GetInverse( *this, ret );
2435 ret.transpose();
2436 }
2437
2438 template<typename T>
2440 {
2441 return mat4( mat[0], mat[4], mat[8], mat[3],
2442 mat[1], mat[5], mat[9], mat[7],
2443 mat[2], mat[6], mat[10], mat[11],
2444 mat[12], mat[13], mat[14], mat[15] );
2445 }
2446
2447 template<typename T>
2449 {
2450 ret.set( mat[0], mat[4], mat[8], mat[3],
2451 mat[1], mat[5], mat[9], mat[7],
2452 mat[2], mat[6], mat[10], mat[11],
2453 mat[12], mat[13], mat[14], mat[15] );
2454 }
2455
2456 template<typename T>
2457 template<typename U>
2458 void mat4<T>::fromRotation( U x, U y, U z, Angle::RADIANS<U> angle ) noexcept
2459 {
2460 vec3<U> v( x, y, z );
2461 v.normalize();
2462
2463 const U c = std::cos( angle );
2464 const U s = std::sin( angle );
2465
2466 const U xx = v.x * v.x;
2467 const U yy = v.y * v.y;
2468 const U zz = v.z * v.z;
2469 const U xy = v.x * v.y;
2470 const U yz = v.y * v.z;
2471 const U zx = v.z * v.x;
2472 const U xs = v.x * s;
2473 const U ys = v.y * s;
2474 const U zs = v.z * s;
2475
2476 set( (1 - c) * xx + c, (1 - c) * xy + zs, (1 - c) * zx - ys, static_cast<U>(mat[3]),
2477 (1 - c) * xy - zs, (1 - c) * yy + c, (1 - c) * yz + xs, static_cast<U>(mat[7]),
2478 (1 - c) * zx + ys, (1 - c) * yz - xs, (1 - c) * zz + c, static_cast<U>(mat[11]),
2479 static_cast<U>(mat[12]), static_cast<U>(mat[13]), static_cast<U>(mat[14]), static_cast<U>(mat[15]) );
2480 }
2481
2482 template<typename T>
2483 template<typename U>
2485 {
2486 const U c = std::cos( angle );
2487 const U s = std::sin( angle );
2488
2489 mat[5] = static_cast<T>(c);
2490 mat[9] = static_cast<T>(-s);
2491 mat[6] = static_cast<T>(s);
2492 mat[10] = static_cast<T>(c);
2493 }
2494
2495 template<typename T>
2496 template<typename U>
2498 {
2499 const U c = std::cos( angle );
2500 const U s = std::sin( angle );
2501
2502 mat[0] = static_cast<T>(c);
2503 mat[8] = static_cast<T>(s);
2504 mat[2] = static_cast<T>(-s);
2505 mat[10] = static_cast<T>(c);
2506 }
2507
2508 template<typename T>
2509 template<typename U>
2511 {
2512 const U c = std::cos( angle );
2513 const U s = std::sin( angle );
2514
2515 mat[0] = static_cast<T>(c);
2516 mat[4] = static_cast<T>(-s);
2517 mat[1] = static_cast<T>(s);
2518 mat[5] = static_cast<T>(c);
2519 }
2520
2521 template<typename T>
2522 template<typename U>
2524 {
2525 setTranslation( v.x, v.y, v.z );
2526 }
2527
2528 template<typename T>
2529 template<typename U>
2530 FORCE_INLINE void mat4<T>::setTranslation( U x, U y, U z ) noexcept
2531 {
2532 mat[12] = static_cast<T>(x);
2533 mat[13] = static_cast<T>(y);
2534 mat[14] = static_cast<T>(z);
2535 }
2536
2537 template<typename T>
2538 template<typename U>
2539 FORCE_INLINE void mat4<T>::setScale( U x, U y, U z ) noexcept
2540 {
2541 mat[0] = static_cast<T>(x);
2542 mat[5] = static_cast<T>(y);
2543 mat[10] = static_cast<T>(z);
2544 }
2545
2546 template<typename T>
2547 template<typename U>
2548 FORCE_INLINE void mat4<T>::setScale( const vec3<U>& v ) noexcept
2549 {
2550 setScale( v.x, v.y, v.z );
2551 }
2552
2553 template<typename T>
2555 {
2556 return {
2557 getRow( 0 ).length(),
2558 getRow( 1 ).length(),
2559 getRow( 2 ).length()
2560 };
2561 }
2562
2563 template<typename T>
2565 {
2566 return {
2567 getRow( 0 ).lengthSquared(),
2568 getRow( 1 ).lengthSquared(),
2569 getRow( 2 ).lengthSquared()
2570 };
2571 }
2572
2573 template<typename T>
2575 {
2576 return getCol( 0 ).xyz;
2577 }
2578
2579 template<typename T>
2581 {
2582 return getCol( 1 ).xyz;
2583 }
2584
2585 template<typename T>
2587 {
2588 // FWD = WORLD_NEG_Z_AXIS
2589 return -getCol( 2 ).xyz;
2590 }
2591
2592 template<typename T>
2594 {
2595 return Normalized( getRightVec() );
2596 }
2597
2598 template<typename T>
2600 {
2601 return Normalized( getUpVec() );
2602 }
2603
2604 template<typename T>
2606 {
2607 // FWD = WORLD_NEG_Z_AXIS
2608 return -Normalized( -getForwardVec() );
2609 }
2610
2611 template<typename T>
2612 template<typename U>
2613 FORCE_INLINE vec3<U> mat4<T>::transform( const vec3<U>& v, bool homogeneous ) const
2614 {
2615 return homogeneous ? transformHomogeneous( v )
2616 : transformNonHomogeneous( v );
2617 }
2618
2619 template<typename T>
2620 template<typename U>
2622 {
2623 //Transforms the given 3-D vector by the matrix, projecting the result back into <i>w</i> = 1. (OGRE reference)
2624 const F32 fInvW = 1.f / (m[0][3] * v.x + m[1][3] * v.y +
2625 m[2][3] * v.z + m[3][3] * 1.f);
2626
2627 return { (m[0][0] * v.x + m[1][1] * v.y + m[2][0] * v.z + m[3][0]) * fInvW,
2628 (m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1]) * fInvW,
2629 (m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2]) * fInvW };
2630 }
2631
2632 template<typename T>
2633 template<typename U>
2635 {
2636 return *this * vec4<U>( v, static_cast<U>(0) );
2637 }
2638
2639 template<typename T>
2640 template<typename U>
2641 FORCE_INLINE void mat4<T>::translate( const vec3<U>& v ) noexcept
2642 {
2643 translate( v.x, v.y, v.z );
2644 }
2645
2646 template<typename T>
2647 template<typename U>
2648 FORCE_INLINE void mat4<T>::translate( U x, U y, U z ) noexcept
2649 {
2650 mat[12] += static_cast<T>(x);
2651 mat[13] += static_cast<T>(y);
2652 mat[14] += static_cast<T>(z);
2653 }
2654
2655 template<typename T>
2656 template<typename U>
2657 void mat4<T>::scale( const vec3<U>& v ) noexcept
2658 {
2659 scale( v.x, v.y, v.z );
2660 }
2661
2662 template<typename T>
2663 template<typename U>
2664 void mat4<T>::scale( U x, U y, U z ) noexcept
2665 {
2666 mat[0] *= static_cast<T>(x);
2667 mat[1] *= static_cast<T>(x);
2668 mat[2] *= static_cast<T>(x);
2669 mat[3] *= static_cast<T>(x);
2670 mat[4] *= static_cast<T>(y);
2671 mat[5] *= static_cast<T>(y);
2672 mat[6] *= static_cast<T>(y);
2673 mat[7] *= static_cast<T>(y);
2674 mat[8] *= static_cast<T>(z);
2675 mat[9] *= static_cast<T>(z);
2676 mat[10] *= static_cast<T>(z);
2677 mat[11] *= static_cast<T>(z);
2678 }
2679
2680 template<typename T>
2682 {
2683 return {
2684 mat[12],
2685 mat[13],
2686 mat[14]
2687 };
2688 }
2689
2690 template<typename T>
2692 {
2693 const T zero = static_cast<T>(0);
2694 const T one = static_cast<T>(1);
2695 mat4 ret( { mat[0], mat[1], mat[2], zero,
2696 mat[4], mat[5], mat[6], zero,
2697 mat[8], mat[9], mat[10], zero,
2698 zero, zero, zero, one } );
2699 ret.orthoNormalize();
2700
2701 return ret;
2702 }
2703
2704 template<typename T>
2705 template<typename U>
2706 FORCE_INLINE const mat4<T>& mat4<T>::reflect( U x, U y, U z, U w ) noexcept
2707 {
2708 return reflect( Plane<U>( x, y, z, w ) );
2709 }
2710
2711 template<typename T>
2712 template<typename U>
2713 const mat4<T>& mat4<T>::reflect( const Plane<U>& plane ) noexcept
2714 {
2715 constexpr U zero = static_cast<U>(0);
2716 constexpr U one = static_cast<U>(1);
2717
2718 const vec4<U>& eq = plane._equation;
2719
2720 U x = eq.x;
2721 U y = eq.y;
2722 U z = eq.z;
2723 U d = eq.w;
2724
2725 *this = mat4( { -2 * x * x + 1, -2 * y * x, -2 * z * x, zero,
2726 -2 * x * y, -2 * y * y + 1, -2 * z * y, zero,
2727 -2 * x * z, -2 * y * z, -2 * z * z + 1, zero,
2728 -2 * x * d, -2 * y * d, -2 * z * d, one } ) * *this;
2729
2730 return *this;
2731 }
2732
2733 template<typename T>
2734 template<typename U>
2735 void mat4<T>::extractMat3( mat3<U>& matrix3 ) const noexcept
2736 {
2737 matrix3.m[0][0] = static_cast<U>(m[0][0]);
2738 matrix3.m[0][1] = static_cast<U>(m[0][1]);
2739 matrix3.m[0][2] = static_cast<U>(m[0][2]);
2740 matrix3.m[1][0] = static_cast<U>(m[1][0]);
2741 matrix3.m[1][1] = static_cast<U>(m[1][1]);
2742 matrix3.m[1][2] = static_cast<U>(m[1][2]);
2743 matrix3.m[2][0] = static_cast<U>(m[2][0]);
2744 matrix3.m[2][1] = static_cast<U>(m[2][1]);
2745 matrix3.m[2][2] = static_cast<U>(m[2][2]);
2746 }
2747
2748 template<typename T>
2749 void mat4<T>::Multiply( const mat4<T>& matrixA, const mat4<T>& matrixB, mat4<T>& ret ) noexcept
2750 {
2751 for ( U8 i = 0u; i < 4u; ++i )
2752 {
2753 const vec4<T>& rowA = matrixB.getRow( i );
2754 ret.setRow( i, matrixA.getRow( 0 ) * rowA[0] +
2755 matrixA.getRow( 1 ) * rowA[1] +
2756 matrixA.getRow( 2 ) * rowA[2] +
2757 matrixA.getRow( 3 ) * rowA[3] );
2758 }
2759 }
2760
2761 template<typename T>
2762 mat4<T> mat4<T>::Multiply( const mat4<T>& matrixA, const mat4<T>& matrixB ) noexcept
2763 {
2764 mat4<T> ret;
2765 Multiply( matrixA, matrixB, ret );
2766 return ret;
2767 }
2768
2769 template<>
2770 FORCE_INLINE void mat4<F32>::Multiply( const mat4<F32>& matrixA, const mat4<F32>& matrixB, mat4<F32>& ret ) noexcept
2771 {
2772#if defined(HAS_AVX2)
2773 // using AVX instructions, 4-wide
2774 // this can be better if A is in memory.
2775 _mm256_zeroupper();
2776 ret._reg[0]._reg = AVX::lincomb_AVX_4mem( matrixB.m[0], matrixA );
2777 ret._reg[1]._reg = AVX::lincomb_AVX_4mem( matrixB.m[1], matrixA );
2778 ret._reg[2]._reg = AVX::lincomb_AVX_4mem( matrixB.m[2], matrixA );
2779 ret._reg[3]._reg = AVX::lincomb_AVX_4mem( matrixB.m[3], matrixA );
2780#else //HAS_AVX2
2781 ret._reg[0]._reg = AVX::lincomb_SSE( matrixB._reg[0]._reg, matrixA);
2782 ret._reg[1]._reg = AVX::lincomb_SSE( matrixB._reg[1]._reg, matrixA );
2783 ret._reg[2]._reg = AVX::lincomb_SSE( matrixB._reg[2]._reg, matrixA );
2784 ret._reg[3]._reg = AVX::lincomb_SSE( matrixB._reg[3]._reg, matrixA );
2785#endif //HAS_AVX2
2786 }
2787
2788 // Copyright 2011 The Closure Library Authors. All Rights Reserved.
2789 template<typename T>
2790 void mat4<T>::Inverse( const T* in, T* out ) noexcept
2791 {
2792 const T m00 = in[0], m10 = in[1], m20 = in[2], m30 = in[3];
2793 const T m01 = in[4], m11 = in[5], m21 = in[6], m31 = in[7];
2794 const T m02 = in[8], m12 = in[9], m22 = in[10], m32 = in[11];
2795 const T m03 = in[12], m13 = in[13], m23 = in[14], m33 = in[15];
2796
2797 const T a0 = m00 * m11 - m10 * m01;
2798 const T a1 = m00 * m21 - m20 * m01;
2799 const T a2 = m00 * m31 - m30 * m01;
2800 const T a3 = m10 * m21 - m20 * m11;
2801 const T a4 = m10 * m31 - m30 * m11;
2802 const T a5 = m20 * m31 - m30 * m21;
2803 const T b0 = m02 * m13 - m12 * m03;
2804 const T b1 = m02 * m23 - m22 * m03;
2805 const T b2 = m02 * m33 - m32 * m03;
2806 const T b3 = m12 * m23 - m22 * m13;
2807 const T b4 = m12 * m33 - m32 * m13;
2808 const T b5 = m22 * m33 - m32 * m23;
2809
2810 // should be accurate enough
2811 F32 idet = to_F32( a0 ) * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0;
2812
2813 if ( !IS_ZERO( idet ) ) [[likely]]
2814 {
2815 idet = 1.f / idet;
2816
2817 out[0] = static_cast<T>(( m11 * b5 - m21 * b4 + m31 * b3) * idet);
2818 out[1] = static_cast<T>((-m10 * b5 + m20 * b4 - m30 * b3) * idet);
2819 out[2] = static_cast<T>(( m13 * a5 - m23 * a4 + m33 * a3) * idet);
2820 out[3] = static_cast<T>((-m12 * a5 + m22 * a4 - m32 * a3) * idet);
2821 out[4] = static_cast<T>((-m01 * b5 + m21 * b2 - m31 * b1) * idet);
2822 out[5] = static_cast<T>(( m00 * b5 - m20 * b2 + m30 * b1) * idet);
2823 out[6] = static_cast<T>((-m03 * a5 + m23 * a2 - m33 * a1) * idet);
2824 out[7] = static_cast<T>(( m02 * a5 - m22 * a2 + m32 * a1) * idet);
2825 out[8] = static_cast<T>(( m01 * b4 - m11 * b2 + m31 * b0) * idet);
2826 out[9] = static_cast<T>((-m00 * b4 + m10 * b2 - m30 * b0) * idet);
2827 out[10] = static_cast<T>(( m03 * a4 - m13 * a2 + m33 * a0) * idet);
2828 out[11] = static_cast<T>((-m02 * a4 + m12 * a2 - m32 * a0) * idet);
2829 out[12] = static_cast<T>((-m01 * b3 + m11 * b1 - m21 * b0) * idet);
2830 out[13] = static_cast<T>(( m00 * b3 - m10 * b1 + m20 * b0) * idet);
2831 out[14] = static_cast<T>((-m03 * a3 + m13 * a1 - m23 * a0) * idet);
2832 out[15] = static_cast<T>(( m02 * a3 - m12 * a1 + m22 * a0) * idet);
2833 }
2834 else
2835 {
2836 memcpy( out, in, sizeof( T ) * 16 );
2837 }
2838 }
2839
2840} //namespace Divide
2841#endif //DVD_MATH_MATRICES_INL_
#define VecShuffle_0101(vec1, vec2)
#define VecSwizzle1(vec, x)
#define VecSwizzle(vec, x, y, z, w)
#define VecShuffle_2323(vec1, vec2)
#define VecShuffle(vec1, vec2, x, y, z, w)
#define FORCE_INLINE
T & operator[](I32 i)
void set(U m0, U m1, U m2, U m3) noexcept
void setCol(I32 index, vec2< U > value) noexcept
bool isIdentity() const noexcept
vec2< T > getRow(I32 index) const noexcept
mat2() noexcept
bool operator!=(const mat2 &B) const noexcept
void identity() noexcept
vec2< T > getCol(I32 index) const noexcept
mat2 & operator+=(const mat2< U > &B) noexcept
mat2 operator+(const mat2< U > &B) const noexcept
void inverse() noexcept
mat2 & operator/=(const mat2< U > &B) noexcept
mat2 getTranspose() const noexcept
T det() const noexcept
void swap(mat2 &B) noexcept
mat2 getInverseTranspose() const noexcept
void transpose() noexcept
mat2 getInverse() const noexcept
mat2 & operator-=(const mat2< U > &B) noexcept
void inverseTranspose() noexcept
T elementSum() const noexcept
bool compare(const mat2 &B, F32 epsilon) const noexcept
bool operator==(const mat2 &B) const noexcept
void zero() noexcept
T & element(U8 row, U8 column) noexcept
void setRow(I32 index, U value) noexcept
vec2< T > operator*(const vec2< U > v) const noexcept
mat2 & operator*=(const mat2< U > &B) noexcept
mat2 operator/(const mat2< U > &B) const noexcept
mat2 operator-(const mat2< U > &B) const noexcept
void fromZRotation(Angle::RADIANS< U > angle)
mat3 & operator*=(const mat3< U > &B) noexcept
T elementSum() const noexcept
T det() const noexcept
vec3< T > getForwardDirection() const noexcept
Returns normalized(getForwardVec())
bool operator==(const mat3 &B) const noexcept
mat3 getTranspose() const noexcept
const vec3< T > & getRow(I32 index) const noexcept
void setCol(I32 index, const vec3< U > &value) noexcept
mat3 & operator/=(const mat3< U > &B) noexcept
T & operator[](I32 i) noexcept
vec3< T > getScaleSq() const noexcept
vec3< T > getScale() const noexcept
mat3 operator/(const mat3< U > &B) const noexcept
void setRow(I32 index, U value) noexcept
vec3< T > getRightVec() const noexcept
Alias for getCol(0)
mat3 getInverseTranspose() const noexcept
mat3 & operator-=(const mat3< U > &B) noexcept
bool isColOrthogonal() const noexcept
vec3< T > getCol(I32 index) const noexcept
void fromXRotation(Angle::RADIANS< U > angle)
void inverse() noexcept
T & element(U8 row, U8 column) noexcept
bool operator!=(const mat3 &B) const noexcept
bool isUniformScale(F32 tolerance=0.0001f) const noexcept
void identity() noexcept
void setScale(U x, U y, U z) noexcept
void set(U m0, U m1, U m2, U m3, U m4, U m5, U m6, U m7, U m8) noexcept
bool compare(const mat3 &B, F32 epsilon) const noexcept
vec2< U > operator*(const vec2< U > v) const noexcept
void inverseTranspose() noexcept
mat3 operator+(const mat3< U > &B) const noexcept
mat3 & operator+=(const mat3< U > &B) noexcept
vec3< T > getRightDirection() const noexcept
Returns normalized(getRightVec())
bool isIdentity() const noexcept
void orthoNormalize()
void zero() noexcept
void transpose() noexcept
mat3 getInverse() const noexcept
vec3< T > getForwardVec() const noexcept
Alias for -getCol(2). Assumes -Z fwd.
mat3 operator-(const mat3< U > &B) const noexcept
vec3< T > getUpDirection() const noexcept
Returns normalized(getUpVec())
void fromRotation(const vec3< U > &v, Angle::RADIANS< U > angle)
vec3< T > getUpVec() const noexcept
Alias for getCol(1)
void swap(mat3 &B) noexcept
mat3() noexcept
void fromYRotation(Angle::RADIANS< U > angle)
vec3< T > getForwardDirection() const noexcept
Returns normalized(getForwardVec())
vec3< T > getScaleSq() const noexcept
vec3< T > getForwardVec() const noexcept
Alias for -getCol(2). Assumes -Z fwd.
T & element(U8 row, U8 column) noexcept
void swap(mat4 &B) noexcept
void setCol(I32 index, const vec4< U > &value) noexcept
mat4 getTransposeRotation() const noexcept
void inverseTranspose() noexcept
bool isUniformScale(F32 tolerance=0.0001f) const noexcept
void zero() noexcept
vec3< T > getTranslation() const noexcept
vec4< T > _vec[4]
Definition: MathMatrices.h:709
void inverse() noexcept
const mat4 & reflect(U x, U y, U z, U w) noexcept
vec3< T > getUpDirection() const noexcept
Returns normalized(getUpVec())
mat4 transposeRotation() const noexcept
void setRow(I32 index, U value) noexcept
T elementSum() const noexcept
vec2< U > operator*(const vec2< U > v) const noexcept
mat4 & operator*=(const mat4< U > &matrix) noexcept
mat4 getInverse() const noexcept
SimdVector< T > _reg[4]
Definition: MathMatrices.h:710
void fromXRotation(Angle::RADIANS< U > angle) noexcept
T & operator[](I32 i) noexcept
void identity() noexcept
void transpose() noexcept
bool isIdentity() const noexcept
vec3< T > getRightVec() const noexcept
Alias for getCol(0)
static mat4< T > Multiply(const mat4< T > &matrixA, const mat4< T > &matrixB) noexcept
ret = A * B
void extractMat3(mat3< U > &matrix3) const noexcept
bool operator==(const mat4 &B) const noexcept
mat4 getRotation() const
void fromZRotation(Angle::RADIANS< U > angle) noexcept
vec3< U > transformHomogeneous(const vec3< U > &v) const
vec3< T > getRightDirection() const noexcept
Returns normalized(getRightVec())
T det() const noexcept
void setScale(U x, U y, U z) noexcept
void fromRotation(U x, U y, U z, Angle::RADIANS< U > angle) noexcept
void fromYRotation(Angle::RADIANS< U > angle) noexcept
static void Inverse(const T *in, T *out) noexcept
const vec4< T > & getRow(I32 index) const noexcept
void setTranslation(const vec3< U > &v) noexcept
vec3< T > getUpVec() const noexcept
Alias for getCol(1)
vec3< U > transformNonHomogeneous(const vec3< U > &v) const noexcept
mat4 & operator/=(const mat4< U > &matrix) noexcept
mat4 operator/(const mat4< U > &matrix) const noexcept
void orthoNormalize() noexcept
void set(std::initializer_list< T > matrix) noexcept
mat4 operator-(const mat4< U > &matrix) const noexcept
mat4 & operator+=(const mat4< U > &matrix) noexcept
mat4 & operator-=(const mat4< U > &matrix) noexcept
void translate(const vec3< U > &v) noexcept
mat4 getInverseTranspose() const noexcept
vec3< T > getScale() const noexcept
vec3< U > transform(const vec3< U > &v, bool homogeneous) const
vec4< T > getCol(I32 index) const noexcept
bool compare(const mat4 &B, F32 epsilon) const noexcept
mat4 getTranspose() const noexcept
mat4 operator+(const mat4< U > &matrix) const noexcept
void scale(const vec3< U > &v) noexcept
bool operator!=(const mat4 &B) const noexcept
bool isColOrthogonal() const noexcept
mat4() noexcept
vec3 & normalize() noexcept
transform the vector to unit length
void cross(const vec3 &v1, const vec3 &v2) noexcept
set this vector to be equal to the cross of the 2 specified vectors
static FORCE_INLINE __m128 lincomb_SSE(const __m128 &a, const mat4< F32 > &B)
FORCE_INLINE void GetTransformInverseNoScale(const mat4< F32 > &inM, mat4< F32 > &r) noexcept
FORCE_INLINE void GetTransformInverse(const mat4< F32 > &inM, mat4< F32 > &r) noexcept
FORCE_INLINE __m128 Mat2Mul(const __m128 vec1, const __m128 vec2) noexcept
FORCE_INLINE __m128 Mat2MulAdj(const __m128 vec1, const __m128 vec2) noexcept
FORCE_INLINE __m128 Mat2AdjMul(const __m128 vec1, const __m128 vec2) noexcept
FORCE_INLINE void M4x4_SSE(const F32 *A, const F32 *B, F32 *C) noexcept
FORCE_INLINE void GetInverse(const mat4< F32 > &inM, mat4< F32 > &r) noexcept
Handle console commands that start with a forward slash.
Definition: AIProcessor.cpp:7
vec2< T > Normalized(vec2< T > vector) noexcept
Definition: MathVectors.inl:98
bool IS_ZERO(const T X) noexcept
T Sqrt(T input) noexcept
Definition: MathHelper.inl:252
int32_t I32
uint8_t U8
vec2< T > Inverse(vec2< T > v) noexcept
Definition: MathVectors.inl:86
constexpr F32 to_F32(const T value)
void GetInverse(const mat4< T > &inM, mat4< T > &r) noexcept
constexpr F32 EPSILON_F32
vec3< T > AreOrthogonal(const vec3< T > &v1, const vec3< T > &v2) noexcept
bool COMPARE_TOLERANCE(const T X, const U Y, const T TOLERANCE) noexcept
double D64
bool COMPARE(T X, U Y) noexcept
static const mat4< F32 > MAT4_IDENTITY
Definition: MathMatrices.h:740