79 using FLOATING = FLOATING_TYPE;
80 static constexpr ::i32 DIMENSION = t_iDimension;
82 FLOATING m_rowa[t_iDimension];
84 constexpr const FLOATING &operator[](::i32 i)
const
90 FLOATING& operator[](::i32 i)
97 static constexpr bool IsNanoGUI =
true;
98 static constexpr bool IsMatrix =
true;
101 using FLOATING = FLOATING_TYPE;
102 static constexpr ::i32 DIMENSION = t_iDimension;
103 static constexpr ::i32 SQUARED_DIMENSION = DIMENSION * DIMENSION;
109 column columna[DIMENSION];
110 FLOATING m[DIMENSION][DIMENSION];
111 FLOATING fa[SQUARED_DIMENSION];
119 constexpr matrix_type(
const matrix_type<FLOATING, 4> &m)
120 requires(DIMENSION==3)
123 this->m[0][0] = m[0][0];
124 this->m[0][1] = m[0][1];
125 this->m[0][2] = m[0][2];
128 this->m[1][0] = m[1][0];
129 this->m[1][1] = m[1][1];
130 this->m[1][2] = m[1][2];
133 this->m[2][0] = m[2][0];
134 this->m[2][1] = m[2][1];
135 this->m[2][2] = m[2][2];
139 constexpr matrix_type(
const matrix_type<FLOATING, 4> &m)
140 requires(DIMENSION == 4)
143 for (::i32 i = 0; i < SQUARED_DIMENSION; i++) this->fa[i] = m.fa[i];
150 template<prototype_
floating FLOATING1>
152 requires(DIMENSION == 4)
155 auto c = SQUARED_DIMENSION;
157 for (::i32 i = 0; i < c; ++i) this->fa[i] = (FLOATING)p[i];
163 requires(DIMENSION == 4)
171 for (::i32 c = 0; c < 3; ++c)
172 for (::i32 r = 0; r < 3; ++r)
173 this->m[c][r] = m.m[c][r];
177 template < prototype_number NUMBER >
178 constexpr matrix_type(NUMBER diagonal)
181 for (::i32 i = 0; i < DIMENSION; i++)
182 for (::i32 j = 0; j < DIMENSION; j++)
183 m[i][j] = i == j ? (FLOATING) diagonal : (FLOATING) 0;
188 matrix_type(
const quaternion_type<FLOATING> & q)
189 requires(DIMENSION == 4)
236 inline sequence_type<FLOATING, 4> mul_scalar(
const sequence_type<FLOATING, 4> &s)
const
237 requires(DIMENSION == 4)
239 const auto &M = *
this;
240 sequence_type<FLOATING, 4> r;
241 r.x = M.fa[0] * s.x + M.fa[4] * s.y + M.fa[8] * s.z + M.fa[12] * s.w;
242 r.y = M.fa[1] * s.x + M.fa[5] * s.y + M.fa[9] * s.z + M.fa[13] * s.w;
243 r.z = M.fa[2] * s.x + M.fa[6] * s.y + M.fa[10] * s.z + M.fa[14] * s.w;
244 r.w = M.fa[3] * s.x + M.fa[7] * s.y + M.fa[11] * s.z + M.fa[15] * s.w;
250 inline f32_sequence4 mul_sse(
const f32_sequence4 &s)
const
251 requires(DIMENSION == 4 && std::is_same_v<FLOATING, ::f32>)
253 const auto &M = *
this;
254 __m128 vx = _mm_set_ps(s.w, s.z, s.y, s.x);
255 __m128 col0 = _mm_loadu_ps(&M.fa[0]);
256 __m128 col1 = _mm_loadu_ps(&M.fa[4]);
257 __m128 col2 = _mm_loadu_ps(&M.fa[8]);
258 __m128 col3 = _mm_loadu_ps(&M.fa[12]);
260 __m128 res = _mm_add_ps(
261 _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(vx, vx, 0x00), col0), _mm_mul_ps(_mm_shuffle_ps(vx, vx, 0x55), col1)),
262 _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(vx, vx, 0xAA), col2), _mm_mul_ps(_mm_shuffle_ps(vx, vx, 0xFF), col3)));
265 _mm_storeu_ps(&out.x, res);
273 inline f32_sequence4 mul_avx(
const f32_sequence4 &s)
const
274 requires(DIMENSION == 4 && std::is_same_v<FLOATING, ::f32>)
276 const auto &M = *
this;
277 __m256 vx = _mm256_setr_m128(_mm_set1_ps(s.x), _mm_set1_ps(s.y));
278 __m256 vy = _mm256_setr_m128(_mm_set1_ps(s.z), _mm_set1_ps(s.w));
280 __m256 col01 = _mm256_loadu_ps(&M.fa[0]);
281 __m256 col23 = _mm256_loadu_ps(&M.fa[8]);
283 __m256 mul01 = _mm256_mul_ps(col01, vx);
284 __m256 mul23 = _mm256_mul_ps(col23, vy);
286 __m128 sum = _mm_add_ps(_mm256_castps256_ps128(_mm256_add_ps(mul01, mul23)),
287 _mm256_extractf128_ps(_mm256_add_ps(mul01, mul23), 1));
290 _mm_storeu_ps(&out.x, sum);
298 inline f32_sequence4 mul_avx2(
const f32_sequence4 &s)
const
299 requires(DIMENSION == 4 && std::is_same_v<FLOATING, ::f32>)
301 const auto &M = *
this;
302 __m256 vx = _mm256_set1_ps(s.x);
303 __m256 vy = _mm256_set1_ps(s.y);
304 __m256 vz = _mm256_set1_ps(s.z);
305 __m256 vw = _mm256_set1_ps(s.w);
307 __m256 col01 = _mm256_loadu_ps(&M.fa[0]);
308 __m256 col23 = _mm256_loadu_ps(&M.fa[8]);
310 __m256 mul0 = _mm256_mul_ps(_mm256_permute_ps(col01, 0x00), vx);
311 __m256 mul1 = _mm256_mul_ps(_mm256_permute_ps(col01, 0xFF), vy);
312 __m256 mul2 = _mm256_mul_ps(_mm256_permute_ps(col23, 0x00), vz);
313 __m256 mul3 = _mm256_mul_ps(_mm256_permute_ps(col23, 0xFF), vw);
315 __m256 total = _mm256_add_ps(_mm256_add_ps(mul0, mul1), _mm256_add_ps(mul2, mul3));
316 __m128 sum = _mm_add_ps(_mm256_castps256_ps128(total), _mm256_extractf128_ps(total, 1));
319 _mm_storeu_ps(&out.x, sum);
360 template < prototype_number NUMBER >
361 inline matrix_type &operator*=(NUMBER n)
364 auto c = SQUARED_DIMENSION;
366 for (::i32 i = 0; i < c; ++i)
369 this->fa[i] = (FLOATING)(this->fa[i] * n);
378 template<prototype_number NUMBER>
379 inline matrix_type operator*(NUMBER n)
const
391 inline f32_sequence4 operator*(
const f32_sequence4 &s)
const
392 requires(DIMENSION == 4 && std::is_same_v<FLOATING, ::f32>)
401 return mul_scalar(s);
405 inline sequence_type<FLOATING, 3> operator*(
const sequence_type<FLOATING, 3> &v)
const
406 requires(DIMENSION == 3)
409 const auto &M = *
this;
410 sequence_type<FLOATING, 3> result;
413 result.x = M[0][0] * v.x + M[1][0] * v.y + M[2][0] * v.z;
414 result.y = M[0][1] * v.x + M[1][1] * v.y + M[2][1] * v.z;
415 result.z = M[0][2] * v.x + M[1][2] * v.y + M[2][2] * v.z;
419 inline matrix_type mul_scalar(
const matrix_type &B)
const
420 requires(DIMENSION == 4)
426 for (::i32 col = 0; col < 4; ++col)
428 for (::i32 row = 0; row < 4; ++row)
430 R.fa[col * 4 + row] =
431 A.fa[0 * 4 + row] * B.fa[col * 4 + 0] +
432 A.fa[1 * 4 + row] * B.fa[col * 4 + 1] +
433 A.fa[2 * 4 + row] * B.fa[col * 4 + 2] +
434 A.fa[3 * 4 + row] * B.fa[col * 4 + 3];
442 inline matrix_type mul_sse(
const matrix_type &B)
const
443 requires(DIMENSION == 4 && std::is_same_v<FLOATING, ::f32>)
449 for (::i32 col = 0; col < 4; ++col)
451 const ::f32 *bCol = &B.fa[col * 4];
454 __m128 a0 = _mm_loadu_ps(&A.fa[0]);
455 __m128 a1 = _mm_loadu_ps(&A.fa[4]);
456 __m128 a2 = _mm_loadu_ps(&A.fa[8]);
457 __m128 a3 = _mm_loadu_ps(&A.fa[12]);
460 __m128 b0 = _mm_set1_ps(bCol[0]);
461 __m128 b1 = _mm_set1_ps(bCol[1]);
462 __m128 b2 = _mm_set1_ps(bCol[2]);
463 __m128 b3 = _mm_set1_ps(bCol[3]);
466 __m128 res = _mm_add_ps(_mm_add_ps(_mm_mul_ps(a0, b0), _mm_mul_ps(a1, b1)),
467 _mm_add_ps(_mm_mul_ps(a2, b2), _mm_mul_ps(a3, b3)));
470 _mm_storeu_ps(&R.fa[col * 4], res);
479 inline matrix_type mul_avx(
const matrix_type &B)
const
480 requires(DIMENSION == 4 && std::is_same_v<FLOATING, ::f32>)
486 for (::i32 col = 0; col < 4; ++col)
488 const ::f32 *bCol = &B.fa[col * 4];
491 __m256 b01 = _mm256_set_ps(bCol[1], bCol[1], bCol[0], bCol[0], bCol[1], bCol[1], bCol[0], bCol[0]);
492 __m256 b23 = _mm256_set_ps(bCol[3], bCol[3], bCol[2], bCol[2], bCol[3], bCol[3], bCol[2], bCol[2]);
495 __m256 a01 = _mm256_loadu_ps(&A.fa[0]);
496 __m256 a23 = _mm256_loadu_ps(&A.fa[8]);
499 __m256 mul01 = _mm256_mul_ps(a01, b01);
500 __m256 mul23 = _mm256_mul_ps(a23, b23);
503 __m256 total = _mm256_add_ps(mul01, mul23);
506 __m128 result = _mm_add_ps(_mm256_castps256_ps128(total), _mm256_extractf128_ps(total, 1));
509 _mm_storeu_ps(&R.fa[col * 4], result);
519inline matrix_type mul_avx2(
const matrix_type &B)
const
520 requires(DIMENSION == 4 && std::is_same_v<FLOATING, ::f32>)
526 for (::i32 col = 0; col < 4; ++col)
529 const ::f32 *bCol = &B.fa[col * 4];
532 __m256 b0 = _mm256_set1_ps(bCol[0]);
533 __m256 b1 = _mm256_set1_ps(bCol[1]);
534 __m256 b2 = _mm256_set1_ps(bCol[2]);
535 __m256 b3 = _mm256_set1_ps(bCol[3]);
538 __m256 a01 = _mm256_loadu_ps(&A.fa[0]);
539 __m256 a23 = _mm256_loadu_ps(&A.fa[8]);
542 __m256 mul0 = _mm256_mul_ps(_mm256_permute_ps(a01, 0x00), b0);
543 __m256 mul1 = _mm256_mul_ps(_mm256_permute_ps(a01, 0xFF), b1);
544 __m256 mul2 = _mm256_mul_ps(_mm256_permute_ps(a23, 0x00), b2);
545 __m256 mul3 = _mm256_mul_ps(_mm256_permute_ps(a23, 0xFF), b3);
548 __m256 total = _mm256_add_ps(_mm256_add_ps(mul0, mul1), _mm256_add_ps(mul2, mul3));
551 __m128 res = _mm_add_ps(_mm256_castps256_ps128(total), _mm256_extractf128_ps(total, 1));
554 _mm_storeu_ps(&R.fa[col * 4], res);
562 inline matrix_type operator*(
const matrix_type &m)
const
563 requires(DIMENSION == 4 && std::is_same_v<FLOATING, ::f32>)
572 return mul_scalar(m);
580 static matrix_type translation(
const sequence_type<FLOATING, DIMENSION - 1> &t)
583 matrix_type m{(FLOATING)1};
585 auto c = DIMENSION - 1;
587 for (::i32 i = 0; i < c; ++i)
598 static matrix_type scaling(
const sequence_type<FLOATING, DIMENSION - 1>& s)
601 matrix_type result{1.0f};
603 auto c = DIMENSION - 1;
605 for (::i32 i = 0; i < c; ++i)
606 result.m[i][i] = s[i];
616 static matrix_type rotation(
const quaternion_type<FLOATING> &q)
647 const column & operator[](::i32 i)
const
653 column & operator[](::i32 i) {
return columna[i]; }
656 matrix_type & rotate(
const sequence_type<FLOATING, 3>& axis, FLOATING angle)
657 requires(DIMENSION == 4)
660 FLOATING s = ::sin(angle);
661 FLOATING c = ::cos(angle);
664 auto & result = *
this;
666 result.m[0][0] = c + axis.x * axis.x * t;
667 result.m[1][1] = c + axis.y * axis.y * t;
668 result.m[2][2] = c + axis.z * axis.z * t;
670 FLOATING tmp1 = axis.x * axis.y * t;
671 FLOATING tmp2 = axis.z * s;
673 result.m[0][1] = tmp1 + tmp2;
674 result.m[1][0] = tmp1 - tmp2;
676 tmp1 = axis.x * axis.z * t;
678 result.m[0][2] = tmp1 - tmp2;
679 result.m[2][0] = tmp1 + tmp2;
681 tmp1 = axis.y * axis.z * t;
683 result.m[1][2] = tmp1 + tmp2;
684 result.m[2][1] = tmp1 - tmp2;
690 static matrix_type rotation(
const sequence_type<FLOATING, 3> &axis, FLOATING angle)
691 requires(DIMENSION == 4)
696 m.rotate(axis, angle);
702 template <::i32 S = DIMENSION, std::enable_if_t<S == 4, ::i32> = 0>
703 static matrix_type perspective(FLOATING fov, FLOATING near_, FLOATING far_, FLOATING aspect = 1.f)
706 FLOATING recip = 1 / (near_ - far_);
707 FLOATING c = 1 / ::tan(.5f * fov);
709 matrix_type trafo = matrix_type::scaling(sequence_type<FLOATING, DIMENSION>(c / aspect, c, (near_ + far_) * recip, 0.f));
711 trafo.m[3][2] = 2.f * near_ * far_ * recip;
712 trafo.m[2][3] = -1.f;
717 template <::i32 S = DIMENSION, std::enable_if_t<S == 4, ::i32> = 0>
718 static matrix_type ortho(FLOATING left, FLOATING right,
719 FLOATING bottom, FLOATING top,
720 FLOATING near_, FLOATING far_)
723 FLOATING rl = 1 / (right - left);
724 FLOATING tb = 1 / (top - bottom);
725 FLOATING fn = 1 / (far_ - near_);
727 matrix_type result(0);
729 result.m[0][0] = 2 * rl;
730 result.m[1][1] = 2 * tb;
731 result.m[2][2] = -2 * fn;
733 result.m[3][0] = -(right + left) * rl;
734 result.m[3][1] = -(top + bottom) * tb;
735 result.m[3][2] = -(far_ + near_) * fn;
741 static matrix_type look_at(
const sequence_type<FLOATING, 3>& origin,
742 const sequence_type<FLOATING, 3>& target,
743 const sequence_type<FLOATING, 3>& up)
744 requires(DIMENSION == 4)
747 auto dir = normalize(target - origin);
748 auto left = normalize(cross(dir, up));
749 auto new_up = cross(left, dir);
752 matrix_type result(0);
753 result.m[0][0] = left.x;
754 result.m[0][1] = left.y;
755 result.m[0][2] = left.c();
756 result.m[1][0] = new_up.x;
757 result.m[1][1] = new_up.y;
758 result.m[1][2] = new_up.c();
759 result.m[2][0] = dir.x;
760 result.m[2][1] = dir.y;
761 result.m[2][2] = dir.c();
762 result.m[3][0] = -dot(left, origin);
763 result.m[3][1] = -dot(new_up, origin);
764 result.m[3][2] = -dot(dir, origin);
765 result.m[3][3] = 1.f;
783 inline sequence_type<FLOATING, 3> operator*(
const sequence_type<FLOATING, 3> &s)
const
784 requires(DIMENSION == 4)
786 auto t = this->operator *( sequence_type<FLOATING, 4>(s, (FLOATING) 1));
791 matrix_type rotated(angle_type<FLOATING> angleRadians,
792 const sequence_type<FLOATING, 3> &axis)
const
793 requires(DIMENSION == 4)
796 const auto &m = *
this;
797 auto a = axis.normalized();
798 auto c = angleRadians.cos();
799 auto s = angleRadians.sin();
803 matrix_type rot(1.0f);
804 rot[0][0] = c + a.x * a.x * t;
805 rot[1][0] = a.x * a.y * t + a.z * s;
806 rot[2][0] = a.x * a.z * t - a.y * s;
808 rot[0][1] = a.y * a.x * t - a.z * s;
809 rot[1][1] = c + a.y * a.y * t;
810 rot[2][1] = a.y * a.z * t + a.x * s;
812 rot[0][2] = a.z * a.x * t + a.y * s;
813 rot[1][2] = a.z * a.y * t - a.x * s;
814 rot[2][2] = c + a.z * a.z * t;
822 matrix_type & rotate(angle_type<FLOATING> angleRadians,
const sequence_type<FLOATING, 3> & axis)
825 return *
this = this->rotated(angleRadians, axis);
850 matrix_type & transpose()
854 ::geometry::_transpose(this->m, source.m);
866 matrix_type & translate(
const sequence_type<FLOATING, 3> &s)
867 requires(DIMENSION == 4)
870 this->m[3][0] += s.x;
871 this->m[3][1] += s.y;
872 this->m[3][2] += s.z;
877 matrix_type translated(
const sequence_type<FLOATING, 3> &s)
const
878 requires(DIMENSION == 4)
883 return m.translate(s);
887 matrix_type & scale(
const sequence_type<FLOATING, 3> &s)
888 requires(DIMENSION == 4)
890 this->m[0][0] *= s.x;
891 this->m[1][0] *= s.x;
892 this->m[2][0] *= s.x;
893 this->m[3][0] *= s.x;
895 this->m[0][1] *= s.y;
896 this->m[1][1] *= s.y;
897 this->m[2][1] *= s.y;
898 this->m[3][1] *= s.y;
900 this->m[0][2] *= s.z;
901 this->m[1][2] *= s.z;
902 this->m[2][2] *= s.z;
903 this->m[3][2] *= s.z;
909 matrix_type scaled(
const sequence_type<FLOATING, 3> &s)
const
910 requires(DIMENSION == 4)
919 FLOATING determinant() const
920 requires(DIMENSION == 3)
924 if constexpr (t_emajor == e_matrix_major_column)
927 return m[0] * (m[4] * m[8] - m[5] * m[7]) -
928 m[3] * (m[1] * m[8] - m[2] * m[7]) +
929 m[6] * (m[1] * m[5] - m[2] * m[4]);
934 return m[0] * (m[4] * m[8] - m[5] * m[7]) -
935 m[1] * (m[3] * m[8] - m[5] * m[6]) +
936 m[2] * (m[3] * m[7] - m[4] * m[6]);
943 FLOATING determinant() const
944 requires(DIMENSION == 4)
949 if constexpr (t_emajor == e_matrix_major_column)
952 return m[0] * (m[5] * (m[10] * m[15] - m[11] * m[14]) - m[9] * (m[6] * m[15] - m[7] * m[14]) +
953 m[13] * (m[6] * m[11] - m[7] * m[10])) -
954 m[4] * (m[1] * (m[10] * m[15] - m[11] * m[14]) - m[9] * (m[2] * m[15] - m[3] * m[14]) +
955 m[13] * (m[2] * m[11] - m[3] * m[10])) +
956 m[8] * (m[1] * (m[6] * m[15] - m[7] * m[14]) - m[5] * (m[2] * m[15] - m[3] * m[14]) +
957 m[13] * (m[2] * m[7] - m[3] * m[6])) -
958 m[12] * (m[1] * (m[6] * m[11] - m[7] * m[10]) - m[5] * (m[2] * m[11] - m[3] * m[10]) +
959 m[9] * (m[2] * m[7] - m[3] * m[6]));
964 return m[0] * (m[5] * (m[10] * m[15] - m[11] * m[14]) - m[6] * (m[9] * m[15] - m[11] * m[13]) +
965 m[7] * (m[9] * m[14] - m[10] * m[13])) -
966 m[1] * (m[4] * (m[10] * m[15] - m[11] * m[14]) - m[6] * (m[8] * m[15] - m[11] * m[12]) +
967 m[7] * (m[8] * m[14] - m[10] * m[12])) +
968 m[2] * (m[4] * (m[9] * m[15] - m[11] * m[13]) - m[5] * (m[8] * m[15] - m[11] * m[12]) +
969 m[7] * (m[8] * m[13] - m[9] * m[12])) -
970 m[3] * (m[4] * (m[9] * m[14] - m[10] * m[13]) - m[5] * (m[8] * m[14] - m[10] * m[12]) +
971 m[6] * (m[8] * m[13] - m[9] * m[12]));
977 inline matrix_type & inverse_scalar()
978 requires(DIMENSION == 3)
981 const auto & A = *
this;
998 auto c00 = (A.fa[4] * A.fa[8] - A.fa[7] * A.fa[5]);
999 auto c01 = -(A.fa[1] * A.fa[8] - A.fa[7] * A.fa[2]);
1000 auto c02 = (A.fa[1] * A.fa[5] - A.fa[4] * A.fa[2]);
1002 auto c10 = -(A.fa[3] * A.fa[8] - A.fa[6] * A.fa[5]);
1003 auto c11 = (A.fa[0] * A.fa[8] - A.fa[6] * A.fa[2]);
1004 auto c12 = -(A.fa[0] * A.fa[5] - A.fa[3] * A.fa[2]);
1006 auto c20 = (A.fa[3] * A.fa[7] - A.fa[6] * A.fa[4]);
1007 auto c21 = -(A.fa[0] * A.fa[7] - A.fa[6] * A.fa[1]);
1008 auto c22 = (A.fa[0] * A.fa[4] - A.fa[3] * A.fa[1]);
1011 auto det = A.fa[0] * c00 + A.fa[3] * c01 + A.fa[6] * c02;
1015 if (fabs(det) < 1e-12f)
1031 auto invDet = (FLOATING) 1 / det;
1036 out.fa[0] = c00 * invDet;
1037 out.fa[1] = c10 * invDet;
1038 out.fa[2] = c20 * invDet;
1040 out.fa[3] = c01 * invDet;
1041 out.fa[4] = c11 * invDet;
1042 out.fa[5] = c21 * invDet;
1044 out.fa[6] = c02 * invDet;
1045 out.fa[7] = c12 * invDet;
1046 out.fa[8] = c22 * invDet;
1054 inline matrix_type inversed_sse() const
1055 requires(DIMENSION == 3 && std::is_same_v<FLOATING, ::f32>)
1058 const auto &A = *
this;
1060 __m128 c0 = _mm_set_ps(0.0f, A.fa[2], A.fa[1], A.fa[0]);
1061 __m128 c1 = _mm_set_ps(0.0f, A.fa[5], A.fa[4], A.fa[3]);
1062 __m128 c2 = _mm_set_ps(0.0f, A.fa[8], A.fa[7], A.fa[6]);
1065 __m128 r0 = _mm_unpacklo_ps(c0, c1);
1071 __m128 t0 = _mm_mul_ps(_mm_shuffle_ps(r0, r0, _MM_SHUFFLE(3, 3, 1, 1)),
1072 _mm_shuffle_ps(r2, r2, _MM_SHUFFLE(3, 3, 3, 0)));
1074 __m128 t1 = _mm_mul_ps(_mm_shuffle_ps(r0, r0, _MM_SHUFFLE(3, 3, 1, 1)),
1075 _mm_shuffle_ps(r2, r2, _MM_SHUFFLE(3, 3, 0, 0)));
1077 __m128 cof0 = _mm_sub_ps(t0, t1);
1080 ::f32 c00 = _mm_cvtss_f32(cof0);
1085 ::f32 a00 = A.fa[0], a01 = A.fa[3], a02 = A.fa[6];
1086 ::f32 a10 = A.fa[1], a11 = A.fa[4], a12 = A.fa[7];
1087 ::f32 a20 = A.fa[2], a21 = A.fa[5], a22 = A.fa[8];
1089 ::f32 c01 = -(a10 * a22 - a12 * a20);
1090 ::f32 c02 = (a10 * a21 - a11 * a20);
1091 ::f32 c10 = -(a01 * a22 - a02 * a21);
1092 ::f32 c11 = (a00 * a22 - a02 * a20);
1093 ::f32 c12 = -(a00 * a21 - a01 * a20);
1094 ::f32 c20 = (a01 * a12 - a02 * a11);
1095 ::f32 c21 = -(a00 * a12 - a02 * a10);
1096 ::f32 c22 = (a00 * a11 - a01 * a10);
1098 ::f32 det = a00 * c00 + a01 * c01 + a02 * c02;
1102 if (fabs(det) < 1e-12f)
1109 ::f32 invDet = 1.0f / det;
1112 out.fa[0] = c00 * invDet;
1113 out.fa[1] = c10 * invDet;
1114 out.fa[2] = c20 * invDet;
1116 out.fa[3] = c01 * invDet;
1117 out.fa[4] = c11 * invDet;
1118 out.fa[5] = c21 * invDet;
1120 out.fa[6] = c02 * invDet;
1121 out.fa[7] = c12 * invDet;
1122 out.fa[8] = c22 * invDet;
1131 inline matrix_type inversed_avx() const
1132 requires(DIMENSION == 3 && std::is_same_v<FLOATING, ::f32>)
1135 const ::f32 *in = this->fa;
1137 ::f32 *out = result.fa;
1139 ::f32 m00 = in[0], m01 = in[3], m02 = in[6];
1140 ::f32 m10 = in[1], m11 = in[4], m12 = in[7];
1141 ::f32 m20 = in[2], m21 = in[5], m22 = in[8];
1146 ::f32 cf00 = m11 * m22 - m12 * m21;
1147 ::f32 cf01 = -(m10 * m22 - m12 * m20);
1148 ::f32 cf02 = m10 * m21 - m11 * m20;
1150 ::f32 cf10 = -(m01 * m22 - m02 * m21);
1151 ::f32 cf11 = m00 * m22 - m02 * m20;
1152 ::f32 cf12 = -(m00 * m21 - m01 * m20);
1154 ::f32 cf20 = m01 * m12 - m02 * m11;
1155 ::f32 cf21 = -(m00 * m12 - m02 * m10);
1156 ::f32 cf22 = m00 * m11 - m01 * m10;
1159 ::f32 det = m00 * cf00 + m01 * cf01 + m02 * cf02;
1160 ::f32 invdet = 1.0f / det;
1166 alignas(32) ::f32 adj[9] = {
1175 __m256 scale = _mm256_set1_ps(invdet);
1176 __m256 adj_lo = _mm256_loadu_ps(&adj[0]);
1177 __m256 out_lo = _mm256_mul_ps(adj_lo, scale);
1182 __m128 last = _mm_mul_ss(_mm_set_ss(adj[8]), _mm256_castps256_ps128(scale));
1187 _mm256_storeu_ps(&out[0], out_lo);
1188 _mm_store_ss(&out[8], last);
1198 inline matrix_type & inverse_scalar()
1199 requires(DIMENSION == 4)
1202 auto source = *
this;
1206 auto inv = this->fa;
1208 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] +
1209 m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
1210 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] -
1211 m[12] * m[6] * m[11] + m[12] * m[7] * m[10];
1212 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] +
1213 m[12] * m[5] * m[11] - m[12] * m[7] * m[9];
1214 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] -
1215 m[12] * m[5] * m[10] + m[12] * m[6] * m[9];
1217 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] -
1218 m[13] * m[2] * m[11] + m[13] * m[3] * m[10];
1219 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] +
1220 m[12] * m[2] * m[11] - m[12] * m[3] * m[10];
1221 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] -
1222 m[12] * m[1] * m[11] + m[12] * m[3] * m[9];
1223 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] +
1224 m[12] * m[1] * m[10] - m[12] * m[2] * m[9];
1226 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] +
1227 m[13] * m[2] * m[7] - m[13] * m[3] * m[6];
1228 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] -
1229 m[12] * m[2] * m[7] + m[12] * m[3] * m[6];
1230 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] +
1231 m[12] * m[1] * m[7] - m[12] * m[3] * m[5];
1232 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] -
1233 m[12] * m[1] * m[6] + m[12] * m[2] * m[5];
1235 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] -
1236 m[9] * m[2] * m[7] + m[9] * m[3] * m[6];
1237 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] +
1238 m[8] * m[2] * m[7] - m[8] * m[3] * m[6];
1239 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] -
1240 m[8] * m[1] * m[7] + m[8] * m[3] * m[5];
1241 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] +
1242 m[8] * m[1] * m[6] - m[8] * m[2] * m[5];
1244 ::f32 det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
1246 ::f32 invDet = 1.0f / det;
1248 for (::i32 i = 0; i < 16; i++)
1257 inline matrix_type inversed_sse() const
1258 requires(DIMENSION == 4 && std::is_same_v<FLOATING, ::f32>)
1261 const auto &a = *
this;
1263 __m128 col0 = _mm_loadu_ps(&a.fa[0]);
1264 __m128 col1 = _mm_loadu_ps(&a.fa[4]);
1265 __m128 col2 = _mm_loadu_ps(&a.fa[8]);
1266 __m128 col3 = _mm_loadu_ps(&a.fa[12]);
1270 _mm_storeu_ps(&m[0], col0);
1271 _mm_storeu_ps(&m[4], col1);
1272 _mm_storeu_ps(&m[8], col2);
1273 _mm_storeu_ps(&m[12], col3);
1278 inv.fa[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] +
1279 m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
1280 inv.fa[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] -
1281 m[13] * m[2] * m[11] + m[13] * m[3] * m[10];
1282 inv.fa[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] +
1283 m[13] * m[2] * m[7] - m[13] * m[3] * m[6];
1284 inv.fa[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] -
1285 m[9] * m[2] * m[7] + m[9] * m[3] * m[6];
1287 inv.fa[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] -
1288 m[12] * m[6] * m[11] + m[12] * m[7] * m[10];
1289 inv.fa[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] +
1290 m[12] * m[2] * m[11] - m[12] * m[3] * m[10];
1291 inv.fa[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] -
1292 m[12] * m[2] * m[7] + m[12] * m[3] * m[6];
1293 inv.fa[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] +
1294 m[8] * m[2] * m[7] - m[8] * m[3] * m[6];
1296 inv.fa[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] +
1297 m[12] * m[5] * m[11] - m[12] * m[7] * m[9];
1298 inv.fa[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] -
1299 m[12] * m[1] * m[11] + m[12] * m[3] * m[9];
1300 inv.fa[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] +
1301 m[12] * m[1] * m[7] - m[12] * m[3] * m[5];
1302 inv.fa[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] -
1303 m[8] * m[1] * m[7] + m[8] * m[3] * m[5];
1305 inv.fa[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] -
1306 m[12] * m[5] * m[10] + m[12] * m[6] * m[9];
1307 inv.fa[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] +
1308 m[12] * m[1] * m[10] - m[12] * m[2] * m[9];
1309 inv.fa[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] -
1310 m[12] * m[1] * m[6] + m[12] * m[2] * m[5];
1311 inv.fa[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] +
1312 m[8] * m[1] * m[6] - m[8] * m[2] * m[5];
1315 ::f32 det = m[0] * inv.fa[0] + m[1] * inv.fa[4] + m[2] * inv.fa[8] + m[3] * inv.fa[12];
1316 ::f32 invDet = 1.0f / det;
1319 __m128 v0 = _mm_loadu_ps(&inv.fa[0]);
1320 __m128 v1 = _mm_loadu_ps(&inv.fa[4]);
1321 __m128 v2 = _mm_loadu_ps(&inv.fa[8]);
1322 __m128 v3 = _mm_loadu_ps(&inv.fa[12]);
1323 __m128 det128 = _mm_set1_ps(invDet);
1325 _mm_storeu_ps(&inv.fa[0], _mm_mul_ps(v0, det128));
1326 _mm_storeu_ps(&inv.fa[4], _mm_mul_ps(v1, det128));
1327 _mm_storeu_ps(&inv.fa[8], _mm_mul_ps(v2, det128));
1328 _mm_storeu_ps(&inv.fa[12], _mm_mul_ps(v3, det128));
1338 inline matrix_type inversed_avx() const
1339 requires(DIMENSION == 4 && std::is_same_v<FLOATING, ::f32>)
1342 const auto &a = *
this;
1344 __m256 col01 = _mm256_loadu_ps(&a.fa[0]);
1345 __m256 col23 = _mm256_loadu_ps(&a.fa[8]);
1349 _mm256_storeu_ps(&m[0], col01);
1350 _mm256_storeu_ps(&m[8], col23);
1355 inv.fa[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] +
1356 m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
1357 inv.fa[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] -
1358 m[13] * m[2] * m[11] + m[13] * m[3] * m[10];
1359 inv.fa[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] +
1360 m[13] * m[2] * m[7] - m[13] * m[3] * m[6];
1361 inv.fa[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] -
1362 m[9] * m[2] * m[7] + m[9] * m[3] * m[6];
1364 inv.fa[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] -
1365 m[12] * m[6] * m[11] + m[12] * m[7] * m[10];
1366 inv.fa[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] +
1367 m[12] * m[2] * m[11] - m[12] * m[3] * m[10];
1368 inv.fa[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] -
1369 m[12] * m[2] * m[7] + m[12] * m[3] * m[6];
1370 inv.fa[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] +
1371 m[8] * m[2] * m[7] - m[8] * m[3] * m[6];
1373 inv.fa[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] +
1374 m[12] * m[5] * m[11] - m[12] * m[7] * m[9];
1375 inv.fa[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] -
1376 m[12] * m[1] * m[11] + m[12] * m[3] * m[9];
1377 inv.fa[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] +
1378 m[12] * m[1] * m[7] - m[12] * m[3] * m[5];
1379 inv.fa[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] -
1380 m[8] * m[1] * m[7] + m[8] * m[3] * m[5];
1382 inv.fa[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] -
1383 m[12] * m[5] * m[10] + m[12] * m[6] * m[9];
1384 inv.fa[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] +
1385 m[12] * m[1] * m[10] - m[12] * m[2] * m[9];
1386 inv.fa[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] -
1387 m[12] * m[1] * m[6] + m[12] * m[2] * m[5];
1388 inv.fa[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] +
1389 m[8] * m[1] * m[6] - m[8] * m[2] * m[5];
1392 ::f32 det = m[0] * inv.fa[0] + m[1] * inv.fa[4] + m[2] * inv.fa[8] + m[3] * inv.fa[12];
1393 ::f32 invDet = 1.0f / det;
1396 __m256 v0 = _mm256_loadu_ps(&inv.fa[0]);
1397 __m256 v1 = _mm256_loadu_ps(&inv.fa[8]);
1398 __m256 invDet256 = _mm256_set1_ps(invDet);
1399 _mm256_storeu_ps(&inv.fa[0], _mm256_mul_ps(v0, invDet256));
1400 _mm256_storeu_ps(&inv.fa[8], _mm256_mul_ps(v1, invDet256));
1408#if defined(__AVX2__)
1410 inline matrix_type inversed_avx2() const
1411 requires(DIMENSION == 4 && std::is_same_v<FLOATING, ::f32>)
1414 const auto &a = *
this;
1416 __m256 col01 = _mm256_loadu_ps(&a.fa[0]);
1417 __m256 col23 = _mm256_loadu_ps(&a.fa[8]);
1420 __m128 r0 = _mm256_castps256_ps128(col01);
1421 __m128 r1 = _mm256_extractf128_ps(col01, 1);
1422 __m128 r2 = _mm256_castps256_ps128(col23);
1423 __m128 r3 = _mm256_extractf128_ps(col23, 1);
1427 _mm_storeu_ps(&m[0], r0);
1428 _mm_storeu_ps(&m[4], r1);
1429 _mm_storeu_ps(&m[8], r2);
1430 _mm_storeu_ps(&m[12], r3);
1435 inv.fa[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] +
1436 m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
1437 inv.fa[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] -
1438 m[13] * m[2] * m[11] + m[13] * m[3] * m[10];
1439 inv.fa[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] +
1440 m[13] * m[2] * m[7] - m[13] * m[3] * m[6];
1441 inv.fa[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] -
1442 m[9] * m[2] * m[7] + m[9] * m[3] * m[6];
1444 inv.fa[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] -
1445 m[12] * m[6] * m[11] + m[12] * m[7] * m[10];
1446 inv.fa[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] +
1447 m[12] * m[2] * m[11] - m[12] * m[3] * m[10];
1448 inv.fa[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] -
1449 m[12] * m[2] * m[7] + m[12] * m[3] * m[6];
1450 inv.fa[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] +
1451 m[8] * m[2] * m[7] - m[8] * m[3] * m[6];
1453 inv.fa[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] +
1454 m[12] * m[5] * m[11] - m[12] * m[7] * m[9];
1455 inv.fa[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] -
1456 m[12] * m[1] * m[11] + m[12] * m[3] * m[9];
1457 inv.fa[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] +
1458 m[12] * m[1] * m[7] - m[12] * m[3] * m[5];
1459 inv.fa[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] -
1460 m[8] * m[1] * m[7] + m[8] * m[3] * m[5];
1462 inv.fa[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] -
1463 m[12] * m[5] * m[10] + m[12] * m[6] * m[9];
1464 inv.fa[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] +
1465 m[12] * m[1] * m[10] - m[12] * m[2] * m[9];
1466 inv.fa[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] -
1467 m[12] * m[1] * m[6] + m[12] * m[2] * m[5];
1468 inv.fa[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] +
1469 m[8] * m[1] * m[6] - m[8] * m[2] * m[5];
1472 ::f32 det = m[0] * inv.fa[0] + m[1] * inv.fa[4] + m[2] * inv.fa[8] + m[3] * inv.fa[12];
1473 ::f32 invDet = 1.0f / det;
1476 __m256 v0 = _mm256_loadu_ps(&inv.fa[0]);
1477 __m256 v1 = _mm256_loadu_ps(&inv.fa[8]);
1478 __m256 invDet256 = _mm256_set1_ps(invDet);
1479 _mm256_storeu_ps(&inv.fa[0], _mm256_mul_ps(v0, invDet256));
1480 _mm256_storeu_ps(&inv.fa[8], _mm256_mul_ps(v1, invDet256));
1487 inline matrix_type & inverse()
1490 if constexpr ( std::is_same_v<FLOATING, ::f32>)
1492 if constexpr (DIMENSION == 4)
1501 return inverse_scalar();
1503 else if constexpr (DIMENSION == 3)
1510 return inverse_scalar();
1514 return inverse_scalar();
1520 return inverse_scalar();
1526 inline matrix_type inversed()
const
1538 inline matrix_type transposed()
const
1550 inline matrix_type &operator=(
const quaternion_type<FLOATING> &q)
1551 requires (DIMENSION == 4)
1555 auto xx = q.x * q.x;
1556 auto yy = q.y * q.y;
1557 auto zz = q.z * q.z;
1559 auto xy = q.x * q.y;
1560 auto xz = q.x * q.z;
1561 auto yz = q.y * q.z;
1563 auto wx = q.w * q.x;
1564 auto wy = q.w * q.y;
1565 auto wz = q.w * q.z;
1568 M.m[0][0] = (FLOATING)1 - (FLOATING)2 * (yy + zz);
1569 M.m[0][1] = (FLOATING)2 * (xy + wz);
1570 M.m[0][2] = (FLOATING)2 * (xz - wy);
1571 M.m[0][3] = (FLOATING)0;
1573 M.m[1][0] = (FLOATING)2 * (xy - wz);
1574 M.m[1][1] = (FLOATING)1 - (FLOATING)2 * (xx + zz);
1575 M.m[1][2] = (FLOATING)2 * (yz + wx);
1576 M.m[1][3] = (FLOATING)0;
1578 M.m[2][0] = (FLOATING)2 * (xz + wy);
1579 M.m[2][1] = (FLOATING)2 * (yz - wx);
1580 M.m[2][2] = (FLOATING)1 - (FLOATING)2 * (xx + yy);
1581 M.m[2][3] = (FLOATING)0;
1583 M.m[3][0] = (FLOATING)0;
1584 M.m[3][1] = (FLOATING)0;
1585 M.m[3][2] = (FLOATING)0;
1586 M.m[3][3] = (FLOATING)1;
1593 static inline matrix_type from(
const quaternion_type<FLOATING> &q)
1594 requires(DIMENSION == 4)
1603 inline row_major_type<FLOATING, t_iDimension> transpose()
const
1605 row_major_type<FLOATING, 4> r;
1606 _transpose(4, this->m);