💿🐜 Antkeeper source code https://antkeeper.com
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.

938 lines
26 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_MATH_MATRIX_FUNCTIONS_HPP
  20. #define ANTKEEPER_MATH_MATRIX_FUNCTIONS_HPP
  21. #include "math/matrix-type.hpp"
  22. #include "math/vector-type.hpp"
  23. #include "math/vector-functions.hpp"
  24. #include <type_traits>
  25. namespace math {
  26. /**
  27. * Adds two matrices.
  28. *
  29. * @param x First matrix.
  30. * @param y Second matrix.
  31. * @return Sum of the two matrices.
  32. */
  33. template <class T>
  34. matrix<T, 2, 2> add(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y);
  35. /// @copydoc add(const matrix<T, 2, 2>&, const matrix<T, 2, 2>&)
  36. template <class T>
  37. matrix<T, 3, 3> add(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y);
  38. /// @copydoc add(const matrix<T, 2, 2>&, const matrix<T, 2, 2>&)
  39. template <class T>
  40. matrix<T, 4, 4> add(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y);
  41. /**
  42. * Reinterprets data as an `NxM` matrix of type `T`.
  43. *
  44. * @tparam N Number of columns.
  45. * @tparam M Number of rows.
  46. * @tparam T Element type.
  47. * @param data Data to reinterpret.
  48. */
  49. template <std::size_t N, std::size_t M, typename T>
  50. matrix<T, N, M>& as_matrix(T& data);
  51. /**
  52. * Calculates the determinant of a matrix.
  53. *
  54. * @param m Matrix of which to take the determinant.
  55. */
  56. template <class T>
  57. T determinant(const matrix<T, 2, 2>& m);
  58. /// @copydoc determinant(const matrix<T, 2, 2>&)
  59. template <class T>
  60. T determinant(const matrix<T, 3, 3>& m);
  61. /// @copydoc determinant(const matrix<T, 2, 2>&)
  62. template <class T>
  63. T determinant(const matrix<T, 4, 4>& m);
  64. /**
  65. * Calculates the inverse of a matrix.
  66. *
  67. * @param m Matrix of which to take the inverse.
  68. */
  69. template <class T>
  70. matrix<T, 2, 2> inverse(const matrix<T, 2, 2>& m);
  71. /// @copydoc inverse(const matrix<T, 2, 2>&)
  72. template <class T>
  73. matrix<T, 3, 3> inverse(const matrix<T, 3, 3>& m);
  74. /// @copydoc inverse(const matrix<T, 2, 2>&)
  75. template <class T>
  76. matrix<T, 4, 4> inverse(const matrix<T, 4, 4>& m);
  77. /**
  78. * Performs a component-wise multiplication of two matrices.
  79. *
  80. * @param x First matrix multiplicand.
  81. * @param y Second matrix multiplicand.
  82. */
  83. template <class T>
  84. matrix<T, 2, 2> componentwise_mul(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y);
  85. /// @copydoc componentwise_mul(const matrix<T, 2, 2>&, const matrix<T, 2, 2>&)
  86. template <class T>
  87. matrix<T, 3, 3> componentwise_mul(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y);
  88. /// @copydoc componentwise_mul(const matrix<T, 2, 2>&, const matrix<T, 2, 2>&)
  89. template <class T>
  90. matrix<T, 4, 4> componentwise_mul(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y);
  91. /**
  92. * Creates a viewing transformation matrix.
  93. *
  94. * @param position Position of the view point.
  95. * @param target Position of the target.
  96. * @param up Normalized direction of the up vector.
  97. * @return Viewing transformation matrix.
  98. */
  99. template <class T>
  100. matrix<T, 4, 4> look_at(const vector<T, 3>& position, const vector<T, 3>& target, vector<T, 3> up);
  101. /**
  102. * Multiplies two matrices.
  103. *
  104. * @param x First matrix.
  105. * @param y Second matrix.
  106. * @return Product of the two matrices.
  107. */
  108. template <class T>
  109. matrix<T, 2, 2> mul(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y);
  110. /// @copydoc mul(const matrix<T, 2, 2>&, const matrix<T, 2, 2>&);
  111. template <class T>
  112. matrix<T, 3, 3> mul(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y);
  113. /// @copydoc mul(const matrix<T, 2, 2>&, const matrix<T, 2, 2>&);
  114. template <class T>
  115. matrix<T, 4, 4> mul(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y);
  116. /**
  117. * Multiplies a matrix by a scalar.
  118. *
  119. * @param m Matrix.
  120. * @param s Scalar.
  121. * @return Product of the matrix and the scalar..
  122. */
  123. template <class T, std::size_t N, std::size_t M>
  124. matrix<T, N, M> mul(const matrix<T, N, M>& m, T s);
  125. /**
  126. * Transforms a vector by a matrix.
  127. *
  128. * @param m Matrix.
  129. * @param v Vector.
  130. * @return Transformed vector.
  131. */
  132. template <class T>
  133. vector<T, 2> mul(const matrix<T, 2, 2>& m, const vector<T, 2>& v);
  134. /// @copydoc mul(const matrix<T, 2, 2>&, const vector<T, 2>&)
  135. template <class T>
  136. vector<T, 3> mul(const matrix<T, 3, 3>& m, const vector<T, 3>& v);
  137. /// @copydoc mul(const matrix<T, 2, 2>&, const vector<T, 2>&)
  138. template <class T>
  139. vector<T, 4> mul(const matrix<T, 4, 4>& m, const vector<T, 4>& v);
  140. /**
  141. * Creates an orthographic projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively.
  142. *
  143. * @param left Signed distance to the left clipping plane.
  144. * @param right Signed distance to the right clipping plane.
  145. * @param bottom Signed distance to the bottom clipping plane.
  146. * @param top Signed distance to the top clipping plane.
  147. * @param z_near Signed distance to the near clipping plane.
  148. * @param z_far Signed distance to the far clipping plane.
  149. * @return Orthographic projection matrix.
  150. */
  151. template <class T>
  152. matrix<T, 4, 4> ortho(T left, T right, T bottom, T top, T z_near, T z_far);
  153. /**
  154. * Creates an orthographic projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively.
  155. *
  156. * @param left Signed distance to the left clipping plane.
  157. * @param right Signed distance to the right clipping plane.
  158. * @param bottom Signed distance to the bottom clipping plane.
  159. * @param top Signed distance to the top clipping plane.
  160. * @param z_near Signed distance to the near clipping plane.
  161. * @param z_far Signed distance to the far clipping plane.
  162. * @return Orthographic projection matrix.
  163. */
  164. template <class T>
  165. matrix<T, 4, 4> ortho_half_z(T left, T right, T bottom, T top, T z_near, T z_far);
  166. /**
  167. * Calculates the outer product of a pair of vectors.
  168. *
  169. * @param c Parameter to be treated as a column vector.
  170. * @param r Parameter to be treated as a row vector.
  171. */
  172. template <class T>
  173. matrix<T, 2, 2> outer_product(const vector<T, 2>& c, const vector<T, 2>& r);
  174. /// @copydoc outer_product(const vector<T, 2>&, const vector<T, 2>&)
  175. template <class T>
  176. matrix<T, 3, 3> outer_product(const vector<T, 3>& c, const vector<T, 3>& r);
  177. /// @copydoc outer_product(const vector<T, 2>&, const vector<T, 2>&)
  178. template <class T>
  179. matrix<T, 4, 4> outer_product(const vector<T, 4>& c, const vector<T, 4> r);
  180. /**
  181. * Creates a perspective projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively.
  182. *
  183. * @param vertical_fov Vertical field of view angle, in radians.
  184. * @param aspect_ratio Aspect ratio which determines the horizontal field of view.
  185. * @param z_near Distance to the near clipping plane.
  186. * @param z_far Distance to the far clipping plane.
  187. * @return Perspective projection matrix.
  188. */
  189. template <class T>
  190. matrix<T, 4, 4> perspective(T vertical_fov, T aspect_ratio, T z_near, T z_far);
  191. /**
  192. * Creates a perspective projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively.
  193. *
  194. * @param vertical_fov Vertical field of view angle, in radians.
  195. * @param aspect_ratio Aspect ratio which determines the horizontal field of view.
  196. * @param z_near Distance to the near clipping plane.
  197. * @param z_far Distance to the far clipping plane.
  198. * @return Perspective projection matrix.
  199. */
  200. template <class T>
  201. matrix<T, 4, 4> perspective_half_z(T vertical_fov, T aspect_ratio, T z_near, T z_far);
  202. /**
  203. * Resizes a matrix. Any new elements will be set to `1` if in the diagonal, and `0` otherwise.
  204. *
  205. * @param m Matrix to resize.
  206. * @return Resized matrix.
  207. */
  208. template <std::size_t N1, std::size_t M1, class T, std::size_t N0, std::size_t M0>
  209. matrix<T, N1, M1> resize(const matrix<T, N0, M0>& m);
  210. /**
  211. * Rotates a matrix.
  212. *
  213. * @param m Matrix to rotate.
  214. * @param angle Angle of rotation (in radians).
  215. * @param axis Axis of rotation
  216. * @return Rotated matrix.
  217. */
  218. template <class T>
  219. matrix<T, 4, 4> rotate(const matrix<T, 4, 4>& m, T angle, const vector<T, 3>& axis);
  220. /**
  221. * Produces a matrix which rotates Cartesian coordinates about the x-axis by a given angle.
  222. *
  223. * @param angle Angle of rotation, in radians.
  224. * @return Rotation matrix.
  225. */
  226. template <class T>
  227. matrix3<T> rotate_x(T angle);
  228. /**
  229. * Produces a matrix which rotates Cartesian coordinates about the y-axis by a given angle.
  230. *
  231. * @param angle Angle of rotation, in radians.
  232. * @return Rotation matrix.
  233. */
  234. template <class T>
  235. matrix3<T> rotate_y(T angle);
  236. /**
  237. * Produces a matrix which rotates Cartesian coordinates about the z-axis by a given angle.
  238. *
  239. * @param angle Angle of rotation, in radians.
  240. * @return Rotation matrix.
  241. */
  242. template <class T>
  243. matrix3<T> rotate_z(T angle);
  244. /**
  245. * Scales a matrix.
  246. *
  247. * @param m Matrix to scale.
  248. * @param v Scale vector.
  249. * @return Scaled matrix.
  250. */
  251. template <class T>
  252. matrix<T, 4, 4> scale(const matrix<T, 4, 4>& m, const vector<T, 3>& v);
  253. /**
  254. * Subtracts a matrix from another matrix.
  255. *
  256. * @param x First matrix.
  257. * @param y Second matrix.
  258. * @return Difference between the two matrices.
  259. */
  260. template <class T>
  261. matrix<T, 2, 2> sub(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y);
  262. /// @copydoc sub(const matrix<T, 2, 2>&, const matrix<T, 2, 2>&)
  263. template <class T>
  264. matrix<T, 3, 3> sub(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y);
  265. /// @copydoc sub(const matrix<T, 2, 2>&, const matrix<T, 2, 2>&)
  266. template <class T>
  267. matrix<T, 4, 4> sub(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y);
  268. /**
  269. * Translates a matrix.
  270. *
  271. * @param m Matrix to translate.
  272. * @param v Translation vector.
  273. * @return Translated matrix.
  274. */
  275. template <class T>
  276. matrix<T, 4, 4> translate(const matrix<T, 4, 4>& m, const vector<T, 3>& v);
  277. /**
  278. * Calculates the transpose of a matrix.
  279. *
  280. * @param m Matrix of which to take the transpose.
  281. */
  282. template <class T>
  283. matrix<T, 2, 2> transpose(const matrix<T, 2, 2>& m);
  284. /// @copydoc transpose(const matrix<T, 2, 2>&)
  285. template <class T>
  286. matrix<T, 3, 3> transpose(const matrix<T, 3, 3>& m);
  287. /// @copydoc transpose(const matrix<T, 2, 2>&)
  288. template <class T>
  289. matrix<T, 4, 4> transpose(const matrix<T, 4, 4>& m);
  290. /**
  291. * Types casts each matrix element and returns a matrix of the casted type.
  292. *
  293. * @tparam T2 Target matrix element type.
  294. * @tparam T1 Source matrix element type.
  295. * @tparam N Number of columns.
  296. * @tparam M Number of rows.
  297. * @param m Matrix to type cast.
  298. * @return Type-casted matrix.
  299. */
  300. template <class T2, class T1, std::size_t N, std::size_t M>
  301. matrix<T2, N, M> type_cast(const matrix<T1, N, M>& m);
  302. template <class T>
  303. matrix<T, 2, 2> add(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y)
  304. {
  305. return
  306. {{
  307. x[0] + y[0],
  308. x[1] + y[1]
  309. }};
  310. }
  311. template <class T>
  312. matrix<T, 3, 3> add(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y)
  313. {
  314. return
  315. {{
  316. x[0] + y[0],
  317. x[1] + y[1],
  318. x[2] + y[2]
  319. }};
  320. }
  321. template <class T>
  322. matrix<T, 4, 4> add(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y)
  323. {
  324. return
  325. {{
  326. x[0] + y[0],
  327. x[1] + y[1],
  328. x[2] + y[2],
  329. x[3] + y[3]
  330. }};
  331. }
  332. template <std::size_t N, std::size_t M, typename T>
  333. inline matrix<T, N, M>& as_matrix(T& data)
  334. {
  335. static_assert(std::is_pod<matrix<T, N, M>>::value);
  336. return reinterpret_cast<matrix<T, N, M>&>(data);
  337. }
  338. template <class T>
  339. T determinant(const matrix<T, 2, 2>& m)
  340. {
  341. return m[0][0] * m[1][1] - m[0][1] * m[1][0];
  342. }
  343. template <class T>
  344. T determinant(const matrix<T, 3, 3>& m)
  345. {
  346. return m[0][0] * m [1][1] * m[2][2] +
  347. m[0][1] * m[1][2] * m[2][0] +
  348. m[0][2] * m[1][0] * m[2][1] -
  349. m[0][0] * m[1][2] * m[2][1] -
  350. m[0][1] * m[1][0] * m[2][2] -
  351. m[0][2] * m[1][1] * m[2][0];
  352. }
  353. template <class T>
  354. T determinant(const matrix<T, 4, 4>& m)
  355. {
  356. return m[0][3] * m[1][2] * m[2][1] * m[3][0] - m[0][2] * m[1][3] * m[2][1] * m[3][0] -
  357. m[0][3] * m[1][1] * m[2][2] * m[3][0] + m[0][1] * m[1][3] * m[2][2] * m[3][0] +
  358. m[0][2] * m[1][1] * m[2][3] * m[3][0] - m[0][1] * m[1][2] * m[2][3] * m[3][0] -
  359. m[0][3] * m[1][2] * m[2][0] * m[3][1] + m[0][2] * m[1][3] * m[2][0] * m[3][1] +
  360. m[0][3] * m[1][0] * m[2][2] * m[3][1] - m[0][0] * m[1][3] * m[2][2] * m[3][1] -
  361. m[0][2] * m[1][0] * m[2][3] * m[3][1] + m[0][0] * m[1][2] * m[2][3] * m[3][1] +
  362. m[0][3] * m[1][1] * m[2][0] * m[3][2] - m[0][1] * m[1][3] * m[2][0] * m[3][2] -
  363. m[0][3] * m[1][0] * m[2][1] * m[3][2] + m[0][0] * m[1][3] * m[2][1] * m[3][2] +
  364. m[0][1] * m[1][0] * m[2][3] * m[3][2] - m[0][0] * m[1][1] * m[2][3] * m[3][2] -
  365. m[0][2] * m[1][1] * m[2][0] * m[3][3] + m[0][1] * m[1][2] * m[2][0] * m[3][3] +
  366. m[0][2] * m[1][0] * m[2][1] * m[3][3] - m[0][0] * m[1][2] * m[2][1] * m[3][3] -
  367. m[0][1] * m[1][0] * m[2][2] * m[3][3] + m[0][0] * m[1][1] * m[2][2] * m[3][3];
  368. }
  369. template <class T>
  370. matrix<T, 2, 2> inverse(const matrix<T, 2, 2>& m)
  371. {
  372. static_assert(std::is_floating_point<T>::value);
  373. const T rd(T(1) / determinant(m));
  374. return
  375. {{
  376. { m[1][1] * rd, -m[0][1] * rd},
  377. {-m[1][0] * rd, m[0][0] * rd}
  378. }};
  379. }
  380. template <class T>
  381. matrix<T, 3, 3> inverse(const matrix<T, 3, 3>& m)
  382. {
  383. static_assert(std::is_floating_point<T>::value);
  384. const T rd(T(1) / determinant(m));
  385. return
  386. {{
  387. {
  388. (m[1][1] * m[2][2] - m[1][2] * m[2][1]) * rd,
  389. (m[0][2] * m[2][1] - m[0][1] * m[2][2]) * rd,
  390. (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * rd
  391. },
  392. {
  393. (m[1][2] * m[2][0] - m[1][0] * m[2][2]) * rd,
  394. (m[0][0] * m[2][2] - m[0][2] * m[2][0]) * rd,
  395. (m[0][2] * m[1][0] - m[0][0] * m[1][2]) * rd
  396. },
  397. {
  398. (m[1][0] * m[2][1] - m[1][1] * m[2][0]) * rd,
  399. (m[0][1] * m[2][0] - m[0][0] * m[2][1]) * rd,
  400. (m[0][0] * m[1][1] - m[0][1] * m[1][0]) * rd
  401. }
  402. }};
  403. }
  404. template <class T>
  405. matrix<T, 4, 4> inverse(const matrix<T, 4, 4>& m)
  406. {
  407. static_assert(std::is_floating_point<T>::value);
  408. const T rd(T(1) / determinant(m));
  409. return
  410. {{
  411. {
  412. (m[1][2] * m[2][3] * m[3][1] - m[1][3] * m[2][2] * m[3][1] + m[1][3] * m[2][1] * m[3][2] - m[1][1] * m[2][3] * m[3][2] - m[1][2] * m[2][1] * m[3][3] + m[1][1] * m[2][2] * m[3][3]) * rd,
  413. (m[0][3] * m[2][2] * m[3][1] - m[0][2] * m[2][3] * m[3][1] - m[0][3] * m[2][1] * m[3][2] + m[0][1] * m[2][3] * m[3][2] + m[0][2] * m[2][1] * m[3][3] - m[0][1] * m[2][2] * m[3][3]) * rd,
  414. (m[0][2] * m[1][3] * m[3][1] - m[0][3] * m[1][2] * m[3][1] + m[0][3] * m[1][1] * m[3][2] - m[0][1] * m[1][3] * m[3][2] - m[0][2] * m[1][1] * m[3][3] + m[0][1] * m[1][2] * m[3][3]) * rd,
  415. (m[0][3] * m[1][2] * m[2][1] - m[0][2] * m[1][3] * m[2][1] - m[0][3] * m[1][1] * m[2][2] + m[0][1] * m[1][3] * m[2][2] + m[0][2] * m[1][1] * m[2][3] - m[0][1] * m[1][2] * m[2][3]) * rd
  416. },
  417. {
  418. (m[1][3] * m[2][2] * m[3][0] - m[1][2] * m[2][3] * m[3][0] - m[1][3] * m[2][0] * m[3][2] + m[1][0] * m[2][3] * m[3][2] + m[1][2] * m[2][0] * m[3][3] - m[1][0] * m[2][2] * m[3][3]) * rd,
  419. (m[0][2] * m[2][3] * m[3][0] - m[0][3] * m[2][2] * m[3][0] + m[0][3] * m[2][0] * m[3][2] - m[0][0] * m[2][3] * m[3][2] - m[0][2] * m[2][0] * m[3][3] + m[0][0] * m[2][2] * m[3][3]) * rd,
  420. (m[0][3] * m[1][2] * m[3][0] - m[0][2] * m[1][3] * m[3][0] - m[0][3] * m[1][0] * m[3][2] + m[0][0] * m[1][3] * m[3][2] + m[0][2] * m[1][0] * m[3][3] - m[0][0] * m[1][2] * m[3][3]) * rd,
  421. (m[0][2] * m[1][3] * m[2][0] - m[0][3] * m[1][2] * m[2][0] + m[0][3] * m[1][0] * m[2][2] - m[0][0] * m[1][3] * m[2][2] - m[0][2] * m[1][0] * m[2][3] + m[0][0] * m[1][2] * m[2][3]) * rd
  422. },
  423. {
  424. (m[1][1] * m[2][3] * m[3][0] - m[1][3] * m[2][1] * m[3][0] + m[1][3] * m[2][0] * m[3][1] - m[1][0] * m[2][3] * m[3][1] - m[1][1] * m[2][0] * m[3][3] + m[1][0] * m[2][1] * m[3][3]) * rd,
  425. (m[0][3] * m[2][1] * m[3][0] - m[0][1] * m[2][3] * m[3][0] - m[0][3] * m[2][0] * m[3][1] + m[0][0] * m[2][3] * m[3][1] + m[0][1] * m[2][0] * m[3][3] - m[0][0] * m[2][1] * m[3][3]) * rd,
  426. (m[0][1] * m[1][3] * m[3][0] - m[0][3] * m[1][1] * m[3][0] + m[0][3] * m[1][0] * m[3][1] - m[0][0] * m[1][3] * m[3][1] - m[0][1] * m[1][0] * m[3][3] + m[0][0] * m[1][1] * m[3][3]) * rd,
  427. (m[0][3] * m[1][1] * m[2][0] - m[0][1] * m[1][3] * m[2][0] - m[0][3] * m[1][0] * m[2][1] + m[0][0] * m[1][3] * m[2][1] + m[0][1] * m[1][0] * m[2][3] - m[0][0] * m[1][1] * m[2][3]) * rd
  428. },
  429. {
  430. (m[1][2] * m[2][1] * m[3][0] - m[1][1] * m[2][2] * m[3][0] - m[1][2] * m[2][0] * m[3][1] + m[1][0] * m[2][2] * m[3][1] + m[1][1] * m[2][0] * m[3][2] - m[1][0] * m[2][1] * m[3][2]) * rd,
  431. (m[0][1] * m[2][2] * m[3][0] - m[0][2] * m[2][1] * m[3][0] + m[0][2] * m[2][0] * m[3][1] - m[0][0] * m[2][2] * m[3][1] - m[0][1] * m[2][0] * m[3][2] + m[0][0] * m[2][1] * m[3][2]) * rd,
  432. (m[0][2] * m[1][1] * m[3][0] - m[0][1] * m[1][2] * m[3][0] - m[0][2] * m[1][0] * m[3][1] + m[0][0] * m[1][2] * m[3][1] + m[0][1] * m[1][0] * m[3][2] - m[0][0] * m[1][1] * m[3][2]) * rd,
  433. (m[0][1] * m[1][2] * m[2][0] - m[0][2] * m[1][1] * m[2][0] + m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] - m[0][1] * m[1][0] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) * rd
  434. }
  435. }};
  436. }
  437. template <class T>
  438. matrix<T, 2, 2> componentwise_mul(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y)
  439. {
  440. return
  441. {{
  442. {x[0][0] * y[0][0], x[0][1] * y[0][1]},
  443. {x[1][0] * y[1][0], x[1][1] * y[1][1]}
  444. }};
  445. }
  446. template <class T>
  447. matrix<T, 3, 3> componentwise_mul(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y)
  448. {
  449. return
  450. {{
  451. {x[0][0] * y[0][0], x[0][1] * y[0][1], x[0][2] * y[0][2]},
  452. {x[1][0] * y[1][0], x[1][1] * y[1][1], x[1][2] * y[1][2]},
  453. {x[2][0] * y[2][0], x[2][1] * y[2][1], x[2][2] * y[2][2]}
  454. }};
  455. }
  456. template <class T>
  457. matrix<T, 4, 4> componentwise_mul(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y)
  458. {
  459. return
  460. {{
  461. {x[0][0] * y[0][0], x[0][1] * y[0][1], x[0][2] * y[0][2], x[0][3] * y[0][3]},
  462. {x[1][0] * y[1][0], x[1][1] * y[1][1], x[1][2] * y[1][2], x[1][3] * y[1][3]},
  463. {x[2][0] * y[2][0], x[2][1] * y[2][1], x[2][2] * y[2][2], x[2][3] * y[2][3]},
  464. {x[3][0] * y[3][0], x[3][1] * y[3][1], x[3][2] * y[3][2], x[3][3] * y[3][3]}
  465. }};
  466. }
  467. template <class T>
  468. matrix<T, 4, 4> look_at(const vector<T, 3>& position, const vector<T, 3>& target, vector<T, 3> up)
  469. {
  470. vector<T, 3> forward = normalize(sub(target, position));
  471. vector<T, 3> right = normalize(cross(forward, up));
  472. up = cross(right, forward);
  473. matrix<T, 4, 4> m =
  474. {{
  475. {right[0], up[0], -forward[0], T(0)},
  476. {right[1], up[1], -forward[1], T(0)},
  477. {right[2], up[2], -forward[2], T(0)},
  478. {T(0), T(0), T(0), T(1)}
  479. }};
  480. return translate(m, negate(position));
  481. }
  482. template <class T>
  483. matrix<T, 2, 2> mul(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y)
  484. {
  485. return
  486. {{
  487. x[0] * y[0][0] + x[1] * y[0][1],
  488. x[0] * y[1][0] + x[1] * y[1][1]
  489. }};
  490. }
  491. template <class T>
  492. matrix<T, 3, 3> mul(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y)
  493. {
  494. return
  495. {{
  496. x[0] * y[0][0] + x[1] * y[0][1] + x[2] * y[0][2],
  497. x[0] * y[1][0] + x[1] * y[1][1] + x[2] * y[1][2],
  498. x[0] * y[2][0] + x[1] * y[2][1] + x[2] * y[2][2]
  499. }};
  500. }
  501. template <class T>
  502. matrix<T, 4, 4> mul(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y)
  503. {
  504. return
  505. {{
  506. x[0] * y[0][0] + x[1] * y[0][1] + x[2] * y[0][2] + x[3] * y[0][3],
  507. x[0] * y[1][0] + x[1] * y[1][1] + x[2] * y[1][2] + x[3] * y[1][3],
  508. x[0] * y[2][0] + x[1] * y[2][1] + x[2] * y[2][2] + x[3] * y[2][3],
  509. x[0] * y[3][0] + x[1] * y[3][1] + x[2] * y[3][2] + x[3] * y[3][3]
  510. }};
  511. }
  512. /// @private
  513. template <class T, std::size_t N, std::size_t M, std::size_t... I>
  514. inline matrix<T, N, M> mul(const matrix<T, N, M>& m, T s, std::index_sequence<I...>)
  515. {
  516. return {{(m[I] * s)...}};
  517. }
  518. template <class T, std::size_t N, std::size_t M>
  519. inline matrix<T, N, M> mul(const matrix<T, N, M>& m, T s)
  520. {
  521. return mul(m, s, std::make_index_sequence<N>{});
  522. }
  523. template <class T>
  524. vector<T, 2> mul(const matrix<T, 2, 2>& m, const vector<T, 2>& v)
  525. {
  526. return
  527. {
  528. m[0][0] * v[0] + m[1][0] * v[1],
  529. m[0][1] * v[0] + m[1][1] * v[1]
  530. };
  531. }
  532. template <class T>
  533. vector<T, 3> mul(const matrix<T, 3, 3>& m, const vector<T, 3>& v)
  534. {
  535. return
  536. {
  537. m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2],
  538. m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2],
  539. m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2]
  540. };
  541. }
  542. template <class T>
  543. vector<T, 4> mul(const matrix<T, 4, 4>& m, const vector<T, 4>& v)
  544. {
  545. return
  546. {
  547. m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0] * v[3],
  548. m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1] * v[3],
  549. m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2] * v[3],
  550. m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3] * v[3]
  551. };
  552. }
  553. template <class T>
  554. matrix<T, 4, 4> ortho(T left, T right, T bottom, T top, T z_near, T z_far)
  555. {
  556. return
  557. {{
  558. {T(2) / (right - left), T(0), T(0), T(0)},
  559. {T(0), T(2) / (top - bottom), T(0), T(0)},
  560. {T(0), T(0), T(-2) / (z_far - z_near), T(0)},
  561. {-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -((z_far + z_near) / (z_far - z_near)), T(1)}
  562. }};
  563. }
  564. template <class T>
  565. matrix<T, 4, 4> ortho_half_z(T left, T right, T bottom, T top, T z_near, T z_far)
  566. {
  567. return
  568. {{
  569. {T(2) / (right - left), T(0), T(0), T(0)},
  570. {T(0), T(2) / (top - bottom), T(0), T(0)},
  571. {T(0), T(0), T(-1) / (z_far - z_near), T(0)},
  572. {-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -z_near / (z_far - z_near), T(1)}
  573. }};
  574. }
  575. template <class T>
  576. matrix<T, 2, 2> outer_product(const vector<T, 2>& c, const vector<T, 2>& r)
  577. {
  578. return
  579. {{
  580. {c[0] * r[0], c[1] * r[0]},
  581. {c[0] * r[1], c[1] * r[1]}
  582. }};
  583. }
  584. template <class T>
  585. matrix<T, 3, 3> outer_product(const vector<T, 3>& c, const vector<T, 3>& r)
  586. {
  587. return
  588. {{
  589. {c[0] * r[0], c[1] * r[0], c[2] * r[0]},
  590. {c[0] * r[1], c[1] * r[1], c[2] * r[1]},
  591. {c[0] * r[2], c[1] * r[2], c[2] * r[2]}
  592. }};
  593. }
  594. template <class T>
  595. matrix<T, 4, 4> outer_product(const vector<T, 4>& c, const vector<T, 4> r)
  596. {
  597. return
  598. {{
  599. {c[0] * r[0], c[1] * r[0], c[2] * r[0], c[3] * r[0]},
  600. {c[0] * r[1], c[1] * r[1], c[2] * r[1], c[3] * r[1]},
  601. {c[0] * r[2], c[1] * r[2], c[2] * r[2], c[3] * r[2]},
  602. {c[0] * r[3], c[1] * r[3], c[2] * r[3], c[3] * r[3]}
  603. }};
  604. }
  605. template <class T>
  606. matrix<T, 4, 4> perspective(T vertical_fov, T aspect_ratio, T z_near, T z_far)
  607. {
  608. T half_fov = vertical_fov * T(0.5);
  609. T f = std::cos(half_fov) / std::sin(half_fov);
  610. return
  611. {{
  612. {f / aspect_ratio, T(0), T(0), T(0)},
  613. {T(0), f, T(0), T(0)},
  614. {T(0), T(0), (z_far + z_near) / (z_near - z_far), T(-1)},
  615. {T(0), T(0), (T(2) * z_far * z_near) / (z_near - z_far), T(0)}
  616. }};
  617. }
  618. template <class T>
  619. matrix<T, 4, 4> perspective_half_z(T vertical_fov, T aspect_ratio, T z_near, T z_far)
  620. {
  621. T half_fov = vertical_fov * T(0.5);
  622. T f = std::cos(half_fov) / std::sin(half_fov);
  623. return
  624. {{
  625. {f / aspect_ratio, T(0), T(0), T(0)},
  626. {T(0), f, T(0), T(0)},
  627. {T(0), T(0), z_far / (z_near - z_far), T(-1)},
  628. {T(0), T(0), -(z_far * z_near) / (z_far - z_near), T(0)}
  629. }};
  630. }
  631. template <std::size_t N1, std::size_t M1, class T, std::size_t N0, std::size_t M0>
  632. matrix<T, N1, M1> resize(const matrix<T, N0, M0>& m)
  633. {
  634. matrix<T, N1, M1> resized;
  635. for (std::size_t i = 0; i < N1; ++i)
  636. {
  637. for (std::size_t j = 0; j < M1; ++j)
  638. {
  639. resized[i][j] = (i < N0 && j < M0) ? m[i][j] : ((i == j) ? T(1) : T(0));
  640. }
  641. }
  642. return resized;
  643. }
  644. template <class T>
  645. matrix<T, 4, 4> rotate(const matrix<T, 4, 4>& m, T angle, const vector<T, 3>& axis)
  646. {
  647. const T c = std::cos(angle);
  648. const T s = std::sin(angle);
  649. const vector<T, 3> temp = mul(axis, T(1) - c);
  650. matrix<T, 4, 4> rotation;
  651. rotation[0][0] = axis[0] * temp[0] + c
  652. rotation[0][1] = axis[1] * temp[0] + axis[2] * s;
  653. rotation[0][2] = axis[2] * temp[0] - axis[1] * s;
  654. rotation[0][3] = T(0);
  655. rotation[1][0] = axis[0] * temp[1] - axis[2] * s
  656. rotation[1][1] = axis[1] * temp[1] + c;
  657. rotation[1][2] = axis[2] * temp[1] + axis[0] * s;
  658. rotation[1][3] = T(0);
  659. rotation[2][0] = axis[0] * temp[2] + axis[1] * s;
  660. rotation[2][1] = axis[1] * temp[2] - axis[0] * s;
  661. rotation[2][2] = axis[2] * temp[2] + c
  662. rotation[2][3] = T(0);
  663. rotation[3][0] = T(0);
  664. rotation[3][1] = T(0);
  665. rotation[3][2] = T(0);
  666. rotation[3][3] = T(1);
  667. return mul(m, rotation);
  668. }
  669. template <class T>
  670. matrix3<T> rotate_x(T angle)
  671. {
  672. const T c = std::cos(angle);
  673. const T s = std::sin(angle);
  674. return matrix3<T>
  675. {
  676. T(1), T(0), T(0),
  677. T(0), c, s,
  678. T(0), -s, c
  679. };
  680. }
  681. template <class T>
  682. matrix3<T> rotate_y(T angle)
  683. {
  684. const T c = std::cos(angle);
  685. const T s = std::sin(angle);
  686. return matrix3<T>
  687. {
  688. c, T(0), -s,
  689. T(0), T(1), T(0),
  690. s, T(0), c
  691. };
  692. }
  693. template <class T>
  694. matrix3<T> rotate_z(T angle)
  695. {
  696. const T c = std::cos(angle);
  697. const T s = std::sin(angle);
  698. return matrix3<T>
  699. {
  700. c, s, T(0),
  701. -s, c, T(0),
  702. T(0), T(0), T(1)
  703. };
  704. }
  705. template <class T>
  706. matrix<T, 4, 4> scale(const matrix<T, 4, 4>& m, const vector<T, 3>& v)
  707. {
  708. return mul(m, matrix<T, 4, 4>
  709. {{
  710. {v[0], T(0), T(0), T(0)},
  711. {T(0), v[1], T(0), T(0)},
  712. {T(0), T(0), v[2], T(0)},
  713. {T(0), T(0), T(0), T(1)}
  714. }});
  715. }
  716. template <class T>
  717. matrix<T, 2, 2> sub(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y)
  718. {
  719. return
  720. {{
  721. x[0] - y[0],
  722. x[1] - y[1]
  723. }};
  724. }
  725. template <class T>
  726. matrix<T, 3, 3> sub(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y)
  727. {
  728. return
  729. {{
  730. x[0] - y[0],
  731. x[1] - y[1],
  732. x[2] - y[2]
  733. }};
  734. }
  735. template <class T>
  736. matrix<T, 4, 4> sub(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y)
  737. {
  738. return
  739. {{
  740. x[0] - y[0],
  741. x[1] - y[1],
  742. x[2] - y[2],
  743. x[3] - y[3]
  744. }};
  745. }
  746. template <class T>
  747. matrix<T, 4, 4> translate(const matrix<T, 4, 4>& m, const vector<T, 3>& v)
  748. {
  749. return mul(m, matrix<T, 4, 4>
  750. {{
  751. {T(1), T(0), T(0), T(0)},
  752. {T(0), T(1), T(0), T(0)},
  753. {T(0), T(0), T(1), T(0)},
  754. {v[0], v[1], v[2], T(1)}
  755. }});
  756. }
  757. template <class T>
  758. matrix<T, 2, 2> transpose(const matrix<T, 2, 2>& m)
  759. {
  760. return
  761. {{
  762. {
  763. m[0][0], m[1][0]
  764. },
  765. {
  766. m[0][1], m[1][1]
  767. }
  768. }};
  769. }
  770. template <class T>
  771. matrix<T, 3, 3> transpose(const matrix<T, 3, 3>& m)
  772. {
  773. return
  774. {{
  775. {
  776. m[0][0], m[1][0], m[2][0]
  777. },
  778. {
  779. m[0][1], m[1][1], m[2][1]
  780. },
  781. {
  782. m[0][2], m[1][2], m[2][2]
  783. }
  784. }};
  785. }
  786. template <class T>
  787. matrix<T, 4, 4> transpose(const matrix<T, 4, 4>& m)
  788. {
  789. return
  790. {{
  791. {
  792. m[0][0], m[1][0], m[2][0], m[3][0]
  793. },
  794. {
  795. m[0][1], m[1][1], m[2][1], m[3][1]
  796. },
  797. {
  798. m[0][2], m[1][2], m[2][2], m[3][2]
  799. },
  800. {
  801. m[0][3], m[1][3], m[2][3], m[3][3]
  802. }
  803. }};
  804. }
  805. /// @private
  806. template <class T2, class T1, std::size_t N, std::size_t M, std::size_t... I>
  807. inline matrix<T2, N, M> type_cast(const matrix<T1, N, M>& m, std::index_sequence<I...>)
  808. {
  809. return {type_cast<T2>(m[I])...};
  810. }
  811. template <class T2, class T1, std::size_t N, std::size_t M>
  812. matrix<T2, N, M> type_cast(const matrix<T1, N, M>& m)
  813. {
  814. return type_cast<T2>(m, std::make_index_sequence<N>{});
  815. }
  816. } // namespace math
  817. #endif // ANTKEEPER_MATH_MATRIX_FUNCTIONS_HPP