HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
matrix.hpp
1// Copyright Take Vos 2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "vector.hpp"
8#include "extent.hpp"
9#include "point.hpp"
10#include "rectangle.hpp"
11#include "axis_aligned_rectangle.hpp"
12#include "../color/color.hpp"
13
14namespace tt {
15namespace geo {
16
17template<int D>
18class matrix {
19public:
20 static_assert(D == 2 || D == 3, "Only 2D or 3D rotation-matrices are supported");
21
22 constexpr matrix(matrix const &) noexcept = default;
23 constexpr matrix(matrix &&) noexcept = default;
24 constexpr matrix &operator=(matrix const &) noexcept = default;
25 constexpr matrix &operator=(matrix &&) noexcept = default;
26
27 constexpr matrix() noexcept :
28 _col0(1.0f, 0.0f, 0.0f, 0.0f),
29 _col1(0.0f, 1.0f, 0.0f, 0.0f),
30 _col2(0.0f, 0.0f, 1.0f, 0.0f),
31 _col3(0.0f, 0.0f, 0.0f, 1.0f){};
32
33 constexpr matrix(f32x4 col0, f32x4 col1, f32x4 col2, f32x4 col3 = f32x4{0.0f, 0.0f, 0.0f, 1.0f}) noexcept :
34 _col0(col0), _col1(col1), _col2(col2), _col3(col3)
35 {
36 }
37
38 constexpr matrix(vector3 col0, vector3 col1, vector3 col2) noexcept requires(D == 3) :
39 _col0(static_cast<f32x4>(col0)),
40 _col1(static_cast<f32x4>(col1)),
41 _col2(static_cast<f32x4>(col2)),
42 _col3{0.0f, 0.0f, 0.0f, 1.0f}
43 {
44 }
45
46 constexpr matrix(
47 float c0r0,
48 float c1r0,
49 float c2r0,
50 float c0r1,
51 float c1r1,
52 float c2r1,
53 float c0r2,
54 float c1r2,
55 float c2r2) noexcept requires(D == 3) :
56 _col0(c0r0, c0r1, c0r2, 0.0f), _col1(c1r0, c1r1, c1r2, 0.0f), _col2(c2r0, c2r1, c2r2, 0.0f), _col3(0.0f, 0.0f, 0.0f, 1.0f)
57 {
58 }
59
60 constexpr matrix(
61 float c0r0,
62 float c1r0,
63 float c2r0,
64 float c3r0,
65 float c0r1,
66 float c1r1,
67 float c2r1,
68 float c3r1,
69 float c0r2,
70 float c1r2,
71 float c2r2,
72 float c3r2,
73 float c0r3,
74 float c1r3,
75 float c2r3,
76 float c3r3) noexcept requires(D == 3) :
77 _col0(c0r0, c0r1, c0r2, c0r3), _col1(c1r0, c1r1, c1r2, c1r3), _col2(c2r0, c2r1, c2r2, c2r3), _col3(c3r0, c3r1, c3r2, c3r3)
78 {
79 }
80
81 template<int E>
82 requires(E < D) [[nodiscard]] constexpr matrix(matrix<E> const &other) noexcept :
83 _col0(get<0>(other)), _col1(get<1>(other)), _col2(get<2>(other)), _col3(get<3>(other))
84 {
85 }
86
87 template<int E>
88 requires(E < D) constexpr matrix &operator=(matrix<E> const &rhs) noexcept
89 {
90 _col0 = get<0>(rhs);
91 _col1 = get<1>(rhs);
92 _col2 = get<2>(rhs);
93 _col3 = get<3>(rhs);
94 return *this;
95 }
96
106 [[nodiscard]] constexpr static matrix uniform(aarectangle src_rectangle, aarectangle dst_rectangle, alignment alignment) noexcept;
107
108 template<int I>
109 [[nodiscard]] friend constexpr f32x4 get(matrix const &rhs) noexcept
110 {
111 if constexpr (I == 0) {
112 return rhs._col0;
113 } else if constexpr (I == 1) {
114 return rhs._col1;
115 } else if constexpr (I == 2) {
116 return rhs._col2;
117 } else if constexpr (I == 3) {
118 return rhs._col3;
119 } else {
120 tt_static_no_default();
121 }
122 }
123
124 [[nodiscard]] constexpr bool is_valid() const noexcept
125 {
126 return true;
127 }
128
129 [[nodiscard]] constexpr auto operator*(f32x4 const &rhs) const noexcept
130 {
131 return f32x4{_col0 * rhs.xxxx() + _col1 * rhs.yyyy() + _col2 * rhs.zzzz() + _col3 * rhs.wwww()};
132 }
133
134 template<int E>
135 [[nodiscard]] constexpr auto operator*(vector<E> const &rhs) const noexcept
136 {
137 tt_axiom(rhs.is_valid());
138 return vector<std::max(D, E)>{
139 _col0 * static_cast<f32x4>(rhs).xxxx() + _col1 * static_cast<f32x4>(rhs).yyyy() +
140 _col2 * static_cast<f32x4>(rhs).zzzz()};
141 }
142
143 template<int E>
144 [[nodiscard]] constexpr auto operator*(extent<E> const &rhs) const noexcept
145 {
146 tt_axiom(rhs.is_valid());
147 return extent<std::max(D, E)>{
148 _col0 * static_cast<f32x4>(rhs).xxxx() + _col1 * static_cast<f32x4>(rhs).yyyy() +
149 _col2 * static_cast<f32x4>(rhs).zzzz()};
150 }
151
152 template<int E>
153 [[nodiscard]] constexpr auto operator*(point<E> const &rhs) const noexcept
154 {
155 tt_axiom(rhs.is_valid());
156 return point<std::max(D, E)>{
157 _col0 * static_cast<f32x4>(rhs).xxxx() + _col1 * static_cast<f32x4>(rhs).yyyy() +
158 _col2 * static_cast<f32x4>(rhs).zzzz() + _col3 * static_cast<f32x4>(rhs).wwww()};
159 }
160
161 [[nodiscard]] constexpr auto operator*(rectangle const &rhs) const noexcept
162 {
163 return rectangle{*this * get<0>(rhs), *this * get<1>(rhs), *this * get<2>(rhs), *this * get<3>(rhs)};
164 }
165
170 [[nodiscard]] constexpr auto operator*(color const &rhs) const noexcept
171 {
172 tt_axiom(rhs.is_valid());
173 auto r = color{
174 _col0 * static_cast<f32x4>(rhs).xxxx() + _col1 * static_cast<f32x4>(rhs).yyyy() +
175 _col2 * static_cast<f32x4>(rhs).zzzz() + _col3};
176
177 r.a() = rhs.a();
178 return r;
179 }
180
183 [[nodiscard]] constexpr auto operator*(matrix<2> const &rhs) const noexcept
184 {
185 return matrix<D>{*this * get<0>(rhs), *this * get<1>(rhs), *this * get<2>(rhs), *this * get<3>(rhs)};
186 }
187
190 [[nodiscard]] constexpr auto operator*(matrix<3> const &rhs) const noexcept
191 {
192 return matrix<3>{*this * get<0>(rhs), *this * get<1>(rhs), *this * get<2>(rhs), *this * get<3>(rhs)};
193 }
194
197 [[nodiscard]] friend constexpr matrix transpose(matrix rhs) noexcept
198 {
199 auto tmp = transpose(rhs._col0, rhs._col1, rhs._col2, rhs._col3);
200 return {std::get<0>(tmp), std::get<1>(tmp), std::get<2>(tmp), std::get<3>(tmp)};
201 }
202
203 template<int E>
204 [[nodiscard]] constexpr bool operator==(matrix<E> const &rhs) const noexcept
205 {
206 return _col0 == rhs._col0 && _col1 == rhs._col1 && _col2 == rhs._col2 && _col3 == rhs._col3;
207 }
208
211 [[nodiscard]] constexpr matrix operator~() const
212 {
213 // rc
214 // var s0 : Number = i00 * i11 -
215 // i10 * i01;
216 // var c0 : Number = i20 * i31 -
217 // i30 * i21;
218 ttlet s0c0 = _col0 * _col1.yxwz();
219
220 // var s1 : Number = i00 * i12 -
221 // i10 * i02;
222 // var c1 : Number = i20 * i32 -
223 // i30 * i22;
224 ttlet s1c1 = _col0 * _col2.yxwz();
225 ttlet s0c0s1c1 = hsub(s0c0, s1c1);
226
227 // var s2 : Number = i00 * i13 -
228 // i10 * i03;
229 // var c2 : Number = i20 * i33 -
230 // i30 * i23;
231 ttlet s2c2 = _col0 * _col3.yxwz();
232
233 // var s3 : Number = i01 * i12 -
234 // i11 * i02;
235 // var c3 : Number = i21 * i32 -
236 // i31 * i22;
237 ttlet s3c3 = _col1 * _col2.yxwz();
238 ttlet s2c2s3c3 = hsub(s2c2, s3c3);
239
240 // var s4 : Number = i01 * i13 -
241 // i11 * i03;
242 // var c4 : Number = i21 * i33 -
243 // i31 * i23;
244 ttlet s4c4 = _col1 * _col3.yxwz();
245
246 // var s5 : Number = i02 * i13 -
247 // i12 * i03;
248 // var c5 : Number = i22 * i33 -
249 // i32 * i23;
250 ttlet s5c5 = _col2 * _col3.yxwz();
251 ttlet s4c4s5c5 = hsub(s4c4, s5c5);
252
253 // det = (s0 * c5 +
254 // -s1 * c4 +
255 // s2 * c3 +
256 // s3 * c2 +
257 // -s4 * c1 +
258 // s5 * c0)
259 ttlet s0123 = s0c0s1c1.xz00() + s2c2s3c3._00xz();
260 ttlet s45__ = s4c4s5c5.xz00();
261
262 ttlet c5432 = s4c4s5c5.wy00() + s2c2s3c3._00wy();
263 ttlet c10__ = s0c0s1c1.wy00();
264
265 ttlet det_prod_half0 = neg<0b0010>(s0123 * c5432);
266 ttlet det_prod_half1 = neg<0b0001>(s45__ * c10__);
267
268 ttlet det_sum0 = hadd(det_prod_half0, det_prod_half1);
269 ttlet det_sum1 = hadd(det_sum0, det_sum0);
270 ttlet det = hadd(det_sum1, det_sum1).xxxx();
271
272 if (det.x() == 0.0f) {
273 throw std::domain_error("Divide by zero");
274 }
275
276 ttlet invdet = rcp(det);
277
278 ttlet t = transpose(*this);
279
280 // rc rc rc rc
281 // m.i00 = (i11 * c5 + i12 * -c4 + i13 * c3) * invdet;
282 // m.i10 = (i10 * -c5 + i12 * c2 + i13 * -c1) * invdet;
283 // m.i20 = (i10 * c4 + i11 * -c2 + i13 * c0) * invdet;
284 // m.i30 = (i10 * -c3 + i11 * c1 + i12 * -c0) * invdet;
285 auto tmp_c5543 = neg<0b1010>(c5432.xxyz());
286 auto tmp_c4221 = neg<0b0101>(c5432.yww0() + c10__._000x());
287 auto tmp_c3100 = neg<0b1010>(c5432.z000() + c10__._0xyy());
288 ttlet inv_col0 = ((t._col1.yxxx() * tmp_c5543) + (t._col1.zzyy() * tmp_c4221) + (t._col1.wwwz() * tmp_c3100)) * invdet;
289
290 // m.i01 = (i01 * -c5 + i02 * c4 + i03 * -c3) * invdet;
291 // m.i11 = (i00 * c5 + i02 * -c2 + i03 * c1) * invdet;
292 // m.i21 = (i00 * -c4 + i01 * c2 + i03 * -c0) * invdet;
293 // m.i31 = (i00 * c3 + i01 * -c1 + i02 * c0) * invdet;
294 tmp_c5543 = -tmp_c5543;
295 tmp_c4221 = -tmp_c4221;
296 tmp_c3100 = -tmp_c3100;
297 ttlet inv_col1 = ((t._col0.yxxx() * tmp_c5543) + (t._col0.zzyy() * tmp_c4221) + (t._col0.wwwz() * tmp_c3100)) * invdet;
298
299 // m.i02 = (i31 * s5 + i32 * -s4 + i33 * s3) * invdet;
300 // m.i12 = (i30 * -s5 + i32 * s2 + i33 * -s1) * invdet;
301 // m.i22 = (i30 * s4 + i31 * -s2 + i33 * s0) * invdet;
302 // m.i32 = (i30 * -s3 + i31 * s1 + i32 * -s0) * invdet;
303 auto tmp_s5543 = neg<0b1010>(s45__.yyx0() + s0123._000w());
304 auto tmp_s4221 = neg<0b0101>(s45__.x000() + s0123._0zzy());
305 auto tmp_s3100 = neg<0b1010>(s0123.wyxx());
306 ttlet inv_col2 = ((t._col3.yxxx() * tmp_s5543) + (t._col3.zzyy() * tmp_s4221) + (t._col3.wwwz() * tmp_s3100)) * invdet;
307
308 // m.i03 = (i21 * -s5 + i22 * s4 + i23 * -s3) * invdet;
309 // m.i13 = (i20 * s5 + i22 * -s2 + i23 * s1) * invdet;
310 // m.i23 = (i20 * -s4 + i21 * s2 + i23 * -s0) * invdet;
311 // m.i33 = (i20 * s3 + i21 * -s1 + i22 * s0) * invdet;
312 tmp_s5543 = -tmp_s5543;
313 tmp_s4221 = -tmp_s4221;
314 tmp_s3100 = -tmp_s3100;
315 ttlet inv_col3 = ((t._col2.yxxx() * tmp_s5543) + (t._col2.zzyy() * tmp_s4221) + (t._col2.wwwz() * tmp_s3100)) * invdet;
316
317 return {inv_col0, inv_col1, inv_col2, inv_col3};
318 }
319
320private:
321 f32x4 _col0;
322 f32x4 _col1;
323 f32x4 _col2;
324 f32x4 _col3;
325};
326
327} // namespace geo
328
329using matrix2 = geo::matrix<2>;
330using matrix3 = geo::matrix<3>;
331
332} // namespace tt
This is a RGBA floating point color.
Definition color.hpp:39
Class which represents an axis-aligned rectangle.
Definition axis_aligned_rectangle.hpp:18
A high-level geometric extent.
Definition extent.hpp:20
Definition matrix.hpp:18
constexpr auto operator*(color const &rhs) const noexcept
Transform a color by a color matrix.
Definition matrix.hpp:170
constexpr auto operator*(matrix< 3 > const &rhs) const noexcept
Matrix/Matrix multiplication.
Definition matrix.hpp:190
constexpr matrix operator~() const
Invert matrix.
Definition matrix.hpp:211
friend constexpr matrix transpose(matrix rhs) noexcept
Matrix transpose.
Definition matrix.hpp:197
static constexpr matrix uniform(aarectangle src_rectangle, aarectangle dst_rectangle, alignment alignment) noexcept
Create a transformation matrix to translate and uniformly-scale a src_rectangle to a dst_rectangle.
Definition scale.hpp:141
constexpr auto operator*(matrix< 2 > const &rhs) const noexcept
Matrix/Matrix multiplication.
Definition matrix.hpp:183
A high-level geometric point Part of the high-level vec, point, mat and color types.
Definition point.hpp:21
Class which represents an rectangle.
Definition rectangle.hpp:16
A high-level geometric vector Part of the high-level vector, point, mat and color types.
Definition vector.hpp:20
T max(T... args)