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