VectorN.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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. template<ConvertibleTo<T> U>
  176. constexpr bool operator==(VectorN<N, U> const& other) const
  177. {
  178. UNROLL_LOOP
  179. for (auto i = 0u; i < N; ++i) {
  180. if (m_data[i] != static_cast<T>(other.m_data[i]))
  181. return false;
  182. }
  183. return true;
  184. }
  185. [[nodiscard]] constexpr T dot(VectorN const& other) const
  186. {
  187. T result {};
  188. UNROLL_LOOP
  189. for (auto i = 0u; i < N; ++i)
  190. result += m_data[i] * other.data()[i];
  191. return result;
  192. }
  193. [[nodiscard]] constexpr VectorN cross(VectorN const& other) const
  194. requires(N == 3)
  195. {
  196. return VectorN(
  197. y() * other.z() - z() * other.y(),
  198. z() * other.x() - x() * other.z(),
  199. x() * other.y() - y() * other.x());
  200. }
  201. [[nodiscard]] constexpr VectorN normalized() const
  202. {
  203. VectorN copy { *this };
  204. copy.normalize();
  205. return copy;
  206. }
  207. [[nodiscard]] constexpr VectorN clamped(T m, T x) const
  208. {
  209. VectorN copy { *this };
  210. copy.clamp(m, x);
  211. return copy;
  212. }
  213. constexpr void clamp(T min_value, T max_value)
  214. {
  215. UNROLL_LOOP
  216. for (auto i = 0u; i < N; ++i) {
  217. m_data[i] = max(min_value, m_data[i]);
  218. m_data[i] = min(max_value, m_data[i]);
  219. }
  220. }
  221. constexpr void normalize()
  222. {
  223. T const inv_length = 1 / length();
  224. operator*=(inv_length);
  225. }
  226. template<typename O = T>
  227. [[nodiscard]] constexpr O length() const
  228. {
  229. return AK::sqrt<O>(dot(*this));
  230. }
  231. [[nodiscard]] constexpr VectorN<2, T> xy() const
  232. requires(N >= 3)
  233. {
  234. return VectorN<2, T>(x(), y());
  235. }
  236. [[nodiscard]] constexpr VectorN<3, T> xyz() const
  237. requires(N >= 4)
  238. {
  239. return VectorN<3, T>(x(), y(), z());
  240. }
  241. [[nodiscard]] ByteString to_byte_string() const
  242. {
  243. if constexpr (N == 2)
  244. return ByteString::formatted("[{},{}]", x(), y());
  245. else if constexpr (N == 3)
  246. return ByteString::formatted("[{},{},{}]", x(), y(), z());
  247. else
  248. return ByteString::formatted("[{},{},{},{}]", x(), y(), z(), w());
  249. }
  250. template<typename U>
  251. [[nodiscard]] VectorN<N, U> to_type() const
  252. {
  253. VectorN<N, U> result;
  254. UNROLL_LOOP
  255. for (auto i = 0u; i < N; ++i)
  256. result.data()[i] = static_cast<U>(m_data[i]);
  257. return result;
  258. }
  259. template<typename U>
  260. [[nodiscard]] VectorN<N, U> to_rounded() const
  261. {
  262. VectorN<N, U> result;
  263. UNROLL_LOOP
  264. for (auto i = 0u; i < N; ++i)
  265. result.data()[i] = round_to<U>(m_data[i]);
  266. return result;
  267. }
  268. constexpr auto& data() { return m_data; }
  269. constexpr auto const& data() const { return m_data; }
  270. private:
  271. Array<T, N> m_data;
  272. };
  273. }
  274. namespace AK {
  275. template<size_t N, typename T>
  276. constexpr Gfx::VectorN<N, T> min(Gfx::VectorN<N, T> const& a, Gfx::VectorN<N, T> const& b)
  277. {
  278. Gfx::VectorN<N, T> result;
  279. UNROLL_LOOP
  280. for (auto i = 0u; i < N; ++i)
  281. result[i] = min(a[i], b[i]);
  282. return result;
  283. }
  284. template<size_t N, typename T>
  285. constexpr Gfx::VectorN<N, T> max(Gfx::VectorN<N, T> const& a, Gfx::VectorN<N, T> const& b)
  286. {
  287. Gfx::VectorN<N, T> result;
  288. UNROLL_LOOP
  289. for (auto i = 0u; i < N; ++i)
  290. result[i] = max(a[i], b[i]);
  291. return result;
  292. }
  293. }