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 const &rhs) const noexcept
184 {
185 return matrix{*this * get<0>(rhs), *this * get<1>(rhs), *this * get<2>(rhs), *this * get<3>(rhs)};
186 }
187
190 [[nodiscard]] friend constexpr matrix transpose(matrix rhs) noexcept
191 {
192 auto tmp = transpose(rhs._col0, rhs._col1, rhs._col2, rhs._col3);
193 return {std::get<0>(tmp), std::get<1>(tmp), std::get<2>(tmp), std::get<3>(tmp)};
194 }
195
196 template<int E>
197 [[nodiscard]] constexpr bool operator==(matrix<E> const &rhs) const noexcept
198 {
199 return _col0 == rhs._col0 && _col1 == rhs._col1 && _col2 == rhs._col2 && _col3 == rhs._col3;
200 }
201
204 [[nodiscard]] constexpr matrix operator~() const
205 {
206 // rc
207 // var s0 : Number = i00 * i11 -
208 // i10 * i01;
209 // var c0 : Number = i20 * i31 -
210 // i30 * i21;
211 ttlet s0c0 = _col0 * _col1.yxwz();
212
213 // var s1 : Number = i00 * i12 -
214 // i10 * i02;
215 // var c1 : Number = i20 * i32 -
216 // i30 * i22;
217 ttlet s1c1 = _col0 * _col2.yxwz();
218 ttlet s0c0s1c1 = hsub(s0c0, s1c1);
219
220 // var s2 : Number = i00 * i13 -
221 // i10 * i03;
222 // var c2 : Number = i20 * i33 -
223 // i30 * i23;
224 ttlet s2c2 = _col0 * _col3.yxwz();
225
226 // var s3 : Number = i01 * i12 -
227 // i11 * i02;
228 // var c3 : Number = i21 * i32 -
229 // i31 * i22;
230 ttlet s3c3 = _col1 * _col2.yxwz();
231 ttlet s2c2s3c3 = hsub(s2c2, s3c3);
232
233 // var s4 : Number = i01 * i13 -
234 // i11 * i03;
235 // var c4 : Number = i21 * i33 -
236 // i31 * i23;
237 ttlet s4c4 = _col1 * _col3.yxwz();
238
239 // var s5 : Number = i02 * i13 -
240 // i12 * i03;
241 // var c5 : Number = i22 * i33 -
242 // i32 * i23;
243 ttlet s5c5 = _col2 * _col3.yxwz();
244 ttlet s4c4s5c5 = hsub(s4c4, s5c5);
245
246 // det = (s0 * c5 +
247 // -s1 * c4 +
248 // s2 * c3 +
249 // s3 * c2 +
250 // -s4 * c1 +
251 // s5 * c0)
252 ttlet s0123 = s0c0s1c1.xz00() + s2c2s3c3._00xz();
253 ttlet s45__ = s4c4s5c5.xz00();
254
255 ttlet c5432 = s4c4s5c5.wy00() + s2c2s3c3._00wy();
256 ttlet c10__ = s0c0s1c1.wy00();
257
258 ttlet det_prod_half0 = neg<0b0010>(s0123 * c5432);
259 ttlet det_prod_half1 = neg<0b0001>(s45__ * c10__);
260
261 ttlet det_sum0 = hadd(det_prod_half0, det_prod_half1);
262 ttlet det_sum1 = hadd(det_sum0, det_sum0);
263 ttlet det = hadd(det_sum1, det_sum1).xxxx();
264
265 if (det.x() == 0.0f) {
266 throw std::domain_error("Divide by zero");
267 }
268
269 ttlet invdet = rcp(det);
270
271 ttlet t = transpose(*this);
272
273 // rc rc rc rc
274 // m.i00 := (i11 * c5 + i12 * -c4 + i13 * c3) * invdet;
275 // m.i10 := (i10 * -c5 + i12 * c2 + i13 * -c1) * invdet;
276 // m.i20 := (i10 * c4 + i11 * -c2 + i13 * c0) * invdet;
277 // m.i30 := (i10 * -c3 + i11 * c1 + i12 * -c0) * invdet;
278 auto tmp_c5543 = neg<0b1010>(c5432.xxyz());
279 auto tmp_c4221 = neg<0b0101>(c5432.yww0() + c10__._000x());
280 auto tmp_c3100 = neg<0b1010>(c5432.z000() + c10__._0xyy());
281 ttlet inv_col0 = ((t._col1.yxxx() * tmp_c5543) + (t._col1.zzyy() * tmp_c4221) + (t._col1.wwwz() * tmp_c3100)) * invdet;
282
283 // m.i01 := (i01 * -c5 + i02 * c4 + i03 * -c3) * invdet;
284 // m.i11 := (i00 * c5 + i02 * -c2 + i03 * c1) * invdet;
285 // m.i21 := (i00 * -c4 + i01 * c2 + i03 * -c0) * invdet;
286 // m.i31 := (i00 * c3 + i01 * -c1 + i02 * c0) * invdet;
287 tmp_c5543 = -tmp_c5543;
288 tmp_c4221 = -tmp_c4221;
289 tmp_c3100 = -tmp_c3100;
290 ttlet inv_col1 = ((t._col0.yxxx() * tmp_c5543) + (t._col0.zzyy() * tmp_c4221) + (t._col0.wwwz() * tmp_c3100)) * invdet;
291
292 // m.i02 := (i31 * s5 + i32 * -s4 + i33 * s3) * invdet;
293 // m.i12 := (i30 * -s5 + i32 * s2 + i33 * -s1) * invdet;
294 // m.i22 := (i30 * s4 + i31 * -s2 + i33 * s0) * invdet;
295 // m.i32 := (i30 * -s3 + i31 * s1 + i32 * -s0) * invdet;
296 auto tmp_s5543 = neg<0b1010>(s45__.yyx0() + s0123._000w());
297 auto tmp_s4221 = neg<0b0101>(s45__.x000() + s0123._0zzy());
298 auto tmp_s3100 = neg<0b1010>(s0123.wyxx());
299 ttlet inv_col2 = ((t._col3.yxxx() * tmp_s5543) + (t._col3.zzyy() * tmp_s4221) + (t._col3.wwwz() * tmp_s3100)) * invdet;
300
301 // m.i03 := (i21 * -s5 + i22 * s4 + i23 * -s3) * invdet;
302 // m.i13 := (i20 * s5 + i22 * -s2 + i23 * s1) * invdet;
303 // m.i23 := (i20 * -s4 + i21 * s2 + i23 * -s0) * invdet;
304 // m.i33 := (i20 * s3 + i21 * -s1 + i22 * s0) * invdet;
305 tmp_s5543 = -tmp_s5543;
306 tmp_s4221 = -tmp_s4221;
307 tmp_s3100 = -tmp_s3100;
308 ttlet inv_col3 = ((t._col2.yxxx() * tmp_s5543) + (t._col2.zzyy() * tmp_s4221) + (t._col2.wwwz() * tmp_s3100)) * invdet;
309
310 return {inv_col0, inv_col1, inv_col2, inv_col3};
311 }
312
313private:
314 f32x4 _col0;
315 f32x4 _col1;
316 f32x4 _col2;
317 f32x4 _col3;
318};
319
320} // namespace geo
321
322using matrix2 = geo::matrix<2>;
323using matrix3 = geo::matrix<3>;
324
325} // namespace tt
alignment
Vertical and horizontal alignment.
Definition alignment.hpp:47
This is a RGBA floating point color.
Definition color.hpp:36
Class which represents an axis-aligned rectangle.
Definition axis_aligned_rectangle.hpp:20
A high-level geometric extent.
Definition extent.hpp:20
Definition matrix.hpp:18
constexpr auto operator*(matrix const &rhs) const noexcept
Matrix/Matrix multiplication.
Definition matrix.hpp:183
constexpr auto operator*(color const &rhs) const noexcept
Transform a color by a color matrix.
Definition matrix.hpp:170
constexpr matrix operator~() const
Invert matrix.
Definition matrix.hpp:204
friend constexpr matrix transpose(matrix rhs) noexcept
Matrix transpose.
Definition matrix.hpp:190
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:151
A high-level geometric point Part of the high-level vec, point, mat and color types.
Definition point.hpp:22
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)