Move Vectormath main
C++20 game and graphics mathematics
Loading...
Searching...
No Matches
Vec4.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cassert>
5#include <cmath>
6#include <cstddef>
7#include <cstdint>
8#include <type_traits>
9
10#include <mv/math/Vec2.hpp>
11#include <mv/math/Vec3.hpp>
12#include <mv/math/detail/VectorOps.hpp>
13
14namespace mv::math
15{
16 template <typename T>
17 requires std::is_floating_point_v<T>
18 class Mat4;
19
20 template <typename T>
21 requires std::is_arithmetic_v<T>
22 class alignas(sizeof(T) * 4U) Vec4
23 {
24 public:
25 using Component = T;
26
27 constexpr Vec4() noexcept = default;
28
29 constexpr Vec4(T x, T y, T z, T w) noexcept : Components_{x, y, z, w}
30 {
31 }
32
33 template <typename U>
34 requires(std::is_arithmetic_v<U> && !std::is_same_v<T, U>)
35 explicit constexpr Vec4(const Vec4<U>& other) noexcept :
36 Components_{static_cast<T>(other.X()), static_cast<T>(other.Y()),
37 static_cast<T>(other.Z()), static_cast<T>(other.W())}
38 {
39 }
40
41 template <typename U>
42 requires std::is_arithmetic_v<U>
43 explicit constexpr Vec4(const Vec2<U>& xy,
44 T z = T(0),
45 T w = T(0)) noexcept :
46 Components_{static_cast<T>(xy.X()), static_cast<T>(xy.Y()), z, w}
47 {
48 }
49
50 template <typename U>
51 requires std::is_arithmetic_v<U>
52 explicit Vec4(const Vec3<U>& xyz, T w = T(0)) noexcept :
53 Components_{static_cast<T>(xyz.X()), static_cast<T>(xyz.Y()),
54 static_cast<T>(xyz.Z()), w}
55 {
56 }
57
58 [[nodiscard]] static constexpr Vec4 Zero() noexcept
59 {
60 return Vec4(T(0), T(0), T(0), T(0));
61 }
62
63 [[nodiscard]] static constexpr Vec4 One() noexcept
64 {
65 return Vec4(T(1), T(1), T(1), T(1));
66 }
67
68 [[nodiscard]] static constexpr Vec4 Filled(T value) noexcept
69 {
70 return Vec4(value, value, value, value);
71 }
72
73 [[nodiscard]] static constexpr Vec4 AxisX() noexcept
74 {
75 return Vec4(T(1), T(0), T(0), T(0));
76 }
77
78 [[nodiscard]] static constexpr Vec4 AxisY() noexcept
79 {
80 return Vec4(T(0), T(1), T(0), T(0));
81 }
82
83 [[nodiscard]] static constexpr Vec4 AxisZ() noexcept
84 {
85 return Vec4(T(0), T(0), T(1), T(0));
86 }
87
88 [[nodiscard]] static constexpr Vec4 AxisW() noexcept
89 {
90 return Vec4(T(0), T(0), T(0), T(1));
91 }
92
93 [[nodiscard]] constexpr T X() const noexcept
94 {
95 return Components_[0];
96 }
97 [[nodiscard]] constexpr T Y() const noexcept
98 {
99 return Components_[1];
100 }
101 [[nodiscard]] constexpr T Z() const noexcept
102 {
103 return Components_[2];
104 }
105 [[nodiscard]] constexpr T W() const noexcept
106 {
107 return Components_[3];
108 }
109
110 [[nodiscard]] constexpr T operator[](std::size_t index) const noexcept
111 {
112 assert(index < 4U);
113 return Components_[index];
114 }
115
116 template <std::size_t Index>
117 [[nodiscard]] constexpr T Get() const noexcept
118 {
119 static_assert(Index < 4U);
120 return Components_[Index];
121 }
122
123 [[nodiscard]] constexpr bool SetComponent(std::size_t index,
124 T value) noexcept
125 {
126 if (index >= 4U)
127 {
128 return false;
129 }
130 Components_[index] = value;
131 return true;
132 }
133
134 template <std::size_t Index>
135 constexpr void Set(T value) noexcept
136 {
137 static_assert(Index < 4U);
138 Components_[Index] = value;
139 }
140
142 {
143 return Vec2<T>(X(), Y());
144 }
145
147 {
148 return Vec2<T>(Z(), W());
149 }
150
152 {
153 return Vec3<T>(X(), Y(), Z());
154 }
155
156 [[nodiscard]] Vec4 operator+(const Vec4& other) const noexcept
157 {
158 return FromNative(Ops::Add(Ops::Load4(Components_),
159 Ops::Load4(other.Components_)));
160 }
161
162 [[nodiscard]] Vec4 operator-(const Vec4& other) const noexcept
163 {
164 return FromNative(Ops::Subtract(Ops::Load4(Components_),
165 Ops::Load4(other.Components_)));
166 }
167
168 [[nodiscard]] Vec4 operator*(const Vec4& other) const noexcept
169 {
170 return FromNative(Ops::Multiply(Ops::Load4(Components_),
171 Ops::Load4(other.Components_)));
172 }
173
174 [[nodiscard]] Vec4 operator/(const Vec4& other) const noexcept
175 {
176 return FromNative(Ops::Divide(Ops::Load4(Components_),
177 Ops::Load4(other.Components_)));
178 }
179
180 [[nodiscard]] Vec4 operator+(T scalar) const noexcept
181 {
182 return FromNative(Ops::Add(Ops::Load4(Components_), scalar));
183 }
184
185 [[nodiscard]] Vec4 operator-(T scalar) const noexcept
186 {
187 return FromNative(Ops::Subtract(Ops::Load4(Components_), scalar));
188 }
189
190 [[nodiscard]] Vec4 operator*(T scalar) const noexcept
191 {
192 return FromNative(Ops::Multiply(Ops::Load4(Components_), scalar));
193 }
194
195 [[nodiscard]] Vec4 operator/(T scalar) const noexcept
196 {
197 return FromNative(Ops::Divide(Ops::Load4(Components_), scalar));
198 }
199
201 {
202 return FromNative(Ops::Negate(Ops::Load4(Components_)));
203 }
204
205 Vec4& operator+=(const Vec4& other) noexcept
206 {
207 *this = *this + other;
208 return *this;
209 }
210
211 Vec4& operator-=(const Vec4& other) noexcept
212 {
213 *this = *this - other;
214 return *this;
215 }
216
217 Vec4& operator*=(const Vec4& other) noexcept
218 {
219 *this = *this * other;
220 return *this;
221 }
222
223 Vec4& operator/=(const Vec4& other) noexcept
224 {
225 *this = *this / other;
226 return *this;
227 }
228
230 {
231 *this = *this + scalar;
232 return *this;
233 }
234
236 {
237 *this = *this - scalar;
238 return *this;
239 }
240
242 {
243 *this = *this * scalar;
244 return *this;
245 }
246
248 {
249 *this = *this / scalar;
250 return *this;
251 }
252
254 const Vec4& vector) noexcept
255 {
256 return vector * scalar;
257 }
258
259 [[nodiscard]] friend constexpr bool operator==(
260 const Vec4&, const Vec4&) noexcept = default;
261
262 private:
263 using Ops = detail::SelectedVectorOps<T>;
264
265 [[nodiscard]] static Vec4 FromNative(
266 typename Ops::Native value) noexcept
267 {
268 Vec4 result;
269 Ops::Store4(value, result.Components_);
270 return result;
271 }
272
273 T Components_[4]{};
274
275 template <typename U>
276 requires std::is_floating_point_v<U>
277 friend class Mat4;
278 };
279
290 using Vec4i = Vec4i32;
291 using Vec4u = Vec4u32;
292
293 template <typename T>
294 [[nodiscard]] T Dot(const Vec4<T>& left, const Vec4<T>& right) noexcept
295 {
296 using Ops = detail::SelectedVectorOps<T>;
297 const T leftValues[4] = {left.X(), left.Y(), left.Z(), left.W()};
298 const T rightValues[4] = {right.X(), right.Y(), right.Z(), right.W()};
299 return Ops::Dot4(Ops::Load4(leftValues), Ops::Load4(rightValues));
300 }
301
302 template <typename T>
303 [[nodiscard]] T LengthSquared(const Vec4<T>& value) noexcept
304 {
305 return Dot(value, value);
306 }
307
308 template <typename T>
309 requires std::is_floating_point_v<T>
311 const Vec4<T>& left,
312 const Vec4<T>& right,
314 {
315 return IsNearlyEqual(left.X(), right.X(), tolerance) &&
316 IsNearlyEqual(left.Y(), right.Y(), tolerance) &&
317 IsNearlyEqual(left.Z(), right.Z(), tolerance) &&
319 }
320
321 template <typename T>
322 requires std::is_floating_point_v<T>
332
333 template <typename T>
334 requires std::is_floating_point_v<T>
335 [[nodiscard]] T Length(const Vec4<T>& value) noexcept
336 {
337 // Semantics follow GLSL 4.60 section 8.5's length operation.
338 return std::sqrt(LengthSquared(value));
339 }
340
341 template <typename T>
343 const Vec4<T>& right) noexcept
344 {
345 return LengthSquared(left - right);
346 }
347
348 template <typename T>
349 requires std::is_floating_point_v<T>
350 [[nodiscard]] T Distance(const Vec4<T>& left, const Vec4<T>& right) noexcept
351 {
352 // Semantics follow GLSL 4.60 section 8.5's distance operation.
353 return Length(left - right);
354 }
355
356 template <typename T>
358 const Vec4<T>& right) noexcept
359 {
360 return Vec4<T>(
361 std::min(left.X(), right.X()), std::min(left.Y(), right.Y()),
362 std::min(left.Z(), right.Z()), std::min(left.W(), right.W()));
363 }
364
365 template <typename T>
367 const Vec4<T>& right) noexcept
368 {
369 return Vec4<T>(
370 std::max(left.X(), right.X()), std::max(left.Y(), right.Y()),
371 std::max(left.Z(), right.Z()), std::max(left.W(), right.W()));
372 }
373
374 template <typename T>
376 const Vec4<T>& minimum,
377 const Vec4<T>& maximum) noexcept
378 {
379 // Component semantics follow GLSL 4.60 section 8.3's clamp operation.
380 return Min(Max(value, minimum), maximum);
381 }
382
383 template <typename T>
385 T minimum,
386 T maximum) noexcept
387 {
389 }
390
391 template <typename T>
392 requires(std::is_signed_v<T> || std::is_floating_point_v<T>)
393 [[nodiscard]] Vec4<T> Abs(const Vec4<T>& value) noexcept
394 {
395 return Vec4<T>(static_cast<T>(std::abs(value.X())),
396 static_cast<T>(std::abs(value.Y())),
397 static_cast<T>(std::abs(value.Z())),
398 static_cast<T>(std::abs(value.W())));
399 }
400
401 template <typename T>
402 requires(std::is_signed_v<T> || std::is_floating_point_v<T>)
403 [[nodiscard]] Vec4<T> Sign(const Vec4<T>& value) noexcept
404 {
405 // Component semantics follow GLSL 4.60 section 8.3's sign operation.
406 const auto sign = [](T component)
407 {
408 return static_cast<T>((T(0) < component) - (component < T(0)));
409 };
410 return Vec4<T>(sign(value.X()), sign(value.Y()), sign(value.Z()),
411 sign(value.W()));
412 }
413
414 template <typename T>
415 requires std::is_floating_point_v<T>
417 const Vec4<T>& to,
418 T amount) noexcept
419 {
420 // Algebra follows GLSL 4.60 section 8.3's mix operation.
421 return from + (to - from) * amount;
422 }
423
424 template <typename T>
425 requires std::is_floating_point_v<T>
427 const Vec4<T>& to,
428 T amount) noexcept
429 {
430 return LerpUnclamped(from, to, std::clamp(amount, T(0), T(1)));
431 }
432} // namespace mv::math
433
434static_assert(sizeof(mv::math::Vec4f) == 16);
435static_assert(alignof(mv::math::Vec4f) == 16);
436static_assert(std::is_trivially_copyable_v<mv::math::Vec4f>);
437static_assert(std::is_standard_layout_v<mv::math::Vec4f>);
Vec4 operator*(T scalar) const noexcept
Definition Vec4.hpp:190
Vec4 operator/(T scalar) const noexcept
Definition Vec4.hpp:195
Vec4 & operator+=(const Vec4 &other) noexcept
Definition Vec4.hpp:205
Vec4 operator+(T scalar) const noexcept
Definition Vec4.hpp:180
constexpr T Get() const noexcept
Definition Vec4.hpp:117
constexpr T operator[](std::size_t index) const noexcept
Definition Vec4.hpp:110
friend Vec4 operator*(T scalar, const Vec4 &vector) noexcept
Definition Vec4.hpp:253
static constexpr Vec4 AxisY() noexcept
Definition Vec4.hpp:78
Vec4 operator-(T scalar) const noexcept
Definition Vec4.hpp:185
Vec4 operator-() const noexcept
Definition Vec4.hpp:200
Vec4 & operator/=(T scalar) noexcept
Definition Vec4.hpp:247
Vec4 operator/(const Vec4 &other) const noexcept
Definition Vec4.hpp:174
Vec4 operator*(const Vec4 &other) const noexcept
Definition Vec4.hpp:168
Vec4 operator-(const Vec4 &other) const noexcept
Definition Vec4.hpp:162
constexpr Vec4() noexcept=default
Vec4(const Vec3< U > &xyz, T w=T(0)) noexcept
Definition Vec4.hpp:52
constexpr T Z() const noexcept
Definition Vec4.hpp:101
Vec4 & operator-=(const Vec4 &other) noexcept
Definition Vec4.hpp:211
Vec4 operator+(const Vec4 &other) const noexcept
Definition Vec4.hpp:156
Vec4 & operator*=(T scalar) noexcept
Definition Vec4.hpp:241
constexpr T Y() const noexcept
Definition Vec4.hpp:97
static constexpr Vec4 AxisW() noexcept
Definition Vec4.hpp:88
constexpr Vec2< T > ZW() const noexcept
Definition Vec4.hpp:146
static constexpr Vec4 AxisX() noexcept
Definition Vec4.hpp:73
static constexpr Vec4 One() noexcept
Definition Vec4.hpp:63
Vec4 & operator+=(T scalar) noexcept
Definition Vec4.hpp:229
Vec4 & operator-=(T scalar) noexcept
Definition Vec4.hpp:235
constexpr Vec2< T > XY() const noexcept
Definition Vec4.hpp:141
constexpr Vec4(const Vec4< U > &other) noexcept
Definition Vec4.hpp:35
constexpr Vec4(const Vec2< U > &xy, T z=T(0), T w=T(0)) noexcept
Definition Vec4.hpp:43
static constexpr Vec4 Filled(T value) noexcept
Definition Vec4.hpp:68
Vec4 & operator/=(const Vec4 &other) noexcept
Definition Vec4.hpp:223
constexpr T W() const noexcept
Definition Vec4.hpp:105
constexpr T X() const noexcept
Definition Vec4.hpp:93
Vec3< T > XYZ() const noexcept
Definition Vec4.hpp:151
friend constexpr bool operator==(const Vec4 &, const Vec4 &) noexcept=default
static constexpr Vec4 AxisZ() noexcept
Definition Vec4.hpp:83
Vec4 & operator*=(const Vec4 &other) noexcept
Definition Vec4.hpp:217
constexpr void Set(T value) noexcept
Definition Vec4.hpp:135
static constexpr Vec4 Zero() noexcept
Definition Vec4.hpp:58
constexpr bool SetComponent(std::size_t index, T value) noexcept
Definition Vec4.hpp:123
Vec2< T > Sign(const Vec2< T > &value) noexcept
Definition Vec2.hpp:349
constexpr T Dot(const Quat< T > &left, const Quat< T > &right) noexcept
Definition Quat.hpp:102
Vec4< std::uint32_t > Vec4u32
Definition Vec4.hpp:287
Vec2< T > LerpUnclamped(const Vec2< T > &from, const Vec2< T > &to, T amount) noexcept
Definition Vec2.hpp:361
Vec4< std::int32_t > Vec4i32
Definition Vec4.hpp:286
T Distance(const Point3< T > &point, const Line3< T > &line) noexcept
bool IsNearlyEqual(const Quat< T > &left, const Quat< T > &right, Tolerance< T > tolerance=Tolerance< T >::Default()) noexcept
Definition Quat.hpp:176
constexpr T LengthSquared(const Quat< T > &value) noexcept
Definition Quat.hpp:110
Vec2< T > Min(const Vec2< T > &left, const Vec2< T > &right) noexcept
Definition Vec2.hpp:307
Vec2< T > Clamp(const Vec2< T > &value, const Vec2< T > &minimum, const Vec2< T > &maximum) noexcept
Definition Vec2.hpp:323
T Length(const Quat< T > &value) noexcept
Definition Quat.hpp:116
constexpr bool IsNearlyZero(T value, T absoluteTolerance=Tolerance< T >::Default().Absolute) noexcept
Definition Tolerance.hpp:54
Vec2< T > Max(const Vec2< T > &left, const Vec2< T > &right) noexcept
Definition Vec2.hpp:315
Vec4< float > Vec4f
Definition Vec4.hpp:280
Vec2< T > Lerp(const Vec2< T > &from, const Vec2< T > &to, T amount) noexcept
Definition Vec2.hpp:371
Vec2< T > Abs(const Vec2< T > &value) noexcept
Definition Vec2.hpp:341
T DistanceSquared(const Point3< T > &point, const Line3< T > &line) noexcept