openMSX
gl_vec.hh
Go to the documentation of this file.
1#ifndef GL_VEC_HH
2#define GL_VEC_HH
3
4// This code implements a mathematical vector, comparable in functionality
5// and syntax to the vector types in GLSL.
6//
7// Only vector sizes 2, 3 and 4 are supported. Though when it doesn't
8// complicate stuff the code was written to support any size.
9//
10// Most basic functionality is already there, but this is not meant to be a
11// full set of GLSL functions. We can always extend the functionality if/when
12// required.
13//
14// In the past we had (some) manual SSE optimizations in this code. Though for
15// the functions that matter (matrix-vector and matrix-matrix multiplication are
16// built on top of the functions in this file), the compiler's
17// auto-vectorization has become as good as the manually vectorized code.
18
19#include "Math.hh"
20#include "narrow.hh"
21#include "unreachable.hh"
22#include "xrange.hh"
23#include <algorithm>
24#include <array>
25#include <cmath>
26#include <iostream>
27#include <utility>
28
29namespace gl {
30
31// Vector with N components of type T.
32template<int N, typename T> class vecN;
33
34// Specialization for N=2.
35template<typename T> class vecN<2, T>
36{
37public:
38 // Default copy-constructor and assignment operator.
39
40 // Construct vector containing all zeros.
41 constexpr vecN() : x(T(0)), y(T(0)) {}
42
43 // Construct vector containing the same value repeated N times.
44 constexpr explicit vecN(T t) : x(t), y(t) {}
45
46 // Conversion constructor from vector of same size but different type.
47 template<typename T2>
48 constexpr explicit vecN(const vecN<2, T2>& v) : x(T(v.x)), y(T(v.y)) {}
49
50 // Construct from larger vector (higher order elements are dropped).
51 template<int N2> constexpr explicit vecN(const vecN<N2, T>& v) : x(v.x), y(v.y) {}
52
53 // Construct vector from 2 given values.
54 constexpr vecN(T a, T b) : x(a), y(b) {}
55
56 // Access the i-th element of this vector.
57 [[nodiscard]] constexpr T operator[](unsigned i) const {
58 if (i == 0) return x;
59 if (i == 1) return y;
61 }
62 [[nodiscard]] constexpr T& operator[](unsigned i) {
63 if (i == 0) return x;
64 if (i == 1) return y;
66 }
67
68 [[nodiscard]] constexpr const T* data() const { return &x; }
69 [[nodiscard]] constexpr T* data() { return &x; }
70
71 // For structured bindings
72 template<size_t I> [[nodiscard]] constexpr T get() const noexcept { return (*this)[I]; }
73 template<size_t I> [[nodiscard]] constexpr T& get() noexcept { return (*this)[I]; }
74
75 // Assignment version of the +,-,* operations defined below.
76 constexpr vecN& operator+=(const vecN& v) { *this = *this + v; return *this; }
77 constexpr vecN& operator-=(const vecN& v) { *this = *this - v; return *this; }
78 constexpr vecN& operator*=(const vecN& v) { *this = *this * v; return *this; }
79 constexpr vecN& operator*=(T t) { *this = *this * t; return *this; }
80
81 // gcc-10 mis-compiles this (fixed in gcc-11):
82 // [[nodiscard]] constexpr bool operator==(const vecN&) const = default;
83 // For now still manually implement it.
84 [[nodiscard]] friend constexpr bool operator==(const vecN& a, const vecN& b)
85 {
86 return (a.x == b.x) && (a.y == b.y);
87 }
88
89public:
90 T x, y;
91};
92
93// Specialization for N=3.
94template<typename T> class vecN<3, T>
95{
96public:
97 constexpr vecN() : x(T(0)), y(T(0)), z(T(0)) {}
98 constexpr explicit vecN(T t) : x(t), y(t), z(t) {}
99 template<typename T2>
100 constexpr explicit vecN(const vecN<3, T2>& v) : x(T(v.x)), y(T(v.y)), z(T(v.z)) {}
101 constexpr explicit vecN(const vecN<4, T>& v) : x(v.x), y(v.y), z(v.z) {}
102 constexpr vecN(T a, T b, T c) : x(a), y(b), z(c) {}
103 constexpr vecN(T a, const vecN<2, T>& b) : x(a), y(b.x), z(b.y) {}
104 constexpr vecN(const vecN<2, T>& a, T b) : x(a.x), y(a.y), z(b) {}
105
106 [[nodiscard]] constexpr T operator[](unsigned i) const {
107 if (i == 0) return x;
108 if (i == 1) return y;
109 if (i == 2) return z;
111 }
112 [[nodiscard]] constexpr T& operator[](unsigned i) {
113 if (i == 0) return x;
114 if (i == 1) return y;
115 if (i == 2) return z;
117 }
118
119 [[nodiscard]] constexpr const T* data() const { return &x; }
120 [[nodiscard]] constexpr T* data() { return &x; }
121
122 template<size_t I> [[nodiscard]] constexpr T get() const noexcept { return (*this)[I]; }
123 template<size_t I> [[nodiscard]] constexpr T& get() noexcept { return (*this)[I]; }
124
125 constexpr vecN& operator+=(const vecN& v) { *this = *this + v; return *this; }
126 constexpr vecN& operator-=(const vecN& v) { *this = *this - v; return *this; }
127 constexpr vecN& operator*=(const vecN& v) { *this = *this * v; return *this; }
128 constexpr vecN& operator*=(T t) { *this = *this * t; return *this; }
129
130 [[nodiscard]] friend constexpr bool operator==(const vecN& a, const vecN& b)
131 {
132 return (a.x == b.x) && (a.y == b.y) && (a.z == b.z);
133 }
134
135public:
136 T x, y, z;
137};
138
139// Specialization for N=4.
140template<typename T> class vecN<4, T>
141{
142public:
143 constexpr vecN() : x(T(0)), y(T(0)), z(T(0)), w(T(0)) {}
144 constexpr explicit vecN(T t) : x(t), y(t), z(t), w(t) {}
145 template<typename T2>
146 constexpr explicit vecN(const vecN<4, T2>& v) : x(T(v.x)), y(T(v.y)), z(T(v.z)), w(T(v.w)) {}
147 constexpr vecN(T a, T b, T c, T d) : x(a), y(b), z(c), w(d) {}
148 constexpr vecN(T a, const vecN<3, T>& b) : x(a), y(b.x), z(b.y), w(b.z) {}
149 constexpr vecN(const vecN<3, T>& a, T b) : x(a.x), y(a.y), z(a.z), w(b) {}
150 constexpr vecN(const vecN<2, T>& a, const vecN<2, T>& b) : x(a.x), y(a.y), z(b.x), w(b.y) {}
151
152 [[nodiscard]] constexpr T operator[](unsigned i) const {
153 if (i == 0) return x;
154 if (i == 1) return y;
155 if (i == 2) return z;
156 if (i == 3) return w;
158 }
159 [[nodiscard]] constexpr T& operator[](unsigned i) {
160 if (i == 0) return x;
161 if (i == 1) return y;
162 if (i == 2) return z;
163 if (i == 3) return w;
165 }
166
167 [[nodiscard]] constexpr const T* data() const { return &x; }
168 [[nodiscard]] constexpr T* data() { return &x; }
169
170 template<size_t I> [[nodiscard]] constexpr T get() const noexcept { return (*this)[I]; }
171 template<size_t I> [[nodiscard]] constexpr T& get() noexcept { return (*this)[I]; }
172
173 // Assignment version of the +,-,* operations defined below.
174 constexpr vecN& operator+=(const vecN& v) { *this = *this + v; return *this; }
175 constexpr vecN& operator-=(const vecN& v) { *this = *this - v; return *this; }
176 constexpr vecN& operator*=(const vecN& v) { *this = *this * v; return *this; }
177 constexpr vecN& operator*=(T t) { *this = *this * t; return *this; }
178
179 [[nodiscard]] friend constexpr bool operator==(const vecN& a, const vecN& b)
180 {
181 return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w);
182 }
183
184public:
185 T x, y, z, w;
186};
187
188
189// Convenience typedefs (same names as used by GLSL).
196
197static_assert(sizeof( vec2) == 2 * sizeof(float));
198static_assert(sizeof( vec3) == 3 * sizeof(float));
199static_assert(sizeof( vec4) == 4 * sizeof(float));
200static_assert(sizeof(ivec2) == 2 * sizeof(int));
201static_assert(sizeof(ivec3) == 3 * sizeof(int));
202static_assert(sizeof(ivec4) == 4 * sizeof(int));
203
204
205// -- Scalar functions --
206
207// reciprocal square root
208[[nodiscard]] inline float rsqrt(float x)
209{
210 return 1.0f / sqrtf(x);
211}
212[[nodiscard]] inline double rsqrt(double x)
213{
214 return 1.0 / sqrt(x);
215}
216
217// convert radians <-> degrees
218template<typename T> [[nodiscard]] constexpr T radians(T d)
219{
220 return d * T(Math::pi / 180.0);
221}
222template<typename T> [[nodiscard]] constexpr T degrees(T r)
223{
224 return r * T(180.0 / Math::pi);
225}
226
227
228// -- Vector functions --
229
230// vector negation
231template<int N, typename T>
232[[nodiscard]] constexpr vecN<N, T> operator-(const vecN<N, T>& x)
233{
234 return vecN<N, T>() - x;
235}
236
237// vector + vector
238template<int N, typename T>
239[[nodiscard]] constexpr vecN<N, T> operator+(const vecN<N, T>& x, const vecN<N, T>& y)
240{
241 vecN<N, T> r;
242 for (auto i : xrange(N)) r[i] = x[i] + y[i];
243 return r;
244}
245
246// vector - vector
247template<int N, typename T>
248[[nodiscard]] constexpr vecN<N, T> operator-(const vecN<N, T>& x, const vecN<N, T>& y)
249{
250 vecN<N, T> r;
251 for (auto i : xrange(N)) r[i] = x[i] - y[i];
252 return r;
253}
254
255// scalar * vector
256template<int N, typename T>
257[[nodiscard]] constexpr vecN<N, T> operator*(T x, const vecN<N, T>& y)
258{
259 vecN<N, T> r;
260 for (auto i : xrange(N)) r[i] = x * y[i];
261 return r;
262}
263
264// vector * scalar
265template<int N, typename T>
266[[nodiscard]] constexpr vecN<N, T> operator*(const vecN<N, T>& x, T y)
267{
268 vecN<N, T> r;
269 for (auto i : xrange(N)) r[i] = x[i] * y;
270 return r;
271}
272
273// vector * vector
274template<int N, typename T>
275[[nodiscard]] constexpr vecN<N, T> operator*(const vecN<N, T>& x, const vecN<N, T>& y)
276{
277 vecN<N, T> r;
278 for (auto i : xrange(N)) r[i] = x[i] * y[i];
279 return r;
280}
281
282// element-wise reciprocal
283template<int N, typename T>
284[[nodiscard]] constexpr vecN<N, T> recip(const vecN<N, T>& x)
285{
286 vecN<N, T> r;
287 for (auto i : xrange(N)) r[i] = T(1) / x[i];
288 return r;
289}
290
291// scalar / vector
292template<int N, typename T>
293[[nodiscard]] constexpr vecN<N, T> operator/(T x, const vecN<N, T>& y)
294{
295 return x * recip(y);
296}
297
298// vector / scalar
299template<int N, typename T>
300[[nodiscard]] constexpr vecN<N, T> operator/(const vecN<N, T>& x, T y)
301{
302 return x * (T(1) / y);
303}
304
305// vector / vector
306template<int N, typename T>
307[[nodiscard]] constexpr vecN<N, T> operator/(const vecN<N, T>& x, const vecN<N, T>& y)
308{
309 return x * recip(y);
310}
311
312// min(vector, vector)
313template<int N, typename T>
314[[nodiscard]] constexpr vecN<N, T> min(const vecN<N, T>& x, const vecN<N, T>& y)
315{
316 vecN<N, T> r;
317 for (auto i : xrange(N)) r[i] = std::min(x[i], y[i]);
318 return r;
319}
320
321// min(vector, vector)
322template<int N, typename T>
323[[nodiscard]] constexpr T min_component(const vecN<N, T>& x)
324{
325 T r = x[0];
326 for (auto i : xrange(1, N)) r = std::min(r, x[i]);
327 return r;
328}
329
330// max(vector, vector)
331template<int N, typename T>
332[[nodiscard]] constexpr vecN<N, T> max(const vecN<N, T>& x, const vecN<N, T>& y)
333{
334 vecN<N, T> r;
335 for (auto i : xrange(N)) r[i] = std::max(x[i], y[i]);
336 return r;
337}
338
339// clamp(vector, vector, vector)
340template<int N, typename T>
341[[nodiscard]] constexpr vecN<N, T> clamp(const vecN<N, T>& x, const vecN<N, T>& minVal, const vecN<N, T>& maxVal)
342{
343 return min(maxVal, max(minVal, x));
344}
345
346// clamp(vector, scalar, scalar)
347template<int N, typename T>
348[[nodiscard]] constexpr vecN<N, T> clamp(const vecN<N, T>& x, T minVal, T maxVal)
349{
350 return clamp(x, vecN<N, T>(minVal), vecN<N, T>(maxVal));
351}
352
353// sum of components
354template<int N, typename T>
355[[nodiscard]] constexpr T sum(const vecN<N, T>& x)
356{
357 T result(0);
358 for (auto i : xrange(N)) result += x[i];
359 return result;
360}
361template<int N, typename T>
362[[nodiscard]] constexpr vecN<N, T> sum_broadcast(const vecN<N, T>& x)
363{
364 return vecN<N, T>(sum(x));
365}
366
367// dot product
368template<int N, typename T>
369[[nodiscard]] constexpr T dot(const vecN<N, T>& x, const vecN<N, T>& y)
370{
371 return sum(x * y);
372}
373template<int N, typename T>
374[[nodiscard]] constexpr vecN<N, T> dot_broadcast(const vecN<N, T>& x, const vecN<N, T>& y)
375{
376 return sum_broadcast(x * y);
377}
378
379// squared length (norm-2)
380template<int N, typename T>
381[[nodiscard]] constexpr T length2(const vecN<N, T>& x)
382{
383 return dot(x, x);
384}
385
386// length (norm-2)
387template<int N, typename T>
388[[nodiscard]] inline T length(const vecN<N, T>& x)
389{
390 return std::sqrt(length2(x));
391}
392
393// normalize vector
394template<int N, typename T>
395[[nodiscard]] inline vecN<N, T> normalize(const vecN<N, T>& x)
396{
397 return x * rsqrt(length2(x));
398}
399
400// cross product (only defined for vectors of length 3)
401template<typename T>
402[[nodiscard]] constexpr vecN<3, T> cross(const vecN<3, T>& a, const vecN<3, T>& b)
403{
404 return vecN<3, T>(a.y * b.z - a.z * b.y,
405 a.z * b.x - a.x * b.z,
406 a.x * b.y - a.y * b.x);
407}
408
409// round each component to the nearest integer (returns a vector of integers)
410template<int N, typename T>
411[[nodiscard]] inline vecN<N, int> round(const vecN<N, T>& x)
412{
413 vecN<N, int> r;
414 // note: std::lrint() is more generic (e.g. also works with double),
415 // but Dingux doesn't seem to have std::lrint().
416 for (auto i : xrange(N)) r[i] = narrow_cast<int>(lrintf(narrow_cast<float>(x[i])));
417 return r;
418}
419
420// truncate each component to the nearest integer that is not bigger in
421// absolute value (returns a vector of integers)
422template<int N, typename T>
423[[nodiscard]] constexpr vecN<N, int> trunc(const vecN<N, T>& x)
424{
425 vecN<N, int> r;
426 for (auto i : xrange(N)) r[i] = int(x[i]);
427 return r;
428}
429
430// Textual representation. (Only) used to debug unittest.
431template<int N, typename T>
432std::ostream& operator<<(std::ostream& os, const vecN<N, T>& x)
433{
434 os << "[ ";
435 for (auto i : xrange(N)) {
436 os << x[i] << ' ';
437 }
438 os << ']';
439 return os;
440}
441
442} // namespace gl
443
444// Support for structured bindings
445namespace std {
446// On some platforms tuple_size is a class and on others it is a struct.
447// Such a mismatch is only a problem when targeting the Microsoft C++ ABI,
448// which we don't do when compiling with Clang.
449#if defined(__clang__)
450#pragma clang diagnostic push
451#pragma clang diagnostic ignored "-Wmismatched-tags"
452#endif
453 template<int N, typename T> class tuple_size<gl::vecN<N, T>>
454 : public std::integral_constant<size_t, N> {};
455#if defined(__clang__)
456#pragma clang diagnostic pop
457#endif
458 template<size_t I, int N, typename T> class tuple_element<I, gl::vecN<N, T>> {
459 public:
460 using type = T;
461 };
462}
463
464#endif // GL_VEC_HH
TclObject t
friend constexpr bool operator==(const vecN &a, const vecN &b)
Definition gl_vec.hh:84
constexpr T & get() noexcept
Definition gl_vec.hh:73
constexpr vecN & operator+=(const vecN &v)
Definition gl_vec.hh:76
constexpr T operator[](unsigned i) const
Definition gl_vec.hh:57
constexpr vecN(const vecN< 2, T2 > &v)
Definition gl_vec.hh:48
constexpr T & operator[](unsigned i)
Definition gl_vec.hh:62
constexpr vecN(T a, T b)
Definition gl_vec.hh:54
constexpr T * data()
Definition gl_vec.hh:69
constexpr vecN & operator*=(T t)
Definition gl_vec.hh:79
constexpr const T * data() const
Definition gl_vec.hh:68
constexpr T get() const noexcept
Definition gl_vec.hh:72
constexpr vecN & operator-=(const vecN &v)
Definition gl_vec.hh:77
constexpr vecN()
Definition gl_vec.hh:41
constexpr vecN & operator*=(const vecN &v)
Definition gl_vec.hh:78
constexpr vecN(T t)
Definition gl_vec.hh:44
constexpr vecN(const vecN< N2, T > &v)
Definition gl_vec.hh:51
constexpr vecN & operator-=(const vecN &v)
Definition gl_vec.hh:126
friend constexpr bool operator==(const vecN &a, const vecN &b)
Definition gl_vec.hh:130
constexpr vecN(const vecN< 2, T > &a, T b)
Definition gl_vec.hh:104
constexpr vecN & operator*=(T t)
Definition gl_vec.hh:128
constexpr T & operator[](unsigned i)
Definition gl_vec.hh:112
constexpr vecN(const vecN< 3, T2 > &v)
Definition gl_vec.hh:100
constexpr vecN & operator+=(const vecN &v)
Definition gl_vec.hh:125
constexpr vecN(T a, T b, T c)
Definition gl_vec.hh:102
constexpr T operator[](unsigned i) const
Definition gl_vec.hh:106
constexpr vecN()
Definition gl_vec.hh:97
constexpr T & get() noexcept
Definition gl_vec.hh:123
constexpr vecN(T t)
Definition gl_vec.hh:98
constexpr vecN(const vecN< 4, T > &v)
Definition gl_vec.hh:101
constexpr vecN(T a, const vecN< 2, T > &b)
Definition gl_vec.hh:103
constexpr T * data()
Definition gl_vec.hh:120
constexpr vecN & operator*=(const vecN &v)
Definition gl_vec.hh:127
constexpr T get() const noexcept
Definition gl_vec.hh:122
constexpr const T * data() const
Definition gl_vec.hh:119
friend constexpr bool operator==(const vecN &a, const vecN &b)
Definition gl_vec.hh:179
constexpr T & get() noexcept
Definition gl_vec.hh:171
constexpr vecN()
Definition gl_vec.hh:143
constexpr vecN & operator*=(T t)
Definition gl_vec.hh:177
constexpr vecN & operator*=(const vecN &v)
Definition gl_vec.hh:176
constexpr vecN(const vecN< 4, T2 > &v)
Definition gl_vec.hh:146
constexpr vecN & operator+=(const vecN &v)
Definition gl_vec.hh:174
constexpr vecN & operator-=(const vecN &v)
Definition gl_vec.hh:175
constexpr vecN(T a, const vecN< 3, T > &b)
Definition gl_vec.hh:148
constexpr T & operator[](unsigned i)
Definition gl_vec.hh:159
constexpr T * data()
Definition gl_vec.hh:168
constexpr vecN(const vecN< 2, T > &a, const vecN< 2, T > &b)
Definition gl_vec.hh:150
constexpr vecN(T t)
Definition gl_vec.hh:144
constexpr T operator[](unsigned i) const
Definition gl_vec.hh:152
constexpr T get() const noexcept
Definition gl_vec.hh:170
constexpr vecN(T a, T b, T c, T d)
Definition gl_vec.hh:147
constexpr vecN(const vecN< 3, T > &a, T b)
Definition gl_vec.hh:149
constexpr const T * data() const
Definition gl_vec.hh:167
constexpr double pi
Definition Math.hh:24
Definition gl_mat.hh:23
constexpr vecN< N, T > recip(const vecN< N, T > &x)
Definition gl_vec.hh:284
vecN< 3, float > vec3
Definition gl_vec.hh:191
vecN< 3, int > ivec3
Definition gl_vec.hh:194
constexpr T min_component(const vecN< N, T > &x)
Definition gl_vec.hh:323
constexpr T dot(const vecN< N, T > &x, const vecN< N, T > &y)
Definition gl_vec.hh:369
vecN< 2, int > ivec2
Definition gl_vec.hh:193
constexpr vecN< 3, T > cross(const vecN< 3, T > &a, const vecN< 3, T > &b)
Definition gl_vec.hh:402
constexpr vecN< N, int > trunc(const vecN< N, T > &x)
Definition gl_vec.hh:423
vecN< 2, float > vec2
Definition gl_vec.hh:190
constexpr matMxN< M, N, T > operator*(T x, const matMxN< M, N, T > &A)
Definition gl_mat.hh:159
vecN< 4, int > ivec4
Definition gl_vec.hh:195
vecN< 4, float > vec4
Definition gl_vec.hh:192
T length(const vecN< N, T > &x)
Definition gl_vec.hh:388
constexpr vecN< N, T > operator/(T x, const vecN< N, T > &y)
Definition gl_vec.hh:293
vecN< N, int > round(const vecN< N, T > &x)
Definition gl_vec.hh:411
constexpr T length2(const vecN< N, T > &x)
Definition gl_vec.hh:381
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition gl_vec.hh:314
constexpr vecN< N, T > dot_broadcast(const vecN< N, T > &x, const vecN< N, T > &y)
Definition gl_vec.hh:374
constexpr T degrees(T r)
Definition gl_vec.hh:222
constexpr vecN< N, T > sum_broadcast(const vecN< N, T > &x)
Definition gl_vec.hh:362
constexpr T sum(const vecN< N, T > &x)
Definition gl_vec.hh:355
std::ostream & operator<<(std::ostream &os, const matMxN< M, N, T > &A)
Definition gl_mat.hh:334
constexpr T radians(T d)
Definition gl_vec.hh:218
constexpr matMxN< M, N, T > operator-(const matMxN< M, N, T > &A, const matMxN< M, N, T > &B)
Definition gl_mat.hh:143
vecN< N, T > normalize(const vecN< N, T > &x)
Definition gl_vec.hh:395
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition gl_vec.hh:332
float rsqrt(float x)
Definition gl_vec.hh:208
constexpr vecN< N, T > clamp(const vecN< N, T > &x, const vecN< N, T > &minVal, const vecN< N, T > &maxVal)
Definition gl_vec.hh:341
constexpr matMxN< M, N, T > operator+(const matMxN< M, N, T > &A, const matMxN< M, N, T > &B)
Definition gl_mat.hh:134
STL namespace.
#define UNREACHABLE
constexpr auto xrange(T e)
Definition xrange.hh:132