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 
27 namespace gl {
28 
29 // Vector with N components of type T.
30 template<int N, typename T> class vecN
31 {
32 public:
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 private:
134  T e[N];
135 };
136 
137 
138 // Convenience typedefs (same names as used by GLSL).
145 
146 
147 // -- Scalar functions --
148 
149 // reciprocal square root
150 [[nodiscard]] inline float rsqrt(float x)
151 {
152  return 1.0f / sqrtf(x);
153 }
154 [[nodiscard]] inline double rsqrt(double x)
155 {
156  return 1.0 / sqrt(x);
157 }
158 
159 // convert radians <-> degrees
160 template<typename T> [[nodiscard]] constexpr T radians(T d)
161 {
162  return d * T(M_PI / 180.0);
163 }
164 template<typename T> [[nodiscard]] constexpr T degrees(T r)
165 {
166  return r * T(180.0 / M_PI);
167 }
168 
169 
170 // -- Vector functions --
171 
172 // vector equality / inequality
173 template<int N, typename T>
174 [[nodiscard]] constexpr bool operator==(const vecN<N, T>& x, const vecN<N, T>& y)
175 {
176  for (auto i : xrange(N)) if (x[i] != y[i]) return false;
177  return true;
178 }
179 template<int N, typename T>
180 [[nodiscard]] constexpr bool operator!=(const vecN<N, T>& x, const vecN<N, T>& y)
181 {
182  return !(x == y);
183 }
184 
185 // vector negation
186 template<int N, typename T>
187 [[nodiscard]] constexpr vecN<N, T> operator-(const vecN<N, T>& x)
188 {
189  return vecN<N, T>() - x;
190 }
191 
192 // vector + vector
193 template<int N, typename T>
194 [[nodiscard]] constexpr vecN<N, T> operator+(const vecN<N, T>& x, const vecN<N, T>& y)
195 {
196  vecN<N, T> r;
197  for (auto i : xrange(N)) r[i] = x[i] + y[i];
198  return r;
199 }
200 
201 // vector - vector
202 template<int N, typename T>
203 [[nodiscard]] constexpr vecN<N, T> operator-(const vecN<N, T>& x, const vecN<N, T>& y)
204 {
205  vecN<N, T> r;
206  for (auto i : xrange(N)) r[i] = x[i] - y[i];
207  return r;
208 }
209 
210 // scalar * vector
211 template<int N, typename T>
212 [[nodiscard]] constexpr vecN<N, T> operator*(T x, const vecN<N, T>& y)
213 {
214  vecN<N, T> r;
215  for (auto i : xrange(N)) r[i] = x * y[i];
216  return r;
217 }
218 
219 // vector * scalar
220 template<int N, typename T>
221 [[nodiscard]] constexpr vecN<N, T> operator*(const vecN<N, T>& x, T y)
222 {
223  vecN<N, T> r;
224  for (auto i : xrange(N)) r[i] = x[i] * y;
225  return r;
226 }
227 
228 // vector * vector
229 template<int N, typename T>
230 [[nodiscard]] constexpr vecN<N, T> operator*(const vecN<N, T>& x, const vecN<N, T>& y)
231 {
232  vecN<N, T> r;
233  for (auto i : xrange(N)) r[i] = x[i] * y[i];
234  return r;
235 }
236 
237 // element-wise reciprocal
238 template<int N, typename T>
239 [[nodiscard]] constexpr vecN<N, T> recip(const vecN<N, T>& x)
240 {
241  vecN<N, T> r;
242  for (auto i : xrange(N)) r[i] = T(1) / x[i];
243  return r;
244 }
245 
246 // scalar / vector
247 template<int N, typename T>
248 [[nodiscard]] constexpr vecN<N, T> operator/(T x, const vecN<N, T>& y)
249 {
250  return x * recip(y);
251 }
252 
253 // vector / scalar
254 template<int N, typename T>
255 [[nodiscard]] constexpr vecN<N, T> operator/(const vecN<N, T>& x, T y)
256 {
257  return x * (T(1) / y);
258 }
259 
260 // vector / vector
261 template<int N, typename T>
262 [[nodiscard]] constexpr vecN<N, T> operator/(const vecN<N, T>& x, const vecN<N, T>& y)
263 {
264  return x * recip(y);
265 }
266 
267 // min(vector, vector)
268 template<int N, typename T>
269 [[nodiscard]] constexpr vecN<N, T> min(const vecN<N, T>& x, const vecN<N, T>& y)
270 {
271  vecN<N, T> r;
272  for (auto i : xrange(N)) r[i] = std::min(x[i], y[i]);
273  return r;
274 }
275 
276 // min(vector, vector)
277 template<int N, typename T>
278 [[nodiscard]] constexpr T min_component(const vecN<N, T>& x)
279 {
280  T r = x[0];
281  for (auto i : xrange(1, N)) r = std::min(r, x[i]);
282  return r;
283 }
284 
285 // max(vector, vector)
286 template<int N, typename T>
287 [[nodiscard]] constexpr vecN<N, T> max(const vecN<N, T>& x, const vecN<N, T>& y)
288 {
289  vecN<N, T> r;
290  for (auto i : xrange(N)) r[i] = std::max(x[i], y[i]);
291  return r;
292 }
293 
294 // clamp(vector, vector, vector)
295 template<int N, typename T>
296 [[nodiscard]] constexpr vecN<N, T> clamp(const vecN<N, T>& x, const vecN<N, T>& minVal, const vecN<N, T>& maxVal)
297 {
298  return min(maxVal, max(minVal, x));
299 }
300 
301 // clamp(vector, scalar, scalar)
302 template<int N, typename T>
303 [[nodiscard]] constexpr vecN<N, T> clamp(const vecN<N, T>& x, T minVal, T maxVal)
304 {
305  return clamp(x, vecN<N, T>(minVal), vecN<N, T>(maxVal));
306 }
307 
308 // sum of components
309 template<int N, typename T>
310 [[nodiscard]] constexpr T sum(const vecN<N, T>& x)
311 {
312  T result(0);
313  for (auto i : xrange(N)) result += x[i];
314  return result;
315 }
316 template<int N, typename T>
317 [[nodiscard]] constexpr vecN<N, T> sum_broadcast(const vecN<N, T>& x)
318 {
319  return vecN<N, T>(sum(x));
320 }
321 
322 // dot product
323 template<int N, typename T>
324 [[nodiscard]] constexpr T dot(const vecN<N, T>& x, const vecN<N, T>& y)
325 {
326  return sum(x * y);
327 }
328 template<int N, typename T>
329 [[nodiscard]] constexpr vecN<N, T> dot_broadcast(const vecN<N, T>& x, const vecN<N, T>& y)
330 {
331  return sum_broadcast(x * y);
332 }
333 
334 // squared length (norm-2)
335 template<int N, typename T>
336 [[nodiscard]] constexpr T length2(const vecN<N, T>& x)
337 {
338  return dot(x, x);
339 }
340 
341 // length (norm-2)
342 template<int N, typename T>
343 [[nodiscard]] inline T length(const vecN<N, T>& x)
344 {
345  return sqrt(length2(x));
346 }
347 
348 // normalize vector
349 template<int N, typename T>
350 [[nodiscard]] inline vecN<N, T> normalize(const vecN<N, T>& x)
351 {
352  return x * rsqrt(length2(x));
353 }
354 
355 // cross product (only defined for vectors of length 3)
356 template<typename T>
357 [[nodiscard]] constexpr vecN<3, T> cross(const vecN<3, T>& x, const vecN<3, T>& y)
358 {
359  return vecN<3, T>(x[1] * y[2] - x[2] * y[1],
360  x[2] * y[0] - x[0] * y[2],
361  x[0] * y[1] - x[1] * y[0]);
362 }
363 
364 // round each component to the nearest integer (returns a vector of integers)
365 template<int N, typename T>
366 [[nodiscard]] inline vecN<N, int> round(const vecN<N, T>& x)
367 {
368  vecN<N, int> r;
369  // note: std::lrint() is more generic (e.g. also works with double),
370  // but Dingux doesn't seem to have std::lrint().
371  for (auto i : xrange(N)) r[i] = lrintf(x[i]);
372  return r;
373 }
374 
375 // truncate each component to the nearest integer that is not bigger in
376 // absolute value (returns a vector of integers)
377 template<int N, typename T>
378 [[nodiscard]] constexpr vecN<N, int> trunc(const vecN<N, T>& x)
379 {
380  vecN<N, int> r;
381  for (auto i : xrange(N)) r[i] = int(x[i]);
382  return r;
383 }
384 
385 // Textual representation. (Only) used to debug unittest.
386 template<int N, typename T>
387 std::ostream& operator<<(std::ostream& os, const vecN<N, T>& x)
388 {
389  os << "[ ";
390  for (auto i : xrange(N)) {
391  os << x[i] << ' ';
392  }
393  os << ']';
394  return os;
395 }
396 
397 } // namespace gl
398 
399 // Support for structured bindings
400 namespace std {
401 // On some platforms tuple_size is a class and on others it is a struct.
402 // Such a mismatch is only a problem when targeting the Microsoft C++ ABI,
403 // which we don't do when compiling with Clang.
404 #if defined(__clang__)
405 #pragma clang diagnostic push
406 #pragma clang diagnostic ignored "-Wmismatched-tags"
407 #endif
408  template<int N, typename T> class tuple_size<gl::vecN<N, T>>
409  : public std::integral_constant<size_t, N> {};
410 #if defined(__clang__)
411 #pragma clang diagnostic pop
412 #endif
413  template<size_t I, int N, typename T> class tuple_element<I, gl::vecN<N, T>> {
414  public:
415  using type = T;
416  };
417 }
418 
419 #endif // GL_VEC_HH
#define M_PI
Definition: Math.hh:27
constexpr T operator[](unsigned i) const
Definition: gl_vec.hh:110
constexpr vecN & operator-=(const vecN &x)
Definition: gl_vec.hh:129
constexpr vecN & operator*=(T x)
Definition: gl_vec.hh:131
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+=(const vecN &x)
Definition: gl_vec.hh:128
constexpr vecN(T x, T y, T z, T w)
Definition: gl_vec.hh:76
constexpr T & operator[](unsigned i)
Definition: gl_vec.hh:116
constexpr vecN(const vecN< N1, T > &x, const vecN< N2, T > &y)
Definition: gl_vec.hh:102
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 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 T & get() noexcept
Definition: gl_vec.hh:125
constexpr vecN()
Definition: gl_vec.hh:36
constexpr vecN(T x, T y, T z)
Definition: gl_vec.hh:69
constexpr double sqrt(double x)
Definition: cstd.hh:367
Definition: gl_mat.hh:23
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:269
constexpr T min_component(const vecN< N, T > &x)
Definition: gl_vec.hh:278
constexpr T dot(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:324
std::ostream & operator<<(std::ostream &os, const matMxN< M, N, T > &A)
Definition: gl_mat.hh:334
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, int > round(const vecN< N, T > &x)
Definition: gl_vec.hh:366
T length(const vecN< N, T > &x)
Definition: gl_vec.hh:343
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:287
constexpr vecN< N, int > trunc(const vecN< N, T > &x)
Definition: gl_vec.hh:378
vecN< N, T > normalize(const vecN< N, T > &x)
Definition: gl_vec.hh:350
constexpr T length2(const vecN< N, T > &x)
Definition: gl_vec.hh:336
constexpr bool operator!=(const matMxN< M, N, T > &A, const matMxN< M, N, T > &B)
Definition: gl_mat.hh:127
constexpr vecN< 3, T > cross(const vecN< 3, T > &x, const vecN< 3, T > &y)
Definition: gl_vec.hh:357
constexpr vecN< N, T > recip(const vecN< N, T > &x)
Definition: gl_vec.hh:239
constexpr T degrees(T r)
Definition: gl_vec.hh:164
constexpr vecN< N, T > clamp(const vecN< N, T > &x, const vecN< N, T > &minVal, const vecN< N, T > &maxVal)
Definition: gl_vec.hh:296
constexpr T sum(const vecN< N, T > &x)
Definition: gl_vec.hh:310
constexpr T radians(T d)
Definition: gl_vec.hh:160
constexpr vecN< N, T > operator/(T x, const vecN< N, T > &y)
Definition: gl_vec.hh:248
float rsqrt(float x)
Definition: gl_vec.hh:150
constexpr bool operator==(const matMxN< M, N, T > &A, const matMxN< M, N, T > &B)
Definition: gl_mat.hh:121
constexpr vecN< N, T > sum_broadcast(const vecN< N, T > &x)
Definition: gl_vec.hh:317
constexpr matMxN< M, N, T > operator*(T x, const matMxN< M, N, T > &A)
Definition: gl_mat.hh:159
constexpr matMxN< M, N, T > operator+(const matMxN< M, N, T > &A, const matMxN< M, N, T > &B)
Definition: gl_mat.hh:134
constexpr vecN< N, T > dot_broadcast(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:329
constexpr unsigned N2
Definition: ResampleHQ.cc:231
constexpr unsigned N1
Definition: ResampleHQ.cc:230
constexpr unsigned N
Definition: ResampleHQ.cc:229
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:124
constexpr auto xrange(T e)
Definition: xrange.hh:155