HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
matrix3.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 "matrix2.hpp"
12#include "translate3.hpp"
13#include "scale3.hpp"
14#include "rotate3.hpp"
15#include <array>
16
17namespace hi { inline namespace v1 {
18
19class matrix3;
20[[nodiscard]] constexpr matrix3 operator*(translate3 const& lhs, scale3 const& rhs) noexcept;
21[[nodiscard]] constexpr matrix3 operator*(translate3 const& lhs, rotate3 const& rhs) noexcept;
22
29class matrix3 {
30public:
31 constexpr matrix3(matrix3 const&) noexcept = default;
32 constexpr matrix3(matrix3&&) noexcept = default;
33 constexpr matrix3& operator=(matrix3 const&) noexcept = default;
34 constexpr matrix3& operator=(matrix3&&) noexcept = default;
35
38 constexpr matrix3() noexcept
39 {
40 hilet a = f32x4::broadcast(1.0f);
41 _col0 = a.x000();
42 _col1 = a._0y00();
43 _col2 = a._00z0();
44 _col3 = a._000w();
45 };
46
54 constexpr matrix3(f32x4 col0, f32x4 col1, f32x4 col2, f32x4 col3 = f32x4{0.0f, 0.0f, 0.0f, 1.0f}) noexcept :
55 _col0(col0), _col1(col1), _col2(col2), _col3(col3)
56 {
57 }
58
66 constexpr matrix3(vector3 col0, vector3 col1, vector3 col2, vector3 col3 = vector3{}) noexcept :
67 _col0(static_cast<f32x4>(col0)),
68 _col1(static_cast<f32x4>(col1)),
69 _col2(static_cast<f32x4>(col2)),
70 _col3(static_cast<f32x4>(col3).xyz1())
71 {
72 }
73
79 // constexpr matrix3(vector2 col0, vector2 col1) noexcept
80 // :
81 // _col0(static_cast<f32x4>(col0)),
82 // _col1(static_cast<f32x4>(col1)),
83 // _col2(f32x4{0.0f, 0.0f, 1.0f, 0.0f}),
84 // _col3(f32x4{0.0f, 0.0f, 0.0f, 1.0f})
85 //{
86 // }
87
103 constexpr matrix3(
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 }
116
139 constexpr matrix3(
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 }
159
162 [[nodiscard]] constexpr matrix3(matrix2 const& other) noexcept :
163 _col0(get<0>(other)), _col1(get<1>(other)), _col2(get<2>(other)), _col3(get<3>(other))
164 {
165 }
166
167 [[nodiscard]] constexpr explicit operator matrix2() const noexcept
168 {
169 auto tmp0 = _col0;
170 auto tmp1 = _col1;
171 auto tmp2 = _col2;
172 auto tmp3 = _col3;
173 tmp0.z() = 0.0f;
174 tmp0.w() = 0.0f;
175 tmp1.z() = 0.0f;
176 tmp1.w() = 0.0f;
177 tmp2.x() = 0.0f;
178 tmp2.y() = 0.0f;
179 tmp2.z() = 1.0f;
180 tmp2.w() = 0.0f;
181 tmp3.z() = 0.0f;
182 tmp3.w() = 1.0f;
183 return matrix2{tmp0, tmp1, tmp2, tmp3};
184 }
185
186 [[nodiscard]] constexpr matrix3(scale3 const& rhs) noexcept
187 {
188 _col0 = f32x4{rhs}.x000();
189 _col1 = f32x4{rhs}._0y00();
190 _col2 = f32x4{rhs}._00z0();
191 _col3 = f32x4{rhs}._000w();
192 }
193
194 [[nodiscard]] constexpr matrix3(translate3 const& rhs) noexcept
195 {
196 hilet ones = f32x4::broadcast(1.0f);
197 _col0 = ones.x000();
198 _col1 = ones._0y00();
199 _col2 = ones._00z0();
200 _col3 = ones._000w() + f32x4{rhs};
201 }
202
206 [[nodiscard]] constexpr matrix3(rotate3 const& rhs) noexcept
207 {
208 // Original from https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
209 // 1 - 2(yy + zz) | 2(xy - zw) | 2(xz + yw)
210 // 2(xy + zw) | 1 - 2(xx + zz) | 2(yz - xw)
211 // 2(xz - yw) | 2(yz + xw) | 1 - 2(xx + yy)
212
213 // Flipping adds and multiplies:
214 // 1 - 2(zz + yy) | 2(xy - zw) | 2(yw + xz)
215 // 2(zw + yx) | 1 - 2(xx + zz) | 2(yz - xw)
216 // 2(zx - yw) | 2(xw + zy) | 1 - 2(yy + xx)
217
218 // All multiplies.
219 hilet x_mul = f32x4{rhs}.xxxx() * f32x4{rhs};
220 hilet y_mul = f32x4{rhs}.yyyy() * f32x4{rhs};
221 hilet z_mul = f32x4{rhs}.zzzz() * f32x4{rhs};
222
223 auto twos = f32x4{-2.0f, 2.0f, 2.0f, 0.0f};
224 auto one = f32x4{1.0f, 0.0f, 0.0f, 0.0f};
225 _col0 = one + addsub<0b0011>(z_mul.zwxy(), y_mul.yxwz()) * twos;
226 one = one.yxzw();
227 twos = twos.yxzw();
228 _col1 = one + addsub<0b0110>(x_mul.yxwz(), z_mul.wzyx()) * twos;
229 one = one.xzyw();
230 twos = twos.xzyw();
231 _col2 = one + addsub<0b0101>(y_mul.wzyx(), x_mul.zwxy()) * twos;
232 _col3 = one.xywz();
233 }
234
237 [[nodiscard]] constexpr explicit operator std::array<f32x4, 4>() const noexcept
238 {
239 hi_axiom(holds_invariant());
240 return {_col0, _col1, _col2, _col3};
241 }
242
252 [[nodiscard]] constexpr static matrix3
253 uniform(aarectangle src_rectangle, aarectangle dst_rectangle, alignment alignment) noexcept
254 {
255 return matrix3{matrix2::uniform(src_rectangle, dst_rectangle, alignment)};
256 }
257
263 template<int I>
264 [[nodiscard]] friend constexpr f32x4 const& get(matrix3 const& 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 {
276 }
277 }
278
284 template<int I>
285 [[nodiscard]] friend constexpr f32x4& get(matrix3& rhs) noexcept
286 {
287 if constexpr (I == 0) {
288 return rhs._col0;
289 } else if constexpr (I == 1) {
290 return rhs._col1;
291 } else if constexpr (I == 2) {
292 return rhs._col2;
293 } else if constexpr (I == 3) {
294 return rhs._col3;
295 } else {
297 }
298 }
299
300 [[nodiscard]] constexpr bool holds_invariant() const noexcept
301 {
302 return true;
303 }
304
310 [[nodiscard]] constexpr f32x4 operator*(f32x4 const& rhs) const noexcept
311 {
312 return {_col0 * rhs.xxxx() + _col1 * rhs.yyyy() + _col2 * rhs.zzzz() + _col3 * rhs.wwww()};
313 }
314
315
318 [[nodiscard]] friend constexpr matrix3 transpose(matrix3 const& rhs) noexcept
319 {
320 auto tmp = transpose(rhs._col0, rhs._col1, rhs._col2, rhs._col3);
321 return matrix3{std::get<0>(tmp), std::get<1>(tmp), std::get<2>(tmp), std::get<3>(tmp)};
322 }
323
357 template<char DstX, char DstY, char DstZ, char DstW = 'w'>
358 [[nodiscard]] friend constexpr matrix3 reflect(matrix3 const& rhs) noexcept
359 {
360 return matrix3{reflect_column<DstX>(), reflect_column<DstY>(), reflect_column<DstZ>(), reflect_column<DstW>()} * rhs;
361 }
362
368 [[nodiscard]] constexpr friend bool operator==(matrix3 const& lhs, matrix3 const& rhs) noexcept
369 {
370 return equal(lhs._col0, rhs._col0) and equal(lhs._col1, rhs._col1) and equal(lhs._col2, rhs._col2) and
371 equal(lhs._col3, rhs._col3);
372 }
373
376 [[nodiscard]] constexpr matrix3 operator~() const
377 {
378 // rc
379 // var s0 : Number = i00 * i11 -
380 // i10 * i01;
381 // var c0 : Number = i20 * i31 -
382 // i30 * i21;
383 hilet s0c0 = _col0 * _col1.yxwz();
384
385 // var s1 : Number = i00 * i12 -
386 // i10 * i02;
387 // var c1 : Number = i20 * i32 -
388 // i30 * i22;
389 hilet s1c1 = _col0 * _col2.yxwz();
390 hilet s0c0s1c1 = hsub(s0c0, s1c1);
391
392 // var s2 : Number = i00 * i13 -
393 // i10 * i03;
394 // var c2 : Number = i20 * i33 -
395 // i30 * i23;
396 hilet s2c2 = _col0 * _col3.yxwz();
397
398 // var s3 : Number = i01 * i12 -
399 // i11 * i02;
400 // var c3 : Number = i21 * i32 -
401 // i31 * i22;
402 hilet s3c3 = _col1 * _col2.yxwz();
403 hilet s2c2s3c3 = hsub(s2c2, s3c3);
404
405 // var s4 : Number = i01 * i13 -
406 // i11 * i03;
407 // var c4 : Number = i21 * i33 -
408 // i31 * i23;
409 hilet s4c4 = _col1 * _col3.yxwz();
410
411 // var s5 : Number = i02 * i13 -
412 // i12 * i03;
413 // var c5 : Number = i22 * i33 -
414 // i32 * i23;
415 hilet s5c5 = _col2 * _col3.yxwz();
416 hilet s4c4s5c5 = hsub(s4c4, s5c5);
417
418 // det = (s0 * c5 +
419 // -s1 * c4 +
420 // s2 * c3 +
421 // s3 * c2 +
422 // -s4 * c1 +
423 // s5 * c0)
424 hilet s0123 = s0c0s1c1.xz00() + s2c2s3c3._00xz();
425 hilet s45__ = s4c4s5c5.xz00();
426
427 hilet c5432 = s4c4s5c5.wy00() + s2c2s3c3._00wy();
428 hilet c10__ = s0c0s1c1.wy00();
429
430 hilet det_prod_half0 = neg<0b0010>(s0123 * c5432);
431 hilet det_prod_half1 = neg<0b0001>(s45__ * c10__);
432
433 hilet det_sum0 = hadd(det_prod_half0, det_prod_half1);
434 hilet det_sum1 = hadd(det_sum0, det_sum0);
435 hilet det = hadd(det_sum1, det_sum1).xxxx();
436
437 if (det.x() == 0.0f) {
438 throw std::domain_error("Divide by zero");
439 }
440
441 hilet invdet = rcp(det);
442
443 hilet t = transpose(*this);
444
445 // rc rc rc rc
446 // m.i00 := (i11 * c5 + i12 * -c4 + i13 * c3) * invdet;
447 // m.i10 := (i10 * -c5 + i12 * c2 + i13 * -c1) * invdet;
448 // m.i20 := (i10 * c4 + i11 * -c2 + i13 * c0) * invdet;
449 // m.i30 := (i10 * -c3 + i11 * c1 + i12 * -c0) * invdet;
450 auto tmp_c5543 = neg<0b1010>(c5432.xxyz());
451 auto tmp_c4221 = neg<0b0101>(c5432.yww0() + c10__._000x());
452 auto tmp_c3100 = neg<0b1010>(c5432.z000() + c10__._0xyy());
453 hilet inv_col0 = ((t._col1.yxxx() * tmp_c5543) + (t._col1.zzyy() * tmp_c4221) + (t._col1.wwwz() * tmp_c3100)) * invdet;
454
455 // m.i01 := (i01 * -c5 + i02 * c4 + i03 * -c3) * invdet;
456 // m.i11 := (i00 * c5 + i02 * -c2 + i03 * c1) * invdet;
457 // m.i21 := (i00 * -c4 + i01 * c2 + i03 * -c0) * invdet;
458 // m.i31 := (i00 * c3 + i01 * -c1 + i02 * c0) * invdet;
459 tmp_c5543 = -tmp_c5543;
460 tmp_c4221 = -tmp_c4221;
461 tmp_c3100 = -tmp_c3100;
462 hilet inv_col1 = ((t._col0.yxxx() * tmp_c5543) + (t._col0.zzyy() * tmp_c4221) + (t._col0.wwwz() * tmp_c3100)) * invdet;
463
464 // m.i02 := (i31 * s5 + i32 * -s4 + i33 * s3) * invdet;
465 // m.i12 := (i30 * -s5 + i32 * s2 + i33 * -s1) * invdet;
466 // m.i22 := (i30 * s4 + i31 * -s2 + i33 * s0) * invdet;
467 // m.i32 := (i30 * -s3 + i31 * s1 + i32 * -s0) * invdet;
468 auto tmp_s5543 = neg<0b1010>(s45__.yyx0() + s0123._000w());
469 auto tmp_s4221 = neg<0b0101>(s45__.x000() + s0123._0zzy());
470 auto tmp_s3100 = neg<0b1010>(s0123.wyxx());
471 hilet inv_col2 = ((t._col3.yxxx() * tmp_s5543) + (t._col3.zzyy() * tmp_s4221) + (t._col3.wwwz() * tmp_s3100)) * invdet;
472
473 // m.i03 := (i21 * -s5 + i22 * s4 + i23 * -s3) * invdet;
474 // m.i13 := (i20 * s5 + i22 * -s2 + i23 * s1) * invdet;
475 // m.i23 := (i20 * -s4 + i21 * s2 + i23 * -s0) * invdet;
476 // m.i33 := (i20 * s3 + i21 * -s1 + i22 * s0) * invdet;
477 tmp_s5543 = -tmp_s5543;
478 tmp_s4221 = -tmp_s4221;
479 tmp_s3100 = -tmp_s3100;
480 hilet inv_col3 = ((t._col2.yxxx() * tmp_s5543) + (t._col2.zzyy() * tmp_s4221) + (t._col2.wwwz() * tmp_s3100)) * invdet;
481
482 return matrix3{inv_col0, inv_col1, inv_col2, inv_col3};
483 }
484
485private:
486 f32x4 _col0;
487 f32x4 _col1;
488 f32x4 _col2;
489 f32x4 _col3;
490
491 template<char Axis>
492 [[nodiscard]] static constexpr f32x4 reflect_column() noexcept
493 {
494 if constexpr (Axis == 'x') {
495 return f32x4{1.0f, 0.0f, 0.0f, 0.0f};
496 } else if constexpr (Axis == 'X') {
497 return f32x4{-1.0f, 0.0f, 0.0f, 0.0f};
498 } else if constexpr (Axis == 'y') {
499 return f32x4{0.0f, 1.0f, 0.0f, 0.0f};
500 } else if constexpr (Axis == 'Y') {
501 return f32x4{0.0f, -1.0f, 0.0f, 0.0f};
502 } else if constexpr (Axis == 'z') {
503 return f32x4{0.0f, 0.0f, 1.0f, 0.0f};
504 } else if constexpr (Axis == 'Z') {
505 return f32x4{0.0f, 0.0f, -1.0f, 0.0f};
506 } else if constexpr (Axis == 'w') {
507 return f32x4{0.0f, 0.0f, 0.0f, 1.0f};
508 } else if constexpr (Axis == 'W') {
509 return f32x4{0.0f, 0.0f, 0.0f, -1.0f};
510 } else {
512 }
513 }
514};
515
516
517
518}} // 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
@ other
The gui_event does not have associated data.
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
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
A 2D or 3D homogenius matrix for transforming homogenious vectors and points.
Definition matrix3.hpp:29
friend constexpr matrix3 transpose(matrix3 const &rhs) noexcept
Matrix transpose.
Definition matrix3.hpp:318
constexpr f32x4 operator*(f32x4 const &rhs) const noexcept
Transform a f32x4 numeric array by the matrix.
Definition matrix3.hpp:310
friend constexpr matrix3 reflect(matrix3 const &rhs) noexcept
Reflect axis of a matrix.
Definition matrix3.hpp:358
constexpr matrix3(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 matrix3.hpp:54
constexpr matrix3(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 matrix3.hpp:139
constexpr matrix3(matrix2 const &other) noexcept
Copy-construct a matrix from a smaller matrix.
Definition matrix3.hpp:162
constexpr matrix3(rotate3 const &rhs) noexcept
Convert quaternion to matrix.
Definition matrix3.hpp:206
constexpr friend bool operator==(matrix3 const &lhs, matrix3 const &rhs) noexcept
Compare two matrices potentially of different dimensions.
Definition matrix3.hpp:368
constexpr matrix3() noexcept
Constructs an identity matrix.
Definition matrix3.hpp:38
friend constexpr f32x4 & get(matrix3 &rhs) noexcept
Get a column.
Definition matrix3.hpp:285
constexpr matrix3 operator~() const
Invert matrix.
Definition matrix3.hpp:376
friend constexpr f32x4 const & get(matrix3 const &rhs) noexcept
Get a column.
Definition matrix3.hpp:264
constexpr matrix3(float c0r0, float c1r0, float c2r0, float c0r1, float c1r1, float c2r1, float c0r2, float c1r2, float c2r2) noexcept
Construct a matrix from two vectors.
Definition matrix3.hpp:103
static constexpr matrix3 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 matrix3.hpp:253
constexpr matrix3(vector3 col0, vector3 col1, vector3 col2, vector3 col3=vector3{}) noexcept
Construct a matrix from four vectors.
Definition matrix3.hpp:66
Definition rotate3.hpp:11
A high-level geometric vector Part of the high-level vector, point, mat and color types.
Definition vector3.hpp:19