You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

661 lines
19 KiB

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