LeviLamina
Loading...
Searching...
No Matches
VecImpl.h
1#pragma once
2
3#include <cmath> // IWYU pragma: keep
4
5#include "ll/api/base/Macro.h" // IWYU pragma: keep
6
7#define LL_VEC_X_MEMBER(T) \
8 union { \
9 T x, r, s; \
10 }
11#define LL_VEC_Y_MEMBER(T) \
12 union { \
13 T y, g, t; \
14 }
15#define LL_VEC_Z_MEMBER(T) \
16 union { \
17 T z, b, p; \
18 }
19#define LL_VEC_W_MEMBER(T) \
20 union { \
21 T w, a, q; \
22 }
23
24// NOLINTBEGIN
25
26#define LL_VEC2_IMPL(NAME, BNAME, TYPE, BASE) \
27 class LL_EBO NAME : public BASE<BNAME, TYPE, TYPE> { \
28 public: \
29 LL_VEC_X_MEMBER(TYPE); \
30 union { \
31 TYPE y, g, t, z, b, p; \
32 }; \
33 \
34 [[nodiscard]] constexpr NAME(NAME&&) noexcept = default; \
35 LL_MAY_CONSTEXPR NAME& operator=(NAME&&) noexcept = default; \
36 [[nodiscard]] constexpr NAME(NAME const&) noexcept = default; \
37 LL_MAY_CONSTEXPR NAME& operator=(NAME const&) noexcept = default; \
38 \
39 [[nodiscard]] constexpr NAME(TYPE all = 0) noexcept : x(all), z(all) {} \
40 \
41 template <std::convertible_to<TYPE> T0, std::convertible_to<TYPE> T1> \
42 [[nodiscard]] constexpr NAME(T0 x, T1 z) noexcept \
43 : x(static_cast<TYPE>((std::is_floating_point_v<T0> && !std::is_floating_point_v<TYPE>) ? std::floor(x) : x)), \
44 z(static_cast<TYPE>((std::is_floating_point_v<T1> && !std::is_floating_point_v<TYPE>) ? std::floor(z) : z) \
45 ) {} \
46 template <IsField T> \
47 [[nodiscard]] constexpr NAME(T const& vec) \
48 requires((IsIntN<T> || IsFloatN<T> || IsBoolN<T>) && T::size() == 2) \
49 : NAME() { \
50 T::forEachComponent([&]<typename axis_type, size_t iter> { \
51 if constexpr (std::is_floating_point_v<axis_type> && !std::is_floating_point_v<TYPE>) { \
52 this->get<TYPE, iter>() = static_cast<TYPE>(std::floor(vec.template get<axis_type, iter>())); \
53 } else { \
54 this->get<TYPE, iter>() = static_cast<TYPE>((vec.template get<axis_type, iter>())); \
55 } \
56 }); \
57 } \
58 template <typename T, size_t N> \
59 [[nodiscard]] constexpr T& get() noexcept { \
60 if constexpr (N == 0) { \
61 return x; \
62 } else if constexpr (N == 1) { \
63 return y; \
64 } else { \
65 static_assert(ll::traits::always_false<T>); \
66 } \
67 } \
68 template <typename T, size_t N> \
69 [[nodiscard]] constexpr T const& get() const noexcept { \
70 if constexpr (N == 0) { \
71 return x; \
72 } else if constexpr (N == 1) { \
73 return y; \
74 } else { \
75 static_assert(ll::traits::always_false<T>); \
76 } \
77 } \
78 }
79
80#define LL_VEC3_IMPL(NAME, BNAME, TYPE, BASE) \
81 class LL_EBO NAME : public BASE<BNAME, TYPE, TYPE, TYPE> { \
82 public: \
83 LL_VEC_X_MEMBER(TYPE); \
84 LL_VEC_Y_MEMBER(TYPE); \
85 LL_VEC_Z_MEMBER(TYPE); \
86 \
87 [[nodiscard]] constexpr NAME(NAME&&) = default; \
88 LL_MAY_CONSTEXPR NAME& operator=(NAME&&) = default; \
89 [[nodiscard]] constexpr NAME(NAME const&) = default; \
90 LL_MAY_CONSTEXPR NAME& operator=(NAME const&) = default; \
91 \
92 [[nodiscard]] constexpr NAME(TYPE all = 0) noexcept : x(all), y(all), z(all) {} \
93 \
94 template <std::convertible_to<TYPE> T0, std::convertible_to<TYPE> T1, std::convertible_to<TYPE> T2> \
95 [[nodiscard]] constexpr NAME(T0 x, T1 y, T2 z) noexcept \
96 : x(static_cast<TYPE>((std::is_floating_point_v<T0> && !std::is_floating_point_v<TYPE>) ? std::floor(x) : x)), \
97 y(static_cast<TYPE>((std::is_floating_point_v<T1> && !std::is_floating_point_v<TYPE>) ? std::floor(y) : y)), \
98 z(static_cast<TYPE>((std::is_floating_point_v<T2> && !std::is_floating_point_v<TYPE>) ? std::floor(z) : z) \
99 ) {} \
100 template <IsField T> \
101 [[nodiscard]] constexpr NAME(T const& vec) \
102 requires((IsIntN<T> || IsFloatN<T> || IsBoolN<T>) && T::size() == 3) \
103 : NAME() { \
104 T::forEachComponent([&]<typename axis_type, size_t iter> { \
105 if constexpr (std::is_floating_point_v<axis_type> && !std::is_floating_point_v<TYPE>) { \
106 this->get<TYPE, iter>() = static_cast<TYPE>(std::floor(vec.template get<axis_type, iter>())); \
107 } else { \
108 this->get<TYPE, iter>() = static_cast<TYPE>((vec.template get<axis_type, iter>())); \
109 } \
110 }); \
111 } \
112 template <typename T, size_t N> \
113 [[nodiscard]] constexpr T& get() noexcept { \
114 if constexpr (N == 0) { \
115 return x; \
116 } else if constexpr (N == 1) { \
117 return y; \
118 } else if constexpr (N == 2) { \
119 return z; \
120 } else { \
121 static_assert(ll::traits::always_false<T>); \
122 } \
123 } \
124 template <typename T, size_t N> \
125 [[nodiscard]] constexpr T const& get() const noexcept { \
126 if constexpr (N == 0) { \
127 return x; \
128 } else if constexpr (N == 1) { \
129 return y; \
130 } else if constexpr (N == 2) { \
131 return z; \
132 } else { \
133 static_assert(ll::traits::always_false<T>); \
134 } \
135 } \
136 }
137
138#define LL_VEC4_IMPL(NAME, BNAME, TYPE, BASE) \
139 class LL_EBO NAME : public BASE<BNAME, TYPE, TYPE, TYPE, TYPE> { \
140 public: \
141 LL_VEC_X_MEMBER(TYPE); \
142 LL_VEC_Y_MEMBER(TYPE); \
143 LL_VEC_Z_MEMBER(TYPE); \
144 LL_VEC_W_MEMBER(TYPE); \
145 \
146 [[nodiscard]] constexpr NAME(NAME&&) = default; \
147 LL_MAY_CONSTEXPR NAME& operator=(NAME&&) = default; \
148 [[nodiscard]] constexpr NAME(NAME const&) = default; \
149 LL_MAY_CONSTEXPR NAME& operator=(NAME const&) = default; \
150 \
151 [[nodiscard]] constexpr NAME(TYPE all = 0) noexcept : x(all), y(all), z(all), w(all) {} \
152 \
153 template < \
154 std::convertible_to<TYPE> T0, \
155 std::convertible_to<TYPE> T1, \
156 std::convertible_to<TYPE> T2, \
157 std::convertible_to<TYPE> T3> \
158 [[nodiscard]] constexpr NAME(T0 x, T1 y, T2 z, T3 w) noexcept \
159 : x(static_cast<TYPE>((std::is_floating_point_v<T0> && !std::is_floating_point_v<TYPE>) ? std::floor(x) : x)), \
160 y(static_cast<TYPE>((std::is_floating_point_v<T1> && !std::is_floating_point_v<TYPE>) ? std::floor(y) : y)), \
161 z(static_cast<TYPE>((std::is_floating_point_v<T2> && !std::is_floating_point_v<TYPE>) ? std::floor(z) : z)), \
162 w(static_cast<TYPE>((std::is_floating_point_v<T3> && !std::is_floating_point_v<TYPE>) ? std::floor(w) : w) \
163 ) {} \
164 template <IsField T> \
165 [[nodiscard]] constexpr NAME(T const& vec) \
166 requires((IsIntN<T> || IsFloatN<T> || IsBoolN<T>) && T::size() == 4) \
167 : NAME() { \
168 T::forEachComponent([&]<typename axis_type, size_t iter> { \
169 if constexpr (std::is_floating_point_v<axis_type> && !std::is_floating_point_v<TYPE>) { \
170 this->get<TYPE, iter>() = static_cast<TYPE>(std::floor(vec.template get<axis_type, iter>())); \
171 } else { \
172 this->get<TYPE, iter>() = static_cast<TYPE>((vec.template get<axis_type, iter>())); \
173 } \
174 }); \
175 } \
176 template <typename T, size_t N> \
177 [[nodiscard]] constexpr T& get() noexcept { \
178 if constexpr (N == 0) { \
179 return x; \
180 } else if constexpr (N == 1) { \
181 return y; \
182 } else if constexpr (N == 2) { \
183 return z; \
184 } else if constexpr (N == 3) { \
185 return w; \
186 } else { \
187 static_assert(ll::traits::always_false<T>); \
188 } \
189 } \
190 template <typename T, size_t N> \
191 [[nodiscard]] constexpr T const& get() const noexcept { \
192 if constexpr (N == 0) { \
193 return x; \
194 } else if constexpr (N == 1) { \
195 return y; \
196 } else if constexpr (N == 2) { \
197 return z; \
198 } else if constexpr (N == 3) { \
199 return w; \
200 } else { \
201 static_assert(ll::traits::always_false<T>); \
202 } \
203 } \
204 }
205
206// NOLINTEND