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 "xrange.hh"
21#include <algorithm>
22#include <cassert>
23#include <cmath>
24#include <iostream>
25#include <utility>
26
27namespace gl {
28
29// Vector with N components of type T.
30template<int N, typename T> class vecN
31{
32public:
33 // Default copy-constructor and assignment operator.
34
35 // Construct vector containing all zeros.
36 constexpr vecN()
37 {
38 for (auto i : xrange(N)) e[i] = T(0);
39 }
40
41 // Construct vector containing the same value repeated N times.
42 constexpr explicit vecN(T x)
43 {
44 for (auto i : xrange(N)) e[i] = x;
45 }
46
47 // Conversion constructor from vector of same size but different type
48 template<typename T2>
49 constexpr explicit vecN(const vecN<N, T2>& x)
50 {
51 for (auto i : xrange(N)) e[i] = T(x[i]);
52 }
53
54 // Construct from larger vector (higher order elements are dropped).
55 template<int N2> constexpr explicit vecN(const vecN<N2, T>& x)
56 {
57 static_assert(N2 > N, "wrong vector length in constructor");
58 for (auto i : xrange(N)) e[i] = x[i];
59 }
60
61 // Construct vector from 2 given values (only valid when N == 2).
62 constexpr vecN(T x, T y)
63 : e{x, y}
64 {
65 static_assert(N == 2, "wrong #constructor arguments");
66 }
67
68 // Construct vector from 3 given values (only valid when N == 3).
69 constexpr vecN(T x, T y, T z)
70 : e{x, y, z}
71 {
72 static_assert(N == 3, "wrong #constructor arguments");
73 }
74
75 // Construct vector from 4 given values (only valid when N == 4).
76 constexpr vecN(T x, T y, T z, T w)
77 : e{x, y, z, w}
78 {
79 static_assert(N == 4, "wrong #constructor arguments");
80 }
81
82 // Construct vector from concatenating a scalar and a (smaller) vector.
83 template<int N2>
84 constexpr vecN(T x, const vecN<N2, T>& y)
85 {
86 static_assert((1 + N2) == N, "wrong vector length in constructor");
87 e[0] = x;
88 for (auto i : xrange(N2)) e[i + 1] = y[i];
89 }
90
91 // Construct vector from concatenating a (smaller) vector and a scalar.
92 template<int N1>
93 constexpr vecN(const vecN<N1, T>& x, T y)
94 {
95 static_assert((N1 + 1) == N, "wrong vector length in constructor");
96 for (auto i : xrange(N1)) e[i] = x[i];
97 e[N1] = y;
98 }
99
100 // Construct vector from concatenating two (smaller) vectors.
101 template<int N1, int N2>
102 constexpr vecN(const vecN<N1, T>& x, const vecN<N2, T>& y)
103 {
104 static_assert((N1 + N2) == N, "wrong vector length in constructor");
105 for (auto i : xrange(N1)) e[i ] = x[i];
106 for (auto i : xrange(N2)) e[i + N1] = y[i];
107 }
108
109 // Access the i-th element of this vector.
110 [[nodiscard]] constexpr T operator[](unsigned i) const {
111 #ifdef DEBUG
112 assert(i < N);
113 #endif
114 return e[i];
115 }
116 [[nodiscard]] constexpr T& operator[](unsigned i) {
117 #ifdef DEBUG
118 assert(i < N);
119 #endif
120 return e[i];
121 }
122
123 // For structured bindings
124 template<size_t I> [[nodiscard]] constexpr T get() const noexcept { return (*this)[I]; }
125 template<size_t I> [[nodiscard]] constexpr T& get() noexcept { return (*this)[I]; }
126
127 // Assignment version of the +,-,* operations defined below.
128 constexpr vecN& operator+=(const vecN& x) { *this = *this + x; return *this; }
129 constexpr vecN& operator-=(const vecN& x) { *this = *this - x; return *this; }
130 constexpr vecN& operator*=(const vecN& x) { *this = *this * x; return *this; }
131 constexpr vecN& operator*=(T x) { *this = *this * x; return *this; }
132
133 // gcc-10 mis-compiles this (fixed in gcc-11):
134 // [[nodiscard]] constexpr bool operator==(const vecN&) const = default;
135 // For now still manually implement it.
136 [[nodiscard]] friend constexpr bool operator==(const vecN& x, const vecN& y)
137 {
138 for (auto i : xrange(N)) if (x[i] != y[i]) return false;
139 return true;
140 }
141
142private:
143 T e[N];
144};
145
146
147// Convenience typedefs (same names as used by GLSL).
154
155
156// -- Scalar functions --
157
158// reciprocal square root
159[[nodiscard]] inline float rsqrt(float x)
160{
161 return 1.0f / sqrtf(x);
162}
163[[nodiscard]] inline double rsqrt(double x)
164{
165 return 1.0 / sqrt(x);
166}
167
168// convert radians <-> degrees
169template<typename T> [[nodiscard]] constexpr T radians(T d)
170{
171 return d * T(Math::pi / 180.0);
172}
173template<typename T> [[nodiscard]] constexpr T degrees(T r)
174{
175 return r * T(180.0 / Math::pi);
176}
177
178
179// -- Vector functions --
180
181// vector negation
182template<int N, typename T>
183[[nodiscard]] constexpr vecN<N, T> operator-(const vecN<N, T>& x)
184{
185 return vecN<N, T>() - x;
186}
187
188// vector + vector
189template<int N, typename T>
190[[nodiscard]] constexpr vecN<N, T> operator+(const vecN<N, T>& x, const vecN<N, T>& y)
191{
192 vecN<N, T> r;
193 for (auto i : xrange(N)) r[i] = x[i] + y[i];
194 return r;
195}
196
197// vector - vector
198template<int N, typename T>
199[[nodiscard]] constexpr vecN<N, T> operator-(const vecN<N, T>& x, const vecN<N, T>& y)
200{
201 vecN<N, T> r;
202 for (auto i : xrange(N)) r[i] = x[i] - y[i];
203 return r;
204}
205
206// scalar * vector
207template<int N, typename T>
208[[nodiscard]] constexpr vecN<N, T> operator*(T x, const vecN<N, T>& y)
209{
210 vecN<N, T> r;
211 for (auto i : xrange(N)) r[i] = x * y[i];
212 return r;
213}
214
215// vector * scalar
216template<int N, typename T>
217[[nodiscard]] constexpr vecN<N, T> operator*(const vecN<N, T>& x, T y)
218{
219 vecN<N, T> r;
220 for (auto i : xrange(N)) r[i] = x[i] * y;
221 return r;
222}
223
224// vector * vector
225template<int N, typename T>
226[[nodiscard]] constexpr vecN<N, T> operator*(const vecN<N, T>& x, const vecN<N, T>& y)
227{
228 vecN<N, T> r;
229 for (auto i : xrange(N)) r[i] = x[i] * y[i];
230 return r;
231}
232
233// element-wise reciprocal
234template<int N, typename T>
235[[nodiscard]] constexpr vecN<N, T> recip(const vecN<N, T>& x)
236{
237 vecN<N, T> r;
238 for (auto i : xrange(N)) r[i] = T(1) / x[i];
239 return r;
240}
241
242// scalar / vector
243template<int N, typename T>
244[[nodiscard]] constexpr vecN<N, T> operator/(T x, const vecN<N, T>& y)
245{
246 return x * recip(y);
247}
248
249// vector / scalar
250template<int N, typename T>
251[[nodiscard]] constexpr vecN<N, T> operator/(const vecN<N, T>& x, T y)
252{
253 return x * (T(1) / y);
254}
255
256// vector / vector
257template<int N, typename T>
258[[nodiscard]] constexpr vecN<N, T> operator/(const vecN<N, T>& x, const vecN<N, T>& y)
259{
260 return x * recip(y);
261}
262
263// min(vector, vector)
264template<int N, typename T>
265[[nodiscard]] constexpr vecN<N, T> min(const vecN<N, T>& x, const vecN<N, T>& y)
266{
267 vecN<N, T> r;
268 for (auto i : xrange(N)) r[i] = std::min(x[i], y[i]);
269 return r;
270}
271
272// min(vector, vector)
273template<int N, typename T>
274[[nodiscard]] constexpr T min_component(const vecN<N, T>& x)
275{
276 T r = x[0];
277 for (auto i : xrange(1, N)) r = std::min(r, x[i]);
278 return r;
279}
280
281// max(vector, vector)
282template<int N, typename T>
283[[nodiscard]] constexpr vecN<N, T> max(const vecN<N, T>& x, const vecN<N, T>& y)
284{
285 vecN<N, T> r;
286 for (auto i : xrange(N)) r[i] = std::max(x[i], y[i]);
287 return r;
288}
289
290// clamp(vector, vector, vector)
291template<int N, typename T>
292[[nodiscard]] constexpr vecN<N, T> clamp(const vecN<N, T>& x, const vecN<N, T>& minVal, const vecN<N, T>& maxVal)
293{
294 return min(maxVal, max(minVal, x));
295}
296
297// clamp(vector, scalar, scalar)
298template<int N, typename T>
299[[nodiscard]] constexpr vecN<N, T> clamp(const vecN<N, T>& x, T minVal, T maxVal)
300{
301 return clamp(x, vecN<N, T>(minVal), vecN<N, T>(maxVal));
302}
303
304// sum of components
305template<int N, typename T>
306[[nodiscard]] constexpr T sum(const vecN<N, T>& x)
307{
308 T result(0);
309 for (auto i : xrange(N)) result += x[i];
310 return result;
311}
312template<int N, typename T>
313[[nodiscard]] constexpr vecN<N, T> sum_broadcast(const vecN<N, T>& x)
314{
315 return vecN<N, T>(sum(x));
316}
317
318// dot product
319template<int N, typename T>
320[[nodiscard]] constexpr T dot(const vecN<N, T>& x, const vecN<N, T>& y)
321{
322 return sum(x * y);
323}
324template<int N, typename T>
325[[nodiscard]] constexpr vecN<N, T> dot_broadcast(const vecN<N, T>& x, const vecN<N, T>& y)
326{
327 return sum_broadcast(x * y);
328}
329
330// squared length (norm-2)
331template<int N, typename T>
332[[nodiscard]] constexpr T length2(const vecN<N, T>& x)
333{
334 return dot(x, x);
335}
336
337// length (norm-2)
338template<int N, typename T>
339[[nodiscard]] inline T length(const vecN<N, T>& x)
340{
341 return sqrt(length2(x));
342}
343
344// normalize vector
345template<int N, typename T>
346[[nodiscard]] inline vecN<N, T> normalize(const vecN<N, T>& x)
347{
348 return x * rsqrt(length2(x));
349}
350
351// cross product (only defined for vectors of length 3)
352template<typename T>
353[[nodiscard]] constexpr vecN<3, T> cross(const vecN<3, T>& x, const vecN<3, T>& y)
354{
355 return vecN<3, T>(x[1] * y[2] - x[2] * y[1],
356 x[2] * y[0] - x[0] * y[2],
357 x[0] * y[1] - x[1] * y[0]);
358}
359
360// round each component to the nearest integer (returns a vector of integers)
361template<int N, typename T>
362[[nodiscard]] inline vecN<N, int> round(const vecN<N, T>& x)
363{
364 vecN<N, int> r;
365 // note: std::lrint() is more generic (e.g. also works with double),
366 // but Dingux doesn't seem to have std::lrint().
367 for (auto i : xrange(N)) r[i] = lrintf(x[i]);
368 return r;
369}
370
371// truncate each component to the nearest integer that is not bigger in
372// absolute value (returns a vector of integers)
373template<int N, typename T>
374[[nodiscard]] constexpr vecN<N, int> trunc(const vecN<N, T>& x)
375{
376 vecN<N, int> r;
377 for (auto i : xrange(N)) r[i] = int(x[i]);
378 return r;
379}
380
381// Textual representation. (Only) used to debug unittest.
382template<int N, typename T>
383std::ostream& operator<<(std::ostream& os, const vecN<N, T>& x)
384{
385 os << "[ ";
386 for (auto i : xrange(N)) {
387 os << x[i] << ' ';
388 }
389 os << ']';
390 return os;
391}
392
393} // namespace gl
394
395// Support for structured bindings
396namespace std {
397// On some platforms tuple_size is a class and on others it is a struct.
398// Such a mismatch is only a problem when targeting the Microsoft C++ ABI,
399// which we don't do when compiling with Clang.
400#if defined(__clang__)
401#pragma clang diagnostic push
402#pragma clang diagnostic ignored "-Wmismatched-tags"
403#endif
404 template<int N, typename T> class tuple_size<gl::vecN<N, T>>
405 : public std::integral_constant<size_t, N> {};
406#if defined(__clang__)
407#pragma clang diagnostic pop
408#endif
409 template<size_t I, int N, typename T> class tuple_element<I, gl::vecN<N, T>> {
410 public:
411 using type = T;
412 };
413}
414
415#endif // GL_VEC_HH
constexpr T operator[](unsigned i) const
Definition: gl_vec.hh:110
constexpr vecN & operator*=(const vecN &x)
Definition: gl_vec.hh:130
constexpr vecN(T x, T y)
Definition: gl_vec.hh:62
constexpr T get() const noexcept
Definition: gl_vec.hh:124
constexpr vecN & operator*=(T x)
Definition: gl_vec.hh:131
constexpr vecN(T x, T y, T z, T w)
Definition: gl_vec.hh:76
friend constexpr bool operator==(const vecN &x, const vecN &y)
Definition: gl_vec.hh:136
constexpr vecN(const vecN< N1, T > &x, const vecN< N2, T > &y)
Definition: gl_vec.hh:102
constexpr T & get() noexcept
Definition: gl_vec.hh:125
constexpr vecN(const vecN< N1, T > &x, T y)
Definition: gl_vec.hh:93
constexpr vecN(const vecN< N2, T > &x)
Definition: gl_vec.hh:55
constexpr T & operator[](unsigned i)
Definition: gl_vec.hh:116
constexpr vecN(T x, const vecN< N2, T > &y)
Definition: gl_vec.hh:84
constexpr vecN(const vecN< N, T2 > &x)
Definition: gl_vec.hh:49
constexpr vecN(T x)
Definition: gl_vec.hh:42
constexpr vecN & operator-=(const vecN &x)
Definition: gl_vec.hh:129
constexpr vecN & operator+=(const vecN &x)
Definition: gl_vec.hh:128
constexpr vecN()
Definition: gl_vec.hh:36
constexpr vecN(T x, T y, T z)
Definition: gl_vec.hh:69
constexpr double pi
Definition: Math.hh:21
constexpr double sqrt(double x)
Definition: cstd.hh:258
Definition: gl_mat.hh:23
constexpr vecN< N, T > recip(const vecN< N, T > &x)
Definition: gl_vec.hh:235
constexpr vecN< 3, T > cross(const vecN< 3, T > &x, const vecN< 3, T > &y)
Definition: gl_vec.hh:353
constexpr T min_component(const vecN< N, T > &x)
Definition: gl_vec.hh:274
constexpr T dot(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:320
constexpr vecN< N, int > trunc(const vecN< N, T > &x)
Definition: gl_vec.hh:374
constexpr matMxN< M, N, T > operator*(T x, const matMxN< M, N, T > &A)
Definition: gl_mat.hh:155
T length(const vecN< N, T > &x)
Definition: gl_vec.hh:339
constexpr vecN< N, T > operator/(T x, const vecN< N, T > &y)
Definition: gl_vec.hh:244
vecN< N, int > round(const vecN< N, T > &x)
Definition: gl_vec.hh:362
constexpr T length2(const vecN< N, T > &x)
Definition: gl_vec.hh:332
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:265
constexpr vecN< N, T > dot_broadcast(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:325
constexpr T degrees(T r)
Definition: gl_vec.hh:173
constexpr vecN< N, T > sum_broadcast(const vecN< N, T > &x)
Definition: gl_vec.hh:313
constexpr T sum(const vecN< N, T > &x)
Definition: gl_vec.hh:306
std::ostream & operator<<(std::ostream &os, const matMxN< M, N, T > &A)
Definition: gl_mat.hh:330
constexpr T radians(T d)
Definition: gl_vec.hh:169
constexpr matMxN< M, N, T > operator-(const matMxN< M, N, T > &A, const matMxN< M, N, T > &B)
Definition: gl_mat.hh:139
vecN< N, T > normalize(const vecN< N, T > &x)
Definition: gl_vec.hh:346
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:283
float rsqrt(float x)
Definition: gl_vec.hh:159
constexpr vecN< N, T > clamp(const vecN< N, T > &x, const vecN< N, T > &minVal, const vecN< N, T > &maxVal)
Definition: gl_vec.hh:292
constexpr matMxN< M, N, T > operator+(const matMxN< M, N, T > &A, const matMxN< M, N, T > &B)
Definition: gl_mat.hh:130
constexpr unsigned N2
Definition: ResampleHQ.cc:228
constexpr unsigned N1
Definition: ResampleHQ.cc:227
constexpr unsigned N
Definition: ResampleHQ.cc:226
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:127
STL namespace.
constexpr auto xrange(T e)
Definition: xrange.hh:133