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