VectorN.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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/Error.h>
  11. #include <AK/Format.h>
  12. #include <AK/Math.h>
  13. #include <AK/StdLibExtras.h>
  14. #include <AK/String.h>
  15. #include <AK/StringView.h>
  16. #define LOOP_UNROLL_N 4
  17. #define STRINGIFY_HELPER(x) #x
  18. #define STRINGIFY(x) STRINGIFY_HELPER(x)
  19. #ifdef __clang__
  20. # define UNROLL_LOOP _Pragma(STRINGIFY(unroll))
  21. #else
  22. # define UNROLL_LOOP _Pragma(STRINGIFY(GCC unroll(LOOP_UNROLL_N)))
  23. #endif
  24. namespace Gfx {
  25. template<size_t N, typename T>
  26. requires(N >= 2 && N <= 4) class VectorN final {
  27. static_assert(LOOP_UNROLL_N >= N, "Unroll the entire loop for performance.");
  28. public:
  29. [[nodiscard]] constexpr VectorN() = default;
  30. [[nodiscard]] constexpr VectorN(T x, T y) requires(N == 2)
  31. : m_data { x, y }
  32. {
  33. }
  34. [[nodiscard]] constexpr VectorN(T x, T y, T z) requires(N == 3)
  35. : m_data { x, y, z }
  36. {
  37. }
  38. [[nodiscard]] constexpr VectorN(T x, T y, T z, T w) requires(N == 4)
  39. : m_data { x, y, z, w }
  40. {
  41. }
  42. [[nodiscard]] constexpr T x() const { return m_data[0]; }
  43. [[nodiscard]] constexpr T y() const { return m_data[1]; }
  44. [[nodiscard]] constexpr T z() const requires(N >= 3) { return m_data[2]; }
  45. [[nodiscard]] constexpr T w() const requires(N >= 4) { return m_data[3]; }
  46. constexpr void set_x(T value) { m_data[0] = value; }
  47. constexpr void set_y(T value) { m_data[1] = value; }
  48. constexpr void set_z(T value) requires(N >= 3) { m_data[2] = value; }
  49. constexpr void set_w(T value) requires(N >= 4) { m_data[3] = value; }
  50. [[nodiscard]] constexpr T operator[](size_t index) const
  51. {
  52. VERIFY(index < N);
  53. return m_data[index];
  54. }
  55. constexpr VectorN& operator+=(VectorN const& other)
  56. {
  57. UNROLL_LOOP
  58. for (auto i = 0u; i < N; ++i)
  59. m_data[i] += other.data()[i];
  60. return *this;
  61. }
  62. constexpr VectorN& operator-=(VectorN const& other)
  63. {
  64. UNROLL_LOOP
  65. for (auto i = 0u; i < N; ++i)
  66. m_data[i] -= other.data()[i];
  67. return *this;
  68. }
  69. constexpr VectorN& operator*=(const T& t)
  70. {
  71. UNROLL_LOOP
  72. for (auto i = 0u; i < N; ++i)
  73. m_data[i] *= t;
  74. return *this;
  75. }
  76. [[nodiscard]] constexpr VectorN operator+(VectorN const& other) const
  77. {
  78. VectorN result;
  79. UNROLL_LOOP
  80. for (auto i = 0u; i < N; ++i)
  81. result.m_data[i] = m_data[i] + other.data()[i];
  82. return result;
  83. }
  84. [[nodiscard]] constexpr VectorN operator-(VectorN const& other) const
  85. {
  86. VectorN result;
  87. UNROLL_LOOP
  88. for (auto i = 0u; i < N; ++i)
  89. result.m_data[i] = m_data[i] - other.data()[i];
  90. return result;
  91. }
  92. [[nodiscard]] constexpr VectorN operator*(VectorN const& other) const
  93. {
  94. VectorN result;
  95. UNROLL_LOOP
  96. for (auto i = 0u; i < N; ++i)
  97. result.m_data[i] = m_data[i] * other.data()[i];
  98. return result;
  99. }
  100. [[nodiscard]] constexpr VectorN operator-() const
  101. {
  102. VectorN result;
  103. UNROLL_LOOP
  104. for (auto i = 0u; i < N; ++i)
  105. result.m_data[i] = -m_data[i];
  106. return result;
  107. }
  108. [[nodiscard]] constexpr VectorN operator/(VectorN const& other) const
  109. {
  110. VectorN result;
  111. UNROLL_LOOP
  112. for (auto i = 0u; i < N; ++i)
  113. result.m_data[i] = m_data[i] / other.data()[i];
  114. return result;
  115. }
  116. template<typename U>
  117. [[nodiscard]] constexpr VectorN operator*(U f) const
  118. {
  119. VectorN result;
  120. UNROLL_LOOP
  121. for (auto i = 0u; i < N; ++i)
  122. result.m_data[i] = m_data[i] * f;
  123. return result;
  124. }
  125. template<typename U>
  126. [[nodiscard]] constexpr VectorN operator/(U f) const
  127. {
  128. VectorN result;
  129. UNROLL_LOOP
  130. for (auto i = 0u; i < N; ++i)
  131. result.m_data[i] = m_data[i] / f;
  132. return result;
  133. }
  134. [[nodiscard]] constexpr T dot(VectorN const& other) const
  135. {
  136. T result {};
  137. UNROLL_LOOP
  138. for (auto i = 0u; i < N; ++i)
  139. result += m_data[i] * other.data()[i];
  140. return result;
  141. }
  142. [[nodiscard]] constexpr VectorN cross(VectorN const& other) const requires(N == 3)
  143. {
  144. return VectorN(
  145. y() * other.z() - z() * other.y(),
  146. z() * other.x() - x() * other.z(),
  147. x() * other.y() - y() * other.x());
  148. }
  149. [[nodiscard]] constexpr VectorN normalized() const
  150. {
  151. VectorN copy { *this };
  152. copy.normalize();
  153. return copy;
  154. }
  155. [[nodiscard]] constexpr VectorN clamped(T m, T x) const
  156. {
  157. VectorN copy { *this };
  158. copy.clamp(m, x);
  159. return copy;
  160. }
  161. constexpr void clamp(T min_value, T max_value)
  162. {
  163. UNROLL_LOOP
  164. for (auto i = 0u; i < N; ++i) {
  165. m_data[i] = max(min_value, m_data[i]);
  166. m_data[i] = min(max_value, m_data[i]);
  167. }
  168. }
  169. constexpr void normalize()
  170. {
  171. T const inv_length = 1 / length();
  172. operator*=(inv_length);
  173. }
  174. [[nodiscard]] constexpr T length() const
  175. {
  176. return AK::sqrt(dot(*this));
  177. }
  178. [[nodiscard]] constexpr VectorN<2, T> xy() const requires(N >= 3)
  179. {
  180. return VectorN<2, T>(x(), y());
  181. }
  182. [[nodiscard]] constexpr VectorN<3, T> xyz() const requires(N >= 4)
  183. {
  184. return VectorN<3, T>(x(), y(), z());
  185. }
  186. [[nodiscard]] String to_string() const
  187. {
  188. if constexpr (N == 2)
  189. return String::formatted("[{},{}]", x(), y());
  190. else if constexpr (N == 3)
  191. return String::formatted("[{},{},{}]", x(), y(), z());
  192. else
  193. return String::formatted("[{},{},{},{}]", x(), y(), z(), w());
  194. }
  195. template<typename U>
  196. [[nodiscard]] VectorN<N, U> to_rounded() const
  197. {
  198. VectorN<N, U> result;
  199. UNROLL_LOOP
  200. for (auto i = 0u; i < N; ++i) {
  201. if constexpr (IsSame<T, float>)
  202. result.data()[i] = static_cast<U>(lrintf(m_data[i]));
  203. else
  204. result.data()[i] = static_cast<U>(lrint(m_data[i]));
  205. }
  206. return result;
  207. }
  208. auto& data() { return m_data; }
  209. auto const& data() const { return m_data; }
  210. private:
  211. AK::Array<T, N> m_data;
  212. };
  213. }