639 lines
18 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010—2019 Sam Hocevar <sam@hocevar.net>
  5. //
  6. // Lol Engine is free software. It comes without any warranty, to
  7. // the extent permitted by applicable law. You can redistribute it
  8. // and/or modify it under the terms of the Do What the Fuck You Want
  9. // to Public License, Version 2, as published by the WTFPL Task Force.
  10. // See http://www.wtfpl.net/ for more details.
  11. //
  12. #pragma once
  13. //
  14. // The matrix classes
  15. // ------------------
  16. //
  17. #include <ostream>
  18. #include <lol/math/vector.h>
  19. #include <lol/math/transform.h>
  20. #if _WIN32
  21. # pragma push_macro("near")
  22. # pragma push_macro("far")
  23. # undef near
  24. # undef far
  25. #endif
  26. namespace lol
  27. {
  28. /*
  29. * The generic “mat_t” type, which is fixed-size
  30. */
  31. template<typename T, int COLS, int ROWS>
  32. struct lol_attr_nodiscard mat_t
  33. : public linear_ops::base<vec_t<T,ROWS>>
  34. {
  35. static int const count = COLS;
  36. typedef T scalar_element;
  37. typedef vec_t<T,ROWS> element;
  38. typedef mat_t<T,COLS,ROWS> type;
  39. inline mat_t() {}
  40. explicit inline mat_t(T const &val)
  41. {
  42. T const zero = T(0);
  43. for (int i = 0; i < COLS; ++i)
  44. for (int j = 0; j < ROWS; ++j)
  45. m_data[i][j] = i == j ? val : zero;
  46. }
  47. /* Explicit constructor for type conversion */
  48. template<typename U>
  49. explicit inline mat_t(mat_t<U, COLS, ROWS> const &m)
  50. {
  51. for (int i = 0; i < COLS; ++i)
  52. m_data[i] = (vec_t<T,ROWS>)m[i];
  53. }
  54. inline vec_t<T,ROWS>& operator[](size_t n) { return m_data[n]; }
  55. inline vec_t<T,ROWS> const& operator[](size_t n) const { return m_data[n]; }
  56. private:
  57. vec_t<T,ROWS> m_data[COLS];
  58. };
  59. /*
  60. * 2×2-element matrices
  61. */
  62. template <typename T>
  63. struct lol_attr_nodiscard mat_t<T, 2, 2>
  64. : public linear_ops::base<vec_t<T,2>>
  65. {
  66. static int const count = 2;
  67. typedef T scalar_element;
  68. typedef vec_t<T,2> element;
  69. typedef mat_t<T,2,2> type;
  70. inline mat_t() {}
  71. inline mat_t(vec_t<T,2> v0, vec_t<T,2> v1)
  72. : m_data{ v0, v1 } {}
  73. explicit inline mat_t(T const &val)
  74. : m_data{ vec_t<T,2>(val, T(0)),
  75. vec_t<T,2>(T(0), val) } {}
  76. explicit inline mat_t(mat_t<T,4,4> const &m)
  77. : m_data{ m[0].xy, m[1].xy } {}
  78. /* Explicit constructor for type conversion */
  79. template<typename U>
  80. explicit inline mat_t(mat_t<U,2,2> const &m)
  81. : m_data{ (element)m[0], (element)m[1] } {}
  82. inline vec_t<T,2>& operator[](size_t n) { return m_data[n]; }
  83. inline vec_t<T,2> const& operator[](size_t n) const { return m_data[n]; }
  84. /* Helpers for transformation matrices */
  85. static mat_t<T,2,2> rotate(T radians);
  86. static inline mat_t<T,2,2> rotate(mat_t<T,2,2> m, T radians)
  87. {
  88. return rotate(radians) * m;
  89. }
  90. void printf() const;
  91. std::string tostring() const;
  92. static const mat_t<T,2,2> identity;
  93. private:
  94. vec_t<T,2> m_data[2];
  95. };
  96. static_assert(sizeof(imat2) == 16, "sizeof(imat2) == 16");
  97. static_assert(sizeof(f16mat2) == 8, "sizeof(f16mat2) == 8");
  98. static_assert(sizeof(mat2) == 16, "sizeof(mat2) == 16");
  99. static_assert(sizeof(dmat2) == 32, "sizeof(dmat2) == 32");
  100. /*
  101. * 3×3-element matrices
  102. */
  103. template <typename T>
  104. struct lol_attr_nodiscard mat_t<T, 3, 3>
  105. : public linear_ops::base<vec_t<T,3>>
  106. {
  107. static int const count = 3;
  108. typedef T scalar_element;
  109. typedef vec_t<T,3> element;
  110. typedef mat_t<T,3,3> type;
  111. inline mat_t() {}
  112. inline mat_t(vec_t<T,3> v0, vec_t<T,3> v1, vec_t<T,3> v2)
  113. : m_data{ v0, v1, v2 } {}
  114. explicit inline mat_t(T const &val)
  115. : m_data{ vec_t<T,3>(val, (T)0, (T)0),
  116. vec_t<T,3>((T)0, val, (T)0),
  117. vec_t<T,3>((T)0, (T)0, val) } {}
  118. explicit inline mat_t(mat_t<T,2,2> m, T const &val = T(1))
  119. : m_data{ vec_t<T,3>(m[0], (T)0),
  120. vec_t<T,3>(m[1], (T)0),
  121. vec_t<T,3>((T)0, (T)0, val) } {}
  122. explicit inline mat_t(mat_t<T,4,4> const &m)
  123. : m_data{ m[0].xyz, m[1].xyz, m[2].xyz } {}
  124. /* Explicit constructor for type conversion */
  125. template<typename U>
  126. explicit inline mat_t(mat_t<U,3,3> const &m)
  127. : m_data{ (element)m[0], (element)m[1], (element)m[2] } {}
  128. explicit mat_t(quat_t<T> const &q);
  129. inline vec_t<T,3>& operator[](size_t n) { return m_data[n]; }
  130. inline vec_t<T,3> const& operator[](size_t n) const { return m_data[n]; }
  131. /* Helpers for transformation matrices */
  132. static mat_t<T,3,3> scale(T x);
  133. static mat_t<T,3,3> scale(T x, T y, T z);
  134. static mat_t<T,3,3> scale(vec_t<T,3> v);
  135. static mat_t<T,3,3> rotate(T radians, T x, T y, T z);
  136. static mat_t<T,3,3> rotate(T radians, vec_t<T,3> v);
  137. static mat_t<T,3,3> fromeuler_xyz(vec_t<T,3> const &v);
  138. static mat_t<T,3,3> fromeuler_xzy(vec_t<T,3> const &v);
  139. static mat_t<T,3,3> fromeuler_yxz(vec_t<T,3> const &v);
  140. static mat_t<T,3,3> fromeuler_yzx(vec_t<T,3> const &v);
  141. static mat_t<T,3,3> fromeuler_zxy(vec_t<T,3> const &v);
  142. static mat_t<T,3,3> fromeuler_zyx(vec_t<T,3> const &v);
  143. static mat_t<T,3,3> fromeuler_xyz(T phi, T theta, T psi);
  144. static mat_t<T,3,3> fromeuler_xzy(T phi, T theta, T psi);
  145. static mat_t<T,3,3> fromeuler_yxz(T phi, T theta, T psi);
  146. static mat_t<T,3,3> fromeuler_yzx(T phi, T theta, T psi);
  147. static mat_t<T,3,3> fromeuler_zxy(T phi, T theta, T psi);
  148. static mat_t<T,3,3> fromeuler_zyx(T phi, T theta, T psi);
  149. static mat_t<T,3,3> fromeuler_xyx(vec_t<T,3> const &v);
  150. static mat_t<T,3,3> fromeuler_xzx(vec_t<T,3> const &v);
  151. static mat_t<T,3,3> fromeuler_yxy(vec_t<T,3> const &v);
  152. static mat_t<T,3,3> fromeuler_yzy(vec_t<T,3> const &v);
  153. static mat_t<T,3,3> fromeuler_zxz(vec_t<T,3> const &v);
  154. static mat_t<T,3,3> fromeuler_zyz(vec_t<T,3> const &v);
  155. static mat_t<T,3,3> fromeuler_xyx(T phi, T theta, T psi);
  156. static mat_t<T,3,3> fromeuler_xzx(T phi, T theta, T psi);
  157. static mat_t<T,3,3> fromeuler_yxy(T phi, T theta, T psi);
  158. static mat_t<T,3,3> fromeuler_yzy(T phi, T theta, T psi);
  159. static mat_t<T,3,3> fromeuler_zxz(T phi, T theta, T psi);
  160. static mat_t<T,3,3> fromeuler_zyz(T phi, T theta, T psi);
  161. static inline mat_t<T,3,3> rotate(mat_t<T,3,3> m, T radians, vec_t<T,3> v)
  162. {
  163. return rotate(radians, v) * m;
  164. }
  165. void printf() const;
  166. std::string tostring() const;
  167. static const mat_t<T,3,3> identity;
  168. private:
  169. vec_t<T,3> m_data[3];
  170. };
  171. static_assert(sizeof(imat3) == 36, "sizeof(imat3) == 36");
  172. static_assert(sizeof(f16mat3) == 18, "sizeof(f16mat3) == 18");
  173. static_assert(sizeof(mat3) == 36, "sizeof(mat3) == 36");
  174. static_assert(sizeof(dmat3) == 72, "sizeof(dmat3) == 72");
  175. /*
  176. * 4×4-element matrices
  177. */
  178. template <typename T>
  179. struct lol_attr_nodiscard mat_t<T, 4, 4>
  180. : public linear_ops::base<vec_t<T,4>>
  181. {
  182. static int const count = 4;
  183. typedef T scalar_element;
  184. typedef vec_t<T,4> element;
  185. typedef mat_t<T,4,4> type;
  186. inline mat_t() {}
  187. inline mat_t(vec_t<T,4> v0, vec_t<T,4> v1, vec_t<T,4> v2, vec_t<T,4> v3)
  188. : m_data{ v0, v1, v2, v3 } {}
  189. explicit inline mat_t(T const &val)
  190. : m_data{ vec_t<T,4>(val, (T)0, (T)0, (T)0),
  191. vec_t<T,4>((T)0, val, (T)0, (T)0),
  192. vec_t<T,4>((T)0, (T)0, val, (T)0),
  193. vec_t<T,4>((T)0, (T)0, (T)0, val) } {}
  194. explicit inline mat_t(mat_t<T,2,2> m, T const &val = T(1))
  195. : m_data{ vec_t<T,4>(m[0], (T)0, (T)0),
  196. vec_t<T,4>(m[1], (T)0, (T)0),
  197. vec_t<T,4>((T)0, (T)0, val, (T)0),
  198. vec_t<T,4>((T)0, (T)0, (T)0, val) } {}
  199. explicit inline mat_t(mat_t<T,3,3> m, T const &val = T(1))
  200. : m_data{ vec_t<T,4>(m[0], (T)0),
  201. vec_t<T,4>(m[1], (T)0),
  202. vec_t<T,4>(m[2], (T)0),
  203. vec_t<T,4>((T)0, (T)0, (T)0, val) } {}
  204. /* Explicit constructor for type conversion */
  205. template<typename U>
  206. explicit inline mat_t(mat_t<U,4,4> const &m)
  207. : m_data{ (element)m[0], (element)m[1],
  208. (element)m[2], (element)m[3] } {}
  209. explicit mat_t(quat_t<T> const &q);
  210. inline vec_t<T,4>& operator[](size_t n) { return m_data[n]; }
  211. inline vec_t<T,4> const& operator[](size_t n) const { return m_data[n]; }
  212. /* Helpers for transformation matrices */
  213. static mat_t<T,4,4> translate(T x, T y, T z);
  214. static mat_t<T,4,4> translate(vec_t<T,3> v);
  215. static inline mat_t<T,4,4> scale(T x)
  216. {
  217. return mat_t<T,4,4>(mat_t<T,3,3>::scale(x), (T)1);
  218. }
  219. static inline mat_t<T,4,4> scale(T x, T y, T z)
  220. {
  221. return mat_t<T,4,4>(mat_t<T,3,3>::scale(x, y, z), (T)1);
  222. }
  223. static inline mat_t<T,4,4> scale(vec_t<T,3> v)
  224. {
  225. return mat_t<T,4,4>(mat_t<T,3,3>::scale(v), (T)1);
  226. }
  227. static inline mat_t<T,4,4> translate(mat_t<T,4,4> const &m, vec_t<T,3> v)
  228. {
  229. return translate(v) * m;
  230. }
  231. static inline mat_t<T,4,4> rotate(T radians, T x, T y, T z)
  232. {
  233. return mat_t<T,4,4>(mat_t<T,3,3>::rotate(radians, x, y, z), (T)1);
  234. }
  235. static inline mat_t<T,4,4> rotate(T radians, vec_t<T,3> v)
  236. {
  237. return mat_t<T,4,4>(mat_t<T,3,3>::rotate(radians, v), (T)1);
  238. }
  239. static inline mat_t<T,4,4> rotate(mat_t<T,4,4> &m, T radians, vec_t<T,3> v)
  240. {
  241. return rotate(radians, v) * m;
  242. }
  243. static mat_t<T,4,4> fromeuler_xyz(vec_t<T,3> const &v);
  244. static mat_t<T,4,4> fromeuler_xzy(vec_t<T,3> const &v);
  245. static mat_t<T,4,4> fromeuler_yxz(vec_t<T,3> const &v);
  246. static mat_t<T,4,4> fromeuler_yzx(vec_t<T,3> const &v);
  247. static mat_t<T,4,4> fromeuler_zxy(vec_t<T,3> const &v);
  248. static mat_t<T,4,4> fromeuler_zyx(vec_t<T,3> const &v);
  249. static mat_t<T,4,4> fromeuler_xyz(T phi, T theta, T psi);
  250. static mat_t<T,4,4> fromeuler_xzy(T phi, T theta, T psi);
  251. static mat_t<T,4,4> fromeuler_yxz(T phi, T theta, T psi);
  252. static mat_t<T,4,4> fromeuler_yzx(T phi, T theta, T psi);
  253. static mat_t<T,4,4> fromeuler_zxy(T phi, T theta, T psi);
  254. static mat_t<T,4,4> fromeuler_zyx(T phi, T theta, T psi);
  255. static mat_t<T,4,4> fromeuler_xyx(vec_t<T,3> const &v);
  256. static mat_t<T,4,4> fromeuler_xzx(vec_t<T,3> const &v);
  257. static mat_t<T,4,4> fromeuler_yxy(vec_t<T,3> const &v);
  258. static mat_t<T,4,4> fromeuler_yzy(vec_t<T,3> const &v);
  259. static mat_t<T,4,4> fromeuler_zxz(vec_t<T,3> const &v);
  260. static mat_t<T,4,4> fromeuler_zyz(vec_t<T,3> const &v);
  261. static mat_t<T,4,4> fromeuler_xyx(T phi, T theta, T psi);
  262. static mat_t<T,4,4> fromeuler_xzx(T phi, T theta, T psi);
  263. static mat_t<T,4,4> fromeuler_yxy(T phi, T theta, T psi);
  264. static mat_t<T,4,4> fromeuler_yzy(T phi, T theta, T psi);
  265. static mat_t<T,4,4> fromeuler_zxz(T phi, T theta, T psi);
  266. static mat_t<T,4,4> fromeuler_zyz(T phi, T theta, T psi);
  267. /* Helpers for view matrices */
  268. static mat_t<T,4,4> lookat(vec_t<T,3> eye, vec_t<T,3> center, vec_t<T,3> up);
  269. /* Helpers for projection matrices; FOV values are in radians */
  270. static mat_t<T,4,4> ortho(T left, T right, T bottom, T top, T near, T far);
  271. static mat_t<T,4,4> ortho(T width, T height, T near, T far);
  272. static mat_t<T,4,4> frustum(T left, T right, T bottom, T top, T near, T far);
  273. static mat_t<T,4,4> perspective(T fov_y, T width, T height, T near, T far);
  274. static mat_t<T,4,4> shifted_perspective(T fov_y, T screen_size, T screen_ratio_yx, T near, T far);
  275. void printf() const;
  276. std::string tostring() const;
  277. static const mat_t<T,4,4> identity;
  278. private:
  279. vec_t<T,4> m_data[4];
  280. };
  281. static_assert(sizeof(imat4) == 64, "sizeof(imat4) == 64");
  282. static_assert(sizeof(f16mat4) == 32, "sizeof(f16mat4) == 32");
  283. static_assert(sizeof(mat4) == 64, "sizeof(mat4) == 64");
  284. static_assert(sizeof(dmat4) == 128, "sizeof(dmat4) == 128");
  285. /*
  286. * stdstream method implementations
  287. */
  288. template<class U, int COLS, int ROWS>
  289. static std::ostream &operator<<(std::ostream &stream,
  290. mat_t<U,COLS,ROWS> const &m)
  291. {
  292. for (int y = 0; y < ROWS; ++y)
  293. {
  294. stream << (y == 0 ? "(" : ", ");
  295. for (int x = 0; x < COLS; ++x)
  296. stream << (x == 0 ? "(" : ", ") << m[x][y];
  297. stream << ")";
  298. }
  299. return stream << ")";
  300. }
  301. /*
  302. * Transpose any matrix
  303. */
  304. template<typename T, int COLS, int ROWS>
  305. static inline mat_t<T, ROWS, COLS> transpose(mat_t<T, COLS, ROWS> const &m)
  306. {
  307. mat_t<T, ROWS, COLS> ret;
  308. for (int i = 0; i < COLS; ++i)
  309. for (int j = 0; j < ROWS; ++j)
  310. ret[j][i] = m[i][j];
  311. return ret;
  312. }
  313. /*
  314. * Compute a square submatrix, useful for minors and cofactor matrices
  315. */
  316. template<typename T, int N>
  317. mat_t<T, N - 1, N - 1> submatrix(mat_t<T, N, N> const &m, int i, int j)
  318. {
  319. ASSERT(i >= 0); ASSERT(j >= 0); ASSERT(i < N); ASSERT(j < N);
  320. mat_t<T, N - 1, N - 1> ret;
  321. for (int i2 = 0; i2 < N - 1; ++i2)
  322. for (int j2 = 0; j2 < N - 1; ++j2)
  323. ret[i2][j2] = m[i2 + (i2 >= i)][j2 + (j2 >= j)];
  324. return ret;
  325. }
  326. /*
  327. * Compute square matrix cofactor
  328. */
  329. template<typename T, int N> lol_attr_nodiscard
  330. T cofactor(mat_t<T, N, N> const &m, int i, int j)
  331. {
  332. ASSERT(i >= 0); ASSERT(j >= 0); ASSERT(i < N); ASSERT(j < N);
  333. T tmp = determinant(submatrix(m, i, j));
  334. return ((i + j) & 1) ? -tmp : tmp;
  335. }
  336. template<typename T> lol_attr_nodiscard
  337. T cofactor(mat_t<T, 2, 2> const &m, int i, int j)
  338. {
  339. /* This specialisation shouldn't be needed, but Visual Studio. */
  340. ASSERT(i >= 0); ASSERT(j >= 0); ASSERT(i < 2); ASSERT(j < 2);
  341. T tmp = m[1 - i][1 - j];
  342. return (i ^ j) ? -tmp : tmp;
  343. }
  344. // Lu decomposition with partial pivoting
  345. template<typename T, int N> lol_attr_nodiscard
  346. std::tuple<mat_t<T, N, N>, vec_t<int, N>, int> lu_decomposition(mat_t<T, N, N> const &m)
  347. {
  348. mat_t<T, N, N> lu = m;
  349. vec_t<int, N> perm;
  350. int sign = 1;
  351. for (int i = 0; i < N; ++i)
  352. perm[i] = i;
  353. for (int k = 0; k < N; ++k)
  354. {
  355. // Find row with the largest absolute value
  356. int best_j = k;
  357. for (int j = k + 1; j < N; ++j)
  358. if (abs(lu[k][j]) > lol::abs(lu[k][best_j]))
  359. best_j = j;
  360. // Swap rows in result
  361. if (best_j != k)
  362. {
  363. std::swap(perm[k], perm[best_j]);
  364. sign = -sign;
  365. for (int i = 0; i < N; ++i)
  366. std::swap(lu[i][k], lu[i][best_j]);
  367. }
  368. // Compute the Schur complement in the lower triangular part
  369. for (int j = k + 1; j < N; ++j)
  370. {
  371. lu[k][j] /= lu[k][k];
  372. for (int i = k + 1; i < N; ++i)
  373. lu[i][j] -= lu[i][k] * lu[k][j];
  374. }
  375. }
  376. return std::make_tuple(lu, perm, sign);
  377. }
  378. /*
  379. * Compute square matrix determinant, with a specialisation for 1×1 matrices
  380. */
  381. template<typename T, int N> lol_attr_nodiscard
  382. T determinant(mat_t<T, N, N> const &m)
  383. {
  384. auto lup = lu_decomposition(m);
  385. T det(T(std::get<2>(lup)));
  386. for (int i = 0; i < N; ++i)
  387. det *= std::get<0>(lup)[i][i];
  388. return det;
  389. }
  390. template<typename T> lol_attr_nodiscard
  391. T const & determinant(mat_t<T, 1, 1> const &m)
  392. {
  393. return m[0][0];
  394. }
  395. // Compute inverse of the L matrix of an LU decomposition
  396. template<typename T, int N>
  397. mat_t<T, N, N> l_inverse(mat_t<T, N, N> const & lu)
  398. {
  399. mat_t<T, N, N> ret { 0 };
  400. for (int j = 0; j < N; ++j)
  401. {
  402. for (int i = j; i >= 0; --i)
  403. {
  404. T sum = 0;
  405. for (int k = i + 1; k <= j; ++k)
  406. sum += ret[k][j] * lu[i][k];
  407. ret[i][j] = T(j == i ? 1 : 0) - sum;
  408. }
  409. }
  410. return ret;
  411. }
  412. // Compute inverse of the U matrix of an LU decomposition
  413. template<typename T, int N>
  414. mat_t<T, N, N> u_inverse(mat_t<T, N, N> const & lu)
  415. {
  416. mat_t<T, N, N> ret { 0 };
  417. for (int i = 0; i < N; ++i)
  418. {
  419. for (int j = i; j < N; ++j)
  420. {
  421. T sum = 0;
  422. for (int k = i; k < j; ++k)
  423. sum += ret[k][i] * lu[j][k];
  424. ret[j][i] = ((i == j ? 1 : 0) - sum) / lu[j][j];
  425. }
  426. }
  427. return ret;
  428. }
  429. /*
  430. * Compute square matrix inverse
  431. */
  432. template<typename T, int N>
  433. mat_t<T, N, N> inverse(mat_t<T, N, N> const &m)
  434. {
  435. auto lup = lu_decomposition(m);
  436. auto lu = std::get<0>(lup);
  437. auto p = std::get<1>(lup);
  438. auto invlu = u_inverse(lu) * l_inverse(lu);
  439. // Rearrange columns according to the original permutation vector
  440. mat_t<T, N, N> ret;
  441. for (int i = 0; i < N; ++i)
  442. ret[p[i]] = invlu[i];
  443. return ret;
  444. }
  445. /*
  446. * Matrix-vector and vector-matrix multiplication
  447. */
  448. template<typename T, int COLS, int ROWS, int SWIZZLE>
  449. static inline vec_t<T, ROWS> operator *(mat_t<T, COLS, ROWS> const &m,
  450. vec_t<T, COLS, SWIZZLE> const &v)
  451. {
  452. vec_t<T, ROWS> ret(T(0));
  453. for (int i = 0; i < COLS; ++i)
  454. ret += m[i] * v[i];
  455. return ret;
  456. }
  457. template<typename T, int COLS, int ROWS, int SWIZZLE>
  458. static inline vec_t<T, COLS> operator *(vec_t<T, ROWS, SWIZZLE> const &v,
  459. mat_t<T, COLS, ROWS> const &m)
  460. {
  461. vec_t<T, COLS> ret(T(0));
  462. for (int i = 0; i < COLS; ++i)
  463. ret[i] = dot(v, m[i]);
  464. return ret;
  465. }
  466. /*
  467. * Matrix-matrix multiplication
  468. */
  469. template<typename T, int COLS, int N, int ROWS>
  470. static inline mat_t<T, COLS, ROWS> operator *(mat_t<T, N, ROWS> const &a,
  471. mat_t<T, COLS, N> const &b)
  472. {
  473. mat_t<T, COLS, ROWS> ret;
  474. for (int i = 0; i < COLS; ++i)
  475. ret[i] = a * b[i];
  476. return ret;
  477. }
  478. template<typename T, int N>
  479. static inline mat_t<T, N, N> &operator *=(mat_t<T, N, N> &a,
  480. mat_t<T, N, N> const &b)
  481. {
  482. return a = a * b;
  483. }
  484. /*
  485. * Vector-vector outer product
  486. */
  487. template<typename T, int COLS, int ROWS>
  488. static inline mat_t<T, COLS, ROWS> outer(vec_t<T, ROWS> const &a,
  489. vec_t<T, COLS> const &b)
  490. {
  491. /* Valid cast because mat_t and vec_t have similar layouts */
  492. return *reinterpret_cast<mat_t<T, 1, ROWS> const *>(&a)
  493. * *reinterpret_cast<mat_t<T, COLS, 1> const *>(&b);
  494. }
  495. /*
  496. * Matrix-matrix outer product (Kronecker product)
  497. */
  498. template<typename T, int COLS1, int COLS2, int ROWS1, int ROWS2>
  499. static inline mat_t<T, COLS1 * COLS2, ROWS1 * ROWS2>
  500. outer(mat_t<T, COLS1, ROWS1> const &a, mat_t<T, COLS2, ROWS2> const &b)
  501. {
  502. mat_t<T, COLS1 * COLS2, ROWS1 * ROWS2> ret;
  503. for (int i1 = 0; i1 < COLS1; ++i1)
  504. for (int i2 = 0; i2 < COLS2; ++i2)
  505. {
  506. /* Valid cast because mat_t and vec_t have similar layouts */
  507. *reinterpret_cast<mat_t<T, ROWS1, ROWS2> *>(&ret[i1 * COLS2 + i2])
  508. = outer(b[i2], a[i1]);
  509. }
  510. return ret;
  511. }
  512. /*
  513. * Constants
  514. */
  515. template<typename T>
  516. mat_t<T,2,2> const mat_t<T,2,2>::identity = mat_t<T,2,2>((T)1);
  517. template<typename T>
  518. mat_t<T,3,3> const mat_t<T,3,3>::identity = mat_t<T,3,3>((T)1);
  519. template<typename T>
  520. mat_t<T,4,4> const mat_t<T,4,4>::identity = mat_t<T,4,4>((T)1);
  521. } /* namespace lol */
  522. #if _WIN32
  523. # pragma pop_macro("near")
  524. # pragma pop_macro("far")
  525. #endif