utility 2026.1.9
A comprehensive C++ utilities library tailored for the development of modern desktop and extended reality (XR) applications.
Loading...
Searching...
No Matches
matrix.hpp
1/*
2 Copyright (c) 2026 ETIB Corporation
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in
6 the Software without restriction, including without limitation the rights to
7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8 of the Software, and to permit persons to whom the Software is furnished to do
9 so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 */
22
23#pragma once
24
25#include <cmath>
26#include <stdexcept>
27#include <string>
28#include <type_traits>
29#include <utility>
30#include <ostream>
31
32#include <glm/matrix.hpp>
33
34#include <glm/ext/matrix_clip_space.hpp>
35#include <glm/ext/matrix_transform.hpp>
36
37#include <glm/mat2x2.hpp>
38#include <glm/mat2x3.hpp>
39#include <glm/mat2x4.hpp>
40#include <glm/mat3x2.hpp>
41#include <glm/mat3x3.hpp>
42#include <glm/mat3x4.hpp>
43#include <glm/mat4x2.hpp>
44#include <glm/mat4x3.hpp>
45#include <glm/mat4x4.hpp>
46
47namespace utility::math
48{
49
50 using glm::determinant;
51 using glm::inverse;
52 using glm::matrixCompMult;
53 using glm::outerProduct;
54 using glm::transpose;
55
56 using glm::frustum;
57 using glm::infinitePerspective;
58 using glm::ortho;
59 using glm::perspective;
60 using glm::perspectiveFov;
61 using glm::perspectiveLH;
62 using glm::perspectiveRH;
63 using glm::tweakedInfinitePerspective;
64
65 using glm::identity;
66 using glm::lookAt;
67 using glm::lookAtLH;
68 using glm::lookAtRH;
69 using glm::rotate;
70 using glm::scale;
71 using glm::translate;
72
77 template<typename Type>
78 concept CanBeMatrixComponent = std::is_floating_point_v<Type>;
79
87 template<CanBeMatrixComponent MatrixComponentType, std::size_t Cols,
88 std::size_t Rows,
89 typename = std::enable_if_t<(Cols >= 2) && (Cols <= 4)
90 && (Rows >= 2) && (Rows <= 4)>>
91 class Matrix: public glm::mat<Cols, Rows, MatrixComponentType>
92 {
93 public:
98 Matrix(void)
99 : glm::mat<Cols, Rows, MatrixComponentType>(
100 MatrixComponentType { 0 })
101 {
102 if constexpr (Cols == Rows) {
103 *static_cast<glm::mat<Cols, Rows, MatrixComponentType> *>(
104 this) =
105 glm::mat<Cols, Rows, MatrixComponentType>(
106 MatrixComponentType { 1 });
107 }
108 }
109
116 Matrix(std::initializer_list<MatrixComponentType> values)
117 {
118 if (values.size() != Cols * Rows) {
119 throw std::invalid_argument("Matrix requires exactly "
120 + std::to_string(Cols * Rows)
121 + " components");
122 }
123 const auto it = values.begin();
124 for (std::size_t row = 0; row < Rows; ++row) {
125 for (std::size_t col = 0; col < Cols; ++col) {
126 (*this)[col][row] = *(it + row * Cols + col);
127 }
128 }
129 }
130
135 explicit Matrix(MatrixComponentType value)
136 : glm::mat<Cols, Rows, MatrixComponentType>(value)
137 {
138 }
139
144 explicit Matrix(const glm::mat<Cols, Rows, MatrixComponentType> &value)
145 : glm::mat<Cols, Rows, MatrixComponentType>(value)
146 {
147 }
148
153 Matrix(const Matrix &other) = default;
154
159 Matrix(Matrix &&other) noexcept = default;
160
164 ~Matrix(void) = default;
165
171 Matrix &operator=(const Matrix &other) = default;
172
178 Matrix &operator=(Matrix &&other) noexcept = default;
179
185 Matrix operator+(const Matrix &rhs) const noexcept
186 {
187 return Matrix(
188 static_cast<const glm::mat<Cols, Rows, MatrixComponentType> &>(
189 *this)
190 + static_cast<
191 const glm::mat<Cols, Rows, MatrixComponentType> &>(rhs));
192 }
193
199 Matrix &operator+=(const Matrix &rhs) noexcept
200 {
201 *static_cast<glm::mat<Cols, Rows, MatrixComponentType> *>(this) +=
202 static_cast<const glm::mat<Cols, Rows, MatrixComponentType> &>(
203 rhs);
204 return *this;
205 }
206
212 Matrix operator-(const Matrix &rhs) const noexcept
213 {
214 return Matrix(
215 static_cast<const glm::mat<Cols, Rows, MatrixComponentType> &>(
216 *this)
217 - static_cast<
218 const glm::mat<Cols, Rows, MatrixComponentType> &>(rhs));
219 }
220
226 Matrix &operator-=(const Matrix &rhs) noexcept
227 {
228 *static_cast<glm::mat<Cols, Rows, MatrixComponentType> *>(this) -=
229 static_cast<const glm::mat<Cols, Rows, MatrixComponentType> &>(
230 rhs);
231 return *this;
232 }
233
239 Matrix operator*(MatrixComponentType scalar) const noexcept
240 {
241 return Matrix(
242 static_cast<const glm::mat<Cols, Rows, MatrixComponentType> &>(
243 *this)
244 * scalar);
245 }
246
252 Matrix &operator*=(MatrixComponentType scalar) noexcept
253 {
254 *static_cast<glm::mat<Cols, Rows, MatrixComponentType> *>(this) *=
255 scalar;
256 return *this;
257 }
258
265 Matrix operator/(MatrixComponentType scalar) const
266 {
267 if (scalar == MatrixComponentType { 0 }) {
268 throw std::invalid_argument("Matrix division by zero");
269 }
270 return Matrix(
271 static_cast<const glm::mat<Cols, Rows, MatrixComponentType> &>(
272 *this)
273 / scalar);
274 }
275
282 Matrix &operator/=(MatrixComponentType scalar)
283 {
284 if (scalar == MatrixComponentType { 0 }) {
285 throw std::invalid_argument("Matrix division by zero");
286 }
287 *static_cast<glm::mat<Cols, Rows, MatrixComponentType> *>(this) /=
288 scalar;
289 return *this;
290 }
291
301 template<std::size_t RhsCols, std::size_t RhsRows>
302 requires(Cols == RhsRows)
305 const noexcept
306 {
307 using LhsGlm = glm::mat<Cols, Rows, MatrixComponentType>;
308 using RhsGlm = glm::mat<RhsCols, RhsRows, MatrixComponentType>;
310 static_cast<const LhsGlm &>(*this)
311 * static_cast<const RhsGlm &>(rhs));
312 }
313
319 Matrix &operator*=(const Matrix &rhs) noexcept
320 requires(Cols == Rows)
321 {
322 *static_cast<glm::mat<Cols, Rows, MatrixComponentType> *>(this) =
323 static_cast<const glm::mat<Cols, Rows, MatrixComponentType> &>(
324 *this)
325 * static_cast<
326 const glm::mat<Cols, Rows, MatrixComponentType> &>(rhs);
327 return *this;
328 }
329
338 bool operator==(const Matrix &rhs) const noexcept
339 {
340 return static_cast<
341 const glm::mat<Cols, Rows, MatrixComponentType> &>(*this)
342 == static_cast<
343 const glm::mat<Cols, Rows, MatrixComponentType> &>(rhs);
344 }
345
355 bool equalsEpsilon(const Matrix &rhs,
356 MatrixComponentType epsilon = MatrixComponentType {
357 1e-5 }) const
358 {
359 for (std::size_t col = 0; col < Cols; ++col) {
360 for (std::size_t row = 0; row < Rows; ++row) {
361 if (std::abs((*this)[col][row] - rhs[col][row]) > epsilon) {
362 return false;
363 }
364 }
365 }
366 return true;
367 }
368
374 bool operator!=(const Matrix &rhs) const noexcept
375 {
376 return !(*this == rhs);
377 }
378
383 Matrix operator-(void) const noexcept
384 {
385 return Matrix(
386 -static_cast<const glm::mat<Cols, Rows, MatrixComponentType> &>(
387 *this));
388 }
389
397 friend Matrix operator*(MatrixComponentType scalar, const Matrix &mat)
398 {
399 return mat * scalar;
400 }
401 };
402
406 using Matrix2x2F = Matrix<float, 2, 2>;
407
411 using Matrix2x2D = Matrix<double, 2, 2>;
412
416 using Matrix2x3F = Matrix<float, 2, 3>;
417
421 using Matrix2x3D = Matrix<double, 2, 3>;
422
426 using Matrix2x4F = Matrix<float, 2, 4>;
427
431 using Matrix2x4D = Matrix<double, 2, 4>;
432
436 using Matrix3x2F = Matrix<float, 3, 2>;
437
441 using Matrix3x2D = Matrix<double, 3, 2>;
442
446 using Matrix3x3F = Matrix<float, 3, 3>;
447
451 using Matrix3x3D = Matrix<double, 3, 3>;
452
456 using Matrix3x4F = Matrix<float, 3, 4>;
457
461 using Matrix3x4D = Matrix<double, 3, 4>;
462
466 using Matrix4x2F = Matrix<float, 4, 2>;
467
471 using Matrix4x2D = Matrix<double, 4, 2>;
472
476 using Matrix4x3F = Matrix<float, 4, 3>;
477
481 using Matrix4x3D = Matrix<double, 4, 3>;
482
486 using Matrix4x4F = Matrix<float, 4, 4>;
487
491 using Matrix4x4D = Matrix<double, 4, 4>;
492
499 std::ostream &operator<<(std::ostream &stream, const Matrix2x2F &matrix);
500
507 std::ostream &operator<<(std::ostream &stream, const Matrix2x2D &matrix);
508
515 std::ostream &operator<<(std::ostream &stream, const Matrix4x4F &matrix);
516
523 std::ostream &operator<<(std::ostream &stream, const Matrix4x4D &matrix);
524
531 std::ostream &operator<<(std::ostream &stream, const Matrix3x3F &matrix);
532
539 std::ostream &operator<<(std::ostream &stream, const Matrix3x3D &matrix);
540
547 std::ostream &operator<<(std::ostream &stream, const Matrix3x4F &matrix);
548
555 std::ostream &operator<<(std::ostream &stream, const Matrix3x4D &matrix);
556
563 std::ostream &operator<<(std::ostream &stream, const Matrix4x3F &matrix);
564
571 std::ostream &operator<<(std::ostream &stream, const Matrix4x3D &matrix);
572
579 std::ostream &operator<<(std::ostream &stream, const Matrix2x3F &matrix);
580
587 std::ostream &operator<<(std::ostream &stream, const Matrix2x3D &matrix);
588
595 std::ostream &operator<<(std::ostream &stream, const Matrix2x4F &matrix);
596
603 std::ostream &operator<<(std::ostream &stream, const Matrix2x4D &matrix);
604
611 std::ostream &operator<<(std::ostream &stream, const Matrix3x2F &matrix);
612
619 std::ostream &operator<<(std::ostream &stream, const Matrix3x2D &matrix);
620
627 std::ostream &operator<<(std::ostream &stream, const Matrix4x2F &matrix);
628
635 std::ostream &operator<<(std::ostream &stream, const Matrix4x2D &matrix);
636
643 std::ostream &operator<<(std::ostream &stream, const Matrix4x4F &matrix);
644
651 std::ostream &operator<<(std::ostream &stream, const Matrix4x4D &matrix);
652
653} // namespace utility::math
M x N matrix class inheriting from glm::mat<Cols, Rows, Type>.
Definition matrix.hpp:92
bool equalsEpsilon(const Matrix &rhs, MatrixComponentType epsilon=MatrixComponentType { 1e-5 }) const
Approximate equality using an epsilon threshold.
Definition matrix.hpp:355
Matrix & operator*=(const Matrix &rhs) noexcept
Matrix multiplication assignment (square matrices only).
Definition matrix.hpp:319
~Matrix(void)=default
Default destructor for Matrix.
Matrix & operator=(const Matrix &other)=default
Copy assignment operator.
Matrix & operator-=(const Matrix &rhs) noexcept
Matrix subtraction assignment.
Definition matrix.hpp:226
Matrix & operator*=(MatrixComponentType scalar) noexcept
Scalar multiplication assignment.
Definition matrix.hpp:252
Matrix(const glm::mat< Cols, Rows, MatrixComponentType > &value)
Construct from a GLM matrix.
Definition matrix.hpp:144
Matrix operator-(void) const noexcept
Unary negation.
Definition matrix.hpp:383
bool operator!=(const Matrix &rhs) const noexcept
Inequality comparison.
Definition matrix.hpp:374
friend Matrix operator*(MatrixComponentType scalar, const Matrix &mat)
Friend function for scalar multiplication with scalar on the left.
Definition matrix.hpp:397
Matrix & operator+=(const Matrix &rhs) noexcept
Matrix addition assignment.
Definition matrix.hpp:199
bool operator==(const Matrix &rhs) const noexcept
Equality comparison.
Definition matrix.hpp:338
Matrix(MatrixComponentType value)
Construct by filling all components with the same value.
Definition matrix.hpp:135
Matrix(void)
Default constructor initializing square matrices to identity and non-square matrices to zero.
Definition matrix.hpp:98
Matrix operator*(MatrixComponentType scalar) const noexcept
Scalar multiplication.
Definition matrix.hpp:239
Matrix & operator=(Matrix &&other) noexcept=default
Move assignment operator.
Matrix(const Matrix &other)=default
Copy constructor.
Matrix operator+(const Matrix &rhs) const noexcept
Matrix addition.
Definition matrix.hpp:185
Matrix & operator/=(MatrixComponentType scalar)
Scalar division assignment.
Definition matrix.hpp:282
Matrix operator-(const Matrix &rhs) const noexcept
Matrix subtraction.
Definition matrix.hpp:212
Matrix operator/(MatrixComponentType scalar) const
Scalar division.
Definition matrix.hpp:265
Matrix(std::initializer_list< MatrixComponentType > values)
Construct from initializer list of Cols*Rows values (row-major order).
Definition matrix.hpp:116
Matrix(Matrix &&other) noexcept=default
Move constructor.
Concept to constrain matrix component type.
Definition matrix.hpp:78