VectorN.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /*
  2. * Copyright (c) 2020, Stephan Unverwerth <s.unverwerth@serenityos.org>
  3. * Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl>
  4. * Copyright (c) 2022, the SerenityOS developers.
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #pragma once
  9. #include <AK/Array.h>
  10. #include <AK/ByteString.h>
  11. #include <AK/Error.h>
  12. #include <AK/Math.h>
  13. #include <AK/StdLibExtras.h>
  14. #include <AK/StringView.h>
  15. #define LOOP_UNROLL_N 4
  16. #define STRINGIFY_HELPER(x) #x
  17. #define STRINGIFY(x) STRINGIFY_HELPER(x)
  18. #if defined(AK_COMPILER_CLANG)
  19. # define UNROLL_LOOP _Pragma(STRINGIFY(unroll))
  20. #else
  21. # define UNROLL_LOOP _Pragma(STRINGIFY(GCC unroll(LOOP_UNROLL_N)))
  22. #endif
  23. namespace Gfx {
  24. template<size_t N, typename T>
  25. requires(N >= 2 && N <= 4) class VectorN final {
  26. static_assert(LOOP_UNROLL_N >= N, "Unroll the entire loop for performance.");
  27. public:
  28. [[nodiscard]] constexpr VectorN() = default;
  29. [[nodiscard]] constexpr VectorN(T x, T y)
  30. requires(N == 2)
  31. : m_data { x, y }
  32. {
  33. }
  34. [[nodiscard]] constexpr VectorN(T x, T y, T z)
  35. requires(N == 3)
  36. : m_data { x, y, z }
  37. {
  38. }
  39. [[nodiscard]] constexpr VectorN(T x, T y, T z, T w)
  40. requires(N == 4)
  41. : m_data { x, y, z, w }
  42. {
  43. }
  44. [[nodiscard]] constexpr T x() const { return m_data[0]; }
  45. [[nodiscard]] constexpr T y() const { return m_data[1]; }
  46. [[nodiscard]] constexpr T z() const
  47. requires(N >= 3)
  48. {
  49. return m_data[2];
  50. }
  51. [[nodiscard]] constexpr T w() const
  52. requires(N >= 4)
  53. {
  54. return m_data[3];
  55. }
  56. constexpr void set_x(T value) { m_data[0] = value; }
  57. constexpr void set_y(T value) { m_data[1] = value; }
  58. constexpr void set_z(T value)
  59. requires(N >= 3)
  60. {
  61. m_data[2] = value;
  62. }
  63. constexpr void set_w(T value)
  64. requires(N >= 4)
  65. {
  66. m_data[3] = value;
  67. }
  68. [[nodiscard]] constexpr T const& operator[](size_t index) const
  69. {
  70. VERIFY(index < N);
  71. return m_data[index];
  72. }
  73. [[nodiscard]] constexpr T& operator[](size_t index)
  74. {
  75. VERIFY(index < N);
  76. return m_data[index];
  77. }
  78. constexpr VectorN& operator+=(VectorN const& other)
  79. {
  80. UNROLL_LOOP
  81. for (auto i = 0u; i < N; ++i)
  82. m_data[i] += other.data()[i];
  83. return *this;
  84. }
  85. constexpr VectorN& operator-=(VectorN const& other)
  86. {
  87. UNROLL_LOOP
  88. for (auto i = 0u; i < N; ++i)
  89. m_data[i] -= other.data()[i];
  90. return *this;
  91. }
  92. constexpr VectorN& operator*=(T const& t)
  93. {
  94. UNROLL_LOOP
  95. for (auto i = 0u; i < N; ++i)
  96. m_data[i] *= t;
  97. return *this;
  98. }
  99. [[nodiscard]] constexpr VectorN operator+(VectorN const& other) const
  100. {
  101. VectorN result;
  102. UNROLL_LOOP
  103. for (auto i = 0u; i < N; ++i)
  104. result.m_data[i] = m_data[i] + other.data()[i];
  105. return result;
  106. }
  107. [[nodiscard]] constexpr VectorN operator-(VectorN const& other) const
  108. {
  109. VectorN result;
  110. UNROLL_LOOP
  111. for (auto i = 0u; i < N; ++i)
  112. result.m_data[i] = m_data[i] - other.data()[i];
  113. return result;
  114. }
  115. [[nodiscard]] constexpr VectorN operator*(VectorN const& other) const
  116. {
  117. VectorN result;
  118. UNROLL_LOOP
  119. for (auto i = 0u; i < N; ++i)
  120. result.m_data[i] = m_data[i] * other.data()[i];
  121. return result;
  122. }
  123. [[nodiscard]] constexpr VectorN operator-() const
  124. {
  125. VectorN result;
  126. UNROLL_LOOP
  127. for (auto i = 0u; i < N; ++i)
  128. result.m_data[i] = -m_data[i];
  129. return result;
  130. }
  131. [[nodiscard]] constexpr VectorN operator/(VectorN const& other) const
  132. {
  133. VectorN result;
  134. UNROLL_LOOP
  135. for (auto i = 0u; i < N; ++i)
  136. result.m_data[i] = m_data[i] / other.data()[i];
  137. return result;
  138. }
  139. template<typename U>
  140. [[nodiscard]] constexpr VectorN operator+(U f) const
  141. {
  142. VectorN result;
  143. UNROLL_LOOP
  144. for (auto i = 0u; i < N; ++i)
  145. result.m_data[i] = m_data[i] + f;
  146. return result;
  147. }
  148. template<typename U>
  149. [[nodiscard]] constexpr VectorN operator-(U f) const
  150. {
  151. VectorN result;
  152. UNROLL_LOOP
  153. for (auto i = 0u; i < N; ++i)
  154. result.m_data[i] = m_data[i] - f;
  155. return result;
  156. }
  157. template<typename U>
  158. [[nodiscard]] constexpr VectorN operator*(U f) const
  159. {
  160. VectorN result;
  161. UNROLL_LOOP
  162. for (auto i = 0u; i < N; ++i)
  163. result.m_data[i] = m_data[i] * f;
  164. return result;
  165. }
  166. template<typename U>
  167. [[nodiscard]] constexpr VectorN operator/(U f) const
  168. {
  169. VectorN result;
  170. UNROLL_LOOP
  171. for (auto i = 0u; i < N; ++i)
  172. result.m_data[i] = m_data[i] / f;
  173. return result;
  174. }
  175. [[nodiscard]] constexpr T dot(VectorN const& other) const
  176. {
  177. T result {};
  178. UNROLL_LOOP
  179. for (auto i = 0u; i < N; ++i)
  180. result += m_data[i] * other.data()[i];
  181. return result;
  182. }
  183. [[nodiscard]] constexpr VectorN cross(VectorN const& other) const
  184. requires(N == 3)
  185. {
  186. return VectorN(
  187. y() * other.z() - z() * other.y(),
  188. z() * other.x() - x() * other.z(),
  189. x() * other.y() - y() * other.x());
  190. }
  191. [[nodiscard]] constexpr VectorN normalized() const
  192. {
  193. VectorN copy { *this };
  194. copy.normalize();
  195. return copy;
  196. }
  197. [[nodiscard]] constexpr VectorN clamped(T m, T x) const
  198. {
  199. VectorN copy { *this };
  200. copy.clamp(m, x);
  201. return copy;
  202. }
  203. constexpr void clamp(T min_value, T max_value)
  204. {
  205. UNROLL_LOOP
  206. for (auto i = 0u; i < N; ++i) {
  207. m_data[i] = max(min_value, m_data[i]);
  208. m_data[i] = min(max_value, m_data[i]);
  209. }
  210. }
  211. constexpr void normalize()
  212. {
  213. T const inv_length = 1 / length();
  214. operator*=(inv_length);
  215. }
  216. template<typename O = T>
  217. [[nodiscard]] constexpr O length() const
  218. {
  219. return AK::sqrt<O>(dot(*this));
  220. }
  221. [[nodiscard]] constexpr VectorN<2, T> xy() const
  222. requires(N >= 3)
  223. {
  224. return VectorN<2, T>(x(), y());
  225. }
  226. [[nodiscard]] constexpr VectorN<3, T> xyz() const
  227. requires(N >= 4)
  228. {
  229. return VectorN<3, T>(x(), y(), z());
  230. }
  231. [[nodiscard]] ByteString to_byte_string() const
  232. {
  233. if constexpr (N == 2)
  234. return ByteString::formatted("[{},{}]", x(), y());
  235. else if constexpr (N == 3)
  236. return ByteString::formatted("[{},{},{}]", x(), y(), z());
  237. else
  238. return ByteString::formatted("[{},{},{},{}]", x(), y(), z(), w());
  239. }
  240. template<typename U>
  241. [[nodiscard]] VectorN<N, U> to_type() const
  242. {
  243. VectorN<N, U> result;
  244. UNROLL_LOOP
  245. for (auto i = 0u; i < N; ++i)
  246. result.data()[i] = static_cast<U>(m_data[i]);
  247. return result;
  248. }
  249. template<typename U>
  250. [[nodiscard]] VectorN<N, U> to_rounded() const
  251. {
  252. VectorN<N, U> result;
  253. UNROLL_LOOP
  254. for (auto i = 0u; i < N; ++i)
  255. result.data()[i] = round_to<U>(m_data[i]);
  256. return result;
  257. }
  258. constexpr auto& data() { return m_data; }
  259. constexpr auto const& data() const { return m_data; }
  260. private:
  261. Array<T, N> m_data;
  262. };
  263. }
  264. namespace AK {
  265. template<size_t N, typename T>
  266. constexpr Gfx::VectorN<N, T> min(Gfx::VectorN<N, T> const& a, Gfx::VectorN<N, T> const& b)
  267. {
  268. Gfx::VectorN<N, T> result;
  269. UNROLL_LOOP
  270. for (auto i = 0u; i < N; ++i)
  271. result[i] = min(a[i], b[i]);
  272. return result;
  273. }
  274. template<size_t N, typename T>
  275. constexpr Gfx::VectorN<N, T> max(Gfx::VectorN<N, T> const& a, Gfx::VectorN<N, T> const& b)
  276. {
  277. Gfx::VectorN<N, T> result;
  278. UNROLL_LOOP
  279. for (auto i = 0u; i < N; ++i)
  280. result[i] = max(a[i], b[i]);
  281. return result;
  282. }
  283. }