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