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 // Only the 'common' operations on vec4 (4 float values) are 'well' optimized.
15 // I verified that they can be used to built a 4x4 matrix multiplication
16 // routine that is as efficient as a hand-written SSE assembly routine
17 // (verified with gcc-4.8 on x86_64). Actually the other routines are likely
18 // efficient as well, but I mean it wasn't the main goal for this code.
19 //
20 // Calling convention: vec4 internally takes up one 128-bit xmm register. It
21 // can be efficientlt passed by value. The other vector types are passed by
22 // const-reference. Though also in the latter case usually the compiler can
23 // optimize away the indirection.
24 
25 #include "Math.hh"
26 #include <algorithm>
27 #include <cassert>
28 #include <cmath>
29 #include <iostream>
30 #include <utility>
31 
32 namespace gl {
33 
34 // Vector with N components of type T.
35 template<int N, typename T> class vecN
36 {
37 public:
38  // Default copy-constructor and assignment operator.
39 
40  // Construct vector containing all zeros.
41  vecN()
42  {
43  for (int i = 0; i < N; ++i) e[i] = T(0);
44  }
45 
46  // Construct vector containing the same value repeated N times.
47  explicit vecN(T x)
48  {
49  for (int i = 0; i < N; ++i) e[i] = x;
50  }
51 
52  // Conversion constructor from vector of same size but different type
53  template<typename T2>
54  explicit vecN(const vecN<N, T2>& x)
55  {
56  for (int i = 0; i < N; ++i) e[i] = T(x[i]);
57  }
58 
59  // Construct from larger vector (higher order elements are dropped).
60  template<int N2> explicit vecN(const vecN<N2, T>& x)
61  {
62  static_assert(N2 > N, "wrong vector length in constructor");
63  for (int i = 0; i < N; ++i) e[i] = x[i];
64  }
65 
66  // Construct vector from 2 given values (only valid when N == 2).
67  vecN(T x, T y)
68  {
69  static_assert(N == 2, "wrong #constructor arguments");
70  e[0] = x; e[1] = y;
71  }
72 
73  // Construct vector from 3 given values (only valid when N == 3).
74  vecN(T x, T y, T z)
75  {
76  static_assert(N == 3, "wrong #constructor arguments");
77  e[0] = x; e[1] = y; e[2] = z;
78  }
79 
80  // Construct vector from 4 given values (only valid when N == 4).
81  vecN(T x, T y, T z, T w)
82  {
83  static_assert(N == 4, "wrong #constructor arguments");
84  e[0] = x; e[1] = y; e[2] = z; e[3] = w;
85  }
86 
87  // Construct vector from concatenating a scalar and a (smaller) vector.
88  template<int N2>
89  vecN(T x, const vecN<N2, T>& y)
90  {
91  static_assert((1 + N2) == N, "wrong vector length in constructor");
92  e[0] = x;
93  for (int i = 0; i < N2; ++i) e[i + 1] = y[i];
94  }
95 
96  // Construct vector from concatenating a (smaller) vector and a scalar.
97  template<int N1>
98  vecN(const vecN<N1, T>& x, T y)
99  {
100  static_assert((N1 + 1) == N, "wrong vector length in constructor");
101  for (int i = 0; i < N1; ++i) e[i] = x[i];
102  e[N1] = y;
103  }
104 
105  // Construct vector from concatenating two (smaller) vectors.
106  template<int N1, int N2>
107  vecN(const vecN<N1, T>& x, const vecN<N2, T>& y)
108  {
109  static_assert((N1 + N2) == N, "wrong vector length in constructor");
110  for (int i = 0; i < N1; ++i) e[i ] = x[i];
111  for (int i = 0; i < N2; ++i) e[i + N1] = y[i];
112  }
113 
114  // Access the i-th element of this vector.
115  T operator[](unsigned i) const {
116  #ifdef DEBUG
117  assert(i < N);
118  #endif
119  return e[i];
120  }
121  T& operator[](unsigned i) {
122  #ifdef DEBUG
123  assert(i < N);
124  #endif
125  return e[i];
126  }
127 
128  // For structured bindings
129  template<size_t I> T get() const noexcept { return (*this)[I]; }
130  template<size_t I> T& get() noexcept { return (*this)[I]; }
131 
132  // Assignment version of the +,-,* operations defined below.
133  vecN& operator+=(const vecN& x) { *this = *this + x; return *this; }
134  vecN& operator-=(const vecN& x) { *this = *this - x; return *this; }
135  vecN& operator*=(const vecN& x) { *this = *this * x; return *this; }
136  vecN& operator*=(T x) { *this = *this * x; return *this; }
137 
138 private:
139  T e[N];
140 };
141 
142 
143 // Convenience typedefs (same names as used by GLSL).
150 
151 
152 // -- Scalar functions --
153 
154 // reciprocal square root
155 inline float rsqrt(float x)
156 {
157  return 1.0f / sqrtf(x);
158 }
159 inline double rsqrt(double x)
160 {
161  return 1.0 / sqrt(x);
162 }
163 
164 // convert radians <-> degrees
165 template<typename T> inline T radians(T d)
166 {
167  return d * T(M_PI / 180.0);
168 }
169 template<typename T> inline T degrees(T r)
170 {
171  return r * T(180.0 / M_PI);
172 }
173 
174 
175 // -- Vector functions --
176 
177 // vector equality / inequality
178 template<int N, typename T>
179 inline bool operator==(const vecN<N, T>& x, const vecN<N, T>& y)
180 {
181  for (int i = 0; i < N; ++i) if (x[i] != y[i]) return false;
182  return true;
183 }
184 template<int N, typename T>
185 inline bool operator!=(const vecN<N, T>& x, const vecN<N, T>& y)
186 {
187  return !(x == y);
188 }
189 
190 // vector negation
191 template<int N, typename T>
193 {
194  return vecN<N, T>() - x;
195 }
196 
197 // vector + vector
198 template<int N, typename T>
199 inline vecN<N, T> operator+(const vecN<N, T>& x, const vecN<N, T>& y)
200 {
201  vecN<N, T> r;
202  for (int i = 0; i < N; ++i) r[i] = x[i] + y[i];
203  return r;
204 }
205 
206 // vector - vector
207 template<int N, typename T>
208 inline vecN<N, T> operator-(const vecN<N, T>& x, const vecN<N, T>& y)
209 {
210  vecN<N, T> r;
211  for (int i = 0; i < N; ++i) r[i] = x[i] - y[i];
212  return r;
213 }
214 
215 // scalar * vector
216 template<int N, typename T>
217 inline vecN<N, T> operator*(T x, const vecN<N, T>& y)
218 {
219  vecN<N, T> r;
220  for (int i = 0; i < N; ++i) r[i] = x * y[i];
221  return r;
222 }
223 
224 // vector * scalar
225 template<int N, typename T>
226 inline vecN<N, T> operator*(const vecN<N, T>& x, T y)
227 {
228  vecN<N, T> r;
229  for (int i = 0; i < N; ++i) r[i] = x[i] * y;
230  return r;
231 }
232 
233 // vector * vector
234 template<int N, typename T>
235 inline vecN<N, T> operator*(const vecN<N, T>& x, const vecN<N, T>& y)
236 {
237  vecN<N, T> r;
238  for (int i = 0; i < N; ++i) r[i] = x[i] * y[i];
239  return r;
240 }
241 
242 // element-wise reciprocal
243 template<int N, typename T>
244 inline vecN<N, T> recip(const vecN<N, T>& x)
245 {
246  vecN<N, T> r;
247  for (int i = 0; i < N; ++i) r[i] = T(1) / x[i];
248  return r;
249 }
250 
251 // scalar / vector
252 template<int N, typename T>
253 inline vecN<N, T> operator/(T x, const vecN<N, T>& y)
254 {
255  return x * recip(y);
256 }
257 
258 // vector / scalar
259 template<int N, typename T>
260 inline vecN<N, T> operator/(const vecN<N, T>& x, T y)
261 {
262  return x * (T(1) / y);
263 }
264 
265 // vector / vector
266 template<int N, typename T>
267 inline vecN<N, T> operator/(const vecN<N, T>& x, const vecN<N, T>& y)
268 {
269  return x * recip(y);
270 }
271 
272 // min(vector, vector)
273 template<int N, typename T>
274 inline vecN<N, T> min(const vecN<N, T>& x, const vecN<N, T>& y)
275 {
276  vecN<N, T> r;
277  for (int i = 0; i < N; ++i) r[i] = std::min(x[i], y[i]);
278  return r;
279 }
280 
281 // min(vector, vector)
282 template<int N, typename T>
283 inline T min_component(const vecN<N, T>& x)
284 {
285  T r = x[0];
286  for (int i = 1; i < N; ++i) r = std::min(r, x[i]);
287  return r;
288 }
289 
290 // max(vector, vector)
291 template<int N, typename T>
292 inline vecN<N, T> max(const vecN<N, T>& x, const vecN<N, T>& y)
293 {
294  vecN<N, T> r;
295  for (int i = 0; i < N; ++i) r[i] = std::max(x[i], y[i]);
296  return r;
297 }
298 
299 // clamp(vector, vector, vector)
300 template<int N, typename T>
301 inline vecN<N, T> clamp(const vecN<N, T>& x, const vecN<N, T>& minVal, const vecN<N, T>& maxVal)
302 {
303  return min(maxVal, max(minVal, x));
304 }
305 
306 // clamp(vector, scalar, scalar)
307 template<int N, typename T>
308 inline vecN<N, T> clamp(const vecN<N, T>& x, T minVal, T maxVal)
309 {
310  return clamp(x, vecN<N, T>(minVal), vecN<N, T>(maxVal));
311 }
312 
313 // sum of components
314 template<int N, typename T>
315 inline T sum(const vecN<N, T>& x)
316 {
317  T result(0);
318  for (int i = 0; i < N; ++i) result += x[i];
319  return result;
320 }
321 template<int N, typename T>
323 {
324  return vecN<N, T>(sum(x));
325 }
326 
327 // dot product
328 template<int N, typename T>
329 inline T dot(const vecN<N, T>& x, const vecN<N, T>& y)
330 {
331  return sum(x * y);
332 }
333 template<int N, typename T>
335 {
336  return sum_broadcast(x * y);
337 }
338 
339 // squared length (norm-2)
340 template<int N, typename T>
341 inline T length2(const vecN<N, T>& x)
342 {
343  return dot(x, x);
344 }
345 
346 // length (norm-2)
347 template<int N, typename T>
348 inline T length(const vecN<N, T>& x)
349 {
350  return sqrt(length2(x));
351 }
352 
353 // normalize vector
354 template<int N, typename T>
356 {
357  return x * rsqrt(length2(x));
358 }
359 
360 // cross product (only defined for vectors of length 3)
361 template<typename T>
362 inline vecN<3, T> cross(const vecN<3, T>& x, const vecN<3, T>& y)
363 {
364  return vecN<3, T>(x[1] * y[2] - x[2] * y[1],
365  x[2] * y[0] - x[0] * y[2],
366  x[0] * y[1] - x[1] * y[0]);
367 }
368 
369 // round each component to the nearest integer (returns a vector of integers)
370 template<int N, typename T>
372 {
373  vecN<N, int> r;
374  // note: std::lrint() is more generic (e.g. also works with double),
375  // but Dingux doesn't seem to have std::lrint().
376  for (int i = 0; i < N; ++i) r[i] = lrintf(x[i]);
377  return r;
378 }
379 
380 // truncate each component to the nearest integer that is not bigger in
381 // absolute value (returns a vector of integers)
382 template<int N, typename T>
384 {
385  vecN<N, int> r;
386  for (int i = 0; i < N; ++i) r[i] = int(x[i]);
387  return r;
388 }
389 
390 // Textual representation. (Only) used to debug unittest.
391 template<int N, typename T>
392 std::ostream& operator<<(std::ostream& os, const vecN<N, T>& x)
393 {
394  os << "[ ";
395  for (int i = 0; i < N; ++i) {
396  os << x[i] << ' ';
397  }
398  os << ']';
399  return os;
400 }
401 
402 } // namespace gl
403 
404 // Support for structured bindings
405 namespace std {
406 // On some platforms tuple_size is a class and on others it is a struct.
407 // Such a mismatch is only a problem when targeting the Microsoft C++ ABI,
408 // which we don't do when compiling with Clang.
409 #if defined(__clang__)
410 #pragma clang diagnostic push
411 #pragma clang diagnostic ignored "-Wmismatched-tags"
412 #endif
413  template<int N, typename T> class tuple_size<gl::vecN<N, T>>
414  : public std::integral_constant<size_t, N> {};
415 #if defined(__clang__)
416 #pragma clang diagnostic pop
417 #endif
418  template<size_t I, int N, typename T> class tuple_element<I, gl::vecN<N, T>> {
419  public:
420  using type = T;
421  };
422 }
423 
424 
425 // --- SSE optimizations ---
426 
427 #ifdef __SSE__
428 #include <xmmintrin.h>
429 
430 // Optionally also use SSE3 and SSE4.1
431 #ifdef __SSE3__
432 #include <pmmintrin.h>
433 #endif
434 #ifdef __SSE4_1__
435 #include <smmintrin.h>
436 #endif
437 
438 namespace gl {
439 
440 // Specialization: implement a vector of 4 floats using SSE instructions
441 template<> class vecN<4, float>
442 {
443 public:
444  vecN()
445  {
446  e = _mm_setzero_ps();
447  }
448 
449  explicit vecN(float x)
450  {
451  e = _mm_set1_ps(x);
452  }
453 
454  vecN(float x, const vecN<3, float>& yzw)
455  {
456  e = _mm_setr_ps(x, yzw[0], yzw[1], yzw[2]);
457  }
458 
459  vecN(const vecN<3, float>& xyz, float w)
460  {
461  e = _mm_setr_ps(xyz[0], xyz[1], xyz[2], w);
462  }
463 
464  vecN(const vecN<2, float>& xy, const vecN<2, float>& zw)
465  {
466  e = _mm_setr_ps(xy[0], xy[1], zw[0], zw[1]);
467  }
468 
469  vecN(float x, float y, float z, float w)
470  {
471  e = _mm_setr_ps(x, y, z, w);
472  }
473 
474  float operator[](int i) const { return e_[i]; }
475  float& operator[](int i) { return e_[i]; }
476 
477  // For structured bindings
478  template<size_t I> float get() const noexcept { return (*this)[I]; }
479  template<size_t I> float& get() noexcept { return (*this)[I]; }
480 
481  vecN& operator+=(vecN x) { *this = *this + x; ; return *this; }
482  vecN& operator-=(vecN x) { *this = *this - x; ; return *this; }
483  vecN& operator*=(vecN x) { *this = *this * x; ; return *this; }
484  vecN& operator*=(float x) { *this = *this * x; ; return *this; }
485 
486  explicit vecN(__m128 x) : e(x) {}
487  __m128 sse() const { return e; }
488 
489 private:
490  // With gcc we don't need this union. With clang we need it to
491  // be able to write individual components.
492  union {
493  __m128 e;
494  float e_[4];
495  };
496 };
497 
498 inline bool operator==(vec4 x, vec4 y)
499 {
500  return _mm_movemask_ps(_mm_cmpeq_ps(x.sse(), y.sse())) == 15;
501 }
502 
503 inline vec4 operator+(vec4 x, vec4 y)
504 {
505  return vec4(_mm_add_ps(x.sse(), y.sse()));
506 }
507 
508 inline vec4 operator-(vec4 x, vec4 y)
509 {
510  return vec4(_mm_sub_ps(x.sse(), y.sse()));
511 }
512 
513 inline vec4 operator*(float x, vec4 y)
514 {
515  return vec4(_mm_mul_ps(_mm_set1_ps(x), y.sse()));
516 }
517 
518 inline vec4 operator*(vec4 x, float y)
519 {
520  return vec4(_mm_mul_ps(x.sse(), _mm_set1_ps(y)));
521 }
522 
523 inline vec4 operator*(vec4 x, vec4 y)
524 {
525  return vec4(_mm_mul_ps(x.sse(), y.sse()));
526 }
527 
528 #ifdef __SSE3__
529 inline float sum(vec4 x)
530 {
531  __m128 t = _mm_hadd_ps(x.sse(), x.sse());
532  return _mm_cvtss_f32(_mm_hadd_ps(t, t));
533 }
534 inline vec4 sum_broadcast(vec4 x)
535 {
536  __m128 t = _mm_hadd_ps(x.sse(), x.sse());
537  return vec4(_mm_hadd_ps(t, t));
538 }
539 #else
540 inline float sum(vec4 x)
541 {
542  __m128 t0 = x.sse();
543  __m128 t1 = _mm_add_ps(t0, _mm_movehl_ps (t0, t0));
544  __m128 t2 = _mm_add_ps(t1, _mm_shuffle_ps(t1, t1, _MM_SHUFFLE(1,1,1,1)));
545  return _mm_cvtss_f32(t2);
546 }
547 inline vec4 sum_broadcast(vec4 x)
548 {
549  __m128 t0 = x.sse();
550  __m128 t1 = _mm_add_ps(t0, _mm_shuffle_ps(t0, t0, _MM_SHUFFLE(2,3,0,1)));
551  __m128 t2 = _mm_add_ps(t1, _mm_shuffle_ps(t1, t1, _MM_SHUFFLE(1,0,3,2)));
552  return vec4(t2);
553 }
554 #endif
555 
556 inline vec4 min(vec4 x, vec4 y)
557 {
558  return vec4(_mm_min_ps(x.sse(), y.sse()));
559 }
560 
561 inline vec4 max(vec4 x, vec4 y)
562 {
563  return vec4(_mm_max_ps(x.sse(), y.sse()));
564 }
565 
566 #ifdef __SSE4_1__
567 inline float dot(vec4 x, vec4 y)
568 {
569  return _mm_cvtss_f32(_mm_dp_ps(x.sse(), y.sse(), 0xF1));
570 }
571 inline vec4 dot_broadcast(vec4 x, vec4 y)
572 {
573  return vec4(_mm_dp_ps(x.sse(), y.sse(), 0xFF));
574 }
575 #endif
576 
577 inline vec4 normalize(vec4 x)
578 {
579  // Use 1 Newton-Raphson step to improve 1/sqrt(a) approximation:
580  // let s0 be the initial approximation, then
581  // s1 = (3 - s0^2 * a) * (s0 / 2) is a better approximation
582  vec4 l2 = dot_broadcast(x, x);
583  __m128 s0 = _mm_rsqrt_ps(l2.sse());
584  __m128 ss = _mm_mul_ps(s0, s0);
585  __m128 h = _mm_mul_ps(_mm_set1_ps(-0.5f), s0);
586  __m128 m3 = _mm_sub_ps(_mm_mul_ps(l2.sse(), ss), _mm_set1_ps(3.0f));
587  __m128 s1 = _mm_mul_ps(h, m3);
588  return vec4(_mm_mul_ps(x.sse(), s1));
589 }
590 
591 inline vec4 recip(vec4 a)
592 {
593  // Use 1 Newton-Raphson step to improve 1/a approximation:
594  // let x0 be the initial approximation, then
595  // x1 = x0 + x0 - a * x0 * x0 is a better approximation
596  __m128 x0 = _mm_rcp_ps(a.sse());
597  __m128 m0 = _mm_mul_ps(x0, a.sse());
598  __m128 m1 = _mm_mul_ps(x0, m0);
599  __m128 a0 = _mm_add_ps(x0, x0);
600  __m128 x1 = _mm_sub_ps(a0, m1);
601  return vec4(x1);
602 }
603 
604 } // namespace gl
605 
606 #endif // __SSE__
607 
608 #endif // GL_VEC_HH
gl::vecN::vecN
vecN(const vecN< N2, T > &x)
Definition: gl_vec.hh:60
openmsx::N2
constexpr unsigned N2
Definition: ResampleHQ.cc:227
gl::vecN::operator+=
vecN & operator+=(const vecN &x)
Definition: gl_vec.hh:133
gl::vecN::operator[]
T & operator[](unsigned i)
Definition: gl_vec.hh:121
gl::clamp
vecN< N, T > clamp(const vecN< N, T > &x, const vecN< N, T > &minVal, const vecN< N, T > &maxVal)
Definition: gl_vec.hh:301
gl::vecN::vecN
vecN(T x, T y, T z)
Definition: gl_vec.hh:74
gl::dot
T dot(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:329
gl::min
vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:274
gl::vecN::get
T & get() noexcept
Definition: gl_vec.hh:130
gl::vecN::vecN
vecN(const vecN< N, T2 > &x)
Definition: gl_vec.hh:54
gl::min_component
T min_component(const vecN< N, T > &x)
Definition: gl_vec.hh:283
gl::rsqrt
float rsqrt(float x)
Definition: gl_vec.hh:155
gl::length
T length(const vecN< N, T > &x)
Definition: gl_vec.hh:348
t
TclObject t
Definition: TclObject_test.cc:264
gl::operator/
vecN< N, T > operator/(T x, const vecN< N, T > &y)
Definition: gl_vec.hh:253
gl::sum
T sum(const vecN< N, T > &x)
Definition: gl_vec.hh:315
gl::vecN::vecN
vecN()
Definition: gl_vec.hh:41
gl
Definition: gl_mat.hh:24
gl::vecN
Definition: gl_vec.hh:36
gl::vecN::operator[]
T operator[](unsigned i) const
Definition: gl_vec.hh:115
M_PI
#define M_PI
Definition: Math.hh:27
gl::cross
vecN< 3, T > cross(const vecN< 3, T > &x, const vecN< 3, T > &y)
Definition: gl_vec.hh:362
gl::vecN::vecN
vecN(const vecN< N1, T > &x, const vecN< N2, T > &y)
Definition: gl_vec.hh:107
gl::round
vecN< N, int > round(const vecN< N, T > &x)
Definition: gl_vec.hh:371
gl::vecN::operator*=
vecN & operator*=(const vecN &x)
Definition: gl_vec.hh:135
openmsx::N1
constexpr unsigned N1
Definition: ResampleHQ.cc:226
gl::operator<<
std::ostream & operator<<(std::ostream &os, const matMxN< M, N, T > &A)
Definition: gl_mat.hh:385
gl::vecN::vecN
vecN(T x, T y)
Definition: gl_vec.hh:67
gl::recip
vecN< N, T > recip(const vecN< N, T > &x)
Definition: gl_vec.hh:244
gl::dot_broadcast
vecN< N, T > dot_broadcast(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:334
openmsx::N
constexpr unsigned N
Definition: ResampleHQ.cc:225
gl::vec4
vecN< 4, float > vec4
Definition: gl_vec.hh:146
gl::operator==
bool operator==(const matMxN< M, N, T > &A, const matMxN< M, N, T > &B)
Definition: gl_mat.hh:166
openmsx::x
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:1419
gl::vecN::vecN
vecN(T x, T y, T z, T w)
Definition: gl_vec.hh:81
gl::vecN::operator*=
vecN & operator*=(T x)
Definition: gl_vec.hh:136
gl::operator*
matMxN< M, N, T > operator*(T x, const matMxN< M, N, T > &A)
Definition: gl_mat.hh:204
gl::vecN::get
T get() const noexcept
Definition: gl_vec.hh:129
gl::trunc
vecN< N, int > trunc(const vecN< N, T > &x)
Definition: gl_vec.hh:383
gl::vecN::vecN
vecN(T x, const vecN< N2, T > &y)
Definition: gl_vec.hh:89
gl::operator!=
bool operator!=(const matMxN< M, N, T > &A, const matMxN< M, N, T > &B)
Definition: gl_mat.hh:172
gl::normalize
vecN< N, T > normalize(const vecN< N, T > &x)
Definition: gl_vec.hh:355
gl::max
vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:292
gl::operator+
matMxN< M, N, T > operator+(const matMxN< M, N, T > &A, const matMxN< M, N, T > &B)
Definition: gl_mat.hh:179
gl::degrees
T degrees(T r)
Definition: gl_vec.hh:169
gl::sum_broadcast
vecN< N, T > sum_broadcast(const vecN< N, T > &x)
Definition: gl_vec.hh:322
Math.hh
gl::vecN::vecN
vecN(const vecN< N1, T > &x, T y)
Definition: gl_vec.hh:98
gl::vecN::vecN
vecN(T x)
Definition: gl_vec.hh:47
std::tuple_element< I, gl::vecN< N, T > >::type
T type
Definition: gl_vec.hh:420
gl::radians
T radians(T d)
Definition: gl_vec.hh:165
gl::vecN::operator-=
vecN & operator-=(const vecN &x)
Definition: gl_vec.hh:134
gl::length2
T length2(const vecN< N, T > &x)
Definition: gl_vec.hh:341
gl::operator-
matMxN< M, N, T > operator-(const matMxN< M, N, T > &A, const matMxN< M, N, T > &B)
Definition: gl_mat.hh:188