VectorN.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*
  2. * Copyright (c) 2020, Stephan Unverwerth <s.unverwerth@serenityos.org>
  3. * Copyright (c) 2022, the SerenityOS developers.
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #pragma once
  8. #include <AK/Array.h>
  9. #include <AK/Error.h>
  10. #include <AK/Format.h>
  11. #include <AK/Math.h>
  12. #include <AK/StdLibExtras.h>
  13. #include <AK/String.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. #ifdef __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) requires(N == 2)
  30. : m_data { x, y }
  31. {
  32. }
  33. [[nodiscard]] constexpr VectorN(T x, T y, T z) requires(N == 3)
  34. : m_data { x, y, z }
  35. {
  36. }
  37. [[nodiscard]] constexpr VectorN(T x, T y, T z, T w) requires(N == 4)
  38. : m_data { x, y, z, w }
  39. {
  40. }
  41. [[nodiscard]] constexpr T x() const { return m_data[0]; }
  42. [[nodiscard]] constexpr T y() const { return m_data[1]; }
  43. [[nodiscard]] constexpr T z() const requires(N >= 3) { return m_data[2]; }
  44. [[nodiscard]] constexpr T w() const requires(N >= 4) { return m_data[3]; }
  45. constexpr void set_x(T value) { m_data[0] = value; }
  46. constexpr void set_y(T value) { m_data[1] = value; }
  47. constexpr void set_z(T value) requires(N >= 3) { m_data[2] = value; }
  48. constexpr void set_w(T value) requires(N >= 4) { m_data[3] = value; }
  49. [[nodiscard]] constexpr T operator[](size_t index) const
  50. {
  51. VERIFY(index < N);
  52. return m_data[index];
  53. }
  54. constexpr VectorN& operator+=(VectorN const& other)
  55. {
  56. UNROLL_LOOP
  57. for (auto i = 0u; i < N; ++i)
  58. m_data[i] += other.m_data[i];
  59. return *this;
  60. }
  61. constexpr VectorN& operator-=(VectorN const& other)
  62. {
  63. UNROLL_LOOP
  64. for (auto i = 0u; i < N; ++i)
  65. m_data[i] -= other.m_data[i];
  66. return *this;
  67. }
  68. constexpr VectorN& operator*=(const T& t)
  69. {
  70. UNROLL_LOOP
  71. for (auto i = 0u; i < N; ++i)
  72. m_data[i] *= t;
  73. return *this;
  74. }
  75. [[nodiscard]] constexpr VectorN operator+(VectorN const& other) const
  76. {
  77. VectorN result;
  78. UNROLL_LOOP
  79. for (auto i = 0u; i < N; ++i)
  80. result.m_data[i] = m_data[i] + other.m_data[i];
  81. return result;
  82. }
  83. [[nodiscard]] constexpr VectorN operator-(VectorN const& other) const
  84. {
  85. VectorN result;
  86. UNROLL_LOOP
  87. for (auto i = 0u; i < N; ++i)
  88. result.m_data[i] = m_data[i] - other.m_data[i];
  89. return result;
  90. }
  91. [[nodiscard]] constexpr VectorN operator*(VectorN const& other) const
  92. {
  93. VectorN result;
  94. UNROLL_LOOP
  95. for (auto i = 0u; i < N; ++i)
  96. result.m_data[i] = m_data[i] * other.m_data[i];
  97. return result;
  98. }
  99. [[nodiscard]] constexpr VectorN operator-() const
  100. {
  101. VectorN result;
  102. UNROLL_LOOP
  103. for (auto i = 0u; i < N; ++i)
  104. result.m_data[i] = -m_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.m_data[i];
  113. return result;
  114. }
  115. template<typename U>
  116. [[nodiscard]] constexpr VectorN operator*(U f) const
  117. {
  118. VectorN result;
  119. UNROLL_LOOP
  120. for (auto i = 0u; i < N; ++i)
  121. result.m_data[i] = m_data[i] * f;
  122. return result;
  123. }
  124. template<typename U>
  125. [[nodiscard]] constexpr VectorN operator/(U f) const
  126. {
  127. VectorN result;
  128. UNROLL_LOOP
  129. for (auto i = 0u; i < N; ++i)
  130. result.m_data[i] = m_data[i] / f;
  131. return result;
  132. }
  133. [[nodiscard]] constexpr T dot(VectorN const& other) const
  134. {
  135. T result {};
  136. UNROLL_LOOP
  137. for (auto i = 0u; i < N; ++i)
  138. result += m_data[i] * other.m_data[i];
  139. return result;
  140. }
  141. [[nodiscard]] constexpr VectorN cross(VectorN const& other) const requires(N == 3)
  142. {
  143. return VectorN(
  144. y() * other.z() - z() * other.y(),
  145. z() * other.x() - x() * other.z(),
  146. x() * other.y() - y() * other.x());
  147. }
  148. [[nodiscard]] constexpr VectorN normalized() const
  149. {
  150. VectorN copy { *this };
  151. copy.normalize();
  152. return copy;
  153. }
  154. [[nodiscard]] constexpr VectorN clamped(T m, T x) const
  155. {
  156. VectorN copy { *this };
  157. copy.clamp(m, x);
  158. return copy;
  159. }
  160. constexpr void clamp(T min_value, T max_value)
  161. {
  162. UNROLL_LOOP
  163. for (auto i = 0u; i < N; ++i) {
  164. m_data[i] = max(min_value, m_data[i]);
  165. m_data[i] = min(max_value, m_data[i]);
  166. }
  167. }
  168. constexpr void normalize()
  169. {
  170. T const inv_length = 1 / length();
  171. operator*=(inv_length);
  172. }
  173. [[nodiscard]] constexpr T length() const
  174. {
  175. T squared_sum {};
  176. UNROLL_LOOP
  177. for (auto i = 0u; i < N; ++i)
  178. squared_sum += m_data[i] * m_data[i];
  179. return AK::sqrt(squared_sum);
  180. }
  181. [[nodiscard]] constexpr VectorN<2, T> xy() const requires(N >= 3)
  182. {
  183. return VectorN<2, T>(x(), y());
  184. }
  185. [[nodiscard]] constexpr VectorN<3, T> xyz() const requires(N >= 4)
  186. {
  187. return VectorN<3, T>(x(), y(), z());
  188. }
  189. [[nodiscard]] String to_string() const
  190. {
  191. if constexpr (N == 2)
  192. return String::formatted("[{},{}]", x(), y());
  193. else if constexpr (N == 3)
  194. return String::formatted("[{},{},{}]", x(), y(), z());
  195. else
  196. return String::formatted("[{},{},{},{}]", x(), y(), z(), w());
  197. }
  198. private:
  199. AK::Array<T, N> m_data;
  200. };
  201. }