HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
matrix2.hpp
1// Copyright Take Vos 2021-2022.
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
9#pragma once
10
11#include "translate2.hpp"
12#include "scale2.hpp"
13#include "rotate2.hpp"
14#include "aarectangle.hpp"
15#include "transform_fwd.hpp"
16#include <array>
17
18namespace hi { inline namespace v1 {
19
26class matrix2 {
27public:
28 constexpr matrix2(matrix2 const&) noexcept = default;
29 constexpr matrix2(matrix2&&) noexcept = default;
30 constexpr matrix2& operator=(matrix2 const&) noexcept = default;
31 constexpr matrix2& operator=(matrix2&&) noexcept = default;
32
35 constexpr matrix2() noexcept
36 {
37 hilet a = f32x4::broadcast(1.0f);
38 _col0 = a.x000();
39 _col1 = a._0y00();
40 _col2 = a._00z0();
41 _col3 = a._000w();
42 };
43
51 constexpr matrix2(f32x4 col0, f32x4 col1, f32x4 col2, f32x4 col3 = f32x4{0.0f, 0.0f, 0.0f, 1.0f}) noexcept :
52 _col0(col0), _col1(col1), _col2(col2), _col3(col3)
53 {
54 hi_axiom(holds_invariant());
55 }
56
64 constexpr matrix2(vector3 col0, vector3 col1, vector3 col2, vector3 col3 = vector3{}) noexcept :
65 _col0(static_cast<f32x4>(col0)),
66 _col1(static_cast<f32x4>(col1)),
67 _col2(static_cast<f32x4>(col2)),
68 _col3(static_cast<f32x4>(col3).xyz1())
69 {
70 hi_axiom(holds_invariant());
71 }
72
78 constexpr matrix2(vector2 col0, vector2 col1) noexcept :
79 _col0(static_cast<f32x4>(col0)),
80 _col1(static_cast<f32x4>(col1)),
81 _col2(f32x4{0.0f, 0.0f, 1.0f, 0.0f}),
82 _col3(f32x4{0.0f, 0.0f, 0.0f, 1.0f})
83 {
84 hi_axiom(holds_invariant());
85 }
86
102 constexpr matrix2(
103 float c0r0,
104 float c1r0,
105 float c2r0,
106 float c0r1,
107 float c1r1,
108 float c2r1,
109 float c0r2,
110 float c1r2,
111 float c2r2) noexcept :
112 _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)
113 {
114 hi_axiom(holds_invariant());
115 }
116
139 constexpr matrix2(
140 float c0r0,
141 float c1r0,
142 float c2r0,
143 float c3r0,
144 float c0r1,
145 float c1r1,
146 float c2r1,
147 float c3r1,
148 float c0r2,
149 float c1r2,
150 float c2r2,
151 float c3r2,
152 float c0r3,
153 float c1r3,
154 float c2r3,
155 float c3r3) noexcept :
156 _col0(c0r0, c0r1, c0r2, c0r3), _col1(c1r0, c1r1, c1r2, c1r3), _col2(c2r0, c2r1, c2r2, c2r3), _col3(c3r0, c3r1, c3r2, c3r3)
157 {
158 hi_axiom(holds_invariant());
159 }
160
161 [[nodiscard]] constexpr matrix2(translate2 const& rhs) noexcept
162 {
163 hilet ones = f32x4::broadcast(1.0f);
164 _col0 = ones.x000();
165 _col1 = ones._0y00();
166 _col2 = ones._00z0();
167 _col3 = ones._000w() + f32x4{rhs};
168 }
169
170 [[nodiscard]] constexpr matrix2(scale2 const& rhs) noexcept
171 {
172 _col0 = f32x4{rhs}.x000();
173 _col1 = f32x4{rhs}._0y00();
174 _col2 = f32x4{rhs}._00z0();
175 _col3 = f32x4{rhs}._000w();
176 }
177
181 [[nodiscard]] constexpr matrix2(rotate2 const& rhs) noexcept
182 {
183 // Original from https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
184 // 1 - 2(yy + zz) | 2(xy - zw) | 2(xz + yw)
185 // 2(xy + zw) | 1 - 2(xx + zz) | 2(yz - xw)
186 // 2(xz - yw) | 2(yz + xw) | 1 - 2(xx + yy)
187
188 // Flipping adds and multiplies:
189 // 1 - 2(zz + yy) | 2(xy - zw) | 2(yw + xz)
190 // 2(zw + yx) | 1 - 2(xx + zz) | 2(yz - xw)
191 // 2(zx - yw) | 2(xw + zy) | 1 - 2(yy + xx)
192
193 // All multiplies.
194 hilet x_mul = f32x4{rhs}.xxxx() * f32x4{rhs};
195 hilet y_mul = f32x4{rhs}.yyyy() * f32x4{rhs};
196 hilet z_mul = f32x4{rhs}.zzzz() * f32x4{rhs};
197
198 auto twos = f32x4{-2.0f, 2.0f, 2.0f, 0.0f};
199 auto one = f32x4{1.0f, 0.0f, 0.0f, 0.0f};
200 _col0 = one + addsub<0b0011>(z_mul.zwxy(), y_mul.yxwz()) * twos;
201 one = one.yxzw();
202 twos = twos.yxzw();
203 _col1 = one + addsub<0b0110>(x_mul.yxwz(), z_mul.wzyx()) * twos;
204 one = one.xzyw();
205 twos = twos.xzyw();
206 _col2 = one + addsub<0b0101>(y_mul.wzyx(), x_mul.zwxy()) * twos;
207 _col3 = one.xywz();
208 }
209
212 [[nodiscard]] constexpr explicit operator std::array<f32x4, 4>() const noexcept
213 {
214 hi_axiom(holds_invariant());
215 return {_col0, _col1, _col2, _col3};
216 }
217
227 [[nodiscard]] constexpr static matrix2
228 uniform(aarectangle src_rectangle, aarectangle dst_rectangle, alignment alignment) noexcept
229 {
230 hilet scale = scale2::uniform(src_rectangle.size(), dst_rectangle.size());
231 hilet scaled_rectangle = scale * src_rectangle;
232 hilet translation = translate2::align(scaled_rectangle, dst_rectangle, alignment);
233 return translation * scale;
234 }
235
241 template<int I>
242 [[nodiscard]] friend constexpr f32x4 const& get(matrix2 const& rhs) noexcept
243 {
244 if constexpr (I == 0) {
245 return rhs._col0;
246 } else if constexpr (I == 1) {
247 return rhs._col1;
248 } else if constexpr (I == 2) {
249 return rhs._col2;
250 } else if constexpr (I == 3) {
251 return rhs._col3;
252 } else {
254 }
255 }
256
262 template<int I>
263 [[nodiscard]] friend constexpr f32x4& get(matrix2& rhs) noexcept
264 {
265 if constexpr (I == 0) {
266 return rhs._col0;
267 } else if constexpr (I == 1) {
268 return rhs._col1;
269 } else if constexpr (I == 2) {
270 return rhs._col2;
271 } else if constexpr (I == 3) {
272 return rhs._col3;
273 } else {
275 }
276 }
277
278 [[nodiscard]] constexpr bool holds_invariant() const noexcept
279 {
280 return _col0.z() == 0.0f and _col0.w() == 0.0f and _col1.z() == 0.0f and _col1.w() == 0.0f and _col2.x() == 0.0f and
281 _col2.y() == 0.0f and _col2.z() == 1.0f and _col2.w() == 0.0f and _col3.z() == 0.0f and _col3.w() == 1.0f;
282 }
283
289 [[nodiscard]] constexpr f32x4 operator*(f32x4 const& rhs) const noexcept
290 {
291 return {_col0 * rhs.xxxx() + _col1 * rhs.yyyy() + _col2 * rhs.zzzz() + _col3 * rhs.wwww()};
292 }
293
296 [[nodiscard]] friend constexpr matrix2 transpose(matrix2 const& rhs) noexcept
297 {
298 auto tmp = transpose(rhs._col0, rhs._col1, rhs._col2, rhs._col3);
299 return matrix2{std::get<0>(tmp), std::get<1>(tmp), std::get<2>(tmp), std::get<3>(tmp)};
300 }
301
335 template<char DstX, char DstY, char DstZ, char DstW = 'w'>
336 [[nodiscard]] friend constexpr matrix2 reflect(matrix2 const& rhs) noexcept
337 {
338 return matrix2{reflect_column<DstX>(), reflect_column<DstY>(), reflect_column<DstZ>(), reflect_column<DstW>()} * rhs;
339 }
340
346 [[nodiscard]] constexpr friend bool operator==(matrix2 const& lhs, matrix2 const& rhs) noexcept
347 {
348 return equal(lhs._col0, rhs._col0) and equal(lhs._col1, rhs._col1) and equal(lhs._col3, rhs._col3);
349 }
350
353 [[nodiscard]] constexpr matrix2 operator~() const
354 {
355 // rc
356 // var s0 : Number = i00 * i11 -
357 // i10 * i01;
358 // var c0 : Number = i20 * i31 -
359 // i30 * i21;
360 hilet s0c0 = _col0 * _col1.yxwz();
361
362 // var s1 : Number = i00 * i12 -
363 // i10 * i02;
364 // var c1 : Number = i20 * i32 -
365 // i30 * i22;
366 hilet s1c1 = _col0 * _col2.yxwz();
367 hilet s0c0s1c1 = hsub(s0c0, s1c1);
368
369 // var s2 : Number = i00 * i13 -
370 // i10 * i03;
371 // var c2 : Number = i20 * i33 -
372 // i30 * i23;
373 hilet s2c2 = _col0 * _col3.yxwz();
374
375 // var s3 : Number = i01 * i12 -
376 // i11 * i02;
377 // var c3 : Number = i21 * i32 -
378 // i31 * i22;
379 hilet s3c3 = _col1 * _col2.yxwz();
380 hilet s2c2s3c3 = hsub(s2c2, s3c3);
381
382 // var s4 : Number = i01 * i13 -
383 // i11 * i03;
384 // var c4 : Number = i21 * i33 -
385 // i31 * i23;
386 hilet s4c4 = _col1 * _col3.yxwz();
387
388 // var s5 : Number = i02 * i13 -
389 // i12 * i03;
390 // var c5 : Number = i22 * i33 -
391 // i32 * i23;
392 hilet s5c5 = _col2 * _col3.yxwz();
393 hilet s4c4s5c5 = hsub(s4c4, s5c5);
394
395 // det = (s0 * c5 +
396 // -s1 * c4 +
397 // s2 * c3 +
398 // s3 * c2 +
399 // -s4 * c1 +
400 // s5 * c0)
401 hilet s0123 = s0c0s1c1.xz00() + s2c2s3c3._00xz();
402 hilet s45__ = s4c4s5c5.xz00();
403
404 hilet c5432 = s4c4s5c5.wy00() + s2c2s3c3._00wy();
405 hilet c10__ = s0c0s1c1.wy00();
406
407 hilet det_prod_half0 = neg<0b0010>(s0123 * c5432);
408 hilet det_prod_half1 = neg<0b0001>(s45__ * c10__);
409
410 hilet det_sum0 = hadd(det_prod_half0, det_prod_half1);
411 hilet det_sum1 = hadd(det_sum0, det_sum0);
412 hilet det = hadd(det_sum1, det_sum1).xxxx();
413
414 if (det.x() == 0.0f) {
415 throw std::domain_error("Divide by zero");
416 }
417
418 hilet invdet = rcp(det);
419
420 hilet t = transpose(*this);
421
422 // rc rc rc rc
423 // m.i00 := (i11 * c5 + i12 * -c4 + i13 * c3) * invdet;
424 // m.i10 := (i10 * -c5 + i12 * c2 + i13 * -c1) * invdet;
425 // m.i20 := (i10 * c4 + i11 * -c2 + i13 * c0) * invdet;
426 // m.i30 := (i10 * -c3 + i11 * c1 + i12 * -c0) * invdet;
427 auto tmp_c5543 = neg<0b1010>(c5432.xxyz());
428 auto tmp_c4221 = neg<0b0101>(c5432.yww0() + c10__._000x());
429 auto tmp_c3100 = neg<0b1010>(c5432.z000() + c10__._0xyy());
430 hilet inv_col0 = ((t._col1.yxxx() * tmp_c5543) + (t._col1.zzyy() * tmp_c4221) + (t._col1.wwwz() * tmp_c3100)) * invdet;
431
432 // m.i01 := (i01 * -c5 + i02 * c4 + i03 * -c3) * invdet;
433 // m.i11 := (i00 * c5 + i02 * -c2 + i03 * c1) * invdet;
434 // m.i21 := (i00 * -c4 + i01 * c2 + i03 * -c0) * invdet;
435 // m.i31 := (i00 * c3 + i01 * -c1 + i02 * c0) * invdet;
436 tmp_c5543 = -tmp_c5543;
437 tmp_c4221 = -tmp_c4221;
438 tmp_c3100 = -tmp_c3100;
439 hilet inv_col1 = ((t._col0.yxxx() * tmp_c5543) + (t._col0.zzyy() * tmp_c4221) + (t._col0.wwwz() * tmp_c3100)) * invdet;
440
441 // m.i02 := (i31 * s5 + i32 * -s4 + i33 * s3) * invdet;
442 // m.i12 := (i30 * -s5 + i32 * s2 + i33 * -s1) * invdet;
443 // m.i22 := (i30 * s4 + i31 * -s2 + i33 * s0) * invdet;
444 // m.i32 := (i30 * -s3 + i31 * s1 + i32 * -s0) * invdet;
445 auto tmp_s5543 = neg<0b1010>(s45__.yyx0() + s0123._000w());
446 auto tmp_s4221 = neg<0b0101>(s45__.x000() + s0123._0zzy());
447 auto tmp_s3100 = neg<0b1010>(s0123.wyxx());
448 hilet inv_col2 = ((t._col3.yxxx() * tmp_s5543) + (t._col3.zzyy() * tmp_s4221) + (t._col3.wwwz() * tmp_s3100)) * invdet;
449
450 // m.i03 := (i21 * -s5 + i22 * s4 + i23 * -s3) * invdet;
451 // m.i13 := (i20 * s5 + i22 * -s2 + i23 * s1) * invdet;
452 // m.i23 := (i20 * -s4 + i21 * s2 + i23 * -s0) * invdet;
453 // m.i33 := (i20 * s3 + i21 * -s1 + i22 * s0) * invdet;
454 tmp_s5543 = -tmp_s5543;
455 tmp_s4221 = -tmp_s4221;
456 tmp_s3100 = -tmp_s3100;
457 hilet inv_col3 = ((t._col2.yxxx() * tmp_s5543) + (t._col2.zzyy() * tmp_s4221) + (t._col2.wwwz() * tmp_s3100)) * invdet;
458
459 return matrix2{inv_col0, inv_col1, inv_col2, inv_col3};
460 }
461
462private:
463 f32x4 _col0;
464 f32x4 _col1;
465 f32x4 _col2;
466 f32x4 _col3;
467
468 template<char Axis>
469 [[nodiscard]] static constexpr f32x4 reflect_column() noexcept
470 {
471 if constexpr (Axis == 'x') {
472 return f32x4{1.0f, 0.0f, 0.0f, 0.0f};
473 } else if constexpr (Axis == 'X') {
474 return f32x4{-1.0f, 0.0f, 0.0f, 0.0f};
475 } else if constexpr (Axis == 'y') {
476 return f32x4{0.0f, 1.0f, 0.0f, 0.0f};
477 } else if constexpr (Axis == 'Y') {
478 return f32x4{0.0f, -1.0f, 0.0f, 0.0f};
479 } else if constexpr (Axis == 'z') {
480 return f32x4{0.0f, 0.0f, 1.0f, 0.0f};
481 } else if constexpr (Axis == 'Z') {
482 return f32x4{0.0f, 0.0f, -1.0f, 0.0f};
483 } else if constexpr (Axis == 'w') {
484 return f32x4{0.0f, 0.0f, 0.0f, 1.0f};
485 } else if constexpr (Axis == 'W') {
486 return f32x4{0.0f, 0.0f, 0.0f, -1.0f};
487 } else {
489 }
490 }
491};
492
493}} // namespace hi::v1
#define hi_static_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:323
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:13
geometry/margins.hpp
Definition cache.hpp:11
@ one
The number was one, and this means something in the current language.
Class which represents an axis-aligned rectangle.
Definition aarectangle.hpp:26
Horizontal/Vertical alignment combination.
Definition alignment.hpp:239
A 2D or 3D homogenius matrix for transforming homogenious vectors and points.
Definition matrix2.hpp:26
constexpr matrix2(rotate2 const &rhs) noexcept
Convert quaternion to matrix.
Definition matrix2.hpp:181
constexpr matrix2(float c0r0, float c1r0, float c2r0, float c0r1, float c1r1, float c2r1, float c0r2, float c1r2, float c2r2) noexcept
Construct a 3x3 matrix from scalar values.
Definition matrix2.hpp:102
constexpr friend bool operator==(matrix2 const &lhs, matrix2 const &rhs) noexcept
Compare two matrices potentially of different dimensions.
Definition matrix2.hpp:346
constexpr matrix2(vector3 col0, vector3 col1, vector3 col2, vector3 col3=vector3{}) noexcept
Construct a matrix from four vectors.
Definition matrix2.hpp:64
friend constexpr f32x4 & get(matrix2 &rhs) noexcept
Get a column.
Definition matrix2.hpp:263
constexpr matrix2(float c0r0, float c1r0, float c2r0, float c3r0, float c0r1, float c1r1, float c2r1, float c3r1, float c0r2, float c1r2, float c2r2, float c3r2, float c0r3, float c1r3, float c2r3, float c3r3) noexcept
Construct a 4x4 matrix from scalar values.
Definition matrix2.hpp:139
constexpr f32x4 operator*(f32x4 const &rhs) const noexcept
Transform a f32x4 numeric array by the matrix.
Definition matrix2.hpp:289
static constexpr matrix2 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 matrix2.hpp:228
friend constexpr matrix2 transpose(matrix2 const &rhs) noexcept
Matrix transpose.
Definition matrix2.hpp:296
constexpr matrix2 operator~() const
Invert matrix.
Definition matrix2.hpp:353
constexpr matrix2(f32x4 col0, f32x4 col1, f32x4 col2, f32x4 col3=f32x4{0.0f, 0.0f, 0.0f, 1.0f}) noexcept
Construct a matrix from four columns.
Definition matrix2.hpp:51
constexpr matrix2(vector2 col0, vector2 col1) noexcept
Construct a matrix from two vectors.
Definition matrix2.hpp:78
constexpr matrix2() noexcept
Constructs an identity matrix.
Definition matrix2.hpp:35
friend constexpr matrix2 reflect(matrix2 const &rhs) noexcept
Reflect axis of a matrix.
Definition matrix2.hpp:336
friend constexpr f32x4 const & get(matrix2 const &rhs) noexcept
Get a column.
Definition matrix2.hpp:242
Definition rotate2.hpp:9
static constexpr scale2 uniform(extent2 src_extent, extent2 dst_extent) noexcept
Get a uniform-scale-transform to scale an extent to another extent.
Definition scale2.hpp:45
Definition translate2.hpp:13
static constexpr translate2 align(aarectangle src_rectangle, aarectangle dst_rectangle, alignment alignment) noexcept
Align a rectangle within another rectangle.
Definition translate2.hpp:79
A high-level geometric vector Part of the high-level vector, point, mat and color types.
Definition vector2.hpp:18
A high-level geometric vector Part of the high-level vector, point, mat and color types.
Definition vector3.hpp:19