From 1798980ac6829d5d79c162325a2162aa42917958 Mon Sep 17 00:00:00 2001 From: Brett Date: Tue, 10 Dec 2024 00:33:04 -0500 Subject: [PATCH] hash_value on vec --- CMakeLists.txt | 2 +- include/blt/math/vectors.h | 651 +++++++++++++++++++------------------ 2 files changed, 335 insertions(+), 318 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ce8a83..9384be6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.20) include(cmake/color.cmake) -set(BLT_VERSION 2.1.12) +set(BLT_VERSION 2.1.13) set(BLT_TARGET BLT) diff --git a/include/blt/math/vectors.h b/include/blt/math/vectors.h index d6c2d73..7ab4853 100644 --- a/include/blt/math/vectors.h +++ b/include/blt/math/vectors.h @@ -17,287 +17,301 @@ namespace blt { - #define MSVC_COMPILER (!defined(__GNUC__) && !defined(__clang__)) - + constexpr float EPSILON = std::numeric_limits::epsilon(); - + static inline constexpr bool f_equal(float v1, float v2) { return v1 >= v2 - EPSILON && v1 <= v2 + EPSILON; } - - template + + template struct vec { - static_assert(std::is_arithmetic_v && "blt::vec must be created using an arithmetic type!"); - private: - std::array elements; - public: - constexpr static blt::u32 data_size = size; - - constexpr vec() + static_assert(std::is_arithmetic_v && "blt::vec must be created using an arithmetic type!"); + + private: + std::array elements; + + public: + constexpr static blt::u32 data_size = size; + + constexpr vec() + { + for (auto& v : elements) + v = static_cast(0); + } + + /** + * Create a vector with initializer list, if the initializer list doesn't contain enough values to fill this vec, it will use t + * @param t default value to fill with + * @param args list of args + */ + template || std::is_convertible_v, bool> = true> + constexpr vec(U t, std::initializer_list args): elements() + { + auto b = args.begin(); + for (auto& v : elements) { - for (auto& v : elements) - v = static_cast(0); - } - - /** - * Create a vector with initializer list, if the initializer list doesn't contain enough values to fill this vec, it will use t - * @param t default value to fill with - * @param args list of args - */ - template || std::is_convertible_v, bool> = true> - constexpr vec(U t, std::initializer_list args): elements() - { - auto b = args.begin(); - for (auto& v : elements) + if (b == args.end()) { - if (b == args.end()) - { - v = t; - continue; - } - v = *b; - ++b; - } - } - - /** - * Create a vector from an initializer list, if the list doesn't have enough elements it will be filled with the default value (0) - * @param args - */ - template || std::is_convertible_v, bool> = true> - constexpr vec(std::initializer_list args): vec(U(), args) - {} - - template = true> - constexpr explicit vec(Args... args): vec(std::array{static_cast(args)...}) - {} - - constexpr explicit vec(T t) - { - for (auto& v : elements) v = t; - } - - constexpr explicit vec(const T elem[size]) - { - for (size_t i = 0; i < size; i++) - elements[i] = elem[i]; - } - - constexpr explicit vec(std::array elem): elements(elem) - {} - - template, bool> = true> - constexpr explicit vec(std::array el): elements() - { - auto b = el.begin(); - auto m = elements.begin(); - while (b != el.end() && m != elements.end()) - { - *m = *b; - ++m; - ++b; + continue; } + v = *b; + ++b; } - - [[nodiscard]] constexpr inline T x() const + } + + /** + * Create a vector from an initializer list, if the list doesn't have enough elements it will be filled with the default value (0) + * @param args + */ + template || std::is_convertible_v, bool> = true> + constexpr vec(std::initializer_list args): vec(U(), args) + { + } + + template = true> + constexpr explicit vec(Args... args): vec(std::array{static_cast(args)...}) + { + } + + constexpr explicit vec(T t) + { + for (auto& v : elements) + v = t; + } + + constexpr explicit vec(const T elem[size]) + { + for (size_t i = 0; i < size; i++) + elements[i] = elem[i]; + } + + constexpr explicit vec(std::array elem): elements(elem) + { + } + + template , bool> = true> + constexpr explicit vec(std::array el): elements() + { + auto b = el.begin(); + auto m = elements.begin(); + while (b != el.end() && m != elements.end()) { - return elements[0]; - } - - [[nodiscard]] constexpr inline T y() const - { - static_assert(size > 1); - return elements[1]; - } - - [[nodiscard]] constexpr inline T z() const - { - static_assert(size > 2); - return elements[2]; - } - - [[nodiscard]] constexpr inline T w() const - { - static_assert(size > 3); - return elements[3]; - } - - [[nodiscard]] constexpr inline vec abs() const - { - auto copy = *this; - for (auto& v : copy.elements) - v = std::abs(v); - return copy; - } - - [[nodiscard]] constexpr inline vec bipolar() const - { - auto copy = *this; - for (auto& v : copy.elements) - v = v >= 0 ? 1 : -1; - return copy; - } - - [[nodiscard]] constexpr inline T magnitude() const - { - T total = 0; - for (blt::u32 i = 0; i < size; i++) - total += elements[i] * elements[i]; - return std::sqrt(total); - } - - [[nodiscard]] constexpr inline vec normalize() const - { - T mag = this->magnitude(); - if (mag == 0) - return vec(*this); - return *this / mag; - } - - constexpr inline T& operator[](blt::size_t index) - { - return elements[index]; - } - - constexpr inline T operator[](blt::size_t index) const - { - return elements[index]; - } - - constexpr inline vec& operator=(T v) - { - for (blt::u32 i = 0; i < size; i++) - elements[i] = v; - return *this; - } - - constexpr inline vec operator-() - { - vec initializer{}; - for (blt::u32 i = 0; i < size; i++) - initializer[i] = -elements[i]; - return vec{initializer}; - } - - constexpr inline vec& operator+=(const vec& other) - { - for (blt::u32 i = 0; i < size; i++) - elements[i] += other[i]; - return *this; - } - - constexpr inline vec& operator*=(const vec& other) - { - for (blt::u32 i = 0; i < size; i++) - elements[i] *= other[i]; - return *this; - } - - constexpr inline vec& operator+=(T f) - { - for (blt::u32 i = 0; i < size; i++) - elements[i] += f; - return *this; - } - - constexpr inline vec& operator*=(T f) - { - for (blt::u32 i = 0; i < size; i++) - elements[i] *= f; - return *this; - } - - constexpr inline vec& operator-=(const vec& other) - { - for (blt::u32 i = 0; i < size; i++) - elements[i] -= other[i]; - return *this; - } - - constexpr inline vec& operator-=(T f) - { - for (blt::u32 i = 0; i < size; i++) - elements[i] -= f; - return *this; - } - - /** - * performs the dot product of left * right - */ - constexpr static inline T dot(const vec& left, const vec& right) - { - T dot = 0; - for (blt::u32 i = 0; i < size; i++) - dot += left[i] * right[i]; - return dot; - } - - constexpr static inline vec cross( - const vec& left, const vec& right - ) - { - // cross is only defined on vectors of size 3. 2D could be implemented, which is a TODO - static_assert(size == 3); - return {left.y() * right.z() - left.z() * right.y(), - left.z() * right.x() - left.x() * right.z(), - left.x() * right.y() - left.y() * right.x()}; - } - - constexpr static inline vec project( - const vec& u, const vec& v - ) - { - T du = dot(u); - T dv = dot(v); - return (du / dv) * v; - } - - constexpr inline auto* data() - { - return elements.data(); - } - - [[nodiscard]] constexpr inline const auto* data() const - { - return elements.data(); - } - - [[nodiscard]] constexpr auto begin() const - { - return elements.begin(); - } - - [[nodiscard]] constexpr auto end() const - { - return elements.end(); - } - - [[nodiscard]] constexpr auto rbegin() const - { - return elements.rbegin(); - } - - [[nodiscard]] constexpr auto rend() const - { - return elements.rend(); - } - - [[nodiscard]] constexpr auto cbegin() const - { - return elements.cbegin(); - } - - [[nodiscard]] constexpr auto cend() const - { - return elements.cend(); + *m = *b; + ++m; + ++b; } + } + + [[nodiscard]] constexpr inline T x() const + { + return elements[0]; + } + + [[nodiscard]] constexpr inline T y() const + { + static_assert(size > 1); + return elements[1]; + } + + [[nodiscard]] constexpr inline T z() const + { + static_assert(size > 2); + return elements[2]; + } + + [[nodiscard]] constexpr inline T w() const + { + static_assert(size > 3); + return elements[3]; + } + + [[nodiscard]] constexpr inline vec abs() const + { + auto copy = *this; + for (auto& v : copy.elements) + v = std::abs(v); + return copy; + } + + [[nodiscard]] constexpr inline vec bipolar() const + { + auto copy = *this; + for (auto& v : copy.elements) + v = v >= 0 ? 1 : -1; + return copy; + } + + [[nodiscard]] constexpr inline T magnitude() const + { + T total = 0; + for (blt::u32 i = 0; i < size; i++) + total += elements[i] * elements[i]; + return std::sqrt(total); + } + + [[nodiscard]] constexpr inline vec normalize() const + { + T mag = this->magnitude(); + if (mag == 0) + return vec(*this); + return *this / mag; + } + + constexpr inline T& operator[](blt::size_t index) + { + return elements[index]; + } + + constexpr inline T operator[](blt::size_t index) const + { + return elements[index]; + } + + constexpr inline vec& operator=(T v) + { + for (blt::u32 i = 0; i < size; i++) + elements[i] = v; + return *this; + } + + constexpr inline vec operator-() + { + vec initializer{}; + for (blt::u32 i = 0; i < size; i++) + initializer[i] = -elements[i]; + return vec{initializer}; + } + + constexpr inline vec& operator+=(const vec& other) + { + for (blt::u32 i = 0; i < size; i++) + elements[i] += other[i]; + return *this; + } + + constexpr inline vec& operator*=(const vec& other) + { + for (blt::u32 i = 0; i < size; i++) + elements[i] *= other[i]; + return *this; + } + + constexpr inline vec& operator+=(T f) + { + for (blt::u32 i = 0; i < size; i++) + elements[i] += f; + return *this; + } + + constexpr inline vec& operator*=(T f) + { + for (blt::u32 i = 0; i < size; i++) + elements[i] *= f; + return *this; + } + + constexpr inline vec& operator-=(const vec& other) + { + for (blt::u32 i = 0; i < size; i++) + elements[i] -= other[i]; + return *this; + } + + constexpr inline vec& operator-=(T f) + { + for (blt::u32 i = 0; i < size; i++) + elements[i] -= f; + return *this; + } + + /** + * performs the dot product of left * right + */ + constexpr static inline T dot(const vec& left, const vec& right) + { + T dot = 0; + for (blt::u32 i = 0; i < size; i++) + dot += left[i] * right[i]; + return dot; + } + + constexpr static inline vec cross( + const vec& left, const vec& right + ) + { + // cross is only defined on vectors of size 3. 2D could be implemented, which is a TODO + static_assert(size == 3); + return { + left.y() * right.z() - left.z() * right.y(), + left.z() * right.x() - left.x() * right.z(), + left.x() * right.y() - left.y() * right.x() + }; + } + + constexpr static inline vec project( + const vec& u, const vec& v + ) + { + T du = dot(u); + T dv = dot(v); + return (du / dv) * v; + } + + constexpr inline auto* data() + { + return elements.data(); + } + + [[nodiscard]] constexpr inline const auto* data() const + { + return elements.data(); + } + + [[nodiscard]] constexpr auto begin() const + { + return elements.begin(); + } + + [[nodiscard]] constexpr auto end() const + { + return elements.end(); + } + + [[nodiscard]] constexpr auto rbegin() const + { + return elements.rbegin(); + } + + [[nodiscard]] constexpr auto rend() const + { + return elements.rend(); + } + + [[nodiscard]] constexpr auto cbegin() const + { + return elements.cbegin(); + } + + [[nodiscard]] constexpr auto cend() const + { + return elements.cend(); + } + + friend std::size_t hash_value(const vec& obj) + { + std::size_t seed = 0x5410391E; + for (const auto& v : obj) + seed ^= (seed << 6) + (seed >> 2) + std::hash{}(v); + return seed; + } }; - - template() + std::declval())> + + template () + std::declval())> inline constexpr vec operator+(const vec& left, const vec& right) { vec initializer{}; @@ -305,8 +319,8 @@ namespace blt initializer[i] = static_cast(left[i]) + static_cast(right[i]); return initializer; } - - template() - std::declval())> + + template () - std::declval())> inline constexpr vec operator-(const vec& left, const vec& right) { vec initializer{}; @@ -314,8 +328,8 @@ namespace blt initializer[i] = static_cast(left[i]) - static_cast(right[i]); return initializer; } - - template() + std::declval())> + + template () + std::declval())> inline constexpr vec operator+(const vec& left, G right) { vec initializer{}; @@ -323,8 +337,8 @@ namespace blt initializer[i] = static_cast(left[i]) + static_cast(right); return initializer; } - - template() - std::declval())> + + template () - std::declval())> inline constexpr vec operator-(const vec& left, G right) { vec initializer{}; @@ -332,8 +346,8 @@ namespace blt initializer[i] = static_cast(left[i]) - static_cast(right); return initializer; } - - template() + std::declval())> + + template () + std::declval())> inline constexpr vec operator+(G left, const vec& right) { vec initializer{}; @@ -341,8 +355,8 @@ namespace blt initializer[i] = static_cast(left) + static_cast(right[i]); return initializer; } - - template() - std::declval())> + + template () - std::declval())> inline constexpr vec operator-(G left, const vec& right) { vec initializer{}; @@ -350,8 +364,8 @@ namespace blt initializer[i] = static_cast(left) - static_cast(right[i]); return initializer; } - - template() * std::declval())> + + template () * std::declval())> inline constexpr vec operator*(const vec& left, const vec& right) { vec initializer{}; @@ -359,8 +373,8 @@ namespace blt initializer[i] = static_cast(left[i]) * static_cast(right[i]); return initializer; } - - template() * std::declval())> + + template () * std::declval())> inline constexpr vec operator*(const vec& left, G right) { vec initializer{}; @@ -368,8 +382,8 @@ namespace blt initializer[i] = static_cast(left[i]) * static_cast(right); return initializer; } - - template() * std::declval())> + + template () * std::declval())> inline constexpr vec operator*(G left, const vec& right) { vec initializer{}; @@ -377,8 +391,8 @@ namespace blt initializer[i] = static_cast(left) * static_cast(right[i]); return initializer; } - - template() / std::declval())> + + template () / std::declval())> inline constexpr vec operator/(const vec& left, G right) { vec initializer{}; @@ -386,8 +400,8 @@ namespace blt initializer[i] = static_cast(left[i]) / static_cast(right); return initializer; } - - template() / std::declval())> + + template () / std::declval())> inline constexpr vec operator/(G left, const vec& right) { vec initializer{}; @@ -395,8 +409,8 @@ namespace blt initializer[i] = static_cast(left) / static_cast(right[i]); return initializer; } - - template + + template inline constexpr bool operator==(const vec& left, const vec& right) { constexpr double E = std::numeric_limits::epsilon(); @@ -408,14 +422,14 @@ namespace blt } return true; } - - template + + template inline constexpr bool operator!=(const vec& left, const vec& right) { return !(left == right); } - - template + + template inline constexpr vec vec_cast(const vec& conv) { vec initializer{}; @@ -423,62 +437,64 @@ namespace blt initializer[i] = static_cast(conv[i]); return initializer; } - + using vec2f = vec; using vec3f = vec; using vec4f = vec; - + using vec2d = vec; using vec3d = vec; using vec4d = vec; - + using vec2i = vec; using vec3i = vec; using vec4i = vec; - + using vec2l = vec; using vec3l = vec; using vec4l = vec; - + using vec2ui = vec; using vec3ui = vec; using vec4ui = vec; - + using vec2ul = vec; using vec3ul = vec; using vec4ul = vec; - + using vec2 = vec2f; using vec3 = vec3f; using vec4 = vec4f; - + using color4 = vec4; using color3 = vec3; - + inline constexpr color4 make_color(float r, float g, float b) { return color4{r, g, b, 1.0f}; } - - template + + template inline constexpr blt::vec make_vec2(const blt::vec& t, size_t fill = 0) { if constexpr (size >= 2) { return blt::vec(t.x(), t.y()); - } else + } + else { return blt::vec(t.x(), fill); } } - - template + + template inline constexpr blt::vec make_vec3(const blt::vec& t, size_t fill = 0) { if constexpr (size >= 3) { return blt::vec(t.x(), t.y(), t.z()); - } else + } + else { blt::vec ret; for (size_t i = 0; i < size; i++) @@ -488,14 +504,15 @@ namespace blt return ret; } } - - template + + template inline constexpr blt::vec make_vec4(const blt::vec& t, size_t fill = 0) { if constexpr (size >= 4) { return blt::vec(t.x(), t.y(), t.z(), t.w()); - } else + } + else { blt::vec ret; for (size_t i = 0; i < size; i++) @@ -505,33 +522,33 @@ namespace blt return ret; } } - + namespace vec_algorithm { static inline void findOrthogonalBasis(const vec3& v, vec3& v1, vec3& v2, vec3& v3) { v1 = v.normalize(); - + vec3 arbitraryVector{1, 0, 0}; if (std::abs(vec3::dot(v, arbitraryVector)) > 0.9) { arbitraryVector = vec3{0, 1, 0}; } - + v2 = vec3::cross(v, arbitraryVector).normalize(); v3 = vec3::cross(v1, v2); } - + // Gram-Schmidt orthonormalization algorithm static inline void gramSchmidt(std::vector& vectors) { - int n = (int) vectors.size(); + int n = (int)vectors.size(); std::vector basis; - + // normalize first vector basis.push_back(vectors[0]); basis[0] = basis[0].normalize(); - + // iterate over the rest of the vectors for (int i = 1; i < n; ++i) { @@ -548,7 +565,7 @@ namespace blt new_vector = new_vector.normalize(); basis.push_back(new_vector); } - + vectors = basis; } }