gl_vec.hh 14 KB

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