Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 

284 řádky
7.0 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010—2020 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. #include <cassert>
  14. #include <cmath> // std::tan
  15. #include <algorithm> // std::max
  16. namespace lol
  17. {
  18. template<>
  19. inline std::string mat2::tostring() const
  20. {
  21. mat2 const &p = *this;
  22. return format("[ %6.6f %6.6f\n", p[0][0], p[1][0]) +
  23. format(" %6.6f %6.6f ]\n", p[0][1], p[1][1]);
  24. }
  25. template<>
  26. inline std::string mat3::tostring() const
  27. {
  28. mat3 const &p = *this;
  29. return format("[ %6.6f %6.6f %6.6f\n", p[0][0], p[1][0], p[2][0]) +
  30. format(" %6.6f %6.6f %6.6f\n", p[0][1], p[1][1], p[2][1]) +
  31. format(" %6.6f %6.6f %6.6f ]\n", p[0][2], p[1][2], p[2][2]);
  32. }
  33. template<>
  34. inline std::string mat4::tostring() const
  35. {
  36. mat4 const &p = *this;
  37. return format("[ %6.6f %6.6f %6.6f %6.6f\n",
  38. p[0][0], p[1][0], p[2][0], p[3][0]) +
  39. format(" %6.6f %6.6f %6.6f %6.6f\n",
  40. p[0][1], p[1][1], p[2][1], p[3][1]) +
  41. format(" %6.6f %6.6f %6.6f %6.6f\n",
  42. p[0][2], p[1][2], p[2][2], p[3][2]) +
  43. format(" %6.6f %6.6f %6.6f %6.6f ]\n",
  44. p[0][3], p[1][3], p[2][3], p[3][3]);
  45. }
  46. template<typename T>
  47. mat_t<T,3,3> mat_t<T,3,3>::scale(T x, T y, T z)
  48. {
  49. mat_t<T,3,3> ret(T(1));
  50. ret[0][0] = x;
  51. ret[1][1] = y;
  52. ret[2][2] = z;
  53. return ret;
  54. }
  55. template<typename T>
  56. mat_t<T,3,3> mat_t<T,3,3>::scale(T x)
  57. {
  58. return scale(x, x, x);
  59. }
  60. template<typename T>
  61. mat_t<T,3,3> mat_t<T,3,3>::scale(vec_t<T,3> v)
  62. {
  63. return scale(v.x, v.y, v.z);
  64. }
  65. template<typename T>
  66. mat_t<T,4,4> mat_t<T,4,4>::translate(T x, T y, T z)
  67. {
  68. mat_t<T,4,4> ret(T(1));
  69. ret[3][0] = x;
  70. ret[3][1] = y;
  71. ret[3][2] = z;
  72. return ret;
  73. }
  74. template<typename T>
  75. mat_t<T,4,4> mat_t<T,4,4>::translate(vec_t<T,3> v)
  76. {
  77. return translate(v.x, v.y, v.z);
  78. }
  79. template<typename T>
  80. mat_t<T,2,2> mat_t<T,2,2>::rotate(T radians)
  81. {
  82. T st = sin(radians);
  83. T ct = cos(radians);
  84. mat_t<T,2,2> ret;
  85. ret[0][0] = ct;
  86. ret[0][1] = st;
  87. ret[1][0] = -st;
  88. ret[1][1] = ct;
  89. return ret;
  90. }
  91. template<typename T>
  92. mat_t<T,3,3> mat_t<T,3,3>::rotate(T radians, T x, T y, T z)
  93. {
  94. T st = sin(radians);
  95. T ct = cos(radians);
  96. T len = std::sqrt(x * x + y * y + z * z);
  97. T invlen = len ? T(1) / len : T(0);
  98. x *= invlen;
  99. y *= invlen;
  100. z *= invlen;
  101. T mtx = (T(1) - ct) * x;
  102. T mty = (T(1) - ct) * y;
  103. T mtz = (T(1) - ct) * z;
  104. mat_t<T,3,3> ret;
  105. ret[0][0] = x * mtx + ct;
  106. ret[0][1] = x * mty + st * z;
  107. ret[0][2] = x * mtz - st * y;
  108. ret[1][0] = y * mtx - st * z;
  109. ret[1][1] = y * mty + ct;
  110. ret[1][2] = y * mtz + st * x;
  111. ret[2][0] = z * mtx + st * y;
  112. ret[2][1] = z * mty - st * x;
  113. ret[2][2] = z * mtz + ct;
  114. return ret;
  115. }
  116. template<typename T>
  117. mat_t<T,3,3> mat_t<T,3,3>::rotate(T radians, vec_t<T,3> v)
  118. {
  119. return rotate(radians, v.x, v.y, v.z);
  120. }
  121. template<typename T>
  122. mat_t<T,3,3>::mat_t(quat_t<T> const &q)
  123. {
  124. T n = norm(q);
  125. if (!n)
  126. {
  127. for (int j = 0; j < 3; j++)
  128. for (int i = 0; i < 3; i++)
  129. (*this)[i][j] = (i == j) ? T(1) : T(0);
  130. return;
  131. }
  132. T s = T(2) / n;
  133. (*this)[0][0] = T(1) - s * (q.y * q.y + q.z * q.z);
  134. (*this)[0][1] = s * (q.x * q.y + q.z * q.w);
  135. (*this)[0][2] = s * (q.x * q.z - q.y * q.w);
  136. (*this)[1][0] = s * (q.x * q.y - q.z * q.w);
  137. (*this)[1][1] = T(1) - s * (q.z * q.z + q.x * q.x);
  138. (*this)[1][2] = s * (q.y * q.z + q.x * q.w);
  139. (*this)[2][0] = s * (q.x * q.z + q.y * q.w);
  140. (*this)[2][1] = s * (q.y * q.z - q.x * q.w);
  141. (*this)[2][2] = T(1) - s * (q.x * q.x + q.y * q.y);
  142. }
  143. template<typename T>
  144. mat_t<T,4,4>::mat_t(quat_t<T> const &q)
  145. {
  146. *this = mat_t<T,4,4>(mat_t<T,3,3>(q), T(1));
  147. }
  148. // These are only specialised for float type, but could be extended
  149. // to anything else. I’m just not sure it’s worth it.
  150. template<>
  151. inline mat4 mat4::lookat(vec3 eye, vec3 center, vec3 up)
  152. {
  153. vec3 v3 = normalize(eye - center);
  154. vec3 v1 = normalize(cross(up, v3));
  155. vec3 v2 = cross(v3, v1);
  156. return mat4(vec4(v1.x, v2.x, v3.x, 0.f),
  157. vec4(v1.y, v2.y, v3.y, 0.f),
  158. vec4(v1.z, v2.z, v3.z, 0.f),
  159. vec4(-dot(eye, v1), -dot(eye, v2), -dot(eye, v3), 1.f));
  160. }
  161. template<>
  162. inline mat4 mat4::ortho(float left, float right, float bottom,
  163. float top, float near, float far)
  164. {
  165. float invrl = (right != left) ? 1.0f / (right - left) : 0.0f;
  166. float invtb = (top != bottom) ? 1.0f / (top - bottom) : 0.0f;
  167. float invfn = (far != near) ? 1.0f / (far - near) : 0.0f;
  168. mat4 ret(0.0f);
  169. ret[0][0] = 2.0f * invrl;
  170. ret[1][1] = 2.0f * invtb;
  171. ret[2][2] = -2.0f * invfn;
  172. ret[3][0] = - (right + left) * invrl;
  173. ret[3][1] = - (top + bottom) * invtb;
  174. ret[3][2] = - (far + near) * invfn;
  175. ret[3][3] = 1.0f;
  176. return ret;
  177. }
  178. template<>
  179. inline mat4 mat4::ortho(float width, float height,
  180. float near, float far)
  181. {
  182. return mat4::ortho(-0.5f * width, 0.5f * width,
  183. -0.5f * height, 0.5f * height, near, far);
  184. }
  185. template<>
  186. inline mat4 mat4::frustum(float left, float right, float bottom,
  187. float top, float near, float far)
  188. {
  189. float invrl = (right != left) ? 1.0f / (right - left) : 0.0f;
  190. float invtb = (top != bottom) ? 1.0f / (top - bottom) : 0.0f;
  191. float invfn = (far != near) ? 1.0f / (far - near) : 0.0f;
  192. mat4 ret(0.0f);
  193. ret[0][0] = 2.0f * near * invrl;
  194. ret[1][1] = 2.0f * near * invtb;
  195. ret[2][0] = (right + left) * invrl;
  196. ret[2][1] = (top + bottom) * invtb;
  197. ret[2][2] = - (far + near) * invfn;
  198. ret[2][3] = -1.0f;
  199. ret[3][2] = -2.0f * far * near * invfn;
  200. return ret;
  201. }
  202. /*
  203. * Return a standard perspective matrix
  204. */
  205. template<>
  206. inline mat4 mat4::perspective(float fov_y, float width,
  207. float height, float near, float far)
  208. {
  209. using std::tan;
  210. float t2 = tan(fov_y * 0.5f);
  211. float t1 = t2 * width / height;
  212. return frustum(-near * t1, near * t1, -near * t2, near * t2, near, far);
  213. }
  214. /*
  215. * Return a perspective matrix with the camera location shifted to be on
  216. * the near plane
  217. */
  218. template<>
  219. inline mat4 mat4::shifted_perspective(float fov_y, float screen_size,
  220. float screen_ratio_yx,
  221. float near, float far)
  222. {
  223. using std::tan;
  224. float tan_y = tan(fov_y * .5f);
  225. assert(tan_y > 0.000001f);
  226. float dist_scr = (screen_size * screen_ratio_yx * .5f) / tan_y;
  227. return mat4::perspective(fov_y, screen_size, screen_size * screen_ratio_yx,
  228. std::max(.001f, dist_scr + near),
  229. std::max(.001f, dist_scr + far)) *
  230. mat4::translate(.0f, .0f, -dist_scr);
  231. }
  232. } // namespace lol