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( \
45 static_cast<TYPE>((std::is_floating_point_v<T1> && !std::is_floating_point_v<TYPE>) ? std::floor(z) : z) \
46 ) {} \
47 template <IsField T> \
48 [[nodiscard]] constexpr NAME(T const& vec) \
49 requires((IsIntN<T> || IsFloatN<T> || IsBoolN<T>) && T::size() == 2) \
50 : NAME() { \
51 T::forEachComponent([&]<typename axis_type, size_t iter> { \
52 if constexpr (std::is_floating_point_v<axis_type> && !std::is_floating_point_v<TYPE>) { \
53 this->get<TYPE, iter>() = static_cast<TYPE>(std::floor(vec.template get<axis_type, iter>())); \
54 } else { \
55 this->get<TYPE, iter>() = static_cast<TYPE>((vec.template get<axis_type, iter>())); \
56 } \
57 }); \
58 } \
59 template <typename T, size_t N> \
60 [[nodiscard]] constexpr T& get() noexcept { \
61 if constexpr (N == 0) { \
62 return x; \
63 } else if constexpr (N == 1) { \
64 return y; \
65 } else { \
66 static_assert(ll::traits::always_false<T>); \
67 } \
68 } \
69 template <typename T, size_t N> \
70 [[nodiscard]] constexpr T const& get() const noexcept { \
71 if constexpr (N == 0) { \
72 return x; \
73 } else if constexpr (N == 1) { \
74 return y; \
75 } else { \
76 static_assert(ll::traits::always_false<T>); \
77 } \
78 } \
79 }
80
81#define LL_VEC3_IMPL(NAME, BNAME, TYPE, BASE) \
82 class LL_EBO NAME : public BASE<BNAME, TYPE, TYPE, TYPE> { \
83 public: \
84 LL_VEC_X_MEMBER(TYPE); \
85 LL_VEC_Y_MEMBER(TYPE); \
86 LL_VEC_Z_MEMBER(TYPE); \
87 \
88 [[nodiscard]] constexpr NAME(NAME&&) = default; \
89 LL_MAY_CONSTEXPR NAME& operator=(NAME&&) = default; \
90 [[nodiscard]] constexpr NAME(NAME const&) = default; \
91 LL_MAY_CONSTEXPR NAME& operator=(NAME const&) = default; \
92 \
93 [[nodiscard]] constexpr NAME(TYPE all = 0) noexcept : x(all), y(all), z(all) {} \
94 \
95 template <std::convertible_to<TYPE> T0, std::convertible_to<TYPE> T1, std::convertible_to<TYPE> T2> \
96 [[nodiscard]] constexpr NAME(T0 x, T1 y, T2 z) noexcept \
97 : x(static_cast<TYPE>((std::is_floating_point_v<T0> && !std::is_floating_point_v<TYPE>) ? std::floor(x) : x)), \
98 y(static_cast<TYPE>((std::is_floating_point_v<T1> && !std::is_floating_point_v<TYPE>) ? std::floor(y) : y)), \
99 z( \
100 static_cast<TYPE>((std::is_floating_point_v<T2> && !std::is_floating_point_v<TYPE>) ? std::floor(z) : z) \
101 ) {} \
102 template <IsField T> \
103 [[nodiscard]] constexpr NAME(T const& vec) \
104 requires((IsIntN<T> || IsFloatN<T> || IsBoolN<T>) && T::size() == 3) \
105 : NAME() { \
106 T::forEachComponent([&]<typename axis_type, size_t iter> { \
107 if constexpr (std::is_floating_point_v<axis_type> && !std::is_floating_point_v<TYPE>) { \
108 this->get<TYPE, iter>() = static_cast<TYPE>(std::floor(vec.template get<axis_type, iter>())); \
109 } else { \
110 this->get<TYPE, iter>() = static_cast<TYPE>((vec.template get<axis_type, iter>())); \
111 } \
112 }); \
113 } \
114 template <typename T, size_t N> \
115 [[nodiscard]] constexpr T& get() noexcept { \
116 if constexpr (N == 0) { \
117 return x; \
118 } else if constexpr (N == 1) { \
119 return y; \
120 } else if constexpr (N == 2) { \
121 return z; \
122 } else { \
123 static_assert(ll::traits::always_false<T>); \
124 } \
125 } \
126 template <typename T, size_t N> \
127 [[nodiscard]] constexpr T const& get() const noexcept { \
128 if constexpr (N == 0) { \
129 return x; \
130 } else if constexpr (N == 1) { \
131 return y; \
132 } else if constexpr (N == 2) { \
133 return z; \
134 } else { \
135 static_assert(ll::traits::always_false<T>); \
136 } \
137 } \
138 }
139
140#define LL_VEC4_IMPL(NAME, BNAME, TYPE, BASE) \
141 class LL_EBO NAME : public BASE<BNAME, TYPE, TYPE, TYPE, TYPE> { \
142 public: \
143 LL_VEC_X_MEMBER(TYPE); \
144 LL_VEC_Y_MEMBER(TYPE); \
145 LL_VEC_Z_MEMBER(TYPE); \
146 LL_VEC_W_MEMBER(TYPE); \
147 \
148 [[nodiscard]] constexpr NAME(NAME&&) = default; \
149 LL_MAY_CONSTEXPR NAME& operator=(NAME&&) = default; \
150 [[nodiscard]] constexpr NAME(NAME const&) = default; \
151 LL_MAY_CONSTEXPR NAME& operator=(NAME const&) = default; \
152 \
153 [[nodiscard]] constexpr NAME(TYPE all = 0) noexcept : x(all), y(all), z(all), w(all) {} \
154 \
155 template < \
156 std::convertible_to<TYPE> T0, \
157 std::convertible_to<TYPE> T1, \
158 std::convertible_to<TYPE> T2, \
159 std::convertible_to<TYPE> T3> \
160 [[nodiscard]] constexpr NAME(T0 x, T1 y, T2 z, T3 w) noexcept \
161 : x(static_cast<TYPE>((std::is_floating_point_v<T0> && !std::is_floating_point_v<TYPE>) ? std::floor(x) : x)), \
162 y(static_cast<TYPE>((std::is_floating_point_v<T1> && !std::is_floating_point_v<TYPE>) ? std::floor(y) : y)), \
163 z(static_cast<TYPE>((std::is_floating_point_v<T2> && !std::is_floating_point_v<TYPE>) ? std::floor(z) : z)), \
164 w( \
165 static_cast<TYPE>((std::is_floating_point_v<T3> && !std::is_floating_point_v<TYPE>) ? std::floor(w) : w) \
166 ) {} \
167 template <IsField T> \
168 [[nodiscard]] constexpr NAME(T const& vec) \
169 requires((IsIntN<T> || IsFloatN<T> || IsBoolN<T>) && T::size() == 4) \
170 : NAME() { \
171 T::forEachComponent([&]<typename axis_type, size_t iter> { \
172 if constexpr (std::is_floating_point_v<axis_type> && !std::is_floating_point_v<TYPE>) { \
173 this->get<TYPE, iter>() = static_cast<TYPE>(std::floor(vec.template get<axis_type, iter>())); \
174 } else { \
175 this->get<TYPE, iter>() = static_cast<TYPE>((vec.template get<axis_type, iter>())); \
176 } \
177 }); \
178 } \
179 template <typename T, size_t N> \
180 [[nodiscard]] constexpr T& get() noexcept { \
181 if constexpr (N == 0) { \
182 return x; \
183 } else if constexpr (N == 1) { \
184 return y; \
185 } else if constexpr (N == 2) { \
186 return z; \
187 } else if constexpr (N == 3) { \
188 return w; \
189 } else { \
190 static_assert(ll::traits::always_false<T>); \
191 } \
192 } \
193 template <typename T, size_t N> \
194 [[nodiscard]] constexpr T const& get() const noexcept { \
195 if constexpr (N == 0) { \
196 return x; \
197 } else if constexpr (N == 1) { \
198 return y; \
199 } else if constexpr (N == 2) { \
200 return z; \
201 } else if constexpr (N == 3) { \
202 return w; \
203 } else { \
204 static_assert(ll::traits::always_false<T>); \
205 } \
206 } \
207 }
208
209// NOLINTEND