Maipa's Standard Library Extension 1.5.6
mstd
Loading...
Searching...
No Matches
mat.hpp
1/*
2 * mstd - Maipa's Standard Library
3 *
4 * Licensed under the BSD 3-Clause License with Attribution Requirement.
5 * See the LICENSE file for details: https://github.com/MAIPA01/mstd/blob/main/LICENSE
6 *
7 * Copyright (c) 2025, Patryk Antosik (MAIPA01)
8 *
9 * Tested and fixed by Muppetsg2 (https://github.com/Muppetsg2)
10 */
11
12#pragma once
13#ifndef _MSTD_MAT_HPP_
14 #define _MSTD_MAT_HPP_
15
16 #include <mstd/config.hpp>
17
19_MSTD_WARNING("this is only available for c++17 and greater!");
20 #else
21
22 #include <mstd/vec.hpp>
23
24 #undef far
25 #undef near
26
27namespace mstd {
29 template<size_t C, size_t R, arithmetic T>
30 requires (C > 0 && R > 0)
31 #else
32 template<size_t C, size_t R, class T, std::enable_if_t<(C > 0 && R > 0 && std::is_arithmetic_v<T>), bool> >
33 #endif
34 class mat {
35 public:
36 static _MSTD_CONSTEXPR17 const size_t columns = C;
37 static _MSTD_CONSTEXPR17 const size_t rows = R;
38 static _MSTD_CONSTEXPR17 const size_t size = R * C;
39 using column_type = vec<R, T>;
40 using row_type = vec<C, T>;
41 using value_type = T;
42
43 #pragma region COLUMN_CLASS
44
45 class mat_column {
46 private:
47 using mat_type = mat<C, R, T>;
48
50 size_t _column;
51
52 public:
54
56
58 for (size_t y = 0; y != R; ++y) { _parent->_values[_column][y] = other[y]; }
59 return *this;
60 }
61
63 for (size_t y = 0; y != R; ++y) { _parent->_values[_column][y] = other[y]; }
64 return *this;
65 }
66
67 _MSTD_CONSTEXPR20 bool operator==(const mat_column& other) const {
68 for (size_t y = 0; y != R; ++y) {
69 if (_parent->_values[_column][y] != other[y]) { return false; }
70 }
71 return true;
72 }
73
74 _MSTD_CONSTEXPR20 bool operator!=(const mat_column& other) const { return !this->operator==(other); }
75
76 _MSTD_CONSTEXPR20 T& operator[](const size_t& idx) { return _parent->_values[_column][idx]; }
77
78 _MSTD_CONSTEXPR20 T operator[](const size_t& idx) const { return _parent->_values[_column][idx]; }
79
81
82 _MSTD_CONSTEXPR20 operator const T*() const { return _parent->_values[_column]; }
83
86 for (size_t y = 0; y != R; ++y) { res[y] = _parent->_values[_column][y]; }
87 return res;
88 }
89 };
90
92 private:
93 using mat_type = mat<C, R, T>;
94
96 size_t _column;
97
98 public:
100
102
104
105 _MSTD_CONSTEXPR20 bool operator==(const mat_column& other) const {
106 for (size_t y = 0; y != R; ++y) {
107 if (_parent->_values[_column][y] != other[y]) { return false; }
108 }
109 return true;
110 }
111
112 _MSTD_CONSTEXPR20 bool operator!=(const mat_column& other) const { return !this->operator==(other); }
113
114 _MSTD_CONSTEXPR20 bool operator==(const const_mat_column& other) const {
115 for (size_t y = 0; y != R; ++y) {
116 if (_parent->_values[_column][y] != other[y]) { return false; }
117 }
118 return true;
119 }
120
121 _MSTD_CONSTEXPR20 bool operator!=(const const_mat_column& other) const { return !this->operator==(other); }
122
123 _MSTD_CONSTEXPR20 T operator[](const size_t& idx) const { return _parent->_values[_column][idx]; }
124
125 _MSTD_CONSTEXPR20 operator const T*() const { return _parent->_values[_column]; }
126
129 for (size_t y = 0; y != R; ++y) { res[y] = _parent->_values[_column][y]; }
130 return res;
131 }
132 };
133
134 #pragma endregion // COLUMN_CLASS
135 private:
136 T _values[C][R] = {};
137
138 #pragma region PRIVATE_METHODS
140 template<arithmetic... Ts, size_t... Idxs>
141 #else
142 template<class... Ts, size_t... Idxs, std::enable_if_t<are_arithmetic_v<Ts...>, bool> = true>
143 #endif
144 _MSTD_CONSTEXPR20 void _set_values(const std::index_sequence<Idxs...>&, const Ts&... values) {
145 ((_values[Idxs / R][Idxs % R] = static_cast<T>(values)), ...);
146 }
147
149 template<size_t VN, arithmetic VT>
150 #else
151 template<size_t VN, class VT, std::enable_if_t<std::is_arithmetic_v<VT>, bool> = true>
152 #endif
153 _MSTD_CONSTEXPR20 void _set_column(const size_t idx, const vec<VN, VT>& column) {
154 size_t maxSize = std::min(VN, R);
155 if _MSTD_CONSTEXPR17 (std::is_same_v<T, VT>) {
156 std::copy_n(static_cast<const T*>(column), maxSize, &_values[idx]);
157 }
158 else {
159 for (size_t y = 0; y != maxSize; ++y) { _values[idx][y] = (T)column[y]; }
160 }
161 _fill_column_from(maxSize, idx, T(0));
162 }
163
165 template<size_t VN, arithmetic... Ts, size_t... Idxs>
166 #else
167 template<size_t VN, class... Ts, size_t... Idxs, std::enable_if_t<are_arithmetic_v<Ts...>, bool> = true>
168 #endif
169 _MSTD_CONSTEXPR20 void _set_values(const std::index_sequence<Idxs...>&, const vec<VN, Ts>&... columns) {
170 (_set_column(Idxs, columns), ...);
171 }
172
173 _MSTD_CONSTEXPR20 void _fill_column(size_t colIdx, const T& value) {
174 if (colIdx >= C) { return; }
175 std::fill_n(&_values[colIdx], C, value);
176 }
177
178 _MSTD_CONSTEXPR20 void _fill_column_from(size_t firstIdx, size_t colIdx, const T& value) {
179 if (colIdx >= C) { return; }
180 if (firstIdx >= R) { return; }
181 std::fill_n(&_values[colIdx][firstIdx], R - firstIdx, value);
182 }
183
184 _MSTD_CONSTEXPR20 void _fill_values(const T& value) { std::fill_n(&_values[0][0], R * C, value); }
185
186 _MSTD_CONSTEXPR20 void _fill_values_from(size_t firstIdx, const T& value) {
187 if (firstIdx >= size) { return; }
188 std::fill_n(&_values[0][0] + firstIdx, size - firstIdx, value);
189 }
190
192 std::fill_n(&_values[0][0], size, T(0));
193 size_t minSize = std::min(C, R);
194 for (size_t i = 0; i != minSize; ++i) { _values[i][i] = value; }
195 }
196
198 template<arithmetic OT>
199 #else
200 template<class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
201 #endif
202 _MSTD_CONSTEXPR20 void _copy_values_from(const OT* values, size_t size) {
203 if _MSTD_CONSTEXPR17 (std::is_same_v<T, OT>) {
204 std::copy_n(values, std::min(mat<C, R, T>::size, size), &_values[0][0]);
205 }
206 else {
207 size_t sizeLeft = size;
208 for (size_t x = 0; x != C; ++x) {
209 for (size_t y = 0; y != std::min(sizeLeft, R); ++y) {
210 _values[x][y] = static_cast<T>(values[x][y]);
211 }
212 if (sizeLeft <= R) { break; }
213 sizeLeft -= R;
214 }
215 }
216 }
217
219 template<arithmetic OT>
220 #else
221 template<class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
222 #endif
223 _MSTD_CONSTEXPR20 void _copy_values_from(const OT* values, size_t columns, size_t rows) {
224 size_t colSize = std::min(columns, C);
225 size_t rowSize = std::min(rows, R);
226 if _MSTD_CONSTEXPR17 (std::is_same_v<T, OT>) {
227 for (size_t x = 0; x != colSize; ++x) {
228 std::copy_n(&values[x * rowSize], rowSize, &_values[x]);
229 _fill_column_from(rowSize, x, static_cast<T>(0));
230 }
231 }
232 else {
233 for (size_t x = 0; x != colSize; ++x) {
234 for (size_t y = 0; y != rowSize; ++y) { _values[x][y] = static_cast<T>(values[x][y]); }
235 _fill_column_from(rowSize, x, static_cast<T>(0));
236 }
237 }
238 }
239
241 template<size_t ON, arithmetic OT>
242 #else
243 template<size_t ON, class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
244 #endif
245 _MSTD_CONSTEXPR20 void _copy_values_from(const OT (&values)[ON]) {
246 _copy_values_from(&values, ON);
247 }
248
250 template<size_t OC, size_t OR, arithmetic OT>
251 #else
252 template<size_t OC, size_t OR, class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
253 #endif
254 _MSTD_CONSTEXPR20 void _copy_values_from(const OT (&values)[OC][OR]) {
255 _copy_values_from(&values, OC, OR);
256 }
257
259 template<size_t VN, arithmetic OT>
260 #else
261 template<size_t VN, class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
262 #endif
263 _MSTD_CONSTEXPR20 void _copy_values_from(const vec<VN, OT>* columns, size_t size) {
264 size_t colSize = std::min(C, size);
265 size_t rowSize = std::min(VN, R);
266 if _MSTD_CONSTEXPR17 (std::is_same_v<T, OT>) {
267 for (size_t x = 0; x != colSize; ++x) {
268 std::copy_n(static_cast<const T*>(columns[x]), rowSize, &_values[x][0]);
269 _fill_column_from(rowSize, x, static_cast<T>(0));
270 }
271 }
272 else {
273 for (size_t x = 0; x != colSize; ++x) {
274 for (size_t y = 0; y != rowSize; ++y) { _values[x][y] = static_cast<T>(columns[x][y]); }
275 _fill_column_from(rowSize, x, static_cast<T>(0));
276 }
277 }
278 }
279
281 template<size_t VN, size_t N, arithmetic OT>
282 #else
283 template<size_t VN, size_t N, class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
284 #endif
285 _MSTD_CONSTEXPR20 void _copy_values_from(const vec<VN, OT> (&columns)[N]) {
286 _copy_values_from(&columns, N);
287 }
288
290 template<size_t OC, size_t OR, arithmetic OT>
291 #else
292 template<size_t OC, size_t OR, class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
293 #endif
294 _MSTD_CONSTEXPR20 void _copy_values_from(const mat<OC, OR, OT>& other) {
295 size_t colSize = std::min(OC, C);
296 size_t rowSize = std::min(OR, R);
297 if _MSTD_CONSTEXPR17 (std::is_same_v<T, OT>) {
298 for (size_t x = 0; x != colSize; ++x) {
299 std::copy_n(static_cast<const T*>(other[x]), rowSize, &_values[x][0]);
300 _fill_column_from(rowSize, x, static_cast<T>(0));
301 }
302 }
303 else {
304 for (size_t x = 0; x != colSize; ++x) {
305 for (size_t y = 0; y != rowSize; ++y) { _values[x][y] = static_cast<T>(other[x][y]); }
306 _fill_column_from(rowSize, x, static_cast<T>(0));
307 }
308 }
309 }
310
311 #pragma endregion // PRIVATE_METHOD
312
313 public:
314 #pragma region CONSTRUCTORS
315
316 _MSTD_CONSTEXPR20 mat() { _fill_values(0); }
317
319 template<arithmetic OT>
320 #else
321 template<class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
322 #endif
323 _MSTD_CONSTEXPR20 mat(const OT* values, size_t size) {
324 _copy_values_from(values, size);
325 _fill_values_from(size, static_cast<T>(0));
326 }
327
329 template<arithmetic OT>
330 #else
331 template<class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
332 #endif
333 _MSTD_CONSTEXPR20 mat(const OT* values, size_t columns, size_t rows) {
334 _copy_values_from(values, columns, rows);
335 _fill_values_from(columns * R, static_cast<T>(0));
336 }
338 template<size_t ON, arithmetic OT>
339 #else
340 template<size_t ON, class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
341 #endif
342 _MSTD_CONSTEXPR20 mat(const OT (&values)[ON]) : mat(&values, ON) {
343 }
345 template<size_t OC, size_t OR, arithmetic OT>
346 #else
347 template<size_t OC, size_t OR, class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
348 #endif
349 _MSTD_CONSTEXPR20 mat(const OT (&values)[OC][OR]) : mat(&values, OC, OR) {
350 }
352 template<arithmetic... Ts>
353 requires (sizeof...(Ts) > 0 && sizeof...(Ts) <= size)
354 #else
355 template<class... Ts,
356 std::enable_if_t<((sizeof...(Ts) > 0) && (sizeof...(Ts) <= size) && mstd::are_arithmetic_v<Ts...>), bool> = true>
357 #endif
358 _MSTD_CONSTEXPR20 mat(const Ts&... values) {
359 _set_values(std::index_sequence_for<Ts...>(), values...);
360 _fill_values_from(sizeof...(Ts), static_cast<T>(0));
361 }
363 template<size_t VN, arithmetic OT>
364 #else
365 template<size_t VN, class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
366 #endif
367 _MSTD_CONSTEXPR20 mat(const vec<VN, OT>* columns, size_t size) {
368 _copy_values_from(columns, size);
369 _fill_values_from(size * R, static_cast<T>(0));
370 }
372 template<size_t N, size_t VN, arithmetic OT>
373 #else
374 template<size_t N, size_t VN, class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
375 #endif
376 _MSTD_CONSTEXPR20 mat(const vec<VN, OT> (&columns)[N]) : mat(&columns, N) {
377 }
379 template<size_t VN, arithmetic... Ts>
380 requires (sizeof...(Ts) > 0 && sizeof...(Ts) <= C)
381 #else
382 template<size_t VN, class... Ts, std::enable_if_t<(sizeof...(Ts) > 0 && sizeof...(Ts) <= C), bool> = true>
383 #endif
384 _MSTD_CONSTEXPR20 mat(const vec<VN, Ts>&... columns) {
385 _set_values(std::index_sequence_for<Ts...>(), columns...);
386 _fill_values_from(sizeof...(Ts) * R, static_cast<T>(0));
387 }
389 template<size_t OC, size_t OR, arithmetic OT>
390 #else
391 template<size_t OC, size_t OR, class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
392 #endif
393 _MSTD_CONSTEXPR20 mat(const mat<OC, OR, OT>& other) {
394 _copy_values_from(other);
395 _fill_values_from(OC * R, static_cast<T>(0));
396 }
397
398 #pragma endregion // CONSTRUCTORS
399
400 #pragma region DESTRUCTOR
401 _MSTD_CONSTEXPR20 ~mat() noexcept = default;
402 #pragma endregion // DESTRUCTOR
403
404 #pragma region ASSIGN
406 template<size_t ON, arithmetic OT>
407 #else
408 template<size_t ON, class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
409 #endif
410 _MSTD_CONSTEXPR20 mat<C, R, T>& operator=(const OT (&values)[ON]) {
411 _copy_values_from(values);
412 _fill_values_from(ON, static_cast<T>(0));
413 return *this;
414 }
416 template<size_t OC, size_t OR, arithmetic OT>
417 #else
418 template<size_t OC, size_t OR, class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
419 #endif
420 _MSTD_CONSTEXPR20 mat<C, R, T>& operator=(const OT (&values)[OC][OR]) {
421 _copy_values_from(values);
422 _fill_values_from(OC * R, static_cast<T>(0));
423 return *this;
424 }
426 template<size_t VN, arithmetic OT, size_t N>
427 #else
428 template<size_t VN, class OT, size_t N, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
429 #endif
430 _MSTD_CONSTEXPR20 mat<C, R, T>& operator=(const vec<VN, OT> (&columns)[N]) {
431 _copy_values_from(columns);
432 _fill_values_from(N * R, static_cast<T>(0));
433 return *this;
434 }
436 template<size_t OC, size_t OR, arithmetic OT>
437 #else
438 template<size_t OC, size_t OR, class OT, std::enable_if_t<std::is_arithmetic_v<OT>, bool> = true>
439 #endif
440 _MSTD_CONSTEXPR20 mat<C, R, T>& operator=(const mat<OC, OR, OT>& other) {
441 _copy_values_from(other);
442 _fill_values_from(OC * R, static_cast<T>(0));
443 return *this;
444 }
445
446 #pragma endregion // ASSIGN
447
448 #pragma region PREDEFINED
449
450 static _MSTD_CONSTEXPR20 mat<C, R, T> zero() { return mat<C, R, T>(); }
451
452 static _MSTD_CONSTEXPR20 mat<C, R, T> one() { return fill(static_cast<T>(1)); }
453
454 static _MSTD_CONSTEXPR20 mat<C, R, T> fill(const T& value) {
455 mat<C, R, T> res;
456 res._fill_values(value);
457 return res;
458 }
459
460 #pragma region PREDEFINED_SQUARE_MATRIX
461 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && std::is_same_v<Type, value_type>))
462
463 static _MSTD_CONSTEXPR20 mat<C, R, T> identity() _MSTD_REQUIRES(C == R) { return fill_identity(static_cast<T>(1)); }
464 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && std::is_same_v<Type, value_type>))
465
466 static _MSTD_CONSTEXPR20 mat<C, R, T> fill_identity(const T& value) _MSTD_REQUIRES(C == R) {
467 mat<C, R, T> res;
468 res._set_identity_values(value);
469 return res;
470 }
471
472 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && R > 1 && std::is_same_v<Type, value_type>))
473
474 static _MSTD_CONSTEXPR20 mat<C, R, T> translation(const vec<R - 1, T>& transVec) _MSTD_REQUIRES(C == R && R > 1) {
475 mat<C, R, T> res = mat<C, R, T>::identity();
476 for (size_t y = 0; y != R - 1; ++y) { res[C - 1][y] = transVec[y]; }
477 return res;
478 }
479
480 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && R > 1 && std::is_same_v<Type, value_type>))
481
482 static _MSTD_CONSTEXPR20 mat<C, R, T> scale(const vec<R - 1, T>& scaleVec) _MSTD_REQUIRES(C == R && R > 1) {
483 mat<C, R, T> res;
484 for (size_t i = 0; i != R - 1; ++i) { res[i][i] = scaleVec[i]; }
485 res[C - 1][R - 1] = T(1);
486 return res;
487 }
488
489 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && std::is_same_v<Type, value_type>))
490
491 static _MSTD_CONSTEXPR20 mat<C, R, T> scale(const T& scaleFactor) _MSTD_REQUIRES(C == R) {
492 return mat<C, R, T>::fill_identity(scaleFactor);
493 }
494
495 #pragma region PREDEFINED_MATRIX_3x3
496 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && C == 3 && std::is_same_v<Type, value_type>))
497
498 static _MSTD_CONSTEXPR20 mat<C, R, T> screen(const T& left, const T& right, const T& bottom, const T& top, const T& width,
499 const T& height) _MSTD_REQUIRES(C == R && C == 3) {
500 const T& invBt = 1.0 / (bottom - top);
501 const T& invRl = 1.0 / (right - left);
502
503 mat<C, R, T> res = mat<C, R, T>::zero();
504 res[0][0] = width * invRl;
505 res[2][0] = -width * left * invRl;
506 res[1][1] = height * invBt;
507 res[2][1] = -height * top * invBt;
508 return res;
509 }
510
511 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && C == 3 && std::is_same_v<Type, value_type>))
512
513 static _MSTD_CONSTEXPR20 mat<C, R, T> symetric_screen(const T& right, const T& top, const T& width,
514 const T& height) _MSTD_REQUIRES(C == R && C == 3) {
515 return screen(-right, right, -top, top, width, height);
516 }
517
518 #pragma endregion // PREDEFINED_MATRIX_3x3
519
520 #pragma region PREDEFINED_MATRIX_4x4
521 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && C == 4 && std::is_same_v<Type, value_type>))
522
523 static _MSTD_CONSTEXPR20 mat<C, R, T> rot_x(const T& radians) _MSTD_REQUIRES(C == R && C == 4) {
524 T cosA = static_cast<T>(std::cos(radians));
525 T sinA = static_cast<T>(std::sin(radians));
526
527 // 4x4
528 mat<C, R, T> res = mat<C, R, T>::identity();
529 res[1][1] = cosA;
530 res[2][1] = -sinA;
531 res[1][2] = sinA;
532 res[2][2] = cosA;
533 return res;
534 }
535
536 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && C == 4 && std::is_same_v<Type, value_type>))
537
538 static _MSTD_CONSTEXPR20 mat<C, R, T> rot_y(const T& radians) _MSTD_REQUIRES(C == R && C == 4) {
539 T cosA = static_cast<T>(std::cos(radians));
540 T sinA = static_cast<T>(std::sin(radians));
541
542 // 4x4
543 mat<C, R, T> res = mat<C, R, T>::identity();
544 res[0][0] = cosA;
545 res[2][0] = sinA;
546 res[0][2] = -sinA;
547 res[2][2] = cosA;
548 return res;
549 }
550
551 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && C == 4 && std::is_same_v<Type, value_type>))
552
553 static _MSTD_CONSTEXPR20 mat<C, R, T> rot_z(const T& radians) _MSTD_REQUIRES(C == R && C == 4) {
554 T cosA = static_cast<T>(std::cos(radians));
555 T sinA = static_cast<T>(std::sin(radians));
556
557 // 4x4
558 mat<C, R, T> res = mat<C, R, T>::identity();
559 res[0][0] = cosA;
560 res[1][0] = -sinA;
561 res[0][1] = sinA;
562 res[1][1] = cosA;
563 return res;
564 }
565
566 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && C == 4 && std::is_same_v<Type, value_type>))
567
568 static _MSTD_CONSTEXPR20 mat<C, R, T> rot(const vec<R - 1, T>& axis, const T& radians) _MSTD_REQUIRES(C == R && C == 4) {
569 const T& sinA = static_cast<T>(std::sin(radians));
570 const T& cosA = static_cast<T>(std::cos(radians));
571 const T& oneMinCosA = static_cast<T>(1) - cosA;
572
573 vec<R - 1, T> normAxis = axis;
574 if (!normAxis.is_zero()) { normAxis.normalize(); }
575
576 mat<C, R, T> res = mat<C, R, T>::identity();
577 res[0][0] = (normAxis[0] * normAxis[0]) + (cosA * (1 - (normAxis[0] * normAxis[0])));
578 res[0][1] = ((normAxis[0] * normAxis[1]) * oneMinCosA) - (sinA * normAxis[2]);
579 res[0][2] = ((normAxis[0] * normAxis[2]) * oneMinCosA) - (sinA * normAxis[1]);
580
581 res[1][0] = ((normAxis[0] * normAxis[1]) * oneMinCosA) + (sinA * normAxis[2]);
582 res[1][1] = (normAxis[1] * normAxis[1]) + (cosA * (1 - (normAxis[1] * normAxis[1])));
583 res[1][2] = ((normAxis[1] * normAxis[2]) * oneMinCosA) - (sinA * normAxis[0]);
584
585 res[2][0] = ((normAxis[0] * normAxis[2]) * oneMinCosA) - (sinA * normAxis[1]);
586 res[2][1] = ((normAxis[1] * normAxis[2]) * oneMinCosA) + (sinA * normAxis[0]);
587 res[2][2] = (normAxis[2] * normAxis[2]) + (cosA * (1 - (normAxis[2] * normAxis[2])));
588
589 return res;
590 }
591
592 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && C == 4 && std::is_same_v<Type, value_type>))
593
594 static _MSTD_CONSTEXPR20 mat<C, R, T> rot(const quat<T>& quaternion) _MSTD_REQUIRES(C == R && C == 4) {
595 _MSTD_CONSTEXPR17 const float two = 2.f;
596
597 const T& x2 = quaternion.v[0] * quaternion.v[0];
598 const T& y2 = quaternion.v[1] * quaternion.v[1];
599 const T& z2 = quaternion.v[2] * quaternion.v[2];
600
601 const T& sx = quaternion.s * quaternion.v[0];
602 const T& sy = quaternion.s * quaternion.v[1];
603 const T& sz = quaternion.s * quaternion.v[2];
604 const T& xy = quaternion.v[0] * quaternion.v[1];
605 const T& xz = quaternion.v[0] * quaternion.v[2];
606 const T& yz = quaternion.v[1] * quaternion.v[2];
607
608 mat<C, R, T> res = mat<C, R, T>::identity();
609 res[0][0] = 1.f - (two * (y2 + z2));
610 res[1][0] = two * (xy - sz);
611 res[2][0] = two * (xz + sy);
612
613 res[0][1] = two * (xy + sz);
614 res[1][1] = 1.f - (two * (x2 + z2));
615 res[2][1] = two * (yz - sx);
616
617 res[0][2] = two * (xz - sy);
618 res[1][2] = two * (yz + sx);
619 res[2][2] = 1.f - (two * (x2 + y2));
620 return res;
621 }
622
623 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && C == 4 && std::is_same_v<Type, value_type>))
624
625 static _MSTD_CONSTEXPR20 mat<C, R, T> frustrum(const T& left, const T& right, const T& bottom, const T& top,
626 const T& near, const T& far, const T& resLeft = static_cast<T>(-1), const T& resRight = static_cast<T>(1),
627 const T& resBottom = static_cast<T>(-1), const T& resTop = static_cast<T>(1), const T& resNear = static_cast<T>(-1),
628 const T& resFar = static_cast<T>(1)) _MSTD_REQUIRES(C == R && C == 4) {
629 const T& absNear = std::abs(near);
630 const T& absFar = std::abs(far);
631
632 const T& xDir = right > left ? static_cast<T>(1) : static_cast<T>(-1);
633 const T& yDir = top > bottom ? static_cast<T>(1) : static_cast<T>(-1);
634 const T& zDir = -(xDir * yDir);
635
636 const T& invRl = right == left ? 0.f : (1.f / (right - left));
637 const T& invTb = top == bottom ? 0.f : (1.f / (top - bottom));
638 const T& invFn = absFar == absNear ? 0.f : (1.f / (absFar - absNear));
639
640 mat<C, R, T> res;
641 res[0][0] = (resRight - resLeft) * absNear * invRl;
642 res[2][0] = ((resLeft * right) - (resRight * left)) * zDir * invRl;
643 res[1][1] = (resTop - resBottom) * absNear * invTb;
644 res[2][1] = ((resBottom * top) - (resTop * bottom)) * zDir * invTb;
645 res[2][2] = ((resFar * absFar) - (resNear * absNear)) * zDir * invFn;
646 res[3][2] = (resNear - resFar) * absNear * absFar * invFn;
647 res[2][3] = zDir;
648 return res;
649 }
650
651 // left = -right, bottom = -top
652 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && C == 4 && std::is_same_v<Type, value_type>))
653
654 static _MSTD_CONSTEXPR20 mat<C, R, T> symetric_frustrum(const T& right, const T& top, const T& near, const T& far,
655 const T& resRight = static_cast<T>(1), const T& resTop = static_cast<T>(1), const T& resNear = static_cast<T>(-1),
656 const T& resFar = static_cast<T>(1)) _MSTD_REQUIRES(C == R && C == 4) {
657 return frustrum(-right, right, -top, top, near, far, -resRight, resRight, -resTop, resTop, resNear, resFar);
658 }
659
660 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && C == 4 && std::is_same_v<Type, value_type>))
661
662 static _MSTD_CONSTEXPR20 mat<C, R, T> perspective(const T& fov, const T& aspect, const T& near, const T& far,
663 bool rightPosX = true, bool topPosY = true, bool horizontalFov = true, const T& resRight = static_cast<T>(1),
664 const T& resTop = static_cast<T>(1), const T& resNear = static_cast<T>(-1),
665 const T& resFar = static_cast<T>(1)) _MSTD_REQUIRES(C == R && C == 4) {
666 _MSTD_CONSTEXPR17 const double half = 0.5;
667
668 const T& absNear = std::abs(near);
669 const T& absFar = std::abs(far);
670
671 T right;
672 T top;
673 if (horizontalFov) {
674 right = static_cast<T>(std::tan(fov * half) * absNear);
675 top = aspect == static_cast<T>(0) ? static_cast<T>(0) : (right / aspect);
676 }
677 else {
678 top = static_cast<T>(std::tan(fov * half) * absNear);
679 right = top * aspect;
680 }
681
682 return symetric_frustrum(rightPosX ? right : -right, topPosY ? top : -top, absNear, absFar, resRight, resTop, resNear,
683 resFar);
684 }
685
686 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && C == 4 && std::is_same_v<Type, value_type>))
687
688 static _MSTD_CONSTEXPR20 mat<C, R, T> ortographic(const T& left, const T& right, const T& bottom, const T& top,
689 const T& near, const T& far, const T& resLeft = static_cast<T>(-1), const T& resRight = static_cast<T>(1),
690 const T& resBottom = static_cast<T>(-1), const T& resTop = static_cast<T>(1), const T& resNear = static_cast<T>(-1),
691 const T& resFar = static_cast<T>(1)) _MSTD_REQUIRES(C == R && C == 4) {
692 const T& absNear = std::abs(near);
693 const T& absFar = std::abs(far);
694
695 const T& xDir = right > left ? static_cast<T>(1) : static_cast<T>(-1);
696 const T& yDir = top > bottom ? static_cast<T>(1) : static_cast<T>(-1);
697 const T& zDir = -(xDir * yDir);
698
699 const T& invRl = right == left ? 0.0 : (1.0 / (right - left));
700 const T& invTb = top == bottom ? 0.0 : (1.0 / (top - bottom));
701 const T& invFn = absFar == absNear ? 0.0 : (1.0 / (absFar - absNear));
702
703 mat<C, R, T> res;
704 res[0][0] = (resRight - resLeft) * invRl;
705 res[3][0] = ((resLeft * right) - (resRight * left)) * invRl;
706 res[1][1] = (resTop - resBottom) * invTb;
707 res[3][1] = ((resBottom * top) - (resTop * bottom)) * invTb;
708 res[2][2] = (resFar - resNear) * zDir * invFn;
709 res[3][2] = ((resNear * absFar) - (resFar * absNear)) * invFn;
710 res[3][3] = 1;
711 return res;
712 }
713
714 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && C == 4 && std::is_same_v<Type, value_type>))
715
716 static _MSTD_CONSTEXPR20 mat<C, R, T> symetric_ortographic(const T& right, const T& top, const T& near, const T& far,
717 const T& resRight = static_cast<T>(1), const T& resTop = static_cast<T>(1), const T& resNear = static_cast<T>(-1),
718 const T& resFar = static_cast<T>(1)) _MSTD_REQUIRES(C == R && C == 4) {
719 return ortographic(-right, right, -top, top, near, far, -resRight, resRight, -resTop, resTop, resNear, resFar);
720 }
721
722 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && C == 4 && std::is_same_v<Type, value_type>))
723
724 static _MSTD_CONSTEXPR20 mat<C, R, T> view(const vec<3ull, T>& pos, const vec<3ull, T>& right,
725 const vec<3ull, T>& forward, const vec<3ull, T>& up) _MSTD_REQUIRES(C == R && C == 4) {
726 mat<C, R, T> res;
727 res[0] = vec4(right[0], up[0], -forward[0], T(0));
728 res[1] = vec4(right[1], up[1], -forward[1], T(0));
729 res[2] = vec4(right[2], up[2], -forward[2], T(0));
730 res[3] = vec4(-pos[0], -pos[1], -pos[2], T(1));
731 return res;
732 }
733
734 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && C == 4 && std::is_same_v<Type, value_type>))
735
736 static _MSTD_CONSTEXPR20 mat<C, R, T> look_at(const vec<3ull, T>& eyePos, const vec<3ull, T>& lookAtPos,
737 const vec<3ull, T>& worldUp) _MSTD_REQUIRES(C == R && C == 4) {
738 using vec3_type = vec<3ull, T>;
739
740 vec3_type forward = (lookAtPos - eyePos).normalize();
741 vec3_type normWorldUp = worldUp.normalized();
742 vec3_type right = forward.cross(worldUp);
743 vec3_type up = right.cross(forward);
744
745 return view(eyePos, right, forward, up);
746 }
747
748 #pragma endregion // PREDEFINED_MATRIX_4x4
749 #pragma endregion // PREDEFINED_SQUARE_MATRIX
750 #pragma endregion // PREDEFINED
751
752 #pragma region PREDEFINED_CHECKS
753
754 _MSTD_CONSTEXPR20 bool is_zero() const { return is_filled_with(static_cast<T>(0)); }
755
756 _MSTD_CONSTEXPR20 bool is_one() const { return is_filled_with(T(1)); }
757
758 _MSTD_CONSTEXPR20 bool is_filled_with(const T& value) const {
759 for (size_t x = 0; x != C; ++x) {
760 for (size_t y = 0; y != R; ++y) {
761 if (_values[x][y] != value) { return false; }
762 }
763 }
764 return true;
765 }
766
767 #pragma region PREDEFINED_SQUARE_MATRIX_CHECKS
768 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && std::is_same_v<Type, value_type>))
769
770 _MSTD_CONSTEXPR20 bool is_identity() const _MSTD_REQUIRES(C == R) { return is_identity_filled_with(1); }
771
772 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && std::is_same_v<Type, value_type>))
773
774 _MSTD_CONSTEXPR20 bool is_identity_filled_with(const T& value) const _MSTD_REQUIRES(C == R) {
775 for (size_t x = 0; x != C; ++x) {
776 for (size_t y = 0; y != R; ++y) {
777 if ((x == y && mstd::is_not_equal(_values[x][y], value)) ||
778 (x != y && mstd::is_not_equal(_values[x][y], static_cast<T>(0)))) {
779 return false;
780 }
781 }
782 }
783 return true;
784 }
785
786 #pragma endregion // PREDEFINED_SQUARE_MATRIX_CHECKS
787 #pragma endregion // PREDEFINED_CHECKS
788
789 #pragma region MATRIX_OPERATIONS
790
791 _MSTD_CONSTEXPR20 mat<R, C, T> transposed() const {
792 mat<R, C, T> res;
793 for (size_t x = 0; x != C; ++x) {
794 for (size_t y = 0; y != R; ++y) { res[y][x] = _values[x][y]; }
795 }
796 return res;
797 }
798
799 _MSTD_CONSTEXPR20 _MSTD_RETURN_VALUE_IF(C > 1 && R > 1, mat<C - 1, R - 1, T>) get_sub_matrix(size_t rowIdx,
800 size_t colIdx) const _MSTD_REQUIRES(C > 1 && R > 1) {
801 mat<C - 1, R - 1, T> res;
802 for (size_t x = 0, subX = 0; x != C; ++x) {
803 if (x == colIdx) { continue; }
804 size_t subY = 0;
805
806 // kopiuje wartości kolumny od 0 do row_idx - 1
807 if (rowIdx != 0) {
808 std::copy_n(_values[x], std::min(rowIdx, R - 1), static_cast<T*>(res[subX]));
809 subY += rowIdx;
810 }
811 // kopiuje wartości kolumny od row_idx + 1 do R - 1
812 if (rowIdx != R - 1) {
813 std::copy_n(_values[x] + rowIdx + 1, R - rowIdx - 1, static_cast<T*>(res[subX]) + subY);
814 }
815 ++subX;
816 }
817 return res;
818 }
819
821 mat<C, R - 1, T>) get_sub_row_matrix(size_t rowIdx) const _MSTD_REQUIRES(R > 1) {
822 mat<C, R - 1, T> res;
823 for (size_t x = 0; x != C; ++x) {
824 size_t subY = 0;
825
826 // kopiuje wartości kolumny od 0 do row_idx - 1
827 if (rowIdx != 0) {
828 std::copy_n(_values[x], std::min(rowIdx, R - 1), static_cast<T*>(res[x]));
829 subY += rowIdx;
830 }
831 // kopiuje wartości kolumny od row_idx + 1 do R - 1
832 if (rowIdx != R - 1) {
833 std::copy_n(_values[x] + rowIdx + 1, R - 1 - rowIdx, static_cast<T*>(res[x]) + subY);
834 }
835 }
836 return res;
837 }
838
840 mat<C - 1, R, T>) get_sub_col_matrix(size_t colIdx) const _MSTD_REQUIRES(C > 1) {
841 mat<C - 1, R, T> res;
842 for (size_t x = 0, subX = 0; x != C; ++x) {
843 if (x == colIdx) { continue; }
844
845 // kopiuje wartości kolumny
846 std::copy_n(_values[x], R, static_cast<T*>(res[subX]));
847 ++subX;
848 }
849 return res;
850 }
851
852 _MSTD_CONSTEXPR20 mat<C, R, T>& clamp(const T& minVal, const T& maxVal) {
853 for (size_t x = 0; x != C; ++x) {
854 for (size_t y = 0; y != R; ++y) { _values[x][y] = std::clamp(_values[x][y], minVal, maxVal); }
855 }
856 return *this;
857 }
858
859 _MSTD_CONSTEXPR20 mat<C, R, T> clampped(const T& minVal, const T& maxVal) const {
860 mat<C, R, T> res = *this;
861 return res.clamp(minVal, maxVal);
862 }
863
864 _MSTD_CONSTEXPR20 mat<C, R, T>& clamp(const mat<C, R, T>& minVal, const mat<C, R, T>& maxVal) {
865 for (size_t x = 0; x != C; ++x) {
866 for (size_t y = 0; y != R; ++y) { _values[x][y] = std::clamp(_values[x][y], minVal[x][y], maxVal[x][y]); }
867 }
868 return *this;
869 }
870
871 _MSTD_CONSTEXPR20 mat<C, R, T> clampped(const mat<C, R, T>& minVal, const mat<C, R, T>& maxVal) const {
872 mat<C, R, T> res = *this;
873 return res.clamp(minVal, maxVal);
874 }
875
876 #pragma region SQUARE_MATRIX_OPERATIONS
877 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && std::is_same_v<Type, value_type>))
878
879 _MSTD_CONSTEXPR20 mat<R, C, T>& transpose() _MSTD_REQUIRES(R == C) {
880 for (size_t y = 0; y != R; ++y) {
881 for (size_t x = 0; x != C; ++x) {
882 if (x == y) { break; }
883
884 T temp = _values[x][y];
885 _values[x][y] = _values[y][x];
886 _values[y][x] = temp;
887 }
888 }
889 return *this;
890 }
891
892 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && std::is_same_v<Type, value_type>))
893
894 _MSTD_CONSTEXPR20 T determinant() const _MSTD_REQUIRES(R == C) {
895 if _MSTD_CONSTEXPR17 (R == 1) { return _values[0][0]; }
896 else if _MSTD_CONSTEXPR17 (R == 2) { return (_values[0][0] * _values[1][1]) - (_values[0][1] * _values[1][0]); }
897 else if _MSTD_CONSTEXPR17 (R == 3) {
898 T det = 0;
899 if (_values[0][0] != static_cast<T>(0)) {
900 det += _values[0][0] * ((_values[1][1] * _values[2][2]) - (_values[2][1] * _values[1][2]));
901 }
902 if (_values[1][0] != static_cast<T>(0)) {
903 det += _values[1][0] * ((_values[2][1] * _values[0][2]) - (_values[0][1] * _values[2][2]));
904 }
905 if (_values[2][0] != static_cast<T>(0)) {
906 det += _values[2][0] * ((_values[0][1] * _values[1][2]) - (_values[1][1] * _values[0][2]));
907 }
908 return det;
909 }
910 else if _MSTD_CONSTEXPR17 (R == 4) {
911 T det = 0;
912 if (_values[0][0] != static_cast<T>(0)) {
913 det += _values[0][0] *
914 ((_values[1][1] * ((_values[2][2] * _values[3][3]) - (_values[3][2] * _values[2][3]))) +
915 (_values[2][1] * ((_values[3][2] * _values[1][3]) - (_values[1][2] * _values[3][3]))) +
916 (_values[3][1] * ((_values[1][2] * _values[2][3]) - (_values[2][2] * _values[1][3]))));
917 }
918 if (_values[0][1] != static_cast<T>(0)) {
919 det -= _values[1][0] *
920 ((_values[0][1] * ((_values[2][2] * _values[3][3]) - (_values[3][2] * _values[2][3]))) +
921 (_values[2][1] * ((_values[3][2] * _values[0][3]) - (_values[0][2] * _values[3][3]))) +
922 (_values[3][1] * ((_values[0][2] * _values[2][3]) - (_values[2][2] * _values[0][3]))));
923 }
924 if (_values[2][0] != static_cast<T>(0)) {
925 det += _values[2][0] *
926 ((_values[0][1] * ((_values[1][2] * _values[3][3]) - (_values[3][2] * _values[1][3]))) +
927 (_values[1][1] * ((_values[3][2] * _values[0][3]) - (_values[0][2] * _values[3][3]))) +
928 (_values[3][1] * ((_values[0][2] * _values[1][3]) - (_values[1][2] * _values[0][3]))));
929 }
930 if (_values[3][0] != static_cast<T>(0)) {
931 det -= _values[3][0] *
932 ((_values[0][1] * ((_values[1][2] * _values[2][3]) - (_values[2][2] * _values[1][3]))) +
933 (_values[1][1] * ((_values[2][2] * _values[0][3]) - (_values[0][2] * _values[2][3]))) +
934 (_values[2][1] * ((_values[0][2] * _values[1][3]) - (_values[1][2] * _values[0][3]))));
935 }
936 return det;
937 }
938 else {
939 T det = 0;
940 int sign = 1;
941 for (size_t x = 0; x != C; ++x) {
942 if (_values[x][0] != static_cast<T>(0)) {
943 // get sub matrix
944 mat<C - 1, R - 1, T> subMat = get_sub_matrix(0, x);
945
946 // get sub matrixes det
947 T subDet = subMat.determinant();
948
949 // add sub det
950 det += sign * _values[x][0] * subDet;
951 }
952
953 // change sign
954 sign *= -1;
955 }
956 return det;
957 }
958 }
959
960 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && std::is_same_v<Type, value_type>))
961
962 _MSTD_CONSTEXPR20 mat<C, R, T>& invert() _MSTD_REQUIRES(R == C) {
963 *this = inverted();
964 return *this;
965 }
966
967 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && std::is_same_v<Type, value_type>))
968
969 _MSTD_CONSTEXPR20 mat<C, R, T> inverted() const _MSTD_REQUIRES(R == C) {
970 // calculate det
971 T det = determinant();
972
973 T invD = static_cast<T>(det == static_cast<T>(0) ? 0.0 : (1.0 / det));
974
975 if _MSTD_CONSTEXPR17 (R == 1) { return mat<C, R, T>(invD); }
976 else {
977 mat<C, R, T> res;
978 if _MSTD_CONSTEXPR17 (R == 2) {
979 res[0][0] = _values[1][1] * invD;
980 res[1][0] = -_values[1][0] * invD;
981 res[0][1] = -_values[0][1] * invD;
982 res[1][1] = _values[0][0] * invD;
983 }
984 else if _MSTD_CONSTEXPR17 (R == 3) {
985 res[0][0] = ((_values[1][1] * _values[2][2]) - (_values[2][1] * _values[1][2])) * invD;
986 res[1][0] = ((_values[2][0] * _values[1][2]) - (_values[1][0] * _values[2][2])) * invD;
987 res[2][0] = ((_values[1][0] * _values[2][1]) - (_values[2][0] * _values[1][1])) * invD;
988 res[0][1] = ((_values[0][2] * _values[2][1]) - (_values[0][1] * _values[2][2])) * invD;
989 res[1][1] = ((_values[0][0] * _values[2][2]) - (_values[2][0] * _values[0][2])) * invD;
990 res[2][1] = ((_values[2][0] * _values[0][1]) - (_values[0][0] * _values[2][1])) * invD;
991 res[0][2] = ((_values[0][1] * _values[1][2]) - (_values[1][1] * _values[0][2])) * invD;
992 res[1][2] = ((_values[1][0] * _values[0][2]) - (_values[0][0] * _values[1][2])) * invD;
993 res[2][2] = ((_values[0][0] * _values[1][1]) - (_values[0][1] * _values[1][0])) * invD;
994 }
995 else {
996 // transponowana (z niej tworzymy mniejsze macierze, usuwając kolumne (x) i wiersz (y), których obliczamy det
997 // det staje się wartością elementu na pozycji (x, y) ze znakiem w zależności ((x + y) % 2 == 0) -> 1 else -1
998 // na koniec mnożymy wartość elementu na pozycji (x, y) razy invD
999 const mat<R, C, T>& trans = transposed();
1000 for (size_t x = 0; x != C; ++x) {
1001 for (size_t y = 0; y != R; ++y) {
1002 // utworzyć mniejszą macierz
1003 mat<R - 1, C - 1, T> subMat = get_sub_matrix(y, x);
1004
1005 // transponujemy sub_mat
1006 subMat.transpose();
1007
1008 // obliczyć det mniejszej macierzy
1009 T subDet = subMat.determinant();
1010
1011 // jeśli sub_det != 0
1012 if (subDet != static_cast<T>(0)) {
1013 // ustawiamy wartość elementu x, y
1014 res[x][y] = ((x + y) % 2 == 0 ? 1 : -1) * subDet * invD;
1015 }
1016 }
1017 }
1018 res.transpose();
1019 }
1020 return res;
1021 }
1022 }
1023
1024 #pragma endregion // SQUARE_MATRIX_OPERATIONS
1025 #pragma endregion // MATRIX_OPERATIONS
1026
1027 #pragma region OPERATORS
1028
1029 _MSTD_CONSTEXPR20 mat<C, R, T>& operator+=(const mat<C, R, T>& other) {
1030 for (size_t x = 0; x != C; ++x) {
1031 for (size_t y = 0; y != R; ++y) { _values[x][y] += other[x][y]; }
1032 }
1033 return *this;
1034 }
1035
1036 _MSTD_CONSTEXPR20 mat<C, R, T>& operator-=(const mat<C, R, T>& other) {
1037 for (size_t x = 0; x != C; ++x) {
1038 for (size_t y = 0; y != R; ++y) { _values[x][y] -= other[x][y]; }
1039 }
1040 return *this;
1041 }
1042
1043 _MSTD_CONSTEXPR20 mat<C, R, T>& operator+=(const T& other) {
1044 for (size_t x = 0; x != C; ++x) {
1045 for (size_t y = 0; y != R; ++y) { _values[x][y] += other; }
1046 }
1047 return *this;
1048 }
1049
1050 _MSTD_CONSTEXPR20 mat<C, R, T>& operator-=(const T& other) {
1051 for (size_t x = 0; x != C; ++x) {
1052 for (size_t y = 0; y != R; ++y) { _values[x][y] -= other; }
1053 }
1054 return *this;
1055 }
1056
1057 _MSTD_CONSTEXPR20 mat<C, R, T>& operator*=(const T& other) {
1058 for (size_t x = 0; x != C; ++x) {
1059 for (size_t y = 0; y != R; ++y) { _values[x][y] *= other; }
1060 }
1061 return *this;
1062 }
1063
1064 _MSTD_CONSTEXPR20 mat<C, R, T>& operator/=(const T& other) {
1065 if (other == static_cast<T>(0)) { return *this; }
1066 for (size_t x = 0; x != C; ++x) {
1067 for (size_t y = 0; y != R; ++y) { _values[x][y] /= other; }
1068 }
1069 return *this;
1070 }
1071
1072 _MSTD_CONSTEXPR20 mat<C, R, T> operator+(const mat<C, R, T>& other) const {
1073 mat<C, R, T> res = *this;
1074 res += other;
1075 return res;
1076 }
1077
1078 _MSTD_CONSTEXPR20 mat<C, R, T> operator-(const mat<C, R, T>& other) const {
1079 mat<C, R, T> res = *this;
1080 res -= other;
1081 return res;
1082 }
1083
1084 template<size_t OC>
1085 _MSTD_CONSTEXPR20 mat<OC, R, T> operator*(const mat<OC, C, T>& other) const {
1086 mat<OC, R, T> res;
1087 for (size_t x = 0; x != OC; ++x) {
1088 for (size_t y = 0; y != R; ++y) {
1089 for (size_t i = 0; i != C; ++i) { res[x][y] += _values[i][y] * other[x][i]; }
1090 }
1091 }
1092 return res;
1093 }
1094
1095 _MSTD_CONSTEXPR20 mat<C, R, T> operator+(const T& other) const {
1096 mat<C, R, T> res = *this;
1097 res += other;
1098 return res;
1099 }
1100
1101 _MSTD_CONSTEXPR20 mat<C, R, T> operator-(const T& other) const {
1102 mat<C, R, T> res = *this;
1103 res -= other;
1104 return res;
1105 }
1106
1107 _MSTD_CONSTEXPR20 mat<C, R, T> operator*(const T& other) const {
1108 mat<C, R, T> res = *this;
1109 res *= other;
1110 return res;
1111 }
1112
1113 friend _MSTD_CONSTEXPR20 mat<C, R, T> operator*(const T& other, const mat<C, R, T>& matrix) { return matrix * other; }
1114
1115 _MSTD_CONSTEXPR20 mat<C, R, T> operator/(const T& other) const {
1116 mat<C, R, T> res = *this;
1117 res /= other;
1118 return res;
1119 }
1120
1121 _MSTD_CONSTEXPR20 vec<R, T> operator*(const vec<C, T>& other) const {
1122 vec<R, T> res;
1123 for (size_t y = 0; y != R; ++y) {
1124 for (size_t x = 0; x != C; ++x) { res[y] += _values[x][y] * other[x]; }
1125 }
1126 return res;
1127 }
1128
1129 _MSTD_CONSTEXPR20 mat<C, R, T> operator+() const { return mat<C, R, T>(*this); }
1130
1131 _MSTD_CONSTEXPR20 mat<C, R, T> operator-() const { return *this * -1; }
1132
1133 _MSTD_CONSTEXPR20 mat<C, R, T>& operator++() { return *this += 1; }
1134
1135 _MSTD_CONSTEXPR20 mat<C, R, T>& operator--() { return *this -= 1; }
1136
1137 template<size_t OC, size_t OR>
1138 _MSTD_CONSTEXPR20 bool operator==(const mat<OC, OR, T>& other) const {
1139 if _MSTD_CONSTEXPR17 (OC != C || OR != R) { return false; }
1140 else {
1141 for (size_t x = 0; x != C; ++x) {
1142 if (std::memcmp(_values[x], other[x], R * sizeof(T)) != 0) { return false; }
1143 }
1144 return true;
1145 }
1146 }
1147
1148 template<size_t OC, size_t OR>
1149 _MSTD_CONSTEXPR20 bool operator!=(const mat<OC, OR, T>& other) const {
1150 return !(*this == other);
1151 }
1152
1153 _MSTD_CONSTEXPR20 operator const T*() const { return _values; }
1154
1155 _MSTD_CONSTEXPR20 mat_column operator[](size_t idx) { return mat_column(this, idx); }
1156
1157 _MSTD_CONSTEXPR20 const_mat_column operator[](size_t idx) const { return const_mat_column(this, idx); }
1158
1159 friend std::ostream& operator<<(std::ostream& str, const mat<C, R, T>& matrix) {
1160 static _MSTD_CONSTEXPR17 const char left_top_corner = static_cast<char>(0xDA);
1161 static _MSTD_CONSTEXPR17 const char left_bottom_corner = static_cast<char>(0xC0);
1162 static _MSTD_CONSTEXPR17 const char side = static_cast<char>(0xB3);
1163 static _MSTD_CONSTEXPR17 const char right_top_corner = static_cast<char>(0xBF);
1164 static _MSTD_CONSTEXPR17 const char right_bottom_corner = static_cast<char>(0xD9);
1165
1166 size_t cellWidth = 0;
1167
1168 for (size_t y = 0; y != R; ++y) {
1169 for (size_t x = 0; x != C; ++x) {
1170 std::ostringstream oss;
1171 oss << matrix[y][x];
1172 cellWidth = std::max(cellWidth, oss.str().size());
1173 }
1174 }
1175
1176 for (size_t y = 0; y != R; ++y) {
1177 if _MSTD_CONSTEXPR17 (R > 1) {
1178 if (y == 0) { str << left_top_corner; }
1179 else if (y == R - 1) { str << left_bottom_corner; }
1180 else { str << side; }
1181 }
1182 else { str << side; }
1183 str << ' ';
1184
1185 for (size_t x = 0; x != C; ++x) {
1186 str << std::setw(cellWidth) << matrix[x][y];
1187 str << ' ';
1188 }
1189
1190 if _MSTD_CONSTEXPR17 (R > 1) {
1191 if (y == 0) { str << right_top_corner; }
1192 else if (y == R - 1) { str << right_bottom_corner; }
1193 else { str << side; }
1194 }
1195 else { str << side; }
1196
1197 if (y != R - 1) { str << std::endl; }
1198 }
1199 return str;
1200 }
1201
1202 #pragma region SQUARE_MATRIX_OPERATORS
1203 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && std::is_same_v<Type, value_type>))
1204
1205 _MSTD_CONSTEXPR20 mat<C, R, T>& operator*=(const mat<C, R, T>& other) _MSTD_REQUIRES(R == C) {
1206 *this = *this * other;
1207 return *this;
1208 }
1209
1210 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && std::is_same_v<Type, value_type>))
1211
1212 _MSTD_CONSTEXPR20 mat<C, R, T>& operator/=(const mat<C, R, T>& other) _MSTD_REQUIRES(R == C) {
1213 *this *= other.inverted();
1214 return *this;
1215 }
1216
1217 _MSTD_ENABLE_IF_TEMPLATE(Type = value_type, (C == R && std::is_same_v<Type, value_type>))
1218
1219 _MSTD_CONSTEXPR20 mat<C, R, T> operator/(const mat<C, R, T>& other) const _MSTD_REQUIRES(R == C) {
1220 mat<C, R, T> res = *this;
1221 res /= other;
1222 return res;
1223 }
1224
1225 #pragma endregion // SQUARE_MATRIX_OPERATORS
1226 #pragma endregion // OPERATORS
1227 };
1228
1229 #pragma region EXTRA_OPERATIONS
1230 #if _MSTD_HAS_CXX20
1231 template<size_t C, size_t R, arithmetic T>
1232 #else
1233 template<size_t C, size_t R, class T, std::enable_if_t<std::is_arithmetic_v<T>, bool> = true>
1234 #endif
1235 _MSTD_INLINE17 _MSTD_CONSTEXPR20 mat<C, R, T> clamp(const mat<C, R, T>& a, const T& minVal, const T& maxVal) {
1236 return a.clampped(minVal, maxVal);
1237 }
1238
1239 #if _MSTD_HAS_CXX20
1240 template<size_t C, size_t R, arithmetic T>
1241 #else
1242 template<size_t C, size_t R, class T, std::enable_if_t<std::is_arithmetic_v<T>, bool> = true>
1243 #endif
1244 _MSTD_INLINE17 _MSTD_CONSTEXPR20 mat<C, R, T> clamp(const mat<C, R, T>& a, const mat<C, R, T>& minVal,
1245 const mat<C, R, T>& maxVal) {
1246 return a.clampped(minVal, maxVal);
1247 }
1248
1249 #pragma endregion // EXTRA_OPERATIONS
1250} // namespace mstd
1251 #endif
1252#endif
Definition mat.hpp:91
_MSTD_CONSTEXPR20 bool operator!=(const const_mat_column &other) const
Definition mat.hpp:121
_MSTD_CONSTEXPR20 bool operator!=(const mat_column &other) const
Definition mat.hpp:112
size_t _column
Definition mat.hpp:96
_MSTD_CONSTEXPR20 T operator[](const size_t &idx) const
Definition mat.hpp:123
_MSTD_CONSTEXPR20 const_mat_column(const mat_type *parent, size_t column)
Definition mat.hpp:99
_MSTD_CONSTEXPR20 operator column_type() const
Definition mat.hpp:127
_MSTD_CONSTEXPR20 const_mat_column(const mat_column &other)
Definition mat.hpp:101
const mat_type * _parent
Definition mat.hpp:95
_MSTD_CONSTEXPR20 bool operator==(const const_mat_column &other) const
Definition mat.hpp:114
mat< C, R, T > mat_type
Definition mat.hpp:93
_MSTD_CONSTEXPR20 bool operator==(const mat_column &other) const
Definition mat.hpp:105
_MSTD_CONSTEXPR20 const_mat_column(const const_mat_column &other)
Definition mat.hpp:103
_MSTD_CONSTEXPR20 operator const T *() const
Definition mat.hpp:125
Definition mat.hpp:45
_MSTD_CONSTEXPR20 T operator[](const size_t &idx) const
Definition mat.hpp:78
mat_type * _parent
Definition mat.hpp:49
_MSTD_CONSTEXPR20 T & operator[](const size_t &idx)
Definition mat.hpp:76
_MSTD_CONSTEXPR20 mat_column & operator=(const mat_column &other)
Definition mat.hpp:57
_MSTD_CONSTEXPR20 bool operator!=(const mat_column &other) const
Definition mat.hpp:74
_MSTD_CONSTEXPR20 mat_column(mat_type *parent, size_t column)
Definition mat.hpp:53
size_t _column
Definition mat.hpp:50
_MSTD_CONSTEXPR20 mat_column & operator=(const column_type &other)
Definition mat.hpp:62
mat< C, R, T > mat_type
Definition mat.hpp:47
_MSTD_CONSTEXPR20 operator column_type() const
Definition mat.hpp:84
_MSTD_CONSTEXPR20 operator const T *() const
Definition mat.hpp:82
_MSTD_CONSTEXPR20 bool operator==(const mat_column &other) const
Definition mat.hpp:67
_MSTD_CONSTEXPR20 mat_column(const mat_column &other)
Definition mat.hpp:55
_MSTD_CONSTEXPR20 operator T*()
Definition mat.hpp:80
_MSTD_CONSTEXPR20 ~mat() noexcept=default
static _MSTD_CONSTEXPR20 mat< C, R, T > identity() _MSTD_REQUIRES(C
static _MSTD_CONSTEXPR17 const size_t columns
Definition mat.hpp:36
static _MSTD_CONSTEXPR20 mat< C, R, T > zero()
Definition mat.hpp:450
static _MSTD_CONSTEXPR17 const size_t rows
Definition mat.hpp:37
_MSTD_CONSTEXPR20 void _set_values(const std::index_sequence< Idxs... > &, const vec< VN, Ts > &... columns)
Definition mat.hpp:169
_MSTD_CONSTEXPR20 mat(const vec< VN, OT > *columns, size_t size)
Definition mat.hpp:367
_MSTD_CONSTEXPR20 mat(const OT(&values)[ON])
Definition mat.hpp:342
_MSTD_CONSTEXPR20 mat(const Ts &... values)
Definition mat.hpp:358
_MSTD_CONSTEXPR20 void _copy_values_from(const vec< VN, OT >(&columns)[N])
Definition mat.hpp:285
_MSTD_CONSTEXPR20 void _copy_values_from(const OT(&values)[ON])
Definition mat.hpp:245
_MSTD_CONSTEXPR20 mat(const OT *values, size_t columns, size_t rows)
Definition mat.hpp:333
T _values[C][R]
Definition mat.hpp:136
vec< R, T > column_type
Definition mat.hpp:39
_MSTD_CONSTEXPR20 mat< C, R, T > & operator=(const OT(&values)[OC][OR])
Definition mat.hpp:420
_MSTD_CONSTEXPR20 void _fill_values_from(size_t firstIdx, const T &value)
Definition mat.hpp:186
_MSTD_CONSTEXPR20 void _set_values(const std::index_sequence< Idxs... > &, const Ts &... values)
Definition mat.hpp:144
static _MSTD_CONSTEXPR17 const size_t size
Definition mat.hpp:38
_MSTD_CONSTEXPR20 mat(const OT *values, size_t size)
Definition mat.hpp:323
_MSTD_CONSTEXPR20 mat< C, R, T > & operator=(const OT(&values)[ON])
Definition mat.hpp:410
T value_type
Definition mat.hpp:41
_MSTD_CONSTEXPR20 void _set_identity_values(const T &value)
Definition mat.hpp:191
_MSTD_CONSTEXPR20 void _fill_column_from(size_t firstIdx, size_t colIdx, const T &value)
Definition mat.hpp:178
_MSTD_CONSTEXPR20 void _copy_values_from(const OT *values, size_t columns, size_t rows)
Definition mat.hpp:223
_MSTD_CONSTEXPR20 mat(const mat< OC, OR, OT > &other)
Definition mat.hpp:393
static _MSTD_CONSTEXPR20 mat< C, R, T > one()
Definition mat.hpp:452
_MSTD_CONSTEXPR20 void _fill_column(size_t colIdx, const T &value)
Definition mat.hpp:173
_MSTD_CONSTEXPR20 void _set_column(const size_t idx, const vec< VN, VT > &column)
Definition mat.hpp:153
_MSTD_CONSTEXPR20 mat(const vec< VN, OT >(&columns)[N])
Definition mat.hpp:376
_MSTD_CONSTEXPR20 mat(const OT(&values)[OC][OR])
Definition mat.hpp:349
_MSTD_CONSTEXPR20 void _copy_values_from(const mat< OC, OR, OT > &other)
Definition mat.hpp:294
static _MSTD_CONSTEXPR20 mat< C, R, T > T fill_identity(const T &value) _MSTD_REQUIRES(C
_MSTD_CONSTEXPR20 mat< C, R, T > & operator=(const mat< OC, OR, OT > &other)
Definition mat.hpp:440
vec< C, T > row_type
Definition mat.hpp:40
_MSTD_CONSTEXPR20 void _fill_values(const T &value)
Definition mat.hpp:184
_MSTD_CONSTEXPR20 mat()
Definition mat.hpp:316
_MSTD_CONSTEXPR20 mat< C, R, T > & operator=(const vec< VN, OT >(&columns)[N])
Definition mat.hpp:430
static _MSTD_CONSTEXPR20 mat< C, R, T > fill(const T &value)
Definition mat.hpp:454
_MSTD_CONSTEXPR20 void _copy_values_from(const vec< VN, OT > *columns, size_t size)
Definition mat.hpp:263
_MSTD_CONSTEXPR20 void _copy_values_from(const OT *values, size_t size)
Definition mat.hpp:202
_MSTD_CONSTEXPR20 void _copy_values_from(const OT(&values)[OC][OR])
Definition mat.hpp:254
_MSTD_CONSTEXPR20 mat(const vec< VN, Ts > &... columns)
Definition mat.hpp:384
#define _MSTD_HAS_CXX17
Definition config.hpp:45
#define _MSTD_CONSTEXPR17
Definition config.hpp:76
#define _MSTD_RETURN_VALUE_IF(condition,...)
Definition config.hpp:85
#define _MSTD_HAS_CXX20
Definition config.hpp:52
#define _MSTD_REQUIRES(condition)
Definition config.hpp:86
#define _MSTD_ENABLE_IF_TEMPLATE(class_name, condition)
Definition config.hpp:87
#define _MSTD_INLINE17
Definition config.hpp:83
#define _MSTD_CONSTEXPR20
Definition config.hpp:84
Definition arithmetic_types.hpp:23
_MSTD_INLINE17 _MSTD_CONSTEXPR20 mat< C, R, T > clamp(const mat< C, R, T > &a, const mat< C, R, T > &minVal, const mat< C, R, T > &maxVal)
Definition mat.hpp:1244
_MSTD_INLINE17 _MSTD_CONSTEXPR20 mat< C, R, T > clamp(const mat< C, R, T > &a, const T &minVal, const T &maxVal)
Definition mat.hpp:1235