1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
4 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 **************************************************************************/
27 // File: vogl_matrix.h
30 #include "vogl_core.h"
35 // Matrix/vector cheat sheet, because confusingly, depending on how matrices are stored in memory people can use opposite definitions of "rows", "cols", etc.
36 // See http://www.mindcontrol.org/~hplus/graphics/matrix-layout.html
38 // So in this simple general matrix class:
39 // matrix=[NumRows][NumCols] or [R][C], i.e. a 3x3 matrix stored in memory will appear as: R0C0, R0C1, R0C2, R1C0, R1C1, R1C2, etc.
40 // Matrix multiplication: [R0,C0]*[R1,C1]=[R0,C1], C0 must equal R1
43 // A "row vector" type is a vector of size # of matrix cols, 1xC. It's the vector type that is used to store the matrix rows.
44 // A "col vector" type is a vector of size # of matrix rows, Rx1. It's a vector type large enough to hold each matrix column.
46 // Subrow/col vectors: last component is assumed to be either 0 (a "vector") or 1 (a "point")
47 // "subrow vector": vector/point of size # cols-1, 1x(C-1)
48 // "subcol vector": vector/point of size # rows-1, (R-1)x1
51 // vec*matrix, row vector on left (vec dotted against columns)
59 // Now confusingly, in the matrix transform method for vec*matrix below the vector's type is "col_vec", because col_vec will have the proper size for non-square matrices. But the vector on the left is written as row vector, argh.
63 // matrix*vec, col vector on right (vec dotted against rows):
71 template <class X, class Y, class Z>
72 Z &matrix_mul_helper(Z &result, const X &lhs, const Y &rhs)
74 VOGL_ASSUME(Z::num_rows == X::num_rows);
75 VOGL_ASSUME(Z::num_cols == Y::num_cols);
76 VOGL_ASSUME(X::num_cols == Y::num_rows);
77 VOGL_ASSERT(((void *)&result != (void *)&lhs) && ((void *)&result != (void *)&rhs));
78 for (int r = 0; r < X::num_rows; r++)
79 for (int c = 0; c < Y::num_cols; c++)
81 typename Z::scalar_type s = lhs(r, 0) * rhs(0, c);
82 for (uint i = 1; i < X::num_cols; i++)
83 s += lhs(r, i) * rhs(i, c);
89 template <class X, class Y, class Z>
90 Z &matrix_mul_helper_transpose_lhs(Z &result, const X &lhs, const Y &rhs)
92 VOGL_ASSUME(Z::num_rows == X::num_cols);
93 VOGL_ASSUME(Z::num_cols == Y::num_cols);
94 VOGL_ASSUME(X::num_rows == Y::num_rows);
95 VOGL_ASSERT(((void *)&result != (void *)&lhs) && ((void *)&result != (void *)&rhs));
96 for (int r = 0; r < X::num_cols; r++)
97 for (int c = 0; c < Y::num_cols; c++)
99 typename Z::scalar_type s = lhs(0, r) * rhs(0, c);
100 for (uint i = 1; i < X::num_rows; i++)
101 s += lhs(i, r) * rhs(i, c);
107 template <class X, class Y, class Z>
108 Z &matrix_mul_helper_transpose_rhs(Z &result, const X &lhs, const Y &rhs)
110 VOGL_ASSUME(Z::num_rows == X::num_rows);
111 VOGL_ASSUME(Z::num_cols == Y::num_rows);
112 VOGL_ASSUME(X::num_cols == Y::num_cols);
113 VOGL_ASSERT(((void *)&result != (void *)&lhs) && ((void *)&result != (void *)&rhs));
114 for (int r = 0; r < X::num_rows; r++)
115 for (int c = 0; c < Y::num_rows; c++)
117 typename Z::scalar_type s = lhs(r, 0) * rhs(c, 0);
118 for (uint i = 1; i < X::num_cols; i++)
119 s += lhs(r, i) * rhs(c, i);
130 template <uint R, uint C, typename T>
134 typedef T scalar_type;
141 typedef vec<R, T> col_vec;
142 typedef vec < (R > 1) ? (R - 1) : 0, T > subcol_vec;
144 typedef vec<C, T> row_vec;
145 typedef vec < (C > 1) ? (C - 1) : 0, T > subrow_vec;
151 inline matrix(eClear)
156 inline matrix(eIdentity)
158 set_identity_matrix();
161 inline matrix(const T *p)
166 inline matrix(const matrix &other)
168 for (uint i = 0; i < R; i++)
169 m_rows[i] = other.m_rows[i];
172 inline matrix &operator=(const matrix &rhs)
175 for (uint i = 0; i < R; i++)
176 m_rows[i] = rhs.m_rows[i];
180 inline matrix(T val00, T val01,
183 set(val00, val01, val10, val11);
186 inline matrix(T val00, T val01,
190 set(val00, val01, val10, val11, val20, val21);
193 inline matrix(T val00, T val01, T val02,
194 T val10, T val11, T val12,
195 T val20, T val21, T val22)
197 set(val00, val01, val02, val10, val11, val12, val20, val21, val22);
200 inline matrix(T val00, T val01, T val02, T val03,
201 T val10, T val11, T val12, T val13,
202 T val20, T val21, T val22, T val23,
203 T val30, T val31, T val32, T val33)
205 set(val00, val01, val02, val03, val10, val11, val12, val13, val20, val21, val22, val23, val30, val31, val32, val33);
208 inline matrix(T val00, T val01, T val02, T val03,
209 T val10, T val11, T val12, T val13,
210 T val20, T val21, T val22, T val23)
212 set(val00, val01, val02, val03, val10, val11, val12, val13, val20, val21, val22, val23);
215 inline void set(const float *p)
217 for (uint i = 0; i < R; i++)
224 inline void set(T val00, T val01,
227 m_rows[0].set(val00, val01);
230 m_rows[1].set(val10, val11);
232 for (uint i = 2; i < R; i++)
237 inline void set(T val00, T val01,
241 m_rows[0].set(val00, val01);
244 m_rows[1].set(val10, val11);
248 m_rows[2].set(val20, val21);
250 for (uint i = 3; i < R; i++)
256 inline void set(T val00, T val01, T val02,
257 T val10, T val11, T val12,
258 T val20, T val21, T val22)
260 m_rows[0].set(val00, val01, val02);
263 m_rows[1].set(val10, val11, val12);
266 m_rows[2].set(val20, val21, val22);
268 for (uint i = 3; i < R; i++)
274 inline void set(T val00, T val01, T val02, T val03,
275 T val10, T val11, T val12, T val13,
276 T val20, T val21, T val22, T val23,
277 T val30, T val31, T val32, T val33)
279 m_rows[0].set(val00, val01, val02, val03);
282 m_rows[1].set(val10, val11, val12, val13);
285 m_rows[2].set(val20, val21, val22, val23);
289 m_rows[3].set(val30, val31, val32, val33);
291 for (uint i = 4; i < R; i++)
298 inline void set(T val00, T val01, T val02, T val03,
299 T val10, T val11, T val12, T val13,
300 T val20, T val21, T val22, T val23)
302 m_rows[0].set(val00, val01, val02, val03);
305 m_rows[1].set(val10, val11, val12, val13);
308 m_rows[2].set(val20, val21, val22, val23);
310 for (uint i = 3; i < R; i++)
316 inline T operator()(uint r, uint c) const
318 VOGL_ASSERT((r < R) && (c < C));
322 inline T &operator()(uint r, uint c)
324 VOGL_ASSERT((r < R) && (c < C));
328 inline const row_vec &operator[](uint r) const
334 inline row_vec &operator[](uint r)
340 inline const row_vec &get_row(uint r) const
344 inline row_vec &get_row(uint r)
349 inline col_vec get_col(uint c) const
353 for (uint i = 0; i < R; i++)
354 result[i] = m_rows[i][c];
358 inline void set_col(uint c, const col_vec &col)
361 for (uint i = 0; i < R; i++)
362 m_rows[i][c] = col[i];
365 inline void set_col(uint c, const subcol_vec &col)
368 for (uint i = 0; i < (R - 1); i++)
369 m_rows[i][c] = col[i];
371 m_rows[R - 1][c] = 0.0f;
374 inline const row_vec &get_translate() const
376 return m_rows[R - 1];
379 inline matrix &set_translate(const row_vec &r)
385 inline matrix &set_translate(const subrow_vec &r)
387 m_rows[R - 1] = row_vec(r).as_point();
391 inline const T *get_ptr() const
393 return reinterpret_cast<const T *>(&m_rows[0]);
397 return reinterpret_cast<T *>(&m_rows[0]);
400 inline matrix &operator+=(const matrix &other)
402 for (uint i = 0; i < R; i++)
403 m_rows[i] += other.m_rows[i];
407 inline matrix &operator-=(const matrix &other)
409 for (uint i = 0; i < R; i++)
410 m_rows[i] -= other.m_rows[i];
414 inline matrix &operator*=(T val)
416 for (uint i = 0; i < R; i++)
421 inline matrix &operator/=(T val)
423 for (uint i = 0; i < R; i++)
428 inline matrix &operator*=(const matrix &other)
431 matrix_mul_helper(result, *this, other);
436 friend inline matrix operator+(const matrix &lhs, const matrix &rhs)
439 for (uint i = 0; i < R; i++)
440 result[i] = lhs.m_rows[i] + rhs.m_rows[i];
444 friend inline matrix operator-(const matrix &lhs, const matrix &rhs)
447 for (uint i = 0; i < R; i++)
448 result[i] = lhs.m_rows[i] - rhs.m_rows[i];
452 friend inline matrix operator*(const matrix &lhs, T val)
455 for (uint i = 0; i < R; i++)
456 result[i] = lhs.m_rows[i] * val;
460 friend inline matrix operator/(const matrix &lhs, T val)
463 for (uint i = 0; i < R; i++)
464 result[i] = lhs.m_rows[i] / val;
468 friend inline matrix operator*(T val, const matrix &rhs)
471 for (uint i = 0; i < R; i++)
472 result[i] = val * rhs.m_rows[i];
476 friend inline matrix operator*(const matrix &lhs, const matrix &rhs)
479 return matrix_mul_helper(result, lhs, rhs);
482 friend inline row_vec operator*(const col_vec &a, const matrix &b)
484 return transform(a, b);
487 inline matrix operator+() const
492 inline matrix operator-() const
495 for (uint i = 0; i < R; i++)
496 result[i] = -m_rows[i];
500 inline matrix &clear()
502 for (uint i = 0; i < R; i++)
507 inline matrix &set_zero_matrix()
513 inline matrix &set_identity_matrix()
515 for (uint i = 0; i < R; i++)
523 inline matrix &set_scale_matrix(float s)
526 for (int i = 0; i < (R - 1); i++)
528 m_rows[R - 1][C - 1] = 1.0f;
532 inline matrix &set_scale_matrix(const row_vec &s)
535 for (uint i = 0; i < R; i++)
540 inline matrix &set_scale_matrix(float x, float y)
542 set_identity_matrix();
548 inline matrix &set_scale_matrix(float x, float y, float z)
550 set_identity_matrix();
557 inline matrix &set_translate_matrix(const row_vec &s)
559 set_identity_matrix();
564 inline matrix &set_translate_matrix(float x, float y)
566 set_identity_matrix();
567 set_translate(row_vec(x, y).as_point());
571 inline matrix &set_translate_matrix(float x, float y, float z)
573 set_identity_matrix();
574 set_translate(row_vec(x, y, z).as_point());
578 inline matrix get_transposed() const
581 for (uint i = 0; i < R; i++)
582 for (uint j = 0; j < C; j++)
583 result.m_rows[i][j] = m_rows[j][i];
587 inline matrix &transpose_in_place()
590 for (uint i = 0; i < R; i++)
591 for (uint j = 0; j < C; j++)
592 result.m_rows[i][j] = m_rows[j][i];
597 bool invert(matrix &result) const
601 result.set_identity_matrix();
605 for (uint c = 0; c < C; c++)
608 for (uint r = c + 1; r < R; r++)
609 if (fabs(mat[r][c]) > fabs(mat[max_r][c]))
612 if (mat[max_r][c] == 0.0f)
614 result.set_identity_matrix();
618 utils::swap(mat[c], mat[max_r]);
619 utils::swap(result[c], result[max_r]);
621 result[c] /= mat[c][c];
624 for (uint row = 0; row < R; row++)
628 const row_vec temp(mat[row][c]);
629 mat[row] -= row_vec::mul_components(mat[c], temp);
630 result[row] -= row_vec::mul_components(result[c], temp);
638 matrix &invert_in_place()
646 matrix get_inverse() const
656 return det_helper(*this, R);
659 bool equal_tol(const matrix &b, float tol) const
661 for (uint r = 0; r < R; r++)
662 if (!row_vec::equal_tol(m_rows[r], b.m_rows[r], tol))
667 // This method transforms a vec by a matrix (D3D-style: row vector on left).
668 // Confusingly, note that the data type is named "col_vec", but mathematically it's actually written as a row vector (of size equal to the # matrix rows, which is why it's called a "col_vec" in this class).
670 // This dots against the matrix columns.
671 static inline row_vec transform(const col_vec &a, const matrix &b)
673 row_vec result(b[0] * a[0]);
674 for (uint r = 1; r < R; r++)
675 result += b[r] * a[r];
679 // This method transforms a vec by a matrix (D3D-style: row vector on left).
680 // Last component of vec is assumed to be 1.
681 static inline row_vec transform_point(const col_vec &a, const matrix &b)
684 for (int r = 0; r < (R - 1); r++)
685 result += b[r] * a[r];
690 // This method transforms a vec by a matrix (D3D-style: row vector on left).
691 // Last component of vec is assumed to be 0.
692 static inline row_vec transform_vector(const col_vec &a, const matrix &b)
695 for (int r = 0; r < (R - 1); r++)
696 result += b[r] * a[r];
700 // This method transforms a vec by a matrix (D3D-style: row vector on left).
701 // Last component of vec is assumed to be 1.
702 static inline subcol_vec transform_point(const subcol_vec &a, const matrix &b)
704 subcol_vec result(0);
705 for (int r = 0; r < static_cast<int>(R); r++)
707 const T s = (r < subcol_vec::num_elements) ? a[r] : 1.0f;
708 for (int c = 0; c < static_cast<int>(C - 1); c++)
709 result[c] += b[r][c] * s;
714 // This method transforms a vec by a matrix (D3D-style: row vector on left).
715 // Last component of vec is assumed to be 0.
716 static inline subcol_vec transform_vector(const subcol_vec &a, const matrix &b)
718 subcol_vec result(0);
719 for (int r = 0; r < static_cast<int>(R - 1); r++)
722 for (int c = 0; c < static_cast<int>(C - 1); c++)
723 result[c] += b[r][c] * s;
728 // Like transform() above, but the matrix is effectively transposed before the multiply.
729 static inline col_vec transform_transposed(const col_vec &a, const matrix &b)
733 for (uint r = 0; r < R; r++)
734 result[r] = b[r].dot(a);
738 // Like transform() above, but the matrix is effectively transposed before the multiply.
739 // Last component of vec is assumed to be 0.
740 static inline col_vec transform_vector_transposed(const col_vec &a, const matrix &b)
744 for (uint r = 0; r < R; r++)
747 for (uint c = 0; c < (C - 1); c++)
755 // This method transforms a vec by a matrix (D3D-style: row vector on left), but the matrix is effectively transposed before the multiply.
756 // Last component of vec is assumed to be 1.
757 static inline subcol_vec transform_point_transposed(const subcol_vec &a, const matrix &b)
760 subcol_vec result(0);
761 for (int r = 0; r < R; r++)
763 const T s = (r < subcol_vec::num_elements) ? a[r] : 1.0f;
764 for (int c = 0; c < (C - 1); c++)
765 result[c] += b[c][r] * s;
770 // This method transforms a vec by a matrix (D3D-style: row vector on left), but the matrix is effectively transposed before the multiply.
771 // Last component of vec is assumed to be 0.
772 static inline subcol_vec transform_vector_transposed(const subcol_vec &a, const matrix &b)
775 subcol_vec result(0);
776 for (int r = 0; r < static_cast<int>(R - 1); r++)
779 for (int c = 0; c < static_cast<int>(C - 1); c++)
780 result[c] += b[c][r] * s;
785 // This method transforms a matrix by a vector (OGL style, col vector on the right).
786 // Note that the data type is named "row_vec", but mathematically it's actually written as a column vector (of size equal to the # matrix cols).
788 // This dots against the matrix rows.
789 static inline col_vec transform(const matrix &b, const row_vec &a)
792 for (int r = 0; r < static_cast<int>(R); r++)
793 result[r] = b[r].dot(a);
797 // This method transforms a matrix by a vector (OGL style, col vector on the right), except the matrix is effectively transposed before the multiply.
798 // Note that the data type is named "row_vec", but mathematically it's actually written as a column vector (of size equal to the # matrix cols).
800 // This dots against the matrix cols.
801 static inline col_vec transform_transposed(const matrix &b, const row_vec &a)
804 row_vec result(b[0] * a[0]);
805 for (int r = 1; r < static_cast<int>(R); r++)
806 result += b[r] * a[r];
807 return col_vec(result);
810 static inline matrix &mul_components(matrix &result, const matrix &lhs, const matrix &rhs)
812 for (uint r = 0; r < R; r++)
813 result[r] = row_vec::mul_components(lhs[r], rhs[r]);
817 static inline matrix &concat(matrix &lhs, const matrix &rhs)
819 return matrix_mul_helper(lhs, matrix(lhs), rhs);
822 inline matrix &concat_in_place(const matrix &rhs)
824 return concat(*this, rhs);
827 static inline matrix &multiply(matrix &result, const matrix &lhs, const matrix &rhs)
830 matrix *pResult = ((&result == &lhs) || (&result == &rhs)) ? &temp : &result;
832 matrix_mul_helper(*pResult, lhs, rhs);
833 if (pResult != &result)
839 static matrix make_zero_matrix()
846 static matrix make_identity_matrix()
849 result.set_identity_matrix();
853 static matrix make_translate_matrix(const row_vec &t)
855 return matrix(cIdentity).set_translate(t);
858 static matrix make_translate_matrix(float x, float y)
860 return matrix(cIdentity).set_translate_matrix(x, y);
863 static matrix make_translate_matrix(float x, float y, float z)
865 return matrix(cIdentity).set_translate_matrix(x, y, z);
868 static inline matrix make_scale_matrix(float s)
870 return matrix().set_scale_matrix(s);
873 static inline matrix make_scale_matrix(const row_vec &s)
875 return matrix().set_scale_matrix(s);
878 static inline matrix make_scale_matrix(float x, float y)
880 VOGL_ASSUME(R >= 3 && C >= 3);
882 result.set_identity_matrix();
883 result.m_rows[0][0] = x;
884 result.m_rows[1][1] = y;
888 static inline matrix make_scale_matrix(float x, float y, float z)
890 VOGL_ASSUME(R >= 4 && C >= 4);
892 result.set_identity_matrix();
893 result.m_rows[0][0] = x;
894 result.m_rows[1][1] = y;
895 result.m_rows[2][2] = z;
899 // Helpers derived from Graphics Gems 1 and 2 (Matrices and Transformations, Ronald N. Goldman)
900 static matrix make_rotate_matrix(const vec<3, T> &axis, T ang)
902 VOGL_ASSUME(R >= 3 && C >= 3);
904 vec<3, T> norm_axis(axis.get_normalized());
906 double cos_a = cos(ang);
907 double inv_cos_a = 1.0f - cos_a;
909 double sin_a = sin(ang);
911 const T x = norm_axis[0];
912 const T y = norm_axis[1];
913 const T z = norm_axis[2];
915 const double x2 = norm_axis[0] * norm_axis[0];
916 const double y2 = norm_axis[1] * norm_axis[1];
917 const double z2 = norm_axis[2] * norm_axis[2];
920 result.set_identity_matrix();
922 result[0][0] = (T)((inv_cos_a * x2) + cos_a);
923 result[1][0] = (T)((inv_cos_a * x * y) + (sin_a * z));
924 result[2][0] = (T)((inv_cos_a * x * z) - (sin_a * y));
926 result[0][1] = (T)((inv_cos_a * x * y) - (sin_a * z));
927 result[1][1] = (T)((inv_cos_a * y2) + cos_a);
928 result[2][1] = (T)((inv_cos_a * y * z) + (sin_a * x));
930 result[0][2] = (T)((inv_cos_a * x * z) + (sin_a * y));
931 result[1][2] = (T)((inv_cos_a * y * z) - (sin_a * x));
932 result[2][2] = (T)((inv_cos_a * z2) + cos_a);
937 static inline matrix make_rotate_matrix(T ang)
939 VOGL_ASSUME(R >= 2 && C >= 2);
941 matrix ret(cIdentity);
943 const T sin_a = static_cast<T>(sin(ang));
944 const T cos_a = static_cast<T>(cos(ang));
954 static inline matrix make_rotate_matrix(uint axis, T ang)
958 axis_vec[axis] = 1.0f;
959 return make_rotate_matrix(axis_vec, ang);
962 static inline matrix make_cross_product_matrix(const vec<3, scalar_type> &c)
964 VOGL_ASSUME((num_rows >= 3) && (num_cols >= 3));
975 static inline matrix make_reflection_matrix(const vec<4, scalar_type> &n, const vec<4, scalar_type> &q)
977 VOGL_ASSUME((num_rows == 4) && (num_cols == 4));
979 VOGL_ASSERT(n.is_vector() && q.is_vector());
980 ret = make_identity_matrix() - 2.0f * make_tensor_product_matrix(n, n);
981 ret.set_translate((2.0f * q.dot(n) * n).as_point());
985 static inline matrix make_tensor_product_matrix(const row_vec &v, const row_vec &w)
988 for (int r = 0; r < num_rows; r++)
989 ret[r] = row_vec::mul_components(v.broadcast(r), w);
993 static inline matrix make_uniform_scaling_matrix(const vec<4, scalar_type> &q, scalar_type c)
995 VOGL_ASSUME((num_rows == 4) && (num_cols == 4));
996 VOGL_ASSERT(q.is_vector());
998 ret = c * make_identity_matrix();
999 ret.set_translate(((1.0f - c) * q).as_point());
1003 static inline matrix make_nonuniform_scaling_matrix(const vec<4, scalar_type> &q, scalar_type c, const vec<4, scalar_type> &w)
1005 VOGL_ASSUME((num_rows == 4) && (num_cols == 4));
1006 VOGL_ASSERT(q.is_vector() && w.is_vector());
1008 ret = make_identity_matrix() - (1.0f - c) * make_tensor_product_matrix(w, w);
1009 ret.set_translate(((1.0f - c) * q.dot(w) * w).as_point());
1013 // n = normal of plane, q = point on plane
1014 static inline matrix make_ortho_projection_matrix(const vec<4, scalar_type> &n, const vec<4, scalar_type> &q)
1016 VOGL_ASSERT(n.is_vector() && q.is_vector());
1018 ret = make_identity_matrix() - make_tensor_product_matrix(n, n);
1019 ret.set_translate((q.dot(n) * n).as_point());
1023 static inline matrix make_parallel_projection(const vec<4, scalar_type> &n, const vec<4, scalar_type> &q, const vec<4, scalar_type> &w)
1025 VOGL_ASSERT(n.is_vector() && q.is_vector() && w.is_vector());
1027 ret = make_identity_matrix() - (make_tensor_product_matrix(n, w) / (w.dot(n)));
1028 ret.set_translate(((q.dot(n) / w.dot(n)) * w).as_point());
1035 static T det_helper(const matrix &a, uint n)
1037 // Algorithm ported from Numerical Recipes in C.
1041 d = a(0, 0) * a(1, 1) - a(1, 0) * a(0, 1);
1045 for (uint j1 = 1; j1 <= n; j1++)
1047 for (uint i = 2; i <= n; i++)
1050 for (uint j = 1; j <= n; j++)
1054 m(i - 2, j2 - 1) = a(i - 1, j - 1);
1059 d += (((1 + j1) & 1) ? -1.0f : 1.0f) * a(1 - 1, j1 - 1) * det_helper(m, n - 1);
1066 typedef matrix<2, 2, float> matrix22F;
1067 typedef matrix<2, 2, double> matrix22D;
1069 typedef matrix<3, 3, float> matrix33F;
1070 typedef matrix<3, 3, double> matrix33D;
1072 typedef matrix<4, 4, float> matrix44F;
1073 typedef matrix<4, 4, double> matrix44D;
1075 typedef matrix<8, 8, float> matrix88F;
1077 // These helpers create good old D3D-style matrices.
1078 inline matrix44F matrix44F_make_perspective_offcenter_lh(float l, float r, float b, float t, float nz, float fz)
1080 float two_nz = 2.0f * nz;
1081 float one_over_width = 1.0f / (r - l);
1082 float one_over_height = 1.0f / (t - b);
1084 matrix44F view_to_proj;
1085 view_to_proj[0].set(two_nz * one_over_width, 0.0f, 0.0f, 0.0f);
1086 view_to_proj[1].set(0.0f, two_nz * one_over_height, 0.0f, 0.0f);
1087 view_to_proj[2].set(-(l + r) * one_over_width, -(t + b) * one_over_height, fz / (fz - nz), 1.0f);
1088 view_to_proj[3].set(0.0f, 0.0f, -view_to_proj[2][2] * nz, 0.0f);
1089 return view_to_proj;
1092 // fov_y: full Y field of view (radians)
1093 // aspect: viewspace width/height
1094 inline matrix44F matrix44F_make_perspective_fov_lh(float fov_y, float aspect, float nz, float fz)
1096 double sin_fov = sin(0.5f * fov_y);
1097 double cos_fov = cos(0.5f * fov_y);
1099 float y_scale = static_cast<float>(cos_fov / sin_fov);
1100 float x_scale = static_cast<float>(y_scale / aspect);
1102 matrix44F view_to_proj;
1103 view_to_proj[0].set(x_scale, 0, 0, 0);
1104 view_to_proj[1].set(0, y_scale, 0, 0);
1105 view_to_proj[2].set(0, 0, fz / (fz - nz), 1);
1106 view_to_proj[3].set(0, 0, -nz * fz / (fz - nz), 0);
1107 return view_to_proj;
1110 inline matrix44F matrix44F_make_ortho_offcenter_lh(float l, float r, float b, float t, float nz, float fz)
1112 matrix44F view_to_proj;
1113 view_to_proj[0].set(2.0f / (r - l), 0.0f, 0.0f, 0.0f);
1114 view_to_proj[1].set(0.0f, 2.0f / (t - b), 0.0f, 0.0f);
1115 view_to_proj[2].set(0.0f, 0.0f, 1.0f / (fz - nz), 0.0f);
1116 view_to_proj[3].set((l + r) / (l - r), (t + b) / (b - t), nz / (nz - fz), 1.0f);
1117 return view_to_proj;
1120 inline matrix44F matrix44F_make_ortho_lh(float w, float h, float nz, float fz)
1122 return matrix44F_make_ortho_offcenter_lh(-w * .5f, w * .5f, -h * .5f, h * .5f, nz, fz);
1125 inline matrix44F matrix44F_make_projection_to_screen_d3d(int x, int y, int w, int h, float min_z, float max_z)
1127 matrix44F proj_to_screen;
1128 proj_to_screen[0].set(w * .5f, 0.0f, 0.0f, 0.0f);
1129 proj_to_screen[1].set(0, h * -.5f, 0.0f, 0.0f);
1130 proj_to_screen[2].set(0, 0.0f, max_z - min_z, 0.0f);
1131 proj_to_screen[3].set(x + w * .5f, y + h * .5f, min_z, 1.0f);
1132 return proj_to_screen;
1135 inline matrix44F matrix44F_make_lookat_lh(const vec3F &camera_pos, const vec3F &look_at, const vec3F &camera_up, float camera_roll_ang_in_radians)
1137 vec4F col2(look_at - camera_pos);
1138 VOGL_ASSERT(col2.is_vector());
1139 if (col2.normalize() == 0.0f)
1140 col2.set(0, 0, 1, 0);
1142 vec4F col1(camera_up);
1143 VOGL_ASSERT(col1.is_vector());
1144 if (!col2[0] && !col2[2])
1145 col1.set(-1.0f, 0.0f, 0.0f, 0.0f);
1147 if ((col1.dot(col2)) > .9999f)
1148 col1.set(0.0f, 1.0f, 0.0f, 0.0f);
1150 vec4F col0(vec4F::cross3(col1, col2).normalize_in_place());
1151 col1 = vec4F::cross3(col2, col0).normalize_in_place();
1153 matrix44F rotm(matrix44F::make_identity_matrix());
1154 rotm.set_col(0, col0);
1155 rotm.set_col(1, col1);
1156 rotm.set_col(2, col2);
1157 return matrix44F::make_translate_matrix(-camera_pos[0], -camera_pos[1], -camera_pos[2]) * rotm * matrix44F::make_rotate_matrix(2, camera_roll_ang_in_radians);