fennec
Loading...
Searching...
No Matches
matrix.h
Go to the documentation of this file.
1// =====================================================================================================================
2// fennec, a free and open source game engine
3// Copyright © 2025 Medusa Slockbower
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <https://www.gnu.org/licenses/>.
17// =====================================================================================================================
18
30
31#ifndef FENNEC_MATH_MATRIX_H
32#define FENNEC_MATH_MATRIX_H
33
45
46#include <fennec/math/detail/_fwd.h>
47#include <fennec/math/detail/_matrix.h>
48
50
53
54namespace fennec
55{
56
57
63template<typename scalar, size_t rows, size_t...cols>
64constexpr vec<scalar, rows> column(const matrix<scalar, rows, cols...>& m, size_t i) noexcept {
65 return m[i];
66}
67
68
74template<typename scalar, size_t rows, size_t...cols>
75constexpr vec<scalar, sizeof...(cols)> row(const matrix<scalar, rows, cols...>& m, size_t i) noexcept {
76 return vec<scalar, sizeof...(cols)>(m[cols][i]...);
77}
78
79
80template<typename ScalarT>
81using tmat2x2 = mat<ScalarT, 2, 2>;
82template<typename ScalarT> using tmat2x3 = mat<ScalarT, 2, 3>;
83template<typename ScalarT> using tmat2x4 = mat<ScalarT, 2, 4>;
84template<typename ScalarT> using tmat3x2 = mat<ScalarT, 3, 2>;
85template<typename ScalarT> using tmat3x3 = mat<ScalarT, 3, 3>;
86template<typename ScalarT> using tmat3x4 = mat<ScalarT, 3, 4>;
87template<typename ScalarT> using tmat4x2 = mat<ScalarT, 4, 2>;
88template<typename ScalarT> using tmat4x3 = mat<ScalarT, 4, 3>;
89template<typename ScalarT> using tmat4x4 = mat<ScalarT, 4, 4>;
90
91using mat2 = tmat2x2<float_t>;
92using mat3 = tmat3x3<float_t>;
93using mat4 = tmat4x4<float_t>;
94
95using mat2x2 = tmat2x2<float_t>;
96using mat2x3 = tmat2x3<float_t>;
97using mat2x4 = tmat2x4<float_t>;
98using mat3x2 = tmat3x2<float_t>;
99using mat3x3 = tmat3x3<float_t>;
100using mat3x4 = tmat3x4<float_t>;
101using mat4x2 = tmat4x2<float_t>;
102using mat4x3 = tmat4x3<float_t>;
103using mat4x4 = tmat4x4<float_t>;
104
105using dmat2 = tmat2x2<double_t>;
106using dmat3 = tmat3x3<double_t>;
107using dmat4 = tmat3x3<double_t>;
108
109using dmat2x2 = tmat2x2<double_t>;
110using dmat2x3 = tmat2x3<double_t>;
111using dmat2x4 = tmat2x4<double_t>;
112using dmat3x2 = tmat3x2<double_t>;
113using dmat3x3 = tmat3x3<double_t>;
114using dmat3x4 = tmat3x4<double_t>;
115using dmat4x2 = tmat4x2<double_t>;
116using dmat4x3 = tmat4x3<double_t>;
117using dmat4x4 = tmat4x4<double_t>;
118
119
128template<typename scalar, size_t rows, size_t...cols>
129constexpr matrix<scalar, rows, cols...> matrixCompMult(const matrix<scalar, rows, cols...>& x, const matrix<scalar, rows, cols...>& y) noexcept {
130 return matrix<scalar, rows, cols...>(x[cols] * y[cols] ...);
131}
132
145template<typename scalar, size_t...s0, size_t...s1>
146constexpr matrix<scalar, sizeof...(s0), s1...> outerProduct(const vector<scalar, s0...>& c, const vector<scalar, s1...>& r) noexcept {
147 return matrix<scalar, sizeof...(s0), s1...>(
148 c * r[s1]...
149 );
150}
151
157template<typename scalar, size_t rows, size_t...cols>
158constexpr mat<scalar, rows, sizeof...(cols)> transpose(const matrix<scalar, rows, cols...>& m) noexcept {
159 return mat<scalar, rows, sizeof...(cols)>::transpose(m);
160}
161
166template<typename scalar, size_t rows, size_t...cols>
167constexpr scalar determinant(const matrix<scalar, rows, cols...>&) noexcept {
168 // ReSharper disable once CppStaticAssertFailure
169 static_assert(false, "implementation undefined");
170 return 0;
171}
172
173template<typename scalar, size_t rows, size_t...cols>
174constexpr matrix<scalar, rows, cols...> inverse(const matrix<scalar, rows, cols...>&) noexcept {
175 // ReSharper disable once CppStaticAssertFailure
176 static_assert(false, "implementation undefined");
177 return 1;
178}
179
185template<typename ScalarT, size_t RowsV, size_t...ColIndicesV> requires(is_scalar_v<ScalarT>)
186struct matrix
187{
188// Assertions ==========================================================================================================
189
190 static_assert(is_arithmetic_v<ScalarT> or is_bool_v<ScalarT>);
191
192
193// Typedefs & Constants ================================================================================================
194
197 static constexpr size_t rows = RowsV;
198
201 static constexpr size_t columns = sizeof...(ColIndicesV);
202
205 static constexpr size_t num_components = rows * columns;
206
209 using row_t = vec<ScalarT, columns>;
210
213 using column_t = vec<ScalarT, rows>;
214
217 using scalar_t = ScalarT;
218
221 using matrix_t = matrix;
222
225 using transpose_t = mat<ScalarT, rows, columns>;
226
227
230 array<column_t, columns> data;
231
232
233
234// Constructors ========================================================================================================
235
238
239
244 constexpr matrix() = default;
245
246
252 constexpr matrix(const matrix_t& mat)
253 : data{ mat.data } {
254 }
255
261 constexpr matrix(matrix_t&& mat) noexcept
262 : data{ mat.data } {
263 }
264
265 template<typename OScalarT>
266 constexpr matrix(const matrix<OScalarT, RowsV, ColIndicesV...>& mat)
267 : matrix() {
268 for (size_t i = 0; i < columns; ++i) {
269 for (size_t j = 0; j < rows; ++j) {
270 data[i][j] = scalar_t(mat[i][j]);
271 }
272 }
273 }
274
275 template<typename OScalarT>
276 constexpr matrix(matrix<OScalarT, RowsV, ColIndicesV...>&& mat) noexcept
277 : matrix() {
278 for (size_t i = 0; i < columns; ++i) {
279 for (size_t j = 0; j < rows; ++j) {
280 data[i][j] = scalar_t(mat[i][j]);
281 }
282 }
283 }
284
285
300 constexpr matrix(scalar_t s) {
301 (((ColIndicesV < rows) ? data[ColIndicesV][ColIndicesV] = s : 0), ...);
302 }
303
304
311 template<typename...ArgsT> requires(total_component_count_v<ArgsT...> == num_components)
312 constexpr matrix(ArgsT&&...args) {
313 matrix::_construct(fennec::forward<ArgsT>(args)...);
314 }
315
317
318// Assignment Operators ================================================================================================
319
322
329 constexpr matrix_t& operator=(const matrix_t& rhs) {
330 data = rhs.data; return *this;
331 }
332
339 constexpr matrix_t& operator=(matrix_t&& rhs) noexcept {
340 data = rhs.data; return *this;
341 }
342
344
345
346// Access Operators ====================================================================================================
347
350
353 constexpr column_t& operator[](size_t i) {
354 return data[i];
355 }
356
363 constexpr const column_t& operator[](size_t i) const {
364 return data[i];
365 }
366
369 constexpr scalar_t& operator[](size_t i, size_t j) {
370 return data[i][j];
371 }
372
378 constexpr scalar_t operator[](size_t i, size_t j) const {
379 return data[i][j];
380 }
381
383
384// Scalar Operators ====================================================================================================
385
388
394 constexpr friend matrix_t operator+(const matrix_t& lhs, scalar_t rhs) {
395 return matrix_t(lhs[ColIndicesV] + rhs ...);
396 }
397
403 constexpr friend matrix_t operator+(scalar_t lhs, const matrix_t& rhs) {
404 return matrix_t(lhs + rhs[ColIndicesV] ...);
405 }
406
412 constexpr friend matrix_t operator-(const matrix_t& lhs, scalar_t rhs) {
413 return matrix_t(lhs[ColIndicesV] - rhs ...);
414 }
415
421 constexpr friend matrix_t operator-(scalar_t lhs, const matrix_t& rhs) {
422 return matrix_t(lhs - rhs[ColIndicesV] ...);
423 }
424
430 constexpr friend matrix_t operator*(const matrix_t& lhs, scalar_t rhs) {
431 return matrix_t(lhs[ColIndicesV] * rhs ...);
432 }
433
439 constexpr friend matrix_t operator*(scalar_t lhs, const matrix_t& rhs) {
440 return matrix_t(lhs * rhs[ColIndicesV] ...);
441 }
442
448 constexpr friend matrix_t operator/(const matrix_t& lhs, scalar_t rhs) {
449 return matrix_t(lhs[ColIndicesV] / rhs ...);
450 }
451
457 constexpr friend matrix_t operator/(scalar_t lhs, const matrix_t& rhs) {
458 return matrix_t(lhs / rhs[ColIndicesV] ...);
459 }
460
461
462
468 constexpr friend matrix_t& operator+=(matrix_t& lhs, scalar_t rhs) {
469 ((lhs[ColIndicesV] += rhs), ...);
470 return lhs;
471 }
472
478 constexpr friend matrix_t& operator+=(scalar_t lhs, matrix_t& rhs) {
479 ((rhs[ColIndicesV] += lhs), ...);
480 return rhs;
481 }
482
488 constexpr friend matrix_t& operator-=(matrix_t& lhs, scalar_t rhs) {
489 ((lhs[ColIndicesV] -= rhs), ...);
490 return lhs;
491 }
492
498 constexpr friend matrix_t& operator-=(scalar_t lhs, matrix_t& rhs) {
499 ((rhs[ColIndicesV] -= lhs), ...);
500 return rhs;
501 }
502
508 constexpr friend matrix_t& operator*=(matrix_t& lhs, scalar_t rhs) {
509 ((lhs[ColIndicesV] *= rhs), ...);
510 return lhs;
511 }
512
518 constexpr friend matrix_t& operator*=(scalar_t lhs, matrix_t& rhs) {
519 ((rhs[ColIndicesV] *= lhs), ...);
520 return rhs;
521 }
522
528 constexpr friend matrix_t& operator/=(matrix_t& lhs, scalar_t rhs) {
529 ((lhs[ColIndicesV] /= rhs), ...);
530 return lhs;
531 }
532
538 constexpr friend matrix_t& operator/=(scalar_t lhs, matrix_t& rhs) {
539 ((rhs[ColIndicesV] /= lhs), ...);
540 return rhs;
541 }
542
543
544
550 constexpr friend matrix_t operator%(const matrix_t& lhs, scalar_t rhs) requires is_integral_v<scalar_t> {
551 matrix_t retval = lhs;
552 ((retval[ColIndicesV] %= rhs), ...);
553 return retval;
554 }
555
561 constexpr friend matrix_t operator%(scalar_t lhs, const matrix_t& rhs) requires is_integral_v<scalar_t> {
562 matrix_t retval = rhs;
563 ((retval[ColIndicesV] %= lhs), ...);
564 return retval;
565 }
566
572 constexpr friend matrix_t& operator%=(matrix_t& lhs, scalar_t rhs) requires is_integral_v<scalar_t> {
573 ((lhs[ColIndicesV] %= rhs), ...);
574 return lhs;
575 }
576
582 constexpr friend matrix_t& operator%=(scalar_t lhs, matrix_t& rhs) requires is_integral_v<scalar_t> {
583 ((rhs[ColIndicesV] %= lhs), ...);
584 return rhs;
585 }
586
588
589// Vector Operators ====================================================================================================
590
593
599 constexpr friend column_t operator*(const matrix_t& lhs, const row_t& rhs) {
600 return _mul(lhs, rhs);
601 }
602
608 constexpr friend row_t operator*(const column_t& lhs, const matrix_t& rhs) {
609 return row_t(fennec::dot(fennec::column(rhs, ColIndicesV), lhs) ...);
610 }
611
613
614
615
616// Matrix Operators ====================================================================================================
617
620
626 constexpr friend bool operator==(const matrix_t& lhs, const matrix_t& rhs) {
627 return lhs.data == rhs.data;
628 }
629
635 constexpr friend bool operator!=(const matrix_t& lhs, const matrix_t& rhs) {
636 return lhs.data != rhs.data;
637 }
638
643 template<size_t ORowsV, size_t...OColIndicesV> requires(columns == ORowsV)
644 constexpr friend matrix<scalar_t, RowsV, OColIndicesV...> operator*(const matrix_t& lhs, const matrix<scalar_t, ORowsV, OColIndicesV...>& rhs) {
645 return matrix<scalar_t, RowsV, OColIndicesV...>(
646 matrix::_mul(lhs, rhs[OColIndicesV])...
647 );
648 }
649
650 template<size_t ORowsV, size_t...OColIndicesV> requires(columns == ORowsV)
651 constexpr matrix<scalar_t, RowsV, OColIndicesV...>& operator*=(const matrix<scalar_t, ORowsV, OColIndicesV...>& rhs) {
652 return *this = *this * rhs;
653 }
654
656
657
658
659// Helpers =============================================================================================================
660
661public:
662
663 static constexpr matrix_t transpose(const transpose_t& mat) {
664 return matrix_t(fennec::row(mat, ColIndicesV)...);
665 }
666
667private:
668
669 // ReSharper disable once CppMemberFunctionMayBeStatic
670 template<size_t i0 = 0>
671 constexpr void _construct() {
672 // base case, does nothing, this will get optimized away
673 }
674
675 // helper for parsing parameter packs
676 template<size_t i0 = 0, typename HeadT, typename...RestT>
677 constexpr void _construct(HeadT&& head, RestT&&...rest) {
678 matrix::_insert<i0>(head); // insert the head element
679 matrix::_construct<i0 + component_count_v<HeadT>>(std::forward<RestT>(rest)...); // propagate to the rest of the arguments
680 }
681
682 // helper for inserting a scalar value
683 template<size_t i0 = 0>
684 constexpr void _insert(scalar_t s) {
685 data[i0 / rows][i0 % rows] = s;
686 }
687
688 // helper for inserting a scalar value of differing type
689 template<size_t i0 = 0, typename OScalarT> requires(is_arithmetic_v<OScalarT>)
690 constexpr void _insert(OScalarT s) {
691 data[i0 / rows][i0 % rows] = scalar_t(s);
692 }
693
694 // helper for inserting a vector
695 template<size_t i0 = 0, size_t...i>
696 constexpr void _insert(const vector<scalar_t, i...>& v) {
697 (matrix::_insert<i0 + i>(v[i]), ...);
698 }
699
700 // helper for inserting a vector of differing type
701 template<size_t i0 = 0, typename OScalarT, size_t...i>
702 constexpr void _insert(const vector<OScalarT, i...>& v) {
703 (matrix::_insert<i0 + i>(v[i]), ...);
704 }
705
706 // helper for a linear algebraic multiply
707 static constexpr column_t _mul(const matrix_t& lhs, const row_t& rhs) {
708 // the compiler will optimize this better than writing out a specific definition
709 // when compared to glm or CxxSwizzle, this is faster by a significant margin
710 // all implementations provide 7 decimal places of precision
711 return ((lhs[ColIndicesV] * rhs[ColIndicesV]) + ...);
712 }
713};
714
715
716// Internal ============================================================================================================
717
718}
719
720
721#endif // FENNEC_MATH_MATRIX_H
A header containing the definition for a static/stack allocated array.
Geometric
constexpr genType y()
Definition constants.h:672
decltype(detail::_gen_vector< vector, ScalarT >(make_index_metasequence< SizeV >{})) vec
Main vector template.
Definition vector.h:124
constexpr size_t total_component_count_v
shorthand for component_count<T>::value
Definition vector_traits.h:102