SourcePP
Several modern C++20 libraries for sanely parsing Valve's formats.
Loading...
Searching...
No Matches
Math.h
Go to the documentation of this file.
1// ReSharper disable CppMemberFunctionMayBeStatic
2// ReSharper disable CppRedundantParentheses
3
4#pragma once
5
6#include <bit>
7#include <concepts>
8#include <cmath>
9#include <cstdint>
10#include <numbers>
11#include <type_traits>
12
13#include <half.hpp>
14
15// Numeric types are intentionally outside the sourcepp namespace
16using std::int8_t;
17using std::int16_t;
18using std::int32_t;
19using std::int64_t;
20using std::uint8_t;
21using std::uint16_t;
22using std::uint32_t;
23using std::uint64_t;
24using half_float::half;
25
26namespace sourcepp::math {
27
28template<std::floating_point F>
29constexpr F pi = std::numbers::pi_v<F>;
30constexpr auto pi_f32 = pi<float>;
31constexpr auto pi_f64 = pi<double>;
32
33template<typename T>
34concept Arithmetic = std::is_arithmetic_v<T> || std::same_as<T, half>;
35
36template<Arithmetic T>
37[[nodiscard]] constexpr T remap(T value, T l1, T h1, T l2, T h2) {
38 return l2 + (value - l1) * (h2 - l2) / (h1 - l1);
39}
40
41template<Arithmetic T>
42[[nodiscard]] constexpr T remap(T value, T h1, T h2) {
43 return value * h2 / h1;
44}
45
46[[nodiscard]] constexpr bool isPowerOf2(std::unsigned_integral auto n) {
47 return n && !(n & (n - 1));
48}
49
50template<std::unsigned_integral T>
51[[nodiscard]] constexpr T nearestPowerOf2(T n) {
52 if (isPowerOf2(n)) {
53 return n;
54 }
55 auto bigger = std::bit_ceil(n);
56 auto smaller = std::bit_floor(n);
57 return (n - smaller) < (bigger - n) ? smaller : bigger;
58}
59
60[[nodiscard]] constexpr uint32_t log2ceil(uint32_t value) {
61 return ((std::bit_cast<uint32_t>(static_cast<float>(value)) >> 23) & 0xff) - 127;
62}
63
64[[nodiscard]] constexpr uint16_t paddingForAlignment(uint16_t alignment, uint64_t n) {
65 if (const auto rest = n % alignment; rest > 0) {
66 return alignment - rest;
67 }
68 return 0;
69}
70
71template<uint8_t S_, Arithmetic P>
72struct Vec {
73 static constexpr uint8_t S = S_;
74 static_assert(S >= 2, "Vectors must have at least two values!");
75
76 using value_type = P;
77
79
80 constexpr Vec() = default;
81
82 // ReSharper disable once CppNonExplicitConvertingConstructor
83 template<std::convertible_to<P>... Vals>
84 requires (sizeof...(Vals) == S)
85 constexpr Vec(Vals... vals) // NOLINT(*-explicit-constructor)
86 : values{static_cast<P>(vals)...} {}
87
88 [[nodiscard]] constexpr const P* data() const {
89 return this->values;
90 }
91
92 [[nodiscard]] constexpr P* data() {
93 return this->values;
94 }
95
96 [[nodiscard]] constexpr uint8_t size() const {
97 return S;
98 }
99
100 [[nodiscard]] constexpr P& operator[](uint8_t index) {
101 if (index < S) {
102 return this->values[index];
103 }
104 return this->operator[](index % S);
105 }
106
107 [[nodiscard]] constexpr P operator[](uint8_t index) const {
108 if (index < S) {
109 return this->values[index];
110 }
111 return this->operator[](index % S);
112 }
113
114 [[nodiscard]] constexpr Vec operator+() const {
115 return *this;
116 }
117
118 [[nodiscard]] constexpr Vec operator+(Arithmetic auto scalar) const {
119 auto out = *this;
120 for (uint8_t i = 0; i < S; i++) {
121 out[i] += static_cast<P>(scalar);
122 }
123 return out;
124 }
125
126 template<uint8_t SO, Arithmetic PO>
127 [[nodiscard]] constexpr Vec operator+(const Vec<SO, PO>& other) const {
128 auto out = *this;
129 for (uint8_t i = 0; i < (S > SO ? SO : S); i++) {
130 out[i] += static_cast<P>(other[i]);
131 }
132 return out;
133 }
134
135 constexpr void operator+=(Arithmetic auto scalar) const {
136 for (uint8_t i = 0; i < S; i++) {
137 (*this)[i] += static_cast<P>(scalar);
138 }
139 }
140
141 template<uint8_t SO, Arithmetic PO>
142 constexpr void operator+=(const Vec<SO, PO>& other) {
143 for (uint8_t i = 0; i < (S > SO ? SO : S); i++) {
144 (*this)[i] += static_cast<P>(other[i]);
145 }
146 }
147
148 [[nodiscard]] constexpr Vec operator-() const {
149 auto out = *this;
150 for (uint8_t i = 0; i < S; i++) {
151 out[i] *= -1;
152 }
153 return out;
154 }
155
156 [[nodiscard]] constexpr Vec operator-(Arithmetic auto scalar) const {
157 auto out = *this;
158 for (uint8_t i = 0; i < S; i++) {
159 out[i] -= static_cast<P>(scalar);
160 }
161 return out;
162 }
163
164 template<uint8_t SO, Arithmetic PO>
165 [[nodiscard]] constexpr Vec operator-(const Vec<SO, PO>& other) const {
166 auto out = *this;
167 for (uint8_t i = 0; i < (S > SO ? SO : S); i++) {
168 out[i] -= static_cast<P>(other[i]);
169 }
170 return out;
171 }
172
173 constexpr void operator-=(Arithmetic auto scalar) const {
174 for (uint8_t i = 0; i < S; i++) {
175 (*this)[i] -= static_cast<P>(scalar);
176 }
177 }
178
179 template<uint8_t SO, Arithmetic PO>
180 constexpr void operator-=(const Vec<SO, PO>& other) {
181 for (uint8_t i = 0; i < (S > SO ? SO : S); i++) {
182 (*this)[i] -= static_cast<P>(other[i]);
183 }
184 }
185
186 [[nodiscard]] constexpr Vec operator*(Arithmetic auto scalar) const {
187 auto out = *this;
188 for (uint8_t i = 0; i < S; i++) {
189 out[i] *= static_cast<P>(scalar);
190 }
191 return out;
192 }
193
194 constexpr void operator*=(Arithmetic auto scalar) {
195 for (uint8_t i = 0; i < S; i++) {
196 (*this)[i] *= static_cast<P>(scalar);
197 }
198 }
199
200 [[nodiscard]] constexpr Vec operator/(Arithmetic auto scalar) const {
201 auto out = *this;
202 for (uint8_t i = 0; i < S; i++) {
203 out[i] /= static_cast<P>(scalar);
204 }
205 return out;
206 }
207
208 constexpr void operator/=(Arithmetic auto scalar) {
209 for (uint8_t i = 0; i < S; i++) {
210 (*this)[i] /= static_cast<P>(scalar);
211 }
212 }
213
214 [[nodiscard]] constexpr Vec operator%(Arithmetic auto scalar) const {
215 auto out = *this;
216 for (uint8_t i = 0; i < S; i++) {
217 out[i] %= static_cast<P>(scalar);
218 }
219 return out;
220 }
221
222 constexpr void operator%=(Arithmetic auto scalar) {
223 for (uint8_t i = 0; i < S; i++) {
224 (*this)[i] %= static_cast<P>(scalar);
225 }
226 }
227
228 template<uint8_t SO, Arithmetic PO>
229 [[nodiscard]] constexpr bool operator==(const Vec<SO, PO>& other) const {
230 if constexpr (S != SO) {
231 return false;
232 } else {
233 for (uint8_t i = 0; i < S; i++) {
234 if ((*this)[i] != static_cast<P>(other[i])) {
235 return false;
236 }
237 }
238 return true;
239 }
240 }
241
242 template<uint8_t SO, Arithmetic PO = P>
243 [[nodiscard]] constexpr Vec<SO, PO> to() const {
244 Vec<SO, PO> out{};
245 for (uint8_t i = 0; i < (S > SO ? SO : S); i++) {
246 out[i] = static_cast<PO>((*this)[i]);
247 }
248 return out;
249 }
250
251 template<uint8_t SO, Arithmetic PO>
252 [[nodiscard]] constexpr Vec mul(const Vec<SO, PO>& other) const {
253 auto out = *this;
254 for (uint8_t i = 0; i < (S > SO ? SO : S); i++) {
255 out[i] *= static_cast<P>(other[i]);
256 }
257 return out;
258 }
259
260 template<uint8_t SO, Arithmetic PO>
261 [[nodiscard]] constexpr Vec div(const Vec<SO, PO>& other) const {
262 auto out = *this;
263 for (uint8_t i = 0; i < (S > SO ? SO : S); i++) {
264 out[i] /= static_cast<P>(other[i]);
265 }
266 return out;
267 }
268
269 template<uint8_t SO, Arithmetic PO>
270 [[nodiscard]] constexpr Vec mod(const Vec<SO, PO>& other) const {
271 auto out = *this;
272 for (uint8_t i = 0; i < (S > SO ? SO : S); i++) {
273 if constexpr ((std::floating_point<P> && std::floating_point<PO>) || std::floating_point<P>) {
274 out[i] = std::fmod(out[i], static_cast<P>(other[i]));
275 } else {
276 out[i] %= static_cast<P>(other[i]);
277 }
278 }
279 return out;
280 }
281
282 [[nodiscard]] constexpr float magf() const {
283 float out = 0.0;
284 for (uint8_t i = 0; i < S; i++) {
285 out += std::pow((*this)[i], 2);
286 }
287 return std::sqrt(out);
288 }
289
290 [[nodiscard]] constexpr double mag() const {
291 double out = 0.0;
292 for (uint8_t i = 0; i < S; i++) {
293 out += std::pow((*this)[i], 2);
294 }
295 return std::sqrt(out);
296 }
297
298 [[nodiscard]] constexpr P sum() const {
299 P out{};
300 for (uint8_t i = 0; i < S; i++) {
301 out += (*this)[i];
302 }
303 return out;
304 }
305
306 template<Arithmetic PO>
307 [[nodiscard]] constexpr Vec scale(const Vec<S, PO>& other) const {
308 Vec out;
309 for (uint8_t i = 0; i < S; i++) {
310 out[i] = (*this)[i] * static_cast<P>(other[i]);
311 }
312 return out;
313 }
314
315 template<Arithmetic PO>
316 [[nodiscard]] constexpr P dot(const Vec<S, PO>& other) const {
317 return this->scale(other).sum();
318 }
319
320 [[nodiscard]] constexpr Vec abs() const {
321 auto out = *this;
322 for (uint8_t i = 0; i < S; i++) {
323 out[i] = std::abs(out[i]);
324 }
325 return out;
326 }
327
328 [[nodiscard]] static constexpr Vec zero() {
329 return {};
330 }
331
332 [[nodiscard]] constexpr bool isZero() const {
333 return *this == zero();
334 }
335};
336static_assert(std::is_trivially_copyable_v<Vec<2, float>>);
337
338#define SOURCEPP_VEC_DEFINE(S) \
339 template<Arithmetic P> \
340 using Vec##S = Vec<S, P>; \
341 using Vec##S##i8 = Vec##S<int8_t>; \
342 using Vec##S##i16 = Vec##S<int16_t>; \
343 using Vec##S##i32 = Vec##S<int32_t>; \
344 using Vec##S##i64 = Vec##S<int64_t>; \
345 using Vec##S##i = Vec##S##i32; \
346 using Vec##S##ui8 = Vec##S<uint8_t>; \
347 using Vec##S##ui16 = Vec##S<uint16_t>; \
348 using Vec##S##ui32 = Vec##S<uint32_t>; \
349 using Vec##S##ui64 = Vec##S<uint64_t>; \
350 using Vec##S##ui = Vec##S##ui32; \
351 using Vec##S##f16 = Vec##S<half>; \
352 using Vec##S##f32 = Vec##S<float>; \
353 using Vec##S##f64 = Vec##S<double>; \
354 using Vec##S##f = Vec##S##f32
355
359
360#undef SOURCEPP_VEC_DEFINE
361
362using EulerAngles = Vec3f;
363
364using Quat = Vec4f;
365
368 uint16_t x : 16;
369 uint16_t y : 16;
370 uint16_t z : 15;
371 uint16_t wn : 1;
372
373 [[nodiscard]] Quat decompress() const {
374 // Convert from 16-bit (or 15-bit) integers to floating point values in the range [-1, 1]
375 const float fx = (static_cast<float>(this->x) / 32767.5f) - 1.f; // x / ((2^16 - 1) / 2) - 1
376 const float fy = (static_cast<float>(this->y) / 32767.5f) - 1.f; // y / ((2^16 - 1) / 2) - 1
377 const float fz = (static_cast<float>(this->z) / 16383.5f) - 1.f; // z / ((2^15 - 1) / 2) - 1
378
379 // Recalculate w from the constraint that x^2 + y^2 + z^2 + w^2 = 1
380 float fw = std::sqrt(1.f - fx * fx - fy * fy - fz * fz);
381
382 // Adjust w based on the stored sign bit
383 if (this->wn) {
384 fw = -fw;
385 }
386
387 return {fx, fy, fz, fw};
388 }
389};
390static_assert(std::is_trivially_copyable_v<QuatCompressed48>);
391
394 uint32_t x : 21;
395 uint32_t y : 21;
396 uint32_t z : 21;
397 uint32_t wn : 1;
398
399 [[nodiscard]] Quat decompress() const {
400 // Convert from 21-bit integers to floating point values in the range [-1, 1]
401 const double fx = (static_cast<double>(this->x) / 1048575.5) - 1.0f; // x / ((2^21 - 1) / 2) - 1
402 const double fy = (static_cast<double>(this->y) / 1048575.5) - 1.0f; // y / ((2^21 - 1) / 2) - 1
403 const double fz = (static_cast<double>(this->z) / 1048575.5) - 1.0f; // z / ((2^21 - 1) / 2) - 1
404
405 // Recalculate w from the constraint that x^2 + y^2 + z^2 + w^2 = 1
406 double fw = std::sqrt(1.0 - fx * fx - fy * fy - fz * fz);
407
408 // Adjust w based on the stored sign bit
409 if (this->wn) {
410 fw = -fw;
411 }
412
413 return {static_cast<float>(fx), static_cast<float>(fy), static_cast<float>(fz), static_cast<float>(fw)};
414 }
415};
416static_assert(std::is_trivially_copyable_v<QuatCompressed64>);
417
418template<uint8_t M_, uint8_t N_, Arithmetic P>
419struct Mat {
420 static constexpr uint8_t M = M_;
421 static_assert(M >= 2, "Matrices must have at least two rows!");
422 static constexpr uint8_t N = N_;
423 static_assert(N >= 2, "Matrices must have at least two columns!");
424
425 using value_type = P;
426
427 P values[M][N];
428
429 [[nodiscard]] constexpr const P* data() const {
430 return this->values;
431 }
432
433 [[nodiscard]] constexpr P* data() {
434 return this->values;
435 }
436
437 [[nodiscard]] constexpr uint8_t rows() const {
438 return M;
439 }
440
441 [[nodiscard]] constexpr uint8_t cols() const {
442 return N;
443 }
444
445 [[nodiscard]] P* operator[](uint8_t i) { return this->values[i]; }
446
447 [[nodiscard]] const P* operator[](uint8_t i) const { return this->values[i]; }
448};
449static_assert(std::is_trivially_copyable_v<Mat<2, 2, float>>);
450
451#define SOURCEPP_MAT_DEFINE(M, N) \
452 template<Arithmetic P> \
453 using Mat##M##x##N = Mat<M, N, P>; \
454 using Mat##M##x##N##i8 = Mat##M##x##N<int8_t>; \
455 using Mat##M##x##N##i16 = Mat##M##x##N<int16_t>; \
456 using Mat##M##x##N##i32 = Mat##M##x##N<int32_t>; \
457 using Mat##M##x##N##i64 = Mat##M##x##N<int64_t>; \
458 using Mat##M##x##N##i = Mat##M##x##N##i32; \
459 using Mat##M##x##N##ui8 = Mat##M##x##N<uint8_t>; \
460 using Mat##M##x##N##ui16 = Mat##M##x##N<uint16_t>; \
461 using Mat##M##x##N##ui32 = Mat##M##x##N<uint32_t>; \
462 using Mat##M##x##N##ui64 = Mat##M##x##N<uint64_t>; \
463 using Mat##M##x##N##ui = Mat##M##x##N##ui32; \
464 using Mat##M##x##N##f16 = Mat##M##x##N<half>; \
465 using Mat##M##x##N##f32 = Mat##M##x##N<float>; \
466 using Mat##M##x##N##f64 = Mat##M##x##N<double>; \
467 using Mat##M##x##N##f = Mat##M##x##N##f32
468
478
479#undef SOURCEPP_MAT_DEFINE
480
481} // namespace sourcepp::math
#define SOURCEPP_VEC_DEFINE(S)
Definition Math.h:338
#define SOURCEPP_MAT_DEFINE(M, N)
Definition Math.h:451
constexpr T nearestPowerOf2(T n)
Definition Math.h:51
constexpr bool isPowerOf2(std::unsigned_integral auto n)
Definition Math.h:46
constexpr auto pi_f32
Definition Math.h:30
constexpr auto pi_f64
Definition Math.h:31
constexpr uint16_t paddingForAlignment(uint16_t alignment, uint64_t n)
Definition Math.h:64
constexpr T remap(T value, T l1, T h1, T l2, T h2)
Definition Math.h:37
constexpr uint32_t log2ceil(uint32_t value)
Definition Math.h:60
Vec4f Quat
Definition Math.h:364
constexpr F pi
Definition Math.h:29
Vec3f EulerAngles
Definition Math.h:362
constexpr uint8_t rows() const
Definition Math.h:437
constexpr const P * data() const
Definition Math.h:429
const P * operator[](uint8_t i) const
Definition Math.h:447
static constexpr uint8_t M
Definition Math.h:420
constexpr P * data()
Definition Math.h:433
static constexpr uint8_t N
Definition Math.h:422
P * operator[](uint8_t i)
Definition Math.h:445
P values[M][N]
Definition Math.h:427
constexpr uint8_t cols() const
Definition Math.h:441
Lower precision Quat compressed to 6 bytes.
Definition Math.h:367
Lower precision Quat compressed to 8 bytes.
Definition Math.h:393
constexpr Vec mod(const Vec< SO, PO > &other) const
Definition Math.h:270
constexpr P dot(const Vec< S, PO > &other) const
Definition Math.h:316
constexpr Vec operator+(Arithmetic auto scalar) const
Definition Math.h:118
constexpr Vec(Vals... vals)
Definition Math.h:85
constexpr Vec div(const Vec< SO, PO > &other) const
Definition Math.h:261
static constexpr Vec zero()
Definition Math.h:328
constexpr Vec operator-(const Vec< SO, PO > &other) const
Definition Math.h:165
constexpr Vec operator-() const
Definition Math.h:148
constexpr Vec operator-(Arithmetic auto scalar) const
Definition Math.h:156
constexpr void operator/=(Arithmetic auto scalar)
Definition Math.h:208
constexpr void operator-=(Arithmetic auto scalar) const
Definition Math.h:173
constexpr void operator+=(Arithmetic auto scalar) const
Definition Math.h:135
constexpr Vec operator+() const
Definition Math.h:114
constexpr float magf() const
Definition Math.h:282
constexpr Vec operator*(Arithmetic auto scalar) const
Definition Math.h:186
constexpr Vec operator/(Arithmetic auto scalar) const
Definition Math.h:200
constexpr Vec scale(const Vec< S, PO > &other) const
Definition Math.h:307
constexpr Vec operator%(Arithmetic auto scalar) const
Definition Math.h:214
constexpr double mag() const
Definition Math.h:290
constexpr bool isZero() const
Definition Math.h:332
constexpr Vec< SO, PO > to() const
Definition Math.h:243
constexpr uint8_t size() const
Definition Math.h:96
constexpr Vec operator+(const Vec< SO, PO > &other) const
Definition Math.h:127
constexpr bool operator==(const Vec< SO, PO > &other) const
Definition Math.h:229
constexpr Vec()=default
constexpr void operator-=(const Vec< SO, PO > &other)
Definition Math.h:180
constexpr void operator*=(Arithmetic auto scalar)
Definition Math.h:194
constexpr P operator[](uint8_t index) const
Definition Math.h:107
constexpr void operator%=(Arithmetic auto scalar)
Definition Math.h:222
constexpr P * data()
Definition Math.h:92
constexpr Vec mul(const Vec< SO, PO > &other) const
Definition Math.h:252
constexpr P & operator[](uint8_t index)
Definition Math.h:100
static constexpr uint8_t S
Definition Math.h:73
constexpr P sum() const
Definition Math.h:298
constexpr Vec abs() const
Definition Math.h:320
constexpr const P * data() const
Definition Math.h:88
constexpr void operator+=(const Vec< SO, PO > &other)
Definition Math.h:142