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.

369 lines
9.8 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. //
  14. // Operations for vector classes
  15. // —————————————————————————————
  16. //
  17. #include <ostream>
  18. #include <type_traits>
  19. // HACK: if this is declared int const, Visual Studio becomes unable
  20. // to perform template argument deduction.
  21. // FIXME: should we get rid of this #define?
  22. #define FULL_SWIZZLE (-1)
  23. namespace lol
  24. {
  25. template<typename T, int N, int SWIZZLE = FULL_SWIZZLE> struct vec_t;
  26. /*
  27. * Utility namespaces for traits -- this file uses a combination of
  28. * ADL black magic and enable_if to ensure that only the expected type
  29. * conversions are done.
  30. *
  31. * vec_t (swizzle) needs swizzle_ops
  32. * vec_t (generic) needs linear_ops + componentwise_ops
  33. * vec_t (specialisation) needs swizzle_ops + linear_ops + componentwise_ops
  34. * mat_t (all) needs linear_ops
  35. * cmplx_t quat_t need linear_ops
  36. *
  37. * We can only inherit from one class, because Visual Studio will not
  38. * perform EBCO (empty base class optimisation) when there is multiple
  39. * inheritance.
  40. */
  41. namespace linear_ops
  42. {
  43. template<typename T>
  44. struct base {};
  45. }
  46. namespace componentwise_ops
  47. {
  48. template<typename T>
  49. struct base : public linear_ops::base<T> {};
  50. }
  51. namespace swizzle_ops
  52. {
  53. template<typename T, int SWIZZLE = FULL_SWIZZLE>
  54. struct base {};
  55. template<typename T>
  56. struct base<T, FULL_SWIZZLE> : public componentwise_ops::base<T> {};
  57. }
  58. /*
  59. * Operators for swizzled vectors. Since template deduction cannot be
  60. * done for two arbitrary vec_t<> values, we help the compiler understand
  61. * the expected type.
  62. */
  63. namespace swizzle_ops
  64. {
  65. template<typename T, int N, int SWIZZLE1, int SWIZZLE2> [[nodiscard]]
  66. static inline typename std::enable_if<SWIZZLE1 != FULL_SWIZZLE || SWIZZLE2 != FULL_SWIZZLE, bool>::type
  67. operator ==(vec_t<T,N,SWIZZLE1> const &a, vec_t<T,N,SWIZZLE2> const &b)
  68. {
  69. return vec_t<T,N>(a) == vec_t<T,N>(b);
  70. }
  71. template<typename T, int N, int SWIZZLE1, int SWIZZLE2> [[nodiscard]]
  72. static inline typename std::enable_if<SWIZZLE1 != FULL_SWIZZLE || SWIZZLE2 != FULL_SWIZZLE, bool>::type
  73. operator !=(vec_t<T,N,SWIZZLE1> const &a, vec_t<T,N,SWIZZLE2> const &b)
  74. {
  75. return vec_t<T,N>(a) != vec_t<T,N>(b);
  76. }
  77. #define LOL_SWIZZLE_V_VV_OP(op) \
  78. template<typename T, int N, int SWIZZLE1, int SWIZZLE2> \
  79. inline typename std::enable_if<SWIZZLE1 != FULL_SWIZZLE \
  80. || SWIZZLE2 != FULL_SWIZZLE,vec_t<T,N>>::type \
  81. operator op(vec_t<T,N,SWIZZLE1> const &a, \
  82. vec_t<T,N,SWIZZLE2> const &b) \
  83. { \
  84. return vec_t<T,N>(a) op vec_t<T,N>(b); \
  85. } \
  86. \
  87. template<typename T, int N, int SWIZZLE> \
  88. inline typename std::enable_if<SWIZZLE != FULL_SWIZZLE,vec_t<T,N>>::type & \
  89. operator op##=(vec_t<T,N> &a, \
  90. vec_t<T,N,SWIZZLE> const &b) \
  91. { \
  92. return a op##= vec_t<T,N>(b); \
  93. } \
  94. \
  95. template<typename T, int N, int SWIZZLE> \
  96. inline typename std::enable_if<SWIZZLE != FULL_SWIZZLE,vec_t<T,N>>::type \
  97. operator op(vec_t<T,N,SWIZZLE> const &a, T const &b) \
  98. { \
  99. return vec_t<T,N>(a) op b; \
  100. }
  101. LOL_SWIZZLE_V_VV_OP(+)
  102. LOL_SWIZZLE_V_VV_OP(-)
  103. LOL_SWIZZLE_V_VV_OP(*)
  104. LOL_SWIZZLE_V_VV_OP(/)
  105. #undef LOL_SWIZZLE_V_VV_OP
  106. } /* namespace swizzle_ops */
  107. /*
  108. * Linear operations: operators and functions that work on all types
  109. * (vectors, matrices, quaternions...) such as addition or equality test.
  110. *
  111. * Others, e.g. multiplication, cannot be implemented here, since it should
  112. * be implemented as per-component multiplication for vectors, and matrix
  113. * product for matrices.
  114. */
  115. namespace linear_ops
  116. {
  117. /*
  118. * Comparisons
  119. */
  120. template<typename V> [[nodiscard]]
  121. static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type
  122. operator ==(V const &a, V const &b)
  123. {
  124. for (int i = 0; i < V::count; ++i)
  125. if (!(a[i] == b[i]))
  126. return false;
  127. return true;
  128. }
  129. template<typename V> [[nodiscard]]
  130. static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type
  131. operator !=(V const &a, V const &b)
  132. {
  133. for (int i = 0; i < V::count; ++i)
  134. if (a[i] != b[i])
  135. return true;
  136. return false;
  137. }
  138. /*
  139. * Unary plus and minus
  140. */
  141. template<typename V>
  142. static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
  143. operator +(V const &v)
  144. {
  145. return v;
  146. }
  147. template<typename V>
  148. static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
  149. operator -(V const &v)
  150. {
  151. typename V::type ret;
  152. for (int i = 0; i < V::count; ++i)
  153. ret[i] = -v[i];
  154. return ret;
  155. }
  156. /*
  157. * Addition and subtraction
  158. */
  159. template<typename V>
  160. static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
  161. operator +(V const &a, V const &b)
  162. {
  163. typename V::type ret;
  164. for (int i = 0; i < V::count; ++i)
  165. ret[i] = a[i] + b[i];
  166. return ret;
  167. }
  168. template<typename V>
  169. static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
  170. &operator +=(V &a, V const &b)
  171. {
  172. return a = a + b;
  173. }
  174. template<typename V>
  175. static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
  176. operator -(V const &a, V const &b)
  177. {
  178. typename V::type ret;
  179. for (int i = 0; i < V::count; ++i)
  180. ret[i] = a[i] - b[i];
  181. return ret;
  182. }
  183. template<typename V>
  184. static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
  185. &operator -=(V &a, V const &b)
  186. {
  187. return a = a - b;
  188. }
  189. /*
  190. * Multiplication by scalar (left)
  191. */
  192. template<typename V>
  193. static inline typename std::enable_if<std::is_base_of<base<typename V::scalar_element>, V>::value, typename V::type>::type
  194. operator *(typename V::scalar_element const &val, V const &a)
  195. {
  196. typename V::type ret;
  197. for (int i = 0; i < V::count; ++i)
  198. ret[i] = val * a[i];
  199. return ret;
  200. }
  201. /*
  202. * Multiplication/division by scalar (right)
  203. */
  204. template<typename V>
  205. static inline typename std::enable_if<std::is_base_of<base<typename V::scalar_element>, V>::value, typename V::type>::type
  206. operator *(V const &a, typename V::scalar_element const &val)
  207. {
  208. typename V::type ret;
  209. for (int i = 0; i < V::count; ++i)
  210. ret[i] = a[i] * val;
  211. return ret;
  212. }
  213. template<typename V>
  214. static inline typename std::enable_if<std::is_base_of<base<typename V::scalar_element>, V>::value, typename V::type>::type &
  215. operator *=(V &a, typename V::scalar_element const &val)
  216. {
  217. return a = a * val;
  218. }
  219. template<typename V>
  220. static inline typename std::enable_if<std::is_base_of<base<typename V::scalar_element>, V>::value, typename V::type>::type
  221. operator /(V const &a, typename V::scalar_element const &val)
  222. {
  223. typename V::type ret;
  224. for (int i = 0; i < V::count; ++i)
  225. ret[i] = a[i] / val;
  226. return ret;
  227. }
  228. template<typename V>
  229. static inline typename std::enable_if<std::is_base_of<base<typename V::scalar_element>, V>::value, typename V::type>::type &
  230. operator /=(V &a, typename V::scalar_element const &val)
  231. {
  232. return a = a / val;
  233. }
  234. } /* namespace linear_ops */
  235. /*
  236. * Operations that work component-wise, such as comparisons or multiplication.
  237. * This is only for vector types, as the other types (matrices, quaternions,
  238. * complexes) have different meanings.
  239. */
  240. namespace componentwise_ops
  241. {
  242. template<typename V>
  243. static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
  244. operator *(V const &a, V const &b)
  245. {
  246. typename V::type ret;
  247. for (int i = 0; i < V::count; ++i)
  248. ret[i] = a[i] * b[i];
  249. return ret;
  250. }
  251. template<typename V>
  252. static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
  253. &operator *=(V &a, V const &b)
  254. {
  255. return a = a * b;
  256. }
  257. template<typename V>
  258. static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
  259. operator /(V const &a, V const &b)
  260. {
  261. typename V::type ret;
  262. for (int i = 0; i < V::count; ++i)
  263. ret[i] = a[i] / b[i];
  264. return ret;
  265. }
  266. template<typename V>
  267. static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
  268. &operator /=(V &a, V const &b)
  269. {
  270. return a = a / b;
  271. }
  272. /*
  273. * Comparisons
  274. */
  275. template<typename V>
  276. static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type
  277. operator <(V const &a, V const &b)
  278. {
  279. for (int i = 0; i < V::count; ++i)
  280. if (!(a[i] < b[i]))
  281. return false;
  282. return true;
  283. }
  284. template<typename V>
  285. static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type
  286. operator >(V const &a, V const &b)
  287. {
  288. for (int i = 0; i < V::count; ++i)
  289. if (!(a[i] > b[i]))
  290. return false;
  291. return true;
  292. }
  293. template<typename V>
  294. static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type
  295. operator <=(V const &a, V const &b)
  296. {
  297. for (int i = 0; i < V::count; ++i)
  298. if (!(a[i] <= b[i]))
  299. return false;
  300. return true;
  301. }
  302. template<typename V>
  303. static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type
  304. operator >=(V const &a, V const &b)
  305. {
  306. for (int i = 0; i < V::count; ++i)
  307. if (!(a[i] >= b[i]))
  308. return false;
  309. return true;
  310. }
  311. } /* namespace componentwise_ops */
  312. } /* namespace lol */