HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
vec.hpp
1// Copyright 2020 Pokitec
2// All rights reserved.
3
4#pragma once
5
6#include "TTauri/Foundation/required.hpp"
7#include "TTauri/Foundation/numeric_cast.hpp"
8#include "TTauri/Foundation/strings.hpp"
9#include "TTauri/Foundation/exceptions.hpp"
10#include "TTauri/Foundation/float16.hpp"
11#include <fmt/format.h>
12#include <xmmintrin.h>
13#include <immintrin.h>
14#include <smmintrin.h>
15#include <cstdint>
16#include <stdexcept>
17#include <array>
18#include <ostream>
19
20namespace tt {
21
37class vec {
38 /* Intrinsic value of the vec.
39 * Since the __m64 data type is not supported by MSVC on x64 it does
40 * not yield a performance improvement to create a seperate 2D vector
41 * class.
42 *
43 * The elements in __m128 are assigned as follows.
44 * - [127:96] w, alpha
45 * - [95:64] z, blue
46 * - [63:32] y, green
47 * - [31:0] x, red
48 */
49 __m128 v;
50
51public:
52 /* Create a zeroed out vec.
53 */
54 tt_force_inline vec() noexcept : vec(_mm_setzero_ps()) {}
55 tt_force_inline vec(vec const &rhs) noexcept = default;
56 tt_force_inline vec &operator=(vec const &rhs) noexcept = default;
57 tt_force_inline vec(vec &&rhs) noexcept = default;
58 tt_force_inline vec &operator=(vec &&rhs) noexcept = default;
59
60 tt_force_inline vec(__m128 rhs) noexcept :
61 v(rhs) {}
62
63 tt_force_inline vec &operator=(__m128 rhs) noexcept {
64 v = rhs;
65 return *this;
66 }
67
68 tt_force_inline operator __m128 () const noexcept {
69 return v;
70 }
71
72 explicit tt_force_inline vec(std::array<float,4> const &rhs) noexcept :
73 v(_mm_loadu_ps(rhs.data())) {}
74
75 tt_force_inline vec &operator=(std::array<float,4> const &rhs) noexcept {
76 v = _mm_loadu_ps(rhs.data());
77 return *this;
78 }
79
80 explicit tt_force_inline operator std::array<float,4> () const noexcept {
82 _mm_storeu_ps(r.data(), v);
83 return r;
84 }
85
86 explicit tt_force_inline vec(std::array<float,2> const &rhs) noexcept :
87 v(_mm_loadl_pi(_mm_setzero_ps(), reinterpret_cast<__m64 const *>(rhs.data()))) {}
88
89 tt_force_inline vec &operator=(std::array<float,2> const &rhs) noexcept {
90 v = _mm_loadl_pi(_mm_setzero_ps(), reinterpret_cast<__m64 const *>(rhs.data()));
91 return *this;
92 }
93
94 explicit tt_force_inline operator std::array<float,2> () const noexcept {
96 _mm_storel_pi(reinterpret_cast<__m64 *>(r.data()), v);
97 return r;
98 }
99
100 explicit tt_force_inline vec(std::array<float16,4> const &rhs) noexcept :
101 v(_mm_cvtph_ps(_mm_loadu_si64(rhs.data()))) {}
102
103 tt_force_inline vec& operator=(std::array<float16,4> const &rhs) noexcept {
104 v = _mm_cvtph_ps(_mm_loadu_si64(rhs.data()));
105 return *this;
106 }
107
108 explicit tt_force_inline operator std::array<float16,4> () const noexcept {
110 _mm_storeu_si64(r.data(), _mm_cvtps_ph(v, _MM_FROUND_CUR_DIRECTION));
111 return r;
112 }
113
118 template<typename T, std::enable_if_t<std::is_arithmetic_v<T>,int> = 0>
119 explicit tt_force_inline vec(T rhs) noexcept:
120 vec(_mm_set_ps1(numeric_cast<float>(rhs))) {}
121
126 tt_force_inline vec &operator=(float rhs) noexcept {
127 return *this = _mm_set_ps1(rhs);
128 }
129
139 tt_force_inline vec(float x, float y, float z=0.0f, float w=0.0f) noexcept :
140 v(_mm_set_ps(w, z, y, x)) {}
141
142 tt_force_inline vec(double x, double y) noexcept :
143 v(_mm_cvtpd_ps(_mm_set_pd(y, x))) {}
144
145 tt_force_inline vec(double x, double y, double z, double w=0.0f) noexcept :
146 v(_mm256_cvtpd_ps(_mm256_set_pd(w, z, y, x))) {}
147
148 tt_force_inline vec(int x, int y, int z=0, int w=0) noexcept :
149 v(_mm_cvtepi32_ps(_mm_set_epi32(w, z, y, x))) {}
150
151 template<typename T, std::enable_if_t<std::is_arithmetic_v<T>,int> = 0>
152 tt_force_inline static vec make_x(T x) noexcept {
153 return vec{_mm_set_ss(numeric_cast<float>(x))};
154 }
155
156 template<typename T, std::enable_if_t<std::is_arithmetic_v<T>,int> = 0>
157 tt_force_inline static vec make_y(T y) noexcept {
158 return vec{_mm_permute_ps(_mm_set_ss(numeric_cast<float>(y)), _MM_SHUFFLE(1,1,0,1))};
159 }
160
161 template<typename T, std::enable_if_t<std::is_arithmetic_v<T>,int> = 0>
162 tt_force_inline static vec make_z(T z) noexcept {
163 return vec{_mm_permute_ps(_mm_set_ss(numeric_cast<float>(z)), _MM_SHUFFLE(1,0,1,1))};
164 }
165
166 template<typename T, std::enable_if_t<std::is_arithmetic_v<T>,int> = 0>
167 tt_force_inline static vec make_w(T w) noexcept {
168 return vec{_mm_permute_ps(_mm_set_ss(numeric_cast<float>(w)), _MM_SHUFFLE(0,1,1,1))};
169 }
170
180 [[nodiscard]] tt_force_inline static vec point(float x=0.0f, float y=0.0f, float z=0.0f) noexcept {
181 return vec{x, y, z, 1.0f};
182 }
183
184 [[nodiscard]] tt_force_inline static vec point(int x=0.0f, int y=0.0f, int z=0.0f) noexcept {
185 return vec{x, y, z, 1};
186 }
187
188
198 [[nodiscard]] tt_force_inline static vec point(vec rhs) noexcept {
199 return rhs.xyz1();
200 }
201
209 [[nodiscard]] tt_force_inline static vec origin() noexcept {
210 return vec{_mm_permute_ps(_mm_set_ss(1.0f), 0b00'01'10'11)};
211 }
212
226 [[nodiscard]] tt_force_inline static vec color(float r, float g, float b, float a=1.0f) noexcept {
227 return vec{r, g, b, a};
228 }
229
230 [[nodiscard]] static vec colorFromSRGB(float r, float g, float b, float a=1.0f) noexcept;
231
232 [[nodiscard]] static vec colorFromSRGB(uint8_t r, uint8_t g, uint8_t b, uint8_t a=255) noexcept;
233
234 [[nodiscard]] static vec colorFromSRGB(std::string_view str);
235
236 template<size_t I>
237 tt_force_inline vec &set(float rhs) noexcept {
238 static_assert(I <= 3);
239 ttlet tmp = _mm_set_ss(rhs);
240 return *this = _mm_insert_ps(*this, tmp, I << 4);
241 }
242
243 template<size_t I>
244 tt_force_inline float get() const noexcept {
245 static_assert(I <= 3);
246 ttlet tmp = _mm_permute_ps(*this, I);
247 return _mm_cvtss_f32(tmp);
248 }
249
250 tt_force_inline bool is_point() const noexcept {
251 return w() == 1.0f;
252 }
253
254 tt_force_inline bool is_vector() const noexcept {
255 return w() == 0.0f;
256 }
257
258 tt_force_inline bool is_opaque() const noexcept {
259 return a() == 1.0f;
260 }
261
262 tt_force_inline bool is_transparent() const noexcept {
263 return a() == 0.0f;
264 }
265
266 constexpr size_t size() const noexcept {
267 return 4;
268 }
269
270 tt_force_inline float operator[](size_t i) const noexcept {
271 tt_assume(i <= 3);
272 ttlet i_ = _mm_set1_epi32(static_cast<uint32_t>(i));
273 ttlet tmp = _mm_permutevar_ps(*this, i_);
274 return _mm_cvtss_f32(tmp);
275 }
276
277 tt_force_inline vec &x(float rhs) noexcept { return set<0>(rhs); }
278 tt_force_inline vec &y(float rhs) noexcept { return set<1>(rhs); }
279 tt_force_inline vec &z(float rhs) noexcept { return set<2>(rhs); }
280 tt_force_inline vec &w(float rhs) noexcept { return set<3>(rhs); }
281 tt_force_inline vec &r(float rhs) noexcept { return set<0>(rhs); }
282 tt_force_inline vec &g(float rhs) noexcept { return set<1>(rhs); }
283 tt_force_inline vec &b(float rhs) noexcept { return set<2>(rhs); }
284 tt_force_inline vec &a(float rhs) noexcept { return set<3>(rhs); }
285 tt_force_inline vec &width(float rhs) noexcept { return set<0>(rhs); }
286 tt_force_inline vec &height(float rhs) noexcept { return set<1>(rhs); }
287 tt_force_inline vec &depth(float rhs) noexcept { return set<2>(rhs); }
288 tt_force_inline float x() const noexcept { return get<0>(); }
289 tt_force_inline float y() const noexcept { return get<1>(); }
290 tt_force_inline float z() const noexcept { return get<2>(); }
291 tt_force_inline float w() const noexcept { return get<3>(); }
292 tt_force_inline float r() const noexcept { return get<0>(); }
293 tt_force_inline float g() const noexcept { return get<1>(); }
294 tt_force_inline float b() const noexcept { return get<2>(); }
295 tt_force_inline float a() const noexcept { return get<3>(); }
296 tt_force_inline float width() const noexcept { return get<0>(); }
297 tt_force_inline float height() const noexcept { return get<1>(); }
298 tt_force_inline float depth() const noexcept { return get<2>(); }
299
300
301 tt_force_inline vec &operator+=(vec const &rhs) noexcept {
302 return *this = _mm_add_ps(*this, rhs);
303 }
304
305 tt_force_inline vec &operator-=(vec const &rhs) noexcept {
306 return *this = _mm_sub_ps(*this, rhs);
307 }
308
309 tt_force_inline vec &operator*=(vec const &rhs) noexcept {
310 return *this = _mm_mul_ps(*this, rhs);
311 }
312
313 tt_force_inline vec &operator/=(vec const &rhs) noexcept {
314 return *this = _mm_div_ps(*this, rhs);
315 }
316
317 [[nodiscard]] tt_force_inline friend vec operator-(vec const &rhs) noexcept {
318 return _mm_sub_ps(_mm_setzero_ps(), rhs);
319 }
320
321 [[nodiscard]] tt_force_inline friend vec operator+(vec const &lhs, vec const &rhs) noexcept {
322 return _mm_add_ps(lhs, rhs);
323 }
324
325 [[nodiscard]] tt_force_inline friend vec operator-(vec const &lhs, vec const &rhs) noexcept {
326 return _mm_sub_ps(lhs, rhs);
327 }
328
329 [[nodiscard]] tt_force_inline friend vec operator*(vec const &lhs, vec const &rhs) noexcept {
330 return _mm_mul_ps(lhs, rhs);
331 }
332
333 template<typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
334 [[nodiscard]] tt_force_inline friend vec operator*(vec const &lhs, T const &rhs) noexcept {
335 return lhs * vec{rhs};
336 }
337
338 template<typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
339 [[nodiscard]] tt_force_inline friend vec operator*(T const &lhs, vec const &rhs) noexcept {
340 return vec{lhs} * rhs;
341 }
342
343 [[nodiscard]] tt_force_inline friend vec operator/(vec const &lhs, vec const &rhs) noexcept {
344 return _mm_div_ps(lhs, rhs);
345 }
346
347 [[nodiscard]] tt_force_inline friend vec max(vec const &lhs, vec const &rhs) noexcept {
348 return _mm_max_ps(lhs, rhs);
349 }
350
351 [[nodiscard]] tt_force_inline friend vec min(vec const &lhs, vec const &rhs) noexcept {
352 return _mm_min_ps(lhs, rhs);
353 }
354
355 [[nodiscard]] tt_force_inline friend vec abs(vec const &rhs) noexcept {
356 return max(rhs, -rhs);
357 }
358
362 [[nodiscard]] tt_force_inline friend int eq(vec const &lhs, vec const &rhs) noexcept {
363 return _mm_movemask_ps(_mm_cmpeq_ps(lhs, rhs));
364 }
365
369 [[nodiscard]] tt_force_inline friend int ne(vec const &lhs, vec const &rhs) noexcept {
370 return _mm_movemask_ps(_mm_cmpneq_ps(lhs, rhs));
371 }
372
373 [[nodiscard]] tt_force_inline friend bool operator==(vec const &lhs, vec const &rhs) noexcept {
374 return !ne(lhs, rhs);
375 }
376
377 [[nodiscard]] tt_force_inline friend bool operator!=(vec const &lhs, vec const &rhs) noexcept {
378 return !(lhs == rhs);
379 }
380
384 [[nodiscard]] tt_force_inline friend int operator<(vec const &lhs, vec const &rhs) noexcept {
385 return _mm_movemask_ps(_mm_cmplt_ps(lhs, rhs));
386 }
387
391 [[nodiscard]] tt_force_inline friend int operator<=(vec const &lhs, vec const &rhs) noexcept {
392 return _mm_movemask_ps(_mm_cmple_ps(lhs, rhs));
393 }
394
398 [[nodiscard]] tt_force_inline friend int operator>(vec const &lhs, vec const &rhs) noexcept {
399 return _mm_movemask_ps(_mm_cmpgt_ps(lhs, rhs));
400 }
401
405 [[nodiscard]] tt_force_inline friend int operator>=(vec const &lhs, vec const &rhs) noexcept {
406 return _mm_movemask_ps(_mm_cmpge_ps(lhs, rhs));
407 }
408
409 [[nodiscard]] tt_force_inline friend __m128 _length_squared(vec const &rhs) noexcept {
410 ttlet tmp1 = _mm_mul_ps(rhs, rhs);
411 ttlet tmp2 = _mm_hadd_ps(tmp1, tmp1);
412 return _mm_hadd_ps(tmp2, tmp2);
413 }
414
415 [[nodiscard]] tt_force_inline friend float length_squared(vec const &rhs) noexcept {
416 return _mm_cvtss_f32(_length_squared(rhs));
417 }
418
419 [[nodiscard]] tt_force_inline friend float length(vec const &rhs) noexcept {
420 ttlet tmp = _mm_sqrt_ps(_length_squared(rhs));
421 return _mm_cvtss_f32(tmp);
422 }
423
424 [[nodiscard]] tt_force_inline friend vec normalize(vec const &rhs) noexcept {
425 auto ___l = _length_squared(rhs);
426 auto llll = _mm_permute_ps(___l, _MM_SHUFFLE(0,0,0,0));
427 auto iiii = _mm_rsqrt_ps(llll);
428 return _mm_mul_ps(rhs, iiii);
429 }
430
435 [[nodiscard]] vec resize2DRetainingAspectRatio(vec const &rhs) noexcept {
436 ttlet ratio2D = rhs / *this;
437 ttlet ratio = std::min(ratio2D.x(), ratio2D.y());
438 return *this * ratio;
439 }
440
441 [[nodiscard]] tt_force_inline friend vec homogeneous_divide(vec const &rhs) noexcept {
442 auto wwww = _mm_permute_ps(rhs, _MM_SHUFFLE(3,3,3,3));
443 auto rcp_wwww = _mm_rcp_ps(wwww);
444 return _mm_mul_ps(rhs, rcp_wwww);
445 }
446
447 [[nodiscard]] tt_force_inline friend float dot(vec const &lhs, vec const &rhs) noexcept {
448 ttlet tmp1 = _mm_mul_ps(lhs, rhs);
449 ttlet tmp2 = _mm_hadd_ps(tmp1, tmp1);
450 ttlet tmp3 = _mm_hadd_ps(tmp2, tmp2);
451 return _mm_cvtss_f32(tmp3);
452 }
453
454 [[nodiscard]] tt_force_inline friend vec reciprocal(vec const &rhs) noexcept {
455 return _mm_rcp_ps(rhs);
456 }
457
458 template<bool nx, bool ny, bool nz, bool nw>
459 friend vec neg(vec const &rhs) noexcept;
460
461 [[nodiscard]] tt_force_inline friend vec hadd(vec const &lhs, vec const &rhs) noexcept {
462 return _mm_hadd_ps(lhs, rhs);
463 }
464
465 [[nodiscard]] tt_force_inline friend vec hsub(vec const &lhs, vec const &rhs) noexcept {
466 return _mm_hsub_ps(lhs, rhs);
467 }
468
469 [[nodiscard]] tt_force_inline friend float viktor_cross(vec const &lhs, vec const &rhs) noexcept {
470 // a.x * b.y - a.y * b.x
471 ttlet tmp1 = _mm_permute_ps(rhs, _MM_SHUFFLE(2,3,0,1));
472 ttlet tmp2 = _mm_mul_ps(lhs, tmp1);
473 ttlet tmp3 = _mm_hsub_ps(tmp2, tmp2);
474 return _mm_cvtss_f32(tmp3);
475 }
476
477 // x=a.y*b.z - a.z*b.y
478 // y=a.z*b.x - a.x*b.z
479 // z=a.x*b.y - a.y*b.x
480 // w=a.w*b.w - a.w*b.w
481 [[nodiscard]] friend vec cross(vec const &lhs, vec const &rhs) noexcept {
482 ttlet a_left = _mm_permute_ps(lhs, _MM_SHUFFLE(3,0,2,1));
483 ttlet b_left = _mm_permute_ps(rhs, _MM_SHUFFLE(3,1,0,2));
484 ttlet left = _mm_mul_ps(a_left, b_left);
485
486 ttlet a_right = _mm_permute_ps(lhs, _MM_SHUFFLE(3,1,0,2));
487 ttlet b_right = _mm_permute_ps(rhs, _MM_SHUFFLE(3,0,2,1));
488 ttlet right = _mm_mul_ps(a_right, b_right);
489 return _mm_sub_ps(left, right);
490 }
491
494 [[nodiscard]] tt_force_inline friend vec normal(vec const &rhs) noexcept {
495 tt_assume(rhs.z() == 0.0f && rhs.w() == 0.0f);
496 return normalize(vec{-rhs.y(), rhs.x()});
497 }
498
499 [[nodiscard]] friend vec ceil(vec const &rhs) noexcept {
500 return _mm_ceil_ps(rhs);
501 }
502
503 [[nodiscard]] friend vec floor(vec const &rhs) noexcept {
504 return _mm_floor_ps(rhs);
505 }
506
507 [[nodiscard]] friend vec round(vec const &rhs) noexcept {
508 return _mm_round_ps(rhs, _MM_FROUND_CUR_DIRECTION);
509 }
510
511 [[nodiscard]] friend std::array<vec,4> transpose(vec col0, vec col1, vec col2, vec col3) noexcept {
512 _MM_TRANSPOSE4_PS(col0, col1, col2, col3);
513 return { col0, col1, col2, col3 };
514 }
515
518 [[nodiscard]] friend vec midpoint(vec const &p1, vec const &p2) noexcept {
519 return (p1 + p2) * vec{0.5};
520 }
521
522 [[nodiscard]] friend vec desaturate(vec const &color, float brightness) noexcept {
523 // Use luminance ratios and change the brightness.
524 // luminance ratios according to BT.709.
525 ttlet _0BGR = color * vec{0.2126, 0.7152, 0.0722} * vec{brightness};
526 ttlet __SS = _mm_hadd_ps(_0BGR, _0BGR);
527 ttlet ___L = _mm_hadd_ps(__SS, __SS);
528 ttlet LLLL = _mm_permute_ps(___L, _MM_SHUFFLE(0,0,0,0));
529 // grayscale, with original alpha.
530 return _mm_blend_ps(LLLL, color, 0b1000);
531 }
532
533 [[nodiscard]] friend vec composit(vec const &under, vec const &over) noexcept {
534 if (over.is_transparent()) {
535 return under;
536 }
537 if (over.is_opaque()) {
538 return over;
539 }
540
541 ttlet over_alpha = over.wwww();
542 ttlet under_alpha = under.wwww();
543
544 ttlet over_color = over.xyz1();
545 ttlet under_color = under.xyz1();
546
547 ttlet output_color =
548 over_color * over_alpha +
549 under_color * under_alpha * (vec{1.0} - over_alpha);
550
551 return output_color / output_color.www1();
552 }
553
556 [[nodiscard]] friend vec reflect_point(vec const &p, vec const anchor) noexcept {
557 return anchor - (p - anchor);
558 }
559
560 [[nodiscard]] friend std::string to_string(vec const &rhs) noexcept {
561 return fmt::format("({}, {}, {}, {})", rhs.x(), rhs.y(), rhs.z(), rhs.w());
562 }
563
564 std::ostream friend &operator<<(std::ostream &lhs, vec const &rhs) noexcept {
565 return lhs << to_string(rhs);
566 }
567
568 template<std::size_t I>
569 [[nodiscard]] tt_force_inline friend float get(vec const &rhs) noexcept {
570 return rhs.get<I>();
571 }
572
573 template<char a, char b, char c, char d>
574 [[nodiscard]] constexpr static int swizzle_permute_mask() noexcept {
575 int r = 0;
576 switch (a) {
577 case 'x': r |= 0b00'00'00'00; break;
578 case 'y': r |= 0b00'00'00'01; break;
579 case 'z': r |= 0b00'00'00'10; break;
580 case 'w': r |= 0b00'00'00'11; break;
581 case '0': r |= 0b00'00'00'00; break;
582 case '1': r |= 0b00'00'00'00; break;
583 }
584 switch (b) {
585 case 'x': r |= 0b00'00'00'00; break;
586 case 'y': r |= 0b00'00'01'00; break;
587 case 'z': r |= 0b00'00'10'00; break;
588 case 'w': r |= 0b00'00'11'00; break;
589 case '0': r |= 0b00'00'01'00; break;
590 case '1': r |= 0b00'00'01'00; break;
591 }
592 switch (c) {
593 case 'x': r |= 0b00'00'00'00; break;
594 case 'y': r |= 0b00'01'00'00; break;
595 case 'z': r |= 0b00'10'00'00; break;
596 case 'w': r |= 0b00'11'00'00; break;
597 case '0': r |= 0b00'10'00'00; break;
598 case '1': r |= 0b00'10'00'00; break;
599 }
600 switch (d) {
601 case 'x': r |= 0b00'00'00'00; break;
602 case 'y': r |= 0b01'00'00'00; break;
603 case 'z': r |= 0b10'00'00'00; break;
604 case 'w': r |= 0b11'00'00'00; break;
605 case '0': r |= 0b11'00'00'00; break;
606 case '1': r |= 0b11'00'00'00; break;
607 }
608 return r;
609 }
610
611 template<char a, char b, char c, char d>
612 [[nodiscard]] constexpr static int swizzle_zero_mask() noexcept {
613 int r = 0;
614 r |= (a == '1') ? 0 : 0b0001;
615 r |= (b == '1') ? 0 : 0b0010;
616 r |= (c == '1') ? 0 : 0b0100;
617 r |= (d == '1') ? 0 : 0b1000;
618 return r;
619 }
620
621 template<char a, char b, char c, char d>
622 [[nodiscard]] constexpr static int swizzle_number_mask() noexcept {
623 int r = 0;
624 r |= (a == '0' || a == '1') ? 0b0001 : 0;
625 r |= (b == '0' || b == '1') ? 0b0010 : 0;
626 r |= (c == '0' || c == '1') ? 0b0100 : 0;
627 r |= (d == '0' || d == '1') ? 0b1000 : 0;
628 return r;
629 }
630
631 template<char a, char b, char c, char d>
632 [[nodiscard]] tt_force_inline vec swizzle() const noexcept {
633 constexpr int permute_mask = vec::swizzle_permute_mask<a,b,c,d>();
634 constexpr int zero_mask = vec::swizzle_zero_mask<a,b,c,d>();
635 constexpr int number_mask = vec::swizzle_number_mask<a,b,c,d>();
636
637 __m128 swizzled;
638 // Clang is able to optimize these intrinsics, MSVC is not.
639 if constexpr (permute_mask != 0b11'10'01'00) {
640 swizzled = _mm_permute_ps(*this, permute_mask);
641 } else {
642 swizzled = *this;
643 }
644
645 __m128 numbers;
646 if constexpr (zero_mask == 0b0000) {
647 numbers = _mm_set_ps1(1.0f);
648 } else if constexpr (zero_mask == 0b1111) {
649 numbers = _mm_setzero_ps();
650 } else if constexpr (zero_mask == 0b1110) {
651 numbers = _mm_set_ss(1.0f);
652 } else {
653 ttlet _1111 = _mm_set_ps1(1.0f);
654 numbers = _mm_insert_ps(_1111, _1111, zero_mask);
655 }
656
657 __m128 result;
658 if constexpr (number_mask == 0b0000) {
659 result = swizzled;
660 } else if constexpr (number_mask == 0b1111) {
661 result = numbers;
662 } else if constexpr (((zero_mask | ~number_mask) & 0b1111) == 0b1111) {
663 result = _mm_insert_ps(swizzled, swizzled, number_mask);
664 } else {
665 result = _mm_blend_ps(swizzled, numbers, number_mask);
666 }
667 return result;
668 }
669
670#define SWIZZLE4(name, A, B, C, D)\
671 [[nodiscard]] vec name() const noexcept {\
672 return swizzle<A, B, C, D>();\
673 }
674
675#define SWIZZLE4_GEN3(name, A, B, C)\
676 SWIZZLE4(name ## 0, A, B, C, '0')\
677 SWIZZLE4(name ## 1, A, B, C, '1')\
678 SWIZZLE4(name ## x, A, B, C, 'x')\
679 SWIZZLE4(name ## y, A, B, C, 'y')\
680 SWIZZLE4(name ## z, A, B, C, 'z')\
681 SWIZZLE4(name ## w, A, B, C, 'w')
682
683#define SWIZZLE4_GEN2(name, A, B)\
684 SWIZZLE4_GEN3(name ## 0, A, B, '0')\
685 SWIZZLE4_GEN3(name ## 1, A, B, '1')\
686 SWIZZLE4_GEN3(name ## x, A, B, 'x')\
687 SWIZZLE4_GEN3(name ## y, A, B, 'y')\
688 SWIZZLE4_GEN3(name ## z, A, B, 'z')\
689 SWIZZLE4_GEN3(name ## w, A, B, 'w')
690
691#define SWIZZLE4_GEN1(name, A)\
692 SWIZZLE4_GEN2(name ## 0, A, '0')\
693 SWIZZLE4_GEN2(name ## 1, A, '1')\
694 SWIZZLE4_GEN2(name ## x, A, 'x')\
695 SWIZZLE4_GEN2(name ## y, A, 'y')\
696 SWIZZLE4_GEN2(name ## z, A, 'z')\
697 SWIZZLE4_GEN2(name ## w, A, 'w')
698
699 SWIZZLE4_GEN1(_0, '0')
700 SWIZZLE4_GEN1(_1, '1')
701 SWIZZLE4_GEN1(x, 'x')
702 SWIZZLE4_GEN1(y, 'y')
703 SWIZZLE4_GEN1(z, 'z')
704 SWIZZLE4_GEN1(w, 'w')
705
706#define SWIZZLE3(name, A, B, C)\
707 [[nodiscard]] vec name() const noexcept {\
708 return swizzle<A,B,C,'w'>();\
709 }
710
711#define SWIZZLE3_GEN2(name, A, B)\
712 SWIZZLE3(name ## 0, A, B, '0')\
713 SWIZZLE3(name ## 1, A, B, '1')\
714 SWIZZLE3(name ## x, A, B, 'x')\
715 SWIZZLE3(name ## y, A, B, 'y')\
716 SWIZZLE3(name ## z, A, B, 'z')\
717 SWIZZLE3(name ## w, A, B, 'w')
718
719#define SWIZZLE3_GEN1(name, A)\
720 SWIZZLE3_GEN2(name ## 0, A, '0')\
721 SWIZZLE3_GEN2(name ## 1, A, '1')\
722 SWIZZLE3_GEN2(name ## x, A, 'x')\
723 SWIZZLE3_GEN2(name ## y, A, 'y')\
724 SWIZZLE3_GEN2(name ## z, A, 'z')\
725 SWIZZLE3_GEN2(name ## w, A, 'w')
726
727 SWIZZLE3_GEN1(_0, '0')
728 SWIZZLE3_GEN1(_1, '1')
729 SWIZZLE3_GEN1(x, 'x')
730 SWIZZLE3_GEN1(y, 'y')
731 SWIZZLE3_GEN1(z, 'z')
732 SWIZZLE3_GEN1(w, 'w')
733
734#define SWIZZLE2(name, A, B)\
735 [[nodiscard]] vec name() const noexcept {\
736 return swizzle<A,B,'0','w'>();\
737 }
738
739#define SWIZZLE2_GEN1(name, A)\
740 SWIZZLE2(name ## 0, A, '0')\
741 SWIZZLE2(name ## 1, A, '1')\
742 SWIZZLE2(name ## x, A, 'x')\
743 SWIZZLE2(name ## y, A, 'y')\
744 SWIZZLE2(name ## z, A, 'z')\
745 SWIZZLE2(name ## w, A, 'w')
746
747 SWIZZLE2_GEN1(_0, '0')
748 SWIZZLE2_GEN1(_1, '1')
749 SWIZZLE2_GEN1(x, 'x')
750 SWIZZLE2_GEN1(y, 'y')
751 SWIZZLE2_GEN1(z, 'z')
752 SWIZZLE2_GEN1(w, 'w')
753};
754
755template<bool nx, bool ny, bool nz, bool nw>
756[[nodiscard]] vec neg(vec const &rhs) noexcept {
757 ttlet n_rhs = -rhs;
758
759 __m128 tmp = rhs;
760
761 if constexpr (nx) {
762 tmp = _mm_insert_ps(tmp, n_rhs, 0b00'00'0000);
763 }
764 if constexpr (ny) {
765 tmp = _mm_insert_ps(tmp, n_rhs, 0b01'01'0000);
766 }
767 if constexpr (nz) {
768 tmp = _mm_insert_ps(tmp, n_rhs, 0b10'10'0000);
769 }
770 if constexpr (nw) {
771 tmp = _mm_insert_ps(tmp, n_rhs, 0b11'11'0000);
772 }
773
774 return tmp;
775}
776
777}
778
779#undef SWIZZLE4
780#undef SWIZZLE4_GEN1
781#undef SWIZZLE4_GEN2
782#undef SWIZZLE4_GEN3
783#undef SWIZZLE3
784#undef SWIZZLE3_GEN1
785#undef SWIZZLE3_GEN2
786#undef SWIZZLE2
787#undef SWIZZLE2_GEN1
STL namespace.
A 4D vector.
Definition vec.hpp:37
static tt_force_inline vec point(float x=0.0f, float y=0.0f, float z=0.0f) noexcept
Create a point out of 2 to 4 values.
Definition vec.hpp:180
tt_force_inline friend int eq(vec const &lhs, vec const &rhs) noexcept
Equal to.
Definition vec.hpp:362
tt_force_inline vec(float x, float y, float z=0.0f, float w=0.0f) noexcept
Create a vec out of 2 to 4 values.
Definition vec.hpp:139
static tt_force_inline vec origin() noexcept
Get a origin vector(0.0, 0.0, 0.0, 1.0).
Definition vec.hpp:209
tt_force_inline friend int operator<(vec const &lhs, vec const &rhs) noexcept
Less than.
Definition vec.hpp:384
tt_force_inline vec(T rhs) noexcept
Initialize a vec with all elements set to a value.
Definition vec.hpp:119
static tt_force_inline vec point(vec rhs) noexcept
Create a point out of 2 to 4 values.
Definition vec.hpp:198
friend vec midpoint(vec const &p1, vec const &p2) noexcept
Find a point at the midpoint between two points.
Definition vec.hpp:518
tt_force_inline friend int ne(vec const &lhs, vec const &rhs) noexcept
Not equal to.
Definition vec.hpp:369
static tt_force_inline vec color(float r, float g, float b, float a=1.0f) noexcept
Create a color out of 3 to 4 values.
Definition vec.hpp:226
tt_force_inline vec & operator=(float rhs) noexcept
Initialize a vec with all elements set to a value.
Definition vec.hpp:126
tt_force_inline friend int operator<=(vec const &lhs, vec const &rhs) noexcept
Less than or equal.
Definition vec.hpp:391
tt_force_inline friend int operator>(vec const &lhs, vec const &rhs) noexcept
Greater than.
Definition vec.hpp:398
vec resize2DRetainingAspectRatio(vec const &rhs) noexcept
Resize an extent while retaining aspect ratio.
Definition vec.hpp:435
tt_force_inline friend int operator>=(vec const &lhs, vec const &rhs) noexcept
Greater than or equal.
Definition vec.hpp:405
tt_force_inline friend vec normal(vec const &rhs) noexcept
Calculate the 2D normal on a 2D vector.
Definition vec.hpp:494
friend vec reflect_point(vec const &p, vec const anchor) noexcept
Find the point on the other side and at the same distance of an anchor-point.
Definition vec.hpp:556
T data(T... args)
T left(T... args)
T min(T... args)