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ů.
 
 
 

369 řádky
9.4 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 complex, quaternion and dual quaternion classes
  13. // ---------------------------------------------------
  14. //
  15. #include <ostream>
  16. namespace lol
  17. {
  18. #if !LOL_FEATURE_CXX11_CONSTEXPR
  19. # define constexpr /* */
  20. #endif
  21. /*
  22. * 2-element transforms: complex numbers
  23. */
  24. template<typename T>
  25. struct cmplx_t : public linear_ops::base<T>
  26. {
  27. static int const count = 2;
  28. typedef T element;
  29. typedef cmplx_t<T> type;
  30. inline constexpr cmplx_t() {}
  31. inline constexpr cmplx_t(T X) : x(X), y(T(0)) {}
  32. inline constexpr cmplx_t(T X, T Y) : x(X), y(Y) {}
  33. template<typename U>
  34. explicit inline constexpr cmplx_t(cmplx_t<U> const &z)
  35. : x(z.x), y(z.y) {}
  36. LOL_COMMON_MEMBER_OPS(x)
  37. inline cmplx_t<T> operator *(cmplx_t<T> const &val) const
  38. {
  39. return cmplx_t<T>(x * val.x - y * val.y, x * val.y + y * val.x);
  40. }
  41. inline cmplx_t<T> operator *=(cmplx_t<T> const &val)
  42. {
  43. return *this = (*this) * val;
  44. }
  45. inline cmplx_t<T> operator ~() const
  46. {
  47. return cmplx_t<T>(x, -y);
  48. }
  49. template<typename U>
  50. friend std::ostream &operator<<(std::ostream &stream, cmplx_t<U> const &v);
  51. T x, y;
  52. };
  53. static_assert(sizeof(f16cmplx) == 4, "sizeof(f16cmplx) == 4");
  54. static_assert(sizeof(cmplx) == 8, "sizeof(cmplx) == 8");
  55. static_assert(sizeof(dcmplx) == 16, "sizeof(dcmplx) == 16");
  56. /*
  57. * 4-element transforms: quaternions
  58. */
  59. template<typename T>
  60. struct quat_t : public linear_ops::base<T>
  61. {
  62. static int const count = 4;
  63. typedef T element;
  64. typedef quat_t<T> type;
  65. /* Default constructor and copy constructor */
  66. inline constexpr quat_t() : w(), x(), y(), z() {}
  67. inline constexpr quat_t(quat_t<T> const &q)
  68. : w(q.w), x(q.x), y(q.y), z(q.z) {}
  69. /* Explicit constructor for type conversion */
  70. template<typename U>
  71. explicit inline constexpr quat_t(quat_t<U> const &q)
  72. : w(q.w), x(q.x), y(q.y), z(q.z) {}
  73. /* Various explicit constructors */
  74. explicit inline constexpr quat_t(T W, T X, T Y, T Z)
  75. : w(W), x(X), y(Y), z(Z) {}
  76. explicit inline constexpr quat_t(T W)
  77. : w(W), x(0), y(0), z(0) {}
  78. explicit quat_t(mat_t<T,3,3> const &m);
  79. explicit quat_t(mat_t<T,4,4> const &m);
  80. LOL_COMMON_MEMBER_OPS(w)
  81. inline quat_t operator *(quat_t const &val) const
  82. {
  83. vec_t<T,3> v1(x, y, z);
  84. vec_t<T,3> v2(val.x, val.y, val.z);
  85. vec_t<T,3> v3 = cross(v1, v2) + w * v2 + val.w * v1;
  86. return quat_t(w * val.w - dot(v1, v2), v3.x, v3.y, v3.z);
  87. }
  88. inline quat_t operator *=(quat_t const &val)
  89. {
  90. return *this = (*this * val);
  91. }
  92. /* Create a unit quaternion representing a rotation around an axis. */
  93. static quat_t rotate(T degrees, T x, T y, T z);
  94. static quat_t rotate(T degrees, vec_t<T,3> const &v);
  95. /* Create a unit quaternion representing a rotation between two vectors.
  96. * Input vectors need not be normalised. */
  97. static quat_t rotate(vec_t<T,3> const &src, vec_t<T,3> const &dst);
  98. /* Convert from Euler angles. The axes in fromeuler_xyx are
  99. * x, then y', then x", ie. the axes are attached to the model.
  100. * If you want to rotate around static axes, just reverse the order
  101. * of the arguments. Angle values are in degrees. */
  102. static quat_t fromeuler_xyx(vec_t<T,3> const &v);
  103. static quat_t fromeuler_xzx(vec_t<T,3> const &v);
  104. static quat_t fromeuler_yxy(vec_t<T,3> const &v);
  105. static quat_t fromeuler_yzy(vec_t<T,3> const &v);
  106. static quat_t fromeuler_zxz(vec_t<T,3> const &v);
  107. static quat_t fromeuler_zyz(vec_t<T,3> const &v);
  108. static quat_t fromeuler_xyx(T phi, T theta, T psi);
  109. static quat_t fromeuler_xzx(T phi, T theta, T psi);
  110. static quat_t fromeuler_yxy(T phi, T theta, T psi);
  111. static quat_t fromeuler_yzy(T phi, T theta, T psi);
  112. static quat_t fromeuler_zxz(T phi, T theta, T psi);
  113. static quat_t fromeuler_zyz(T phi, T theta, T psi);
  114. /* Convert from Tait-Bryan angles (incorrectly called Euler angles,
  115. * but since everyone does it…). The axes in fromeuler_xyz are
  116. * x, then y', then z", ie. the axes are attached to the model.
  117. * If you want to apply yaw around x, pitch around y, and roll
  118. * around z, use fromeuler_xyz. Angle values are in degrees.
  119. * If you want to rotate around static axes, reverse the order in
  120. * the function name (_zyx instead of _xyz) AND reverse the order
  121. * of the arguments. */
  122. static quat_t fromeuler_xyz(vec_t<T,3> const &v);
  123. static quat_t fromeuler_xzy(vec_t<T,3> const &v);
  124. static quat_t fromeuler_yxz(vec_t<T,3> const &v);
  125. static quat_t fromeuler_yzx(vec_t<T,3> const &v);
  126. static quat_t fromeuler_zxy(vec_t<T,3> const &v);
  127. static quat_t fromeuler_zyx(vec_t<T,3> const &v);
  128. static quat_t fromeuler_xyz(T phi, T theta, T psi);
  129. static quat_t fromeuler_xzy(T phi, T theta, T psi);
  130. static quat_t fromeuler_yxz(T phi, T theta, T psi);
  131. static quat_t fromeuler_yzx(T phi, T theta, T psi);
  132. static quat_t fromeuler_zxy(T phi, T theta, T psi);
  133. static quat_t fromeuler_zyx(T phi, T theta, T psi);
  134. inline quat_t operator ~() const
  135. {
  136. return quat_t(w, -x, -y, -z);
  137. }
  138. inline vec_t<T,3> transform(vec_t<T,3> const &v) const
  139. {
  140. quat_t p = quat_t(0, v.x, v.y, v.z);
  141. quat_t q = *this * p / *this;
  142. return vec_t<T,3>(q.x, q.y, q.z);
  143. }
  144. inline vec_t<T,4> transform(vec_t<T,4> const &v) const
  145. {
  146. quat_t p = quat_t(0, v.x, v.y, v.z);
  147. quat_t q = *this * p / *this;
  148. return vec_t<T,4>(q.x, q.y, q.z, v.w);
  149. }
  150. inline vec_t<T,3> operator *(vec_t<T,3> const &v) const
  151. {
  152. return transform(v);
  153. }
  154. inline vec_t<T,4> operator *(vec_t<T,4> const &v) const
  155. {
  156. return transform(v);
  157. }
  158. inline vec_t<T,3> axis()
  159. {
  160. vec_t<T,3> v(x, y, z);
  161. T n2 = sqlength(v);
  162. if (n2 <= (T)1e-6)
  163. return vec_t<T,3>::axis_x;
  164. return normalize(v);
  165. }
  166. inline T angle()
  167. {
  168. vec_t<T,3> v(x, y, z);
  169. T n2 = sqlength(v);
  170. if (n2 <= (T)1e-6)
  171. return (T)0;
  172. return (T)2 * lol::atan2(lol::sqrt(n2), w);
  173. }
  174. template<typename U>
  175. friend std::ostream &operator<<(std::ostream &stream, quat_t<U> const &v);
  176. /* XXX: storage order is wxyz, unlike vectors! */
  177. T w, x, y, z;
  178. };
  179. static_assert(sizeof(f16quat) == 8, "sizeof(f16quat) == 8");
  180. static_assert(sizeof(quat) == 16, "sizeof(quat) == 16");
  181. static_assert(sizeof(dquat) == 32, "sizeof(dquat) == 32");
  182. /*
  183. * Common operations on transforms
  184. */
  185. template<typename T>
  186. static inline T dot(cmplx_t<T> const &t1, cmplx_t<T> const &t2)
  187. {
  188. T ret(0);
  189. for (size_t i = 0; i < sizeof(t1) / sizeof(T); ++i)
  190. ret += t1[i] * t2[i];
  191. return ret;
  192. }
  193. template<typename T>
  194. static inline T sqlength(cmplx_t<T> const &t)
  195. {
  196. return dot(t, t);
  197. }
  198. template<typename T>
  199. static inline T length(cmplx_t<T> const &t)
  200. {
  201. /* FIXME: this is not very nice */
  202. return (T)sqrt((double)sqlength(t));
  203. }
  204. template<typename T>
  205. static inline T norm(cmplx_t<T> const &t)
  206. {
  207. return length(t);
  208. }
  209. template<typename T>
  210. static inline cmplx_t<T> normalize(cmplx_t<T> const &z)
  211. {
  212. T norm = (T)length(z);
  213. return norm ? z / norm : cmplx_t<T>(T(0));
  214. }
  215. /* XXX: duplicate */
  216. template<typename T>
  217. static inline T dot(quat_t<T> const &t1, quat_t<T> const &t2)
  218. {
  219. T ret(0);
  220. for (size_t i = 0; i < sizeof(t1) / sizeof(T); ++i)
  221. ret += t1[i] * t2[i];
  222. return ret;
  223. }
  224. template<typename T>
  225. static inline T sqlength(quat_t<T> const &t)
  226. {
  227. return dot(t, t);
  228. }
  229. template<typename T>
  230. static inline T length(quat_t<T> const &t)
  231. {
  232. /* FIXME: this is not very nice */
  233. return (T)sqrt((double)sqlength(t));
  234. }
  235. template<typename T>
  236. static inline T norm(quat_t<T> const &t)
  237. {
  238. return length(t);
  239. }
  240. template<typename T>
  241. static inline quat_t<T> normalize(quat_t<T> const &z)
  242. {
  243. T norm = (T)length(z);
  244. return norm ? z / norm : quat_t<T>(T(0));
  245. }
  246. /*
  247. * Complex numbers only
  248. */
  249. template<typename T>
  250. static inline cmplx_t<T> re(cmplx_t<T> const &z)
  251. {
  252. return ~z / sqlength(z);
  253. }
  254. template<typename T>
  255. static inline cmplx_t<T> operator /(T a, cmplx_t<T> const &b)
  256. {
  257. return a * re(b);
  258. }
  259. template<typename T>
  260. static inline cmplx_t<T> operator /(cmplx_t<T> a, cmplx_t<T> const &b)
  261. {
  262. return a * re(b);
  263. }
  264. template<typename T>
  265. static inline bool operator ==(cmplx_t<T> const &a, T b)
  266. {
  267. return (a.x == b) && !a.y;
  268. }
  269. template<typename T>
  270. static inline bool operator !=(cmplx_t<T> const &a, T b)
  271. {
  272. return (a.x != b) || a.y;
  273. }
  274. template<typename T>
  275. static inline bool operator ==(T a, cmplx_t<T> const &b) { return b == a; }
  276. template<typename T>
  277. static inline bool operator !=(T a, cmplx_t<T> const &b) { return b != a; }
  278. /*
  279. * Quaternions only
  280. */
  281. template<typename T>
  282. static inline quat_t<T> re(quat_t<T> const &q)
  283. {
  284. return ~q / sqlength(q);
  285. }
  286. template<typename T>
  287. static inline quat_t<T> operator /(T x, quat_t<T> const &y)
  288. {
  289. return x * re(y);
  290. }
  291. template<typename T>
  292. static inline quat_t<T> operator /(quat_t<T> const &x, quat_t<T> const &y)
  293. {
  294. return x * re(y);
  295. }
  296. template<typename T>
  297. extern quat_t<T> slerp(quat_t<T> const &qa, quat_t<T> const &qb, T f);
  298. #if !LOL_FEATURE_CXX11_CONSTEXPR
  299. #undef constexpr
  300. #endif
  301. } /* namespace lol */