diff options
-rw-r--r-- | Userland/Libraries/LibGfx/Vector2.h | 128 | ||||
-rw-r--r-- | Userland/Libraries/LibGfx/Vector3.h | 145 | ||||
-rw-r--r-- | Userland/Libraries/LibGfx/Vector4.h | 154 | ||||
-rw-r--r-- | Userland/Libraries/LibGfx/VectorN.h | 222 |
4 files changed, 252 insertions, 397 deletions
diff --git a/Userland/Libraries/LibGfx/Vector2.h b/Userland/Libraries/LibGfx/Vector2.h index 43aa58df96..536e41d388 100644 --- a/Userland/Libraries/LibGfx/Vector2.h +++ b/Userland/Libraries/LibGfx/Vector2.h @@ -1,132 +1,24 @@ /* * Copyright (c) 2020, Stephan Unverwerth <s.unverwerth@serenityos.org> + * Copyright (c) 2022, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once -#include <AK/Math.h> -#include <AK/String.h> +#include "VectorN.h" -namespace Gfx { -template<typename T> -class Vector2 final { -public: - constexpr Vector2() = default; - constexpr Vector2(T x, T y) - : m_x(x) - , m_y(y) - { - } - - constexpr T x() const { return m_x; } - constexpr T y() const { return m_y; } - - constexpr void set_x(T value) { m_x = value; } - constexpr void set_y(T value) { m_y = value; } - - constexpr Vector2& operator+=(const Vector2& other) - { - m_x += other.m_x; - m_y += other.m_y; - return *this; - } - - constexpr Vector2& operator-=(const Vector2& other) - { - m_x -= other.m_x; - m_y -= other.m_y; - return *this; - } - - constexpr Vector2 operator+(const Vector2& other) const - { - return Vector2(m_x + other.m_x, m_y + other.m_y); - } - - constexpr Vector2 operator-(const Vector2& other) const - { - return Vector2(m_x - other.m_x, m_y - other.m_y); - } - - constexpr Vector2 operator-() const - { - return Vector2(-m_x, -m_y); - } - - constexpr Vector2 operator*(const Vector2& other) const - { - return Vector2(m_x * other.m_x, m_y * other.m_y); - } - - constexpr Vector2 operator/(const Vector2& other) const - { - return Vector2(m_x / other.m_x, m_y / other.m_y); - } - - template<typename U> - constexpr Vector2 operator*(U f) const - { - return Vector2(m_x * f, m_y * f); - } - - template<typename U> - constexpr Vector2 operator/(U f) const - { - return Vector2(m_x / f, m_y / f); - } - - constexpr T dot(const Vector2& other) const - { - return m_x * other.m_x + m_y * other.m_y; - } - - constexpr Vector2 normalized() const - { - T inv_length = 1 / length(); - return *this * inv_length; - } - - constexpr Vector2 clamped(T m, T x) const - { - Vector2 copy { *this }; - copy.clamp(m, x); - return copy; - } +#include <AK/Error.h> +#include <AK/Format.h> +#include <AK/StringView.h> - constexpr void clamp(T min_value, T max_value) - { - m_x = max(min_value, m_x); - m_y = max(min_value, m_y); - m_x = min(max_value, m_x); - m_y = min(max_value, m_y); - } - - constexpr void normalize() - { - T inv_length = 1 / length(); - m_x *= inv_length; - m_y *= inv_length; - } - - constexpr T length() const - { - return AK::hypot(m_x, m_y); - } - - String to_string() const - { - return String::formatted("[{},{}]", x(), y()); - } - -private: - T m_x; - T m_y; -}; +namespace Gfx { -typedef Vector2<float> FloatVector2; -typedef Vector2<double> DoubleVector2; +template<class T> +using Vector2 = VectorN<2, T>; +using FloatVector2 = Vector2<float>; +using DoubleVector2 = Vector2<double>; } diff --git a/Userland/Libraries/LibGfx/Vector3.h b/Userland/Libraries/LibGfx/Vector3.h index 6b7f4ae26d..058413729a 100644 --- a/Userland/Libraries/LibGfx/Vector3.h +++ b/Userland/Libraries/LibGfx/Vector3.h @@ -1,149 +1,24 @@ /* * Copyright (c) 2020, Stephan Unverwerth <s.unverwerth@serenityos.org> + * Copyright (c) 2022, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once -#include <AK/Math.h> -#include <AK/String.h> +#include "VectorN.h" -namespace Gfx { -template<typename T> -class Vector3 final { -public: - constexpr Vector3() = default; - constexpr Vector3(T x, T y, T z) - : m_x(x) - , m_y(y) - , m_z(z) - { - } - - constexpr T x() const { return m_x; } - constexpr T y() const { return m_y; } - constexpr T z() const { return m_z; } - - constexpr void set_x(T value) { m_x = value; } - constexpr void set_y(T value) { m_y = value; } - constexpr void set_z(T value) { m_z = value; } - - constexpr Vector3& operator+=(const Vector3& other) - { - m_x += other.m_x; - m_y += other.m_y; - m_z += other.m_z; - return *this; - } - - constexpr Vector3& operator-=(const Vector3& other) - { - m_x -= other.m_x; - m_y -= other.m_y; - m_z -= other.m_z; - return *this; - } - - constexpr Vector3 operator+(const Vector3& other) const - { - return Vector3(m_x + other.m_x, m_y + other.m_y, m_z + other.m_z); - } - - constexpr Vector3 operator-(const Vector3& other) const - { - return Vector3(m_x - other.m_x, m_y - other.m_y, m_z - other.m_z); - } - - constexpr Vector3 operator-() const - { - return Vector3(-m_x, -m_y, -m_z); - } - - constexpr Vector3 operator*(const Vector3& other) const - { - return Vector3(m_x * other.m_x, m_y * other.m_y, m_z * other.m_z); - } - - constexpr Vector3 operator/(const Vector3& other) const - { - return Vector3(m_x / other.m_x, m_y / other.m_y, m_z / other.m_z); - } - - template<typename U> - constexpr Vector3 operator*(U f) const - { - return Vector3(m_x * f, m_y * f, m_z * f); - } +#include <AK/Error.h> +#include <AK/Format.h> +#include <AK/StringView.h> - template<typename U> - constexpr Vector3 operator/(U f) const - { - return Vector3(m_x / f, m_y / f, m_z / f); - } - - constexpr T dot(const Vector3& other) const - { - return m_x * other.m_x + m_y * other.m_y + m_z * other.m_z; - } - - constexpr Vector3 cross(const Vector3& other) const - { - return Vector3( - m_y * other.m_z - m_z * other.m_y, - m_z * other.m_x - m_x * other.m_z, - m_x * other.m_y - m_y * other.m_x); - } - - constexpr Vector3 normalized() const - { - T inv_length = 1 / length(); - return *this * inv_length; - } - - constexpr Vector3 clamped(T m, T x) const - { - Vector3 copy { *this }; - copy.clamp(m, x); - return copy; - } - - constexpr void clamp(T min_value, T max_value) - { - m_x = max(min_value, m_x); - m_y = max(min_value, m_y); - m_z = max(min_value, m_z); - m_x = min(max_value, m_x); - m_y = min(max_value, m_y); - m_z = min(max_value, m_z); - } - - constexpr void normalize() - { - T inv_length = 1 / length(); - m_x *= inv_length; - m_y *= inv_length; - m_z *= inv_length; - } - - constexpr T length() const - { - return AK::sqrt(m_x * m_x + m_y * m_y + m_z * m_z); - } - - String to_string() const - { - return String::formatted("[{},{},{}]", x(), y(), z()); - } - -private: - T m_x; - T m_y; - T m_z; -}; +namespace Gfx { -typedef Vector3<float> FloatVector3; -typedef Vector3<double> DoubleVector3; +template<class T> +using Vector3 = VectorN<3, T>; +using FloatVector3 = Vector3<float>; +using DoubleVector3 = Vector3<double>; } diff --git a/Userland/Libraries/LibGfx/Vector4.h b/Userland/Libraries/LibGfx/Vector4.h index 5eea391b60..1e89ce8c2a 100644 --- a/Userland/Libraries/LibGfx/Vector4.h +++ b/Userland/Libraries/LibGfx/Vector4.h @@ -1,158 +1,24 @@ /* * Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org> + * Copyright (c) 2022, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once -#include <AK/Math.h> -#include <AK/String.h> +#include "VectorN.h" -namespace Gfx { -template<typename T> -class Vector3; - -template<typename T> -class Vector4 final { -public: - constexpr Vector4() = default; - constexpr Vector4(T x, T y, T z, T w) - : m_x(x) - , m_y(y) - , m_z(z) - , m_w(w) - { - } - - constexpr T x() const { return m_x; } - constexpr T y() const { return m_y; } - constexpr T z() const { return m_z; } - constexpr T w() const { return m_w; } - - constexpr void set_x(T value) { m_x = value; } - constexpr void set_y(T value) { m_y = value; } - constexpr void set_z(T value) { m_z = value; } - constexpr void set_w(T value) { m_w = value; } +#include <AK/Error.h> +#include <AK/Format.h> +#include <AK/StringView.h> - constexpr Vector4& operator+=(const Vector4& other) - { - m_x += other.m_x; - m_y += other.m_y; - m_z += other.m_z; - m_w += other.m_w; - return *this; - } - - constexpr Vector4& operator-=(const Vector4& other) - { - m_x -= other.m_x; - m_y -= other.m_y; - m_z -= other.m_z; - m_w -= other.m_w; - return *this; - } - - constexpr Vector4 operator+(const Vector4& other) const - { - return Vector4(m_x + other.m_x, m_y + other.m_y, m_z + other.m_z, m_w + other.m_w); - } - - constexpr Vector4 operator-(const Vector4& other) const - { - return Vector4(m_x - other.m_x, m_y - other.m_y, m_z - other.m_z, m_w - other.m_w); - } - - constexpr Vector4 operator-() const - { - return Vector4(-m_x, -m_y, -m_z, -m_w); - } - - constexpr Vector4 operator*(const Vector4& other) const - { - return Vector4(m_x * other.m_x, m_y * other.m_y, m_z * other.m_z, m_w * other.m_w); - } - - constexpr Vector4 operator/(const Vector4& other) const - { - return Vector4(m_x / other.m_x, m_y / other.m_y, m_z / other.m_z, m_w / other.m_w); - } - - template<typename U> - constexpr Vector4 operator*(U f) const - { - return Vector4(m_x * f, m_y * f, m_z * f, m_w * f); - } - - template<typename U> - constexpr Vector4 operator/(U f) const - { - return Vector4(m_x / f, m_y / f, m_z / f, m_w / f); - } - - constexpr T dot(const Vector4& other) const - { - return m_x * other.m_x + m_y * other.m_y + m_z * other.m_z + m_w * other.m_w; - } - - constexpr Vector4 normalized() const - { - T inv_length = 1 / length(); - return *this * inv_length; - } - - constexpr Vector4 clamped(T m, T x) const - { - Vector4 copy { *this }; - copy.clamp(m, x); - return copy; - } - - constexpr void clamp(T min_value, T max_value) - { - m_x = max(min_value, m_x); - m_y = max(min_value, m_y); - m_z = max(min_value, m_z); - m_w = max(min_value, m_w); - m_x = min(max_value, m_x); - m_y = min(max_value, m_y); - m_z = min(max_value, m_z); - m_w = min(max_value, m_w); - } - - constexpr void normalize() - { - T inv_length = 1 / length(); - m_x *= inv_length; - m_y *= inv_length; - m_z *= inv_length; - m_w *= inv_length; - } - - constexpr T length() const - { - return AK::sqrt(m_x * m_x + m_y * m_y + m_z * m_z + m_w * m_w); - } - - constexpr Vector3<T> xyz() const - { - return Vector3<T>(m_x, m_y, m_z); - } - - String to_string() const - { - return String::formatted("[{},{},{},{}]", x(), y(), z(), w()); - } - -private: - T m_x; - T m_y; - T m_z; - T m_w; -}; +namespace Gfx { -typedef Vector4<float> FloatVector4; -typedef Vector4<double> DoubleVector4; +template<class T> +using Vector4 = VectorN<4, T>; +using FloatVector4 = Vector4<float>; +using DoubleVector4 = Vector4<double>; } diff --git a/Userland/Libraries/LibGfx/VectorN.h b/Userland/Libraries/LibGfx/VectorN.h new file mode 100644 index 0000000000..585fdea353 --- /dev/null +++ b/Userland/Libraries/LibGfx/VectorN.h @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2020, Stephan Unverwerth <s.unverwerth@serenityos.org> + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Array.h> +#include <AK/Error.h> +#include <AK/Format.h> +#include <AK/Math.h> +#include <AK/StdLibExtras.h> +#include <AK/String.h> +#include <AK/StringView.h> + +#define LOOP_UNROLL_N 4 + +#define STRINGIFY_HELPER(x) #x +#define STRINGIFY(x) STRINGIFY_HELPER(x) + +#ifdef __clang__ +# define UNROLL_LOOP _Pragma(STRINGIFY(unroll)) +#else +# define UNROLL_LOOP _Pragma(STRINGIFY(GCC unroll(LOOP_UNROLL_N))) +#endif + +namespace Gfx { +template<size_t N, typename T> +requires(N >= 2 && N <= 4) class VectorN final { + static_assert(LOOP_UNROLL_N >= N, "Unroll the entire loop for performance."); + +public: + [[nodiscard]] constexpr VectorN() = default; + [[nodiscard]] constexpr VectorN(T x, T y) requires(N == 2) + : m_data { x, y } + { + } + [[nodiscard]] constexpr VectorN(T x, T y, T z) requires(N == 3) + : m_data { x, y, z } + { + } + [[nodiscard]] constexpr VectorN(T x, T y, T z, T w) requires(N == 4) + : m_data { x, y, z, w } + { + } + + [[nodiscard]] constexpr T x() const { return m_data[0]; } + [[nodiscard]] constexpr T y() const { return m_data[1]; } + [[nodiscard]] constexpr T z() const requires(N >= 3) { return m_data[2]; } + [[nodiscard]] constexpr T w() const requires(N >= 4) { return m_data[3]; } + + constexpr void set_x(T value) { m_data[0] = value; } + constexpr void set_y(T value) { m_data[1] = value; } + constexpr void set_z(T value) requires(N >= 3) { m_data[2] = value; } + constexpr void set_w(T value) requires(N >= 4) { m_data[3] = value; } + + constexpr VectorN& operator+=(const VectorN& other) + { + UNROLL_LOOP + for (auto i = 0u; i < N; ++i) + m_data[i] += other.m_data[i]; + return *this; + } + + constexpr VectorN& operator-=(const VectorN& other) + { + UNROLL_LOOP + for (auto i = 0u; i < N; ++i) + m_data[i] -= other.m_data[i]; + return *this; + } + + constexpr VectorN& operator*=(const T& t) + { + UNROLL_LOOP + for (auto i = 0u; i < N; ++i) + m_data[i] *= t; + return *this; + } + + [[nodiscard]] constexpr VectorN operator+(const VectorN& other) const + { + VectorN result; + UNROLL_LOOP + for (auto i = 0u; i < N; ++i) + result.m_data[i] = m_data[i] + other.m_data[i]; + return result; + } + + [[nodiscard]] constexpr VectorN operator-(const VectorN& other) const + { + VectorN result; + UNROLL_LOOP + for (auto i = 0u; i < N; ++i) + result.m_data[i] = m_data[i] - other.m_data[i]; + return result; + } + + [[nodiscard]] constexpr VectorN operator*(const VectorN& other) const + { + VectorN result; + UNROLL_LOOP + for (auto i = 0u; i < N; ++i) + result.m_data[i] = m_data[i] * other.m_data[i]; + return result; + } + + [[nodiscard]] constexpr VectorN operator-() const + { + VectorN result; + UNROLL_LOOP + for (auto i = 0u; i < N; ++i) + result.m_data[i] = -m_data[i]; + return result; + } + + [[nodiscard]] constexpr VectorN operator/(const VectorN& other) const + { + VectorN result; + UNROLL_LOOP + for (auto i = 0u; i < N; ++i) + result.m_data[i] = m_data[i] / other.m_data[i]; + return result; + } + + template<typename U> + [[nodiscard]] constexpr VectorN operator*(U f) const + { + VectorN result; + UNROLL_LOOP + for (auto i = 0u; i < N; ++i) + result.m_data[i] = m_data[i] * f; + return result; + } + + template<typename U> + [[nodiscard]] constexpr VectorN operator/(U f) const + { + VectorN result; + UNROLL_LOOP + for (auto i = 0u; i < N; ++i) + result.m_data[i] = m_data[i] / f; + return result; + } + + [[nodiscard]] constexpr T dot(const VectorN& other) const + { + T result {}; + UNROLL_LOOP + for (auto i = 0u; i < N; ++i) + result += m_data[i] * other.m_data[i]; + return result; + } + + [[nodiscard]] constexpr VectorN cross(const VectorN& other) const requires(N == 3) + { + return VectorN( + y() * other.z() - z() * other.y(), + z() * other.x() - x() * other.z(), + x() * other.y() - y() * other.x()); + } + + [[nodiscard]] constexpr VectorN normalized() const + { + VectorN copy { *this }; + copy.normalize(); + return copy; + } + + [[nodiscard]] constexpr VectorN clamped(T m, T x) const + { + VectorN copy { *this }; + copy.clamp(m, x); + return copy; + } + + constexpr void clamp(T min_value, T max_value) + { + UNROLL_LOOP + for (auto i = 0u; i < N; ++i) { + m_data[i] = max(min_value, m_data[i]); + m_data[i] = min(max_value, m_data[i]); + } + } + + constexpr void normalize() + { + T const inv_length = 1 / length(); + operator*=(inv_length); + } + + [[nodiscard]] constexpr T length() const + { + if constexpr (N == 2) + return AK::hypot(m_data[0] * m_data[0] + m_data[1] * m_data[1]); + else if constexpr (N == 3) + return AK::sqrt(m_data[0] * m_data[0] + m_data[1] * m_data[1] + m_data[2] * m_data[2]); + else + return AK::sqrt(m_data[0] * m_data[0] + m_data[1] * m_data[1] + m_data[2] * m_data[2] + m_data[3] * m_data[3]); + } + + [[nodiscard]] constexpr VectorN<3, T> xyz() const requires(N == 4) + { + return VectorN<3, T>(x(), y(), z()); + } + + [[nodiscard]] String to_string() const + { + if constexpr (N == 2) + return String::formatted("[{},{}]", x(), y()); + else if constexpr (N == 3) + return String::formatted("[{},{},{}]", x(), y(), z()); + else + return String::formatted("[{},{},{},{}]", x(), y(), z(), w()); + } + +private: + AK::Array<T, N> m_data; +}; +} |