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.
 
 
 

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