From c87eac5e059ece81e4ab97c92bc3e868ae048753 Mon Sep 17 00:00:00 2001 From: ecker Date: Thu, 4 Sep 2025 00:46:01 -0500 Subject: [PATCH] bigly refractors vector/quaternion/matrix all around (and beginning to ensure SIMD optimizations for physics) --- Makefile | 6 +- bin/exe/default/renderer | 2 +- engine/inc/uf/utils/math/math.h | 6 + engine/inc/uf/utils/math/matrix.h | 171 +- engine/inc/uf/utils/math/matrix/class.inl | 207 -- engine/inc/uf/utils/math/matrix/pod.inl | 615 ++--- engine/inc/uf/utils/math/physics/impl.h | 95 +- engine/inc/uf/utils/math/quaternion.h | 162 +- engine/inc/uf/utils/math/quaternion/class.inl | 278 --- engine/inc/uf/utils/math/quaternion/pod.inl | 358 ++- .../uf/utils/math/quaternion/quaternion.inl | 9 +- engine/inc/uf/utils/math/quaternion/simd.inl | 146 ++ engine/inc/uf/utils/math/rayt.h | 36 - engine/inc/uf/utils/math/shapes.h | 16 +- .../inc/uf/utils/math/transform/transform.inl | 4 +- engine/inc/uf/utils/math/vector.h | 594 ++--- engine/inc/uf/utils/math/vector/class.inl | 256 --- engine/inc/uf/utils/math/vector/pod.inl | 710 +++--- .../inc/uf/utils/math/vector/redundancy.inl | 1976 ----------------- engine/inc/uf/utils/math/vector/simd.h | 125 +- engine/inc/uf/utils/math/vector/simd.inl | 435 ++-- engine/inc/uf/utils/math/vector/vector.inl | 3 - engine/inc/uf/utils/memory/unordered_set.h | 23 + engine/src/engine/graph/graph.cpp | 2 +- engine/src/ext/lua/usertypes/vector.cpp | 2 +- engine/src/ext/vulkan/graphic.cpp | 2 +- engine/src/utils/math/physics/aabb.inl | 73 +- engine/src/utils/math/physics/bvh.inl | 24 +- engine/src/utils/math/physics/helpers.inl | 7 - engine/src/utils/math/physics/impl.cpp | 42 +- engine/src/utils/math/physics/mesh.inl | 1 - engine/src/utils/math/physics/solvers.inl | 2 +- engine/src/utils/math/physics/triangle.inl | 47 +- engine/src/utils/math/rayt.cpp | 338 --- 34 files changed, 1680 insertions(+), 5093 deletions(-) delete mode 100644 engine/inc/uf/utils/math/matrix/class.inl delete mode 100644 engine/inc/uf/utils/math/quaternion/class.inl create mode 100644 engine/inc/uf/utils/math/quaternion/simd.inl delete mode 100644 engine/inc/uf/utils/math/rayt.h delete mode 100644 engine/inc/uf/utils/math/vector/class.inl delete mode 100644 engine/inc/uf/utils/math/vector/redundancy.inl create mode 100644 engine/inc/uf/utils/memory/unordered_set.h delete mode 100644 engine/src/utils/math/rayt.cpp diff --git a/Makefile b/Makefile index 19a4ffdb..0c927bba 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,7 @@ ifneq (,$(findstring win64,$(ARCH))) REQ_DEPS += meshoptimizer toml xatlas curl ffx:fsr dc:texconv # vall_e cpptrace # openvr # ncurses draco discord bullet ultralight-ux FLAGS += -march=native -g # -flto # -g endif - REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit reactphysics simd ctti gltf imgui fmt freetype openal ogg wav + REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit r:eactphysics simd ctti gltf imgui fmt freetype openal ogg wav FLAGS += -DUF_ENV_WINDOWS -DUF_ENV_WIN64 -DWIN32_LEAN_AND_MEAN DEPS += -lgdi32 -ldwmapi LINKS += #-Wl,-subsystem,windows @@ -76,13 +76,13 @@ else ifneq (,$(findstring linux,$(ARCH))) REQ_DEPS += toml xatlas curl dc:texconv # meshoptimizer ffx:fsr cpptrace vall_e # ncurses openvr draco discord bullet ultralight-ux FLAGS += -march=native -g # -flto # -g endif - REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit reactphysics simd ctti gltf imgui fmt freetype openal ogg wav + REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit r:eactphysics simd ctti gltf imgui fmt freetype openal ogg wav FLAGS += -DUF_ENV_LINUX -fPIC DEPS += -pthread -ldl -lX11 -lXrandr INCS := -I./dep/master/include $(INCS) else ifneq (,$(findstring dreamcast,$(ARCH))) FLAGS += -DUF_ENV_DREAMCAST # -DUF_LEAN_AND_MEAN # this apparently crashes - REQ_DEPS += opengl gldc json:nlohmann zlib lua reactphysics simd ctti fmt freetype openal aldc ogg wav png # imgui + REQ_DEPS += opengl gldc json:nlohmann zlib lua r:eactphysics simd ctti fmt freetype openal aldc ogg wav png # imgui INCS := -I./dep/dreamcast/include $(INCS) endif diff --git a/bin/exe/default/renderer b/bin/exe/default/renderer index 53395cff..91caa7c1 100644 --- a/bin/exe/default/renderer +++ b/bin/exe/default/renderer @@ -1 +1 @@ -vulkan \ No newline at end of file +opengl \ No newline at end of file diff --git a/engine/inc/uf/utils/math/math.h b/engine/inc/uf/utils/math/math.h index edf22f24..e14bccd2 100644 --- a/engine/inc/uf/utils/math/math.h +++ b/engine/inc/uf/utils/math/math.h @@ -10,6 +10,12 @@ #define UF_EZ_VEC4(vec, size) vec[0], size > 1 ? vec[1] : 0, size > 2 ? vec[2] : 0, size > 3 ? vec[3] : 0 #endif +#define NUM pod::Math::num_t + +#ifndef M_PI + #define M_PI 3.141592653589793f +#endif + namespace pod { namespace Math { typedef float num_t; diff --git a/engine/inc/uf/utils/math/matrix.h b/engine/inc/uf/utils/math/matrix.h index 871689fa..24508792 100644 --- a/engine/inc/uf/utils/math/matrix.h +++ b/engine/inc/uf/utils/math/matrix.h @@ -5,49 +5,41 @@ #include "math.h" namespace pod { - template -#if UF_MATRIX_ALIGNED - struct /*UF_API*/ alignas(16) Matrix { -#else + template struct /*UF_API*/ Matrix { -#endif // n-dimensional/unspecialized matrix access T components[R*C] = {}; - // T components[R][C] = {}; - // T* array = (T*) this; // POD information typedef T type_t; typedef T* container_t; - static const uint_fast8_t rows = R; - static const uint_fast8_t columns = C; + static const size_t rows = R; + static const size_t columns = C; // Overload access // Accessing via subscripts - inline T& operator[](uint_fast8_t i); - inline const T& operator[](uint_fast8_t i) const; + inline T& operator[](size_t i); + inline const T& operator[](size_t i) const; - inline T& operator()(uint_fast8_t r, uint_fast8_t c); - inline const T& operator()(uint_fast8_t r, uint_fast8_t c) const; + inline T& operator()(size_t r, size_t c); + inline const T& operator()(size_t r, size_t c) const; // Arithmetic - Matrix operator()() const; // Creation - Matrix operator-() const; // Negation - Matrix operator*( const Matrix& matrix ) const; // Multiplication between two matrices - Matrix operator*( T scalar ) const; // Multiplication between two matrices - Matrix operator+( const Matrix& matrix ) const; // Multiplication between two matrices - Matrix& operator *=( const Matrix& matrix ); // Multiplication set between two matrices - bool operator==( const Matrix& matrix ) const; // Equality check between two matrices (equals) - bool operator!=( const Matrix& matrix ) const; // Equality check between two matrices (not equals) + Matrix operator*( const Matrix& matrix ) const; + Matrix operator*( T scalar ) const; + Matrix operator+( const Matrix& matrix ) const; + Matrix& operator *=( const Matrix& matrix ); + bool operator==( const Matrix& matrix ) const; + bool operator!=( const Matrix& matrix ) const; }; - template using Matrix2t = Matrix; + template using Matrix2t = Matrix; typedef Matrix2t<> Matrix2; typedef Matrix2t Matrix2f; - template using Matrix3t = Matrix; + template using Matrix3t = Matrix; typedef Matrix3t<> Matrix3; typedef Matrix3t Matrix3f; - template using Matrix4t = Matrix; + template using Matrix4t = Matrix; typedef Matrix4t<> Matrix4; typedef Matrix4t Matrix4f; } @@ -56,61 +48,56 @@ namespace uf { namespace matrix { extern bool UF_API reverseInfiniteProjection; - template pod::Matrix4t /*UF_API*/ identity(); + template pod::Matrix4t /*UF_API*/ identity(); - template pod::Matrix4t /*UF_API*/ initialize( const T* ); - template pod::Matrix4t /*UF_API*/ initialize( const uf::stl::vector& ); + template pod::Matrix4t /*UF_API*/ initialize( const T* ); + template pod::Matrix4t /*UF_API*/ initialize( const uf::stl::vector& ); template pod::Matrix /*UF_API*/ identityi(); - // Equality checking - template int /*UF_API*/ compareTo( const T& left, const T& right ); // Equality check between two matrices (less than) - template bool /*UF_API*/ equals( const T& left, const T& right ); // Equality check between two matrices (equals) - template bool /*UF_API*/ equals( const T& left, const T& right, float eps ); // Equality check between two matrices (equals) - // Basic arithmetic - // template pod::Matrix /*UF_API*/ multiply( const T& left, const T& right ); // Multiplies two matrices of same type and size together - template pod::Matrix multiply( const T& left, const U& right ); // Multiplies two matrices of same type and size together - template pod::Matrix4t multiply( const pod::Matrix4t& left, const pod::Matrix4t& right ); // Multiplies two matrices of same type and size together + template bool /*UF_API*/ equals( const T& left, const T& right, float eps = 1.0e-6f ); + + template pod::Matrix multiply( const T& left, const U& right ); + template pod::Matrix4t multiply( const pod::Matrix4t& left, const pod::Matrix4t& right ); template T /*UF_API*/ transpose( const T& matrix ); - template pod::Matrix2t inverse(const pod::Matrix2t& mat ); - template pod::Matrix3t inverse(const pod::Matrix3t& mat ); - template pod::Matrix4t inverse(const pod::Matrix4t& mat ); + template pod::Matrix2t inverse(const pod::Matrix2t& mat ); + template pod::Matrix3t inverse(const pod::Matrix3t& mat ); + template pod::Matrix4t inverse(const pod::Matrix4t& mat ); - template pod::Vector2t multiply(const pod::Matrix2t& mat, const pod::Vector2t& v ); - template pod::Vector3t multiply(const pod::Matrix3t& mat, const pod::Vector3t& v ); - template pod::Vector3t multiply( const pod::Matrix4t& mat, const pod::Vector3t& vector, T w = 1, bool = false ); - template pod::Vector4t multiply( const pod::Matrix4t& mat, const pod::Vector4t& vector, bool = false ); + template pod::Vector2t multiply(const pod::Matrix2t& mat, const pod::Vector2t& v ); + template pod::Vector3t multiply(const pod::Matrix3t& mat, const pod::Vector3t& v ); + template pod::Vector3t multiply( const pod::Matrix4t& mat, const pod::Vector3t& vector, T w = 1, bool = false ); + template pod::Vector4t multiply( const pod::Matrix4t& mat, const pod::Vector4t& vector, bool = false ); template T /*UF_API*/ multiplyAll( const T& matrix, typename T::type_t scalar ); template T /*UF_API*/ add( const T& lhs, const T& rhs ); - // Writes to first value - template T& /*UF_API*/ invert( T& matrix ); // Flip sign of all components - // template pod::Matrix& /*UF_API*/ multiply_( T& left, const T& right ); // Multiplies two matrices of same type and size together - template pod::Matrix multiply_( T& left, const U& right ); // Multiplies two matrices of same type and size together + + template T& /*UF_API*/ inverse_( T& matrix ); + template pod::Matrix multiply_( T& left, const U& right ); template pod::Matrix multiply_( T& left, const T& right ); template T& /*UF_API*/ translate_( T& matrix, const pod::Vector3t& vector ); template T& /*UF_API*/ rotate_( T& matrix, const pod::Vector3t& vector ); template T& /*UF_API*/ scale_( T& matrix, const pod::Vector3t& vector ); - // Complex arithmetic + template T /*UF_API*/ translate( const T& matrix, const pod::Vector3t& vector ); template T /*UF_API*/ rotate( const T& matrix, const pod::Vector3t& vector ); template T /*UF_API*/ scale( const T& matrix, const pod::Vector3t& vector ); template pod::Vector3t /*UF_API*/ eulerAngles( const T& matrix ); - template pod::Matrix4t /*UF_API*/ orthographic( T, T, T, T, T, T ); - template pod::Matrix4t /*UF_API*/ orthographic( T, T, T, T ); - template pod::Matrix4t inline /*UF_API*/ orthographic( const pod::Vector2t& lr, const pod::Vector2t& bt, const pod::Vector2t& nf ) { + template pod::Matrix4t /*UF_API*/ orthographic( T, T, T, T, T, T ); + template pod::Matrix4t /*UF_API*/ orthographic( T, T, T, T ); + template pod::Matrix4t inline /*UF_API*/ orthographic( const pod::Vector2t& lr, const pod::Vector2t& bt, const pod::Vector2t& nf ) { return orthographic( lr.x, lr.y, bt.x, bt.y, nf.x, nf.y ); } - template pod::Matrix4t inline /*UF_API*/ orthographic( const pod::Vector2t& lr, const pod::Vector2t& bt ) { + template pod::Matrix4t inline /*UF_API*/ orthographic( const pod::Vector2t& lr, const pod::Vector2t& bt ) { return orthographic( lr.x, lr.y, bt.x, bt.y ); } - template pod::Matrix4t /*UF_API*/ perspective( T, T, T, T ); - template pod::Matrix4t inline /*UF_API*/ perspective( T fov, T raidou, const pod::Vector2f& range ) { + template pod::Matrix4t /*UF_API*/ perspective( T, T, T, T ); + template pod::Matrix4t inline /*UF_API*/ perspective( T fov, T raidou, const pod::Vector2f& range ) { return perspective( fov, raidou, range.x, range.y ); } - template pod::Matrix4t inline /*UF_API*/ perspective( T fov, const pod::Vector2ui& size, const pod::Vector2f& range ) { + template pod::Matrix4t inline /*UF_API*/ perspective( T fov, const pod::Vector2ui& size, const pod::Vector2f& range ) { return perspective( fov, (T) size.x / (T) size.y, range.x, range.y ); } // Setting @@ -124,82 +111,6 @@ namespace uf { } } -#if UF_USE_CLASS_OF_PODS -namespace uf { - template - class /*UF_API*/ Matrix { - public: - // Easily access POD's type - typedef pod::Matrix pod_t; - // Replicate POD information - typedef T type_t; - typedef T* container_t; - static const uint_fast8_t rows = R; - static const uint_fast8_t columns = C; - protected: - // POD storage - Matrix::pod_t m_pod; - public: - // C-tor - Matrix(); // initializes POD to 'def' - Matrix(const Matrix::pod_t& pod); // copies POD altogether - Matrix(const T components[R][C]); // copies data into POD from 'components' (typed as C array) - Matrix(const T components[R*C]); // copies data into POD from 'components' (typed as C array) - Matrix(const uf::stl::vector& components); // copies data into POD from 'components' (typed as std::matrix) - // D-tor - // Unneccesary - // POD access - Matrix::pod_t& data(); // Returns a reference of POD - const Matrix::pod_t& data() const; // Returns a const-reference of POD - - template typename Matrix::pod_t convert() const; // Returns a POD converted - // Alternative POD access - T* get(); // Returns a pointer to the entire array - const T* get() const; // Returns a const-pointer to the entire array - T& getComponent( uint_fast8_t i ); // Returns a reference to a single element - const T& getComponent( uint_fast8_t i ) const; // Returns a const-reference to a single element - // POD manipulation - T* set(const T components[R][C]); // Sets the entire array - T* set(const T components[R*C]); // Sets the entire array - T& setComponent( uint_fast8_t i, const T& value ); // Sets a single element - // Validation - bool isValid() const; // Checks if all components are valid (non NaN, inf, etc.) - // Basic arithmetic - inline uf::Matrix multiply( const Matrix& matrix ) const; // Multiplies two matrices of same type and size together - inline uf::Matrix multiply( const Matrix& matrix ); // Multiplies two matrices of same type and size together - inline pod::Vector3t multiply( const pod::Vector3t& vector ) const; - inline pod::Vector4t multiply( const pod::Vector4t& vector ) const; - inline uf::Matrix& negate(); // Flip sign of all components - inline uf::Matrix& translate( const pod::Vector3t& vector ); - inline uf::Matrix& rotate( const pod::Vector3t& vector ); - inline uf::Matrix& scale( const pod::Vector3t& vector ); - inline uf::Matrix& invert(); - inline uf::Matrix inverse() const; - template - inline uf::Matrix multiply( const U& matrix ) const; // Multiplies two matrices of same type and size together - template - inline uf::Matrix multiply( const U& matrix ); // Multiplies two matrices of same type and size together - // Overloaded ops - // Accessing via subscripts - T& operator[](uint_fast8_t i); - const T& operator[](uint_fast8_t i) const; - // Arithmetic - inline Matrix operator-() const; // Negation - inline Matrix operator*( const Matrix& matrix ) const; // Multiplication between two matrices - inline Matrix& operator *=( const Matrix& matrix ); // Multiplication set between two matrices - template inline Matrix operator*( const U& matrix ) const; // Multiplication between two matrices - inline bool operator==( const Matrix& matrix ) const; // Equality check between two matrices (equals) - inline bool operator!=( const Matrix& matrix ) const; // Equality check between two matrices (not equals) - - inline operator pod_t&() { return this->m_pod; } - inline operator const pod_t&() const { return this->m_pod; } - }; - template using Matrix4t = Matrix; - typedef Matrix4t<> Matrix4; - typedef Matrix4t Matrix4f; -} -#endif - #include namespace uf { namespace string { diff --git a/engine/inc/uf/utils/math/matrix/class.inl b/engine/inc/uf/utils/math/matrix/class.inl deleted file mode 100644 index 27af2b0e..00000000 --- a/engine/inc/uf/utils/math/matrix/class.inl +++ /dev/null @@ -1,207 +0,0 @@ -// C-tor -// initializes POD to 'def' -template -uf::Matrix::Matrix() { - this->m_pod = uf::matrix::identityi(); -} -// copies POD altogether -template -uf::Matrix::Matrix(const Matrix::pod_t& pod ) : - m_pod(pod) -{ -} -// copies data into POD from 'components' (typed as C array) -template -uf::Matrix::Matrix(const T components[R][C] ) { - this->set(components); -} -template -uf::Matrix::Matrix(const T components[R*C] ) { - this->set(components); -} -// copies data into POD from 'components' (typed as std::matrix) -template -uf::Matrix::Matrix(const uf::stl::vector& components ) { - this->m_pod = uf::matrix::initialize( components ); -} -// D-tor -// Unneccesary -// POD access -// Returns a reference of POD -template -typename uf::Matrix::pod_t& uf::Matrix::data() { - return this->m_pod; -} -// Returns a const-reference of POD -template -const typename uf::Matrix::pod_t& uf::Matrix::data() const { - return this->m_pod; -} -// Returns a const-reference of POD -template -template -typename uf::Matrix::pod_t uf::Matrix::convert() const { - typename uf::Matrix::pod_t converted; - for ( uint_fast8_t i = 0; i < R*C; ++i ) - converted.components[i] = (float) this->m_pod.components[i]; - return converted; -} -// Alternative POD access -// Returns a pointer to the entire array -template -T* uf::Matrix::get() { - return (T*) this->m_pod.components; -} -// Returns a const-pointer to the entire array -template -const T* uf::Matrix::get() const { - return (T*) this->m_pod.components; -} -// Returns a reference to a single element -template -T& uf::Matrix::getComponent( uint_fast8_t i ) { - return this->m_pod.components[i]; -} -// Returns a const-reference to a single element -template -const T& uf::Matrix::getComponent( uint_fast8_t i ) const { - return this->m_pod.components[i]; -} -// POD manipulation -// Sets the entire array -template -T* uf::Matrix::set(const T components[R][C] ) { - for ( uint_fast8_t r = 0; r < R; ++r ) - for ( uint_fast8_t c = 0; c < C; ++c ) - this->m_pod.components[r+c*C] = components[r][c]; - - return (T*) this->m_pod.components; -} -template -T* uf::Matrix::set(const T components[R*C] ) { -// memcpy( this->m_pod.components, components, sizeof(this->m_pod) ); - for ( uint_fast8_t i = 0; i < R*C; ++i ) - this->m_pod.components[i] = components[i]; -/* - for ( size_t r = 0; r < R; ++r ) - for ( size_t c = 0; c < C; ++c ) - this->m_pod.components[r+c*C] = components[r+c*C]; -*/ - - return (T*) this->m_pod.components; -} -// Sets a single element -template -T& uf::Matrix::setComponent( uint_fast8_t i, const T& value ) { - this->m_pod.components[i] = value; -} -// Validation -// Checks if all components are valid (non NaN, inf, etc.) -template -bool uf::Matrix::isValid() const { - T val; - for ( uint_fast8_t i = 0; i < R * C; ++i ) - if ( (val = this->m_pod.components[i]) != val ) return false; - return true; -} -// Basic arithmetic -// Multiplies two matrices of same type and size together -template -inline uf::Matrix uf::Matrix::multiply( const Matrix& matrix ) { - return uf::matrix::multiply(this->m_pod, matrix.data()); -} -template -inline uf::Matrix uf::Matrix::multiply( const Matrix& matrix ) const { - return uf::matrix::multiply(this->m_pod, matrix.data()); -} -// Flip sign of all components -template -inline uf::Matrix& uf::Matrix::translate( const pod::Vector3t& vector ) { - uf::matrix::translate(this->m_pod, vector); - return *this; -} -template -inline uf::Matrix& uf::Matrix::rotate( const pod::Vector3t& vector ) { - uf::matrix::rotate(this->m_pod, vector); - return *this; -} -template -inline uf::Matrix& uf::Matrix::scale( const pod::Vector3t& vector ) { - uf::matrix::scale(this->m_pod, vector); - return *this; -} -template -inline uf::Matrix& uf::Matrix::invert() { - return uf::matrix::invert(this->m_pod); -} -template -inline uf::Matrix uf::Matrix::inverse() const { - return uf::matrix::inverse(this->m_pod); -} - -template -template inline uf::Matrix uf::Matrix::multiply( const U& matrix ) const { - return uf::matrix::multiply(this->m_pod, matrix.data()); -} -template -template inline uf::Matrix uf::Matrix::multiply( const U& matrix ) { - return uf::matrix::multiply(this->m_pod, matrix.data()); -} -template -inline pod::Vector3t uf::Matrix::multiply( const pod::Vector3t& vector ) const { - return uf::matrix::multiply(this->m_pod, vector); -} -template -inline pod::Vector4t uf::Matrix::multiply( const pod::Vector4t& vector ) const { - return uf::matrix::multiply(this->m_pod, vector); -} -// Overloaded ops -// Accessing via subscripts -/* -template -T* uf::Matrix::operator[](size_t i) { - return this->m_pod[i]; -} -template -const T* uf::Matrix::operator[](size_t i) const { - return this->m_pod[i]; -} -*/ -template -T& uf::Matrix::operator[](uint_fast8_t i) { - return this->m_pod[i]; -} -template -const T& uf::Matrix::operator[](uint_fast8_t i) const { - return this->m_pod[i]; -} -// Arithmetic -// Negation -template -inline uf::Matrix uf::Matrix::operator-() const { - return this->inverse(); -} -// Multiplication between two matrices -template -inline uf::Matrix uf::Matrix::operator*( const Matrix& matrix ) const { - return this->multiply(matrix); -} -// Multiplication set between two matrices -template -inline uf::Matrix& uf::Matrix::operator *=( const Matrix& matrix ) { - return this->multiply(matrix); -} -template -template inline uf::Matrix uf::Matrix::operator*( const U& matrix ) const { - return this->multiply(matrix); -} -// Equality check between two matrices (equals) -template -inline bool uf::Matrix::operator==( const Matrix& matrix ) const { - return uf::matrix::equals( this->m_pod, matrix.m_pod ); -} -// Equality check between two matrices (not equals) -template -inline bool uf::Matrix::operator!=( const Matrix& matrix ) const { - return !uf::matrix::equals( this->m_pod, matrix.m_pod ); -} \ No newline at end of file diff --git a/engine/inc/uf/utils/math/matrix/pod.inl b/engine/inc/uf/utils/math/matrix/pod.inl index e6dae32e..c1d03f87 100644 --- a/engine/inc/uf/utils/math/matrix/pod.inl +++ b/engine/inc/uf/utils/math/matrix/pod.inl @@ -1,171 +1,101 @@ -#if !__clang__ && __GNUC__ - #pragma GCC push_options - #pragma GCC optimize ("unroll-loops") -#endif +#define FOR_EACH_2D( R, C, F ) for_each_index([&](auto r) { for_each_index([&](auto c) F ); }); +#define ROW_MAJOR_INDEX( R, C, r, c ) (r * C + c) +#define COL_MAJOR_INDEX( R, C, r, c ) (c * R + r) + +#define INDEX( R, C, r, c ) COL_MAJOR_INDEX( R, C, r, c ) -// Overloaded ops -// Accessing via subscripts template -inline T& pod::Matrix::operator[](uint_fast8_t i) { -// static T null = 0.0/0.0; -// if ( i >= R*C ) return null; +inline T& pod::Matrix::operator[](size_t i) { return this->components[i]; } template -inline const T& pod::Matrix::operator[](uint_fast8_t i) const { -// static T null = 0.0/0.0; -// if ( i >= R*C ) return null; +inline const T& pod::Matrix::operator[](size_t i) const { return this->components[i]; } template -pod::Matrix pod::Matrix::operator()() const { - pod::Matrix matrix; - #pragma unroll // GCC unroll C - for ( uint_fast8_t c = 0; c < C; ++c ) - #pragma unroll // GCC unroll R - for ( uint_fast8_t r = 0; r < R; ++r ) - matrix[r+c*C] = (r == c ? 1 : 0); - return matrix; +inline T& pod::Matrix::operator()(size_t r, size_t c) { + return this->components[INDEX( R, C, r, c )]; } template -inline T& pod::Matrix::operator()(uint_fast8_t r, uint_fast8_t c) { - return this->components[r+c*C]; +inline const T& pod::Matrix::operator()(size_t r, size_t c) const { + return this->components[INDEX( R, C, r, c )]; } -template -inline const T& pod::Matrix::operator()(uint_fast8_t r, uint_fast8_t c) const { - return this->components[r+c*C]; -} -/* -template -T* pod::Matrix::operator[](size_t i) { - return this->components[i]; -} -template -const T* pod::Matrix::operator[](size_t i) const { - return this->components[i]; -} -*/ + template pod::Matrix4t /*UF_API*/ uf::matrix::identity() { - ALIGN16 pod::Matrix4t matrix; - #pragma unroll // GCC unroll 4 - for ( uint_fast8_t c = 0; c < 4; ++c ) - #pragma unroll // GCC unroll 4 - for ( uint_fast8_t r = 0; r < 4; ++r ) - matrix[r+c*4] = (r == c ? 1 : 0); + pod::Matrix4t matrix; + FOR_EACH_2D(4, 4, { + matrix(r, c) = (r == c ? T{1} : T{0}); + }); return matrix; } template pod::Matrix4t /*UF_API*/ uf::matrix::initialize( const T* list ) { - ALIGN16 pod::Matrix4t matrix; -// memcpy(&matrix[0], list, sizeof(matrix)); - #pragma unroll // GCC unroll 16 - for ( uint_fast8_t i = 0; i < 16; ++i ) + pod::Matrix4t matrix; + FOR_EACH(16, { matrix.components[i] = list[i]; + }); -/* - for ( uint_fast8_t r = 0; r < 4; ++r ) - for ( uint_fast8_t c = 0; c < 4; ++c ) - matrix[r+c*4] = list[r+c*4]; -*/ return matrix; } template pod::Matrix4t /*UF_API*/ uf::matrix::initialize( const uf::stl::vector& list ) { - ALIGN16 pod::Matrix4t matrix; + pod::Matrix4t matrix; if ( list.size() != 16 ) return matrix; -// memcpy(&matrix[0], &list[0], sizeof(matrix)); - #pragma unroll // GCC unroll 16 - for ( uint_fast8_t i = 0; i < 16; ++i ) + FOR_EACH(16, { matrix.components[i] = list[i]; + }); -/* - #pragma unroll // GCC unroll 4 - for ( uint_fast8_t r = 0; r < 4; ++r ) - #pragma unroll // GCC unroll 4 - for ( uint_fast8_t c = 0; c < 4; ++c ) - matrix[r+c*4] = list[r+c*4]; -*/ return matrix; } template pod::Matrix uf::matrix::identityi(){ - ALIGN16 pod::Matrix matrix; - - #pragma unroll // GCC unroll T::columns - for ( uint_fast8_t c = 0; c < T::columns; ++c ) - #pragma unroll // GCC unroll T::rows - for ( uint_fast8_t r = 0; r < T::rows; ++r ) - matrix[r+c*T::columns] = (r == c ? 1 : 0); - + pod::Matrix matrix; + FOR_EACH_2D(T::rows, T::columns, { + matrix(r, c) = (r == c ? 1 : 0); + }); return matrix; } -// Arithmetic -// Negation -template -inline pod::Matrix pod::Matrix::operator-() const { - return uf::matrix::inverse(*this); -} -// Multiplication between two matrices template inline pod::Matrix pod::Matrix::operator*( const Matrix& matrix ) const { return uf::matrix::multiply(*this, matrix); } -// Multiplication between two matrices template inline pod::Matrix pod::Matrix::operator*( T scalar ) const { return uf::matrix::multiplyAll(*this, scalar); } -// Multiplication between two matrices template inline pod::Matrix pod::Matrix::operator+( const Matrix& matrix ) const { return uf::matrix::add(*this, matrix); } -// Multiplication set between two matrices template -inline pod::Matrix& pod::Matrix::operator *=( const Matrix& matrix ) { - return uf::matrix::multiply(*this, matrix); +inline pod::Matrix& pod::Matrix::operator*=( const Matrix& matrix ) { + return uf::matrix::multiply_(*this, matrix); } -// Equality check between two matrices (equals) template inline bool pod::Matrix::operator==( const Matrix& matrix ) const { return uf::matrix::equals( *this, matrix ); } -// Equality check between two matrices (not equals) template inline bool pod::Matrix::operator!=( const Matrix& matrix ) const { return !uf::matrix::equals( *this, matrix ); } - -// Equality checking -// Equality check between two matrices (less than) -template int uf::matrix::compareTo( const T& left, const T& right ) { - return memcmp( &left[0], &right[0], sizeof(left) ); -} -// Equality check between two matrices (equals) -template bool uf::matrix::equals( const T& left, const T& right ) { - return uf::matrix::compareTo(left, right) == 0; -} template bool uf::matrix::equals( const T& left, const T& right, float eps ) { - bool equals = true; - for ( size_t i = 0; i < 16; ++i ) { - if ( abs(left[i] - right[i]) <= eps ) continue; - equals = false; - break; - } - return equals; + bool result = true; + FOR_EACH(T::rows * T::columns, { + if ( fabs(left[i] - right[i]) > eps ) result = false; + }); + return result; } -// Basic arithmetic -// Multiplies two matrices of same type and size together template pod::Matrix uf::matrix::multiply( const pod::Matrix& left, const pod::Matrix& right ) { - ALIGN16 pod::Matrix res; + pod::Matrix res; + #if UF_USE_SIMD auto row1 = uf::simd::load(&left[0]); auto row2 = uf::simd::load(&left[4]); auto row3 = uf::simd::load(&left[8]); auto row4 = uf::simd::load(&left[12]); - #pragma unroll // GCC unroll 4 - for( uint_fast8_t i = 0; i < 4; i++) { + FOR_EACH(4, { auto brod1 = uf::simd::set(right[4*i + 0]); auto brod2 = uf::simd::set(right[4*i + 1]); auto brod3 = uf::simd::set(right[4*i + 2]); @@ -178,7 +108,7 @@ template pod::Matrix uf::matrix::multiply( const pod::Matrix< uf::simd::mul(brod3, row3), uf::simd::mul(brod4, row4))); uf::simd::store(row, &res[4*i]); - } + }); return res; #elif UF_ENV_DREAMCAST @@ -191,40 +121,15 @@ template pod::Matrix uf::matrix::multiply( const pod::Matrix< // MATH_Load_Matrix_Product( (ALL_FLOATS_STRUCT*) &left[0], (ALL_FLOATS_STRUCT*) &right[0] ); // MATH_Store_XMTRX( (ALL_FLOATS_STRUCT*) &res[0]); return res; -#elif 0 - // - float* dstPtr = &res[0]; - const float* leftPtr = &right[0]; - - #pragma unroll // GCC unroll 4 - for (uint_fast8_t i = 0; i < 4; ++i) { - #pragma unroll // GCC unroll 4 - for (uint_fast8_t j = 0; j < 4; ++j) { - const float* rightPtr = &left[0] + j; - - float sum = leftPtr[0] * rightPtr[0]; - #pragma unroll // GCC unroll 3 - for (uint_fast8_t n = 1; n < 4; ++n) { - rightPtr += 4; - sum += leftPtr[n] * rightPtr[0]; - } - *dstPtr++ = sum; +#else +#if 1 + FOR_EACH_2D(4, 4, { + T sum = T{0}; + for (size_t k = 0; k < 4; ++k) { + sum += left(r, k) * right(k, c); } - leftPtr += 4; - } - return res; -#elif 0 - // don't know if it's more performant than below - uint_fast8_t i = 0; - - #pragma unroll // GCC unroll 4 - for ( uint_fast8_t c = 0; c < 4; c++ ) { - #pragma unroll // GCC unroll 4 - for ( uint_fast8_t r = 0; r < 4; r++ ) { - res[i++] = uf::vector::dot( { right[0+c*4], right[1+c*4], right[2+c*4], right[3+c*4] }, { left[r+0*4], left[r+1*4], left[r+2*4], left[r+3*4] } ); - } - } - + res(r, c) = sum; + }); return res; #else // it works @@ -249,22 +154,23 @@ template pod::Matrix uf::matrix::multiply( const pod::Matrix< dst3 = srcA0 * srcB3[0] + srcA1 * srcB3[1] + srcA2 * srcB3[2] + srcA3 * srcB3[3]; return res; #endif +#endif } template pod::Matrix uf::matrix::multiply( const T& left, const U& right ) { - ALIGN16 pod::Matrix res; -#if 1 + pod::Matrix res; + float* dstPtr = &res[0]; - const float* leftPtr = &right[0]; + const float* leftPtr = &left[0]; #pragma unroll // GCC unroll T::rows - for (uint_fast8_t i = 0; i < T::rows; ++i) { + for ( auto i = 0; i < T::rows; ++i) { #pragma unroll // GCC unroll T::columns - for (uint_fast8_t j = 0; j < T::columns; ++j) { - const float* rightPtr = &left[0] + j; + for ( auto j = 0; j < T::columns; ++j) { + const float* rightPtr = &right[0] + j; float sum = leftPtr[0] * rightPtr[0]; #pragma unroll // GCC unroll T::columns - 1 - for (uint_fast8_t n = 1; n < T::columns; ++n) { + for ( auto n = 1; n < T::columns; ++n) { rightPtr += T::columns; sum += leftPtr[n] * rightPtr[0]; } @@ -273,51 +179,35 @@ template pod::Matrix T /*UF_API*/ uf::matrix::multiplyAll( const T& m, typename T::type_t scalar ) { - ALIGN16 T matrix; - #pragma unroll // GCC unroll T::rows * T::columns - for ( uint_fast8_t i = 0; i < T::rows * T::columns; ++i ) + T matrix; + + FOR_EACH(T::rows * T::columns, { matrix[i] = m[i] * scalar; + }); return matrix; } template T /*UF_API*/ uf::matrix::add( const T& lhs, const T& rhs ) { - ALIGN16 T matrix; - #pragma unroll // GCC unroll T::rows * T::columns - for ( uint_fast8_t i = 0; i < T::rows * T::columns; ++i ) + T matrix; + + FOR_EACH(T::rows * T::columns, { matrix[i] = lhs[i] + rhs[i]; + }); return matrix; } -// Transpose matrix template T uf::matrix::transpose( const T& matrix ) { - ALIGN16 T transpose; - - #pragma unroll // GCC unroll T::rows - for ( typename T::type_t r = 0; r < T::rows; ++r ) - #pragma unroll // GCC unroll T::columns - for ( typename T::type_t c = 0; c < T::columns; ++c ) - transpose[c * T::rows + r] = matrix[r * T::columns + c]; + T transpose; + FOR_EACH_2D(T::rows, T::columns, { + transpose(c, r) = matrix(r, c); + }); return transpose; } -// template pod::Matrix2t uf::matrix::inverse( const pod::Matrix2t& m ) { T det = m[0] * m[3] - m[1] * m[2]; if ( std::fabs(det) < 1e-12f ) return m; @@ -331,98 +221,37 @@ template pod::Matrix2t uf::matrix::inverse( const pod::Matrix2t pod::Matrix3t uf::matrix::inverse( const pod::Matrix3t& m ) { -// matrix elements const T* a = &m[0]; - T det = a[0]*(a[4]*a[8] - a[5]*a[7]) - - a[1]*(a[3]*a[8] - a[5]*a[6]) - + a[2]*(a[3]*a[7] - a[4]*a[6]); - - if (std::fabs(det) < 1e-12f) return m; // singular - + T det = a[0]*(a[4]*a[8] - a[5]*a[7]) - a[1]*(a[3]*a[8] - a[5]*a[6]) + a[2]*(a[3]*a[7] - a[4]*a[6]); + if ( std::fabs(det) < 1e-12f ) return m; // singular T invDet = static_cast(1) / det; - return pod::Matrix3t{ - (a[4]*a[8] - a[5]*a[7]) * invDet, - (a[2]*a[7] - a[1]*a[8]) * invDet, - (a[1]*a[5] - a[2]*a[4]) * invDet, - - (a[5]*a[6] - a[3]*a[8]) * invDet, - (a[0]*a[8] - a[2]*a[6]) * invDet, - (a[2]*a[3] - a[0]*a[5]) * invDet, - - (a[3]*a[7] - a[4]*a[6]) * invDet, - (a[1]*a[6] - a[0]*a[7]) * invDet, - (a[0]*a[4] - a[1]*a[3]) * invDet, + (a[4]*a[8] - a[5]*a[7]) * invDet, (a[2]*a[7] - a[1]*a[8]) * invDet, (a[1]*a[5] - a[2]*a[4]) * invDet, + (a[5]*a[6] - a[3]*a[8]) * invDet, (a[0]*a[8] - a[2]*a[6]) * invDet, (a[2]*a[3] - a[0]*a[5]) * invDet, + (a[3]*a[7] - a[4]*a[6]) * invDet, (a[1]*a[6] - a[0]*a[7]) * invDet, (a[0]*a[4] - a[1]*a[3]) * invDet, }; } template pod::Matrix4t uf::matrix::inverse( const pod::Matrix4t& m ) { const T* a = &m[0]; - ALIGN16 pod::Matrix4t inv; + pod::Matrix4t inv; - inv[0] = a[5] * (a[10]*a[15] - a[11]*a[14]) - - a[9] * (a[6]*a[15] - a[7]*a[14]) + - a[13]* (a[6]*a[11] - a[7]*a[10]); - - inv[4] = - a[4] * (a[10]*a[15] - a[11]*a[14]) + - a[8] * (a[6]*a[15] - a[7]*a[14]) - - a[12]* (a[6]*a[11] - a[7]*a[10]); - - inv[8] = a[4] * (a[9]*a[15] - a[11]*a[13]) - - a[8] * (a[5]*a[15] - a[7]*a[13]) + - a[12]* (a[5]*a[11] - a[7]*a[9]); - - inv[12] = - a[4] * (a[9]*a[14] - a[10]*a[13]) + - a[8] * (a[5]*a[14] - a[6]*a[13]) - - a[12]* (a[5]*a[10] - a[6]*a[9]); - - inv[1] = - a[1] * (a[10]*a[15] - a[11]*a[14]) + - a[9] * (a[2]*a[15] - a[3]*a[14]) - - a[13]* (a[2]*a[11] - a[3]*a[10]); - - inv[5] = a[0] * (a[10]*a[15] - a[11]*a[14]) - - a[8] * (a[2]*a[15] - a[3]*a[14]) + - a[12]* (a[2]*a[11] - a[3]*a[10]); - - inv[9] = - a[0] * (a[9]*a[15] - a[11]*a[13]) + - a[8] * (a[1]*a[15] - a[3]*a[13]) - - a[12]* (a[1]*a[11] - a[3]*a[9]); - - inv[13] = a[0] * (a[9]*a[14] - a[10]*a[13]) - - a[8] * (a[1]*a[14] - a[2]*a[13]) + - a[12]* (a[1]*a[10] - a[2]*a[9]); - - inv[2] = a[1] * (a[6]*a[15] - a[7]*a[14]) - - a[5] * (a[2]*a[15] - a[3]*a[14]) + - a[13]* (a[2]*a[7] - a[3]*a[6]); - - inv[6] = - a[0] * (a[6]*a[15] - a[7]*a[14]) + - a[4] * (a[2]*a[15] - a[3]*a[14]) - - a[12]* (a[2]*a[7] - a[3]*a[6]); - - inv[10] = a[0] * (a[5]*a[15] - a[7]*a[13]) - - a[4] * (a[1]*a[15] - a[3]*a[13]) + - a[12]* (a[1]*a[7] - a[3]*a[5]); - - inv[14] = - a[0] * (a[5]*a[14] - a[6]*a[13]) + - a[4] * (a[1]*a[14] - a[2]*a[13]) - - a[12]* (a[1]*a[6] - a[2]*a[5]); - - inv[3] = - a[1] * (a[6]*a[11] - a[7]*a[10]) + - a[5] * (a[2]*a[11] - a[3]*a[10]) - - a[9] * (a[2]*a[7] - a[3]*a[6]); - - inv[7] = a[0] * (a[6]*a[11] - a[7]*a[10]) - - a[4] * (a[2]*a[11] - a[3]*a[10]) + - a[8] * (a[2]*a[7] - a[3]*a[6]); - - inv[11] = - a[0] * (a[5]*a[11] - a[7]*a[9]) + - a[4] * (a[1]*a[11] - a[3]*a[9]) - - a[8] * (a[1]*a[7] - a[3]*a[5]); - - inv[15] = a[0] * (a[5]*a[10] - a[6]*a[9]) - - a[4] * (a[1]*a[10] - a[2]*a[9]) + - a[8] * (a[1]*a[6] - a[2]*a[5]); + inv[0] = a[5] * (a[10]*a[15] - a[11]*a[14]) - a[9] * (a[6]*a[15] - a[7]*a[14]) + a[13]* (a[6]*a[11] - a[7]*a[10]); + inv[4] = - a[4] * (a[10]*a[15] - a[11]*a[14]) + a[8] * (a[6]*a[15] - a[7]*a[14]) - a[12]* (a[6]*a[11] - a[7]*a[10]); + inv[8] = a[4] * (a[9]*a[15] - a[11]*a[13]) - a[8] * (a[5]*a[15] - a[7]*a[13]) + a[12]* (a[5]*a[11] - a[7]*a[9]); + inv[12] = - a[4] * (a[9]*a[14] - a[10]*a[13]) + a[8] * (a[5]*a[14] - a[6]*a[13]) - a[12]* (a[5]*a[10] - a[6]*a[9]); + inv[1] = - a[1] * (a[10]*a[15] - a[11]*a[14]) + a[9] * (a[2]*a[15] - a[3]*a[14]) - a[13]* (a[2]*a[11] - a[3]*a[10]); + inv[5] = a[0] * (a[10]*a[15] - a[11]*a[14]) - a[8] * (a[2]*a[15] - a[3]*a[14]) + a[12]* (a[2]*a[11] - a[3]*a[10]); + inv[9] = - a[0] * (a[9]*a[15] - a[11]*a[13]) + a[8] * (a[1]*a[15] - a[3]*a[13]) - a[12]* (a[1]*a[11] - a[3]*a[9]); + inv[13] = a[0] * (a[9]*a[14] - a[10]*a[13]) - a[8] * (a[1]*a[14] - a[2]*a[13]) + a[12]* (a[1]*a[10] - a[2]*a[9]); + inv[2] = a[1] * (a[6]*a[15] - a[7]*a[14]) - a[5] * (a[2]*a[15] - a[3]*a[14]) + a[13]* (a[2]*a[7] - a[3]*a[6]); + inv[6] = - a[0] * (a[6]*a[15] - a[7]*a[14]) + a[4] * (a[2]*a[15] - a[3]*a[14]) - a[12]* (a[2]*a[7] - a[3]*a[6]); + inv[10] = a[0] * (a[5]*a[15] - a[7]*a[13]) - a[4] * (a[1]*a[15] - a[3]*a[13]) + a[12]* (a[1]*a[7] - a[3]*a[5]); + inv[14] = - a[0] * (a[5]*a[14] - a[6]*a[13]) + a[4] * (a[1]*a[14] - a[2]*a[13]) - a[12]* (a[1]*a[6] - a[2]*a[5]); + inv[3] = - a[1] * (a[6]*a[11] - a[7]*a[10]) + a[5] * (a[2]*a[11] - a[3]*a[10]) - a[9] * (a[2]*a[7] - a[3]*a[6]); + inv[7] = a[0] * (a[6]*a[11] - a[7]*a[10]) - a[4] * (a[2]*a[11] - a[3]*a[10]) + a[8] * (a[2]*a[7] - a[3]*a[6]); + inv[11] = - a[0] * (a[5]*a[11] - a[7]*a[9]) + a[4] * (a[1]*a[11] - a[3]*a[9]) - a[8] * (a[1]*a[7] - a[3]*a[5]); + inv[15] = a[0] * (a[5]*a[10] - a[6]*a[9]) - a[4] * (a[1]*a[10] - a[2]*a[9]) + a[8] * (a[1]*a[6] - a[2]*a[5]); // determinant T det = a[0]*inv[0] + a[1] * inv[4] + a[2] * inv[8] + a[3] * inv[12]; @@ -433,171 +262,184 @@ template pod::Matrix4t uf::matrix::inverse( const pod::Matrix4t pod::Vector3t uf::matrix::multiply( const pod::Matrix4t& mat, const pod::Vector3t& vector, T w, bool div ) { - return uf::matrix::multiply( mat, pod::Vector4t{ vector[0], vector[1], vector[2], w }, div ); +template pod::Vector3t uf::matrix::multiply( const pod::Matrix4t& mat, const pod::Vector3t& v, T w, bool div ) { + auto res4 = uf::matrix::multiply(mat, pod::Vector4t{ v[0], v[1], v[2], w }, div); + return pod::Vector3t{ res4[0], res4[1], res4[2] }; } template pod::Vector2t uf::matrix::multiply(const pod::Matrix2t& mat, const pod::Vector2t& v ) { return pod::Vector2t{ - v[0]* mat[0] + v[1]* mat[2], - v[0]* mat[1] + v[1]* mat[3], - }; + v[0] * mat(0,0) + v[1] * mat(0,1), + v[0] * mat(1,0) + v[1] * mat(1,1) + }; } template pod::Vector3t uf::matrix::multiply(const pod::Matrix3t& mat, const pod::Vector3t& v ) { return pod::Vector3t{ - v[0]* mat[0] + v[1]* mat[3] + v[2] * mat[6], - v[0]* mat[1] + v[1]* mat[4] + v[2] * mat[7], - v[0]* mat[2] + v[1]* mat[5] + v[2] * mat[8], + v[0] * mat(0,0) + v[1] * mat(0,1) + v[2] * mat(0,2), + v[0] * mat(1,0) + v[1] * mat(1,1) + v[2] * mat(1,2), + v[0] * mat(2,0) + v[1] * mat(2,1) + v[2] * mat(2,2) }; } -template pod::Vector4t uf::matrix::multiply( const pod::Matrix4t& mat, const pod::Vector4t& vector, bool div ) { +template pod::Vector4t uf::matrix::multiply( const pod::Matrix4t& mat, const pod::Vector4t& v, bool div ) { #if UF_ENV_DREAMCAST MATH_Load_XMTRX( (ALL_FLOATS_STRUCT*) &mat[0] ); - auto t = MATH_Matrix_Transform( vector[0], vector[1], vector[2], vector[3] ); + auto t = MATH_Matrix_Transform( v[0], v[1], v[2], v[3] ); auto res = *((pod::Vector4t*) &t); if ( div && res.w > 0 ) res /= res.w; return res; #else - ALIGN16 auto res = pod::Vector4t{ - vector[0] * mat[0] + vector[1] * mat[4] + vector[2] * mat[8] + vector[3] * mat[12], - vector[0] * mat[1] + vector[1] * mat[5] + vector[2] * mat[9] + vector[3] * mat[13], - vector[0] * mat[2] + vector[1] * mat[6] + vector[2] * mat[10] + vector[3] * mat[14], - vector[0] * mat[3] + vector[1] * mat[7] + vector[2] * mat[11] + vector[3] * mat[15] + auto res = pod::Vector4t{ + v[0] * mat(0,0) + v[1] * mat(0,1) + v[2] * mat(0,2) + v[3] * mat(0,3), + v[0] * mat(1,0) + v[1] * mat(1,1) + v[2] * mat(1,2) + v[3] * mat(1,3), + v[0] * mat(2,0) + v[1] * mat(2,1) + v[2] * mat(2,2) + v[3] * mat(2,3), + v[0] * mat(3,0) + v[1] * mat(3,1) + v[2] * mat(3,2) + v[3] * mat(3,3) }; if ( div && res.w > 0 ) res /= res.w; return res; #endif } -// Writes to first value -template T& uf::matrix::invert( T& matrix ) { - return matrix = uf::matrix::inverse((const T&) matrix); + +// functions that serve as the basis to creating SRT matrices, specifically for applying to an identity matrix +template T uf::matrix::translate( const T& matrix, const pod::Vector3t& vector ) { + T res = matrix; + res(0,3) = vector.x; + res(1,3) = vector.y; + res(2,3) = vector.z; + return res; +} +template T uf::matrix::rotate( const T& matrix, const pod::Vector3t& vector ) { + T res = matrix; + + if (vector.x != 0) { + T Rx = uf::matrix::identity(); + Rx(1,1) = cos(vector.x); Rx(1,2) = -sin(vector.x); + Rx(2,1) = sin(vector.x); Rx(2,2) = cos(vector.x); + res = uf::matrix::multiply(res, Rx); + } + if (vector.y != 0) { + T Ry = uf::matrix::identity(); + Ry(0,0) = cos(vector.y); Ry(0,2) = sin(vector.y); + Ry(2,0) = -sin(vector.y); Ry(2,2) = cos(vector.y); + res = uf::matrix::multiply(res, Ry); + } + if (vector.z != 0) { + T Rz = uf::matrix::identity(); + Rz(0,0) = cos(vector.z); Rz(0,1) = -sin(vector.z); + Rz(1,0) = sin(vector.z); Rz(1,1) = cos(vector.z); + res = uf::matrix::multiply(res, Rz); + } + return res; +} +template T uf::matrix::scale( const T& matrix, const pod::Vector3t& vector ) { + T res = matrix; + res(0,0) = vector.x; + res(1,1) = vector.y; + res(2,2) = vector.z; + return res; } template pod::Matrix uf::matrix::multiply_( T& left, const T& right ) { return left = uf::matrix::multiply((const T&) left, right); } template T& uf::matrix::translate_( T& matrix, const pod::Vector3t& vector ) { - matrix[12] = vector.x; - matrix[13] = vector.y; - matrix[14] = vector.z; - return matrix; + return matrix = uf::matrix::translate((const T&) matrix, vector); } template T& uf::matrix::rotate_( T& matrix, const pod::Vector3t& vector ) { - if ( vector.x != 0 ) { - matrix[5] = cos( vector.x ); - matrix[6] = sin( vector.x ); - matrix[9] = -1 * sin( vector.x ); - matrix[10] = cos( vector.x ); - } - - if ( vector.y != 0 ) { - matrix[0] = cos( vector.y ); - matrix[2] = -1 * sin( vector.y ); - matrix[8] = sin( vector.y ); - matrix[10] = cos( vector.y ); - } - - if ( vector.z != 0 ) { - matrix[0] = cos( vector.z ); - matrix[1] = sin( vector.z ); - matrix[4] = -1 * sin( vector.z ); - matrix[5] = cos( vector.z ); - } - return matrix; + return matrix = uf::matrix::rotate((const T&) matrix, vector); } template T& uf::matrix::scale_( T& matrix, const pod::Vector3t& vector ) { - matrix[0] = vector.x; - matrix[5] = vector.y; - matrix[10] = vector.z; - return matrix; + return matrix = uf::matrix::scale((const T&) matrix, vector); } -// Complex arithmetic -template T uf::matrix::translate( const T& matrix, const pod::Vector3t& vector ) { - ALIGN16 T res = matrix; - res[12] = vector.x; - res[13] = vector.y; - res[14] = vector.z; - return res; +template T& uf::matrix::inverse_( T& matrix ) { + return matrix = uf::matrix::inverse((const T&) matrix); } -template T uf::matrix::rotate( const T& matrix, const pod::Vector3t& vector ) { - ALIGN16 T res = matrix; - if ( vector.x != 0 ) { - res[5] = cos( vector.x ); - res[6] = sin( vector.x ); - res[9] = -1 * sin( vector.x ); - res[10] = cos( vector.x ); - } - - if ( vector.y != 0 ) { - res[0] = cos( vector.y ); - res[2] = -1 * sin( vector.y ); - res[8] = sin( vector.y ); - res[10] = cos( vector.y ); - } - if ( vector.z != 0 ) { - res[0] = cos( vector.z ); - res[1] = sin( vector.z ); - res[4] = -1 * sin( vector.z ); - res[5] = cos( vector.z ); - } - return res; -} -template T uf::matrix::scale( const T& matrix, const pod::Vector3t& vector ) { - ALIGN16 T res = matrix; - res[0] = vector.x; - res[5] = vector.y; - res[10] = vector.z; - return res; -} template pod::Matrix4t /*UF_API*/ uf::matrix::orthographic( T l, T r, T b, T t, T f, T n ) { - ALIGN16 pod::Matrix4t m = uf::matrix::identity(); - m[0*4+0] = 2 / (r - l); - m[1*4+1] = 2 / (t - b); - m[2*4+2] = - 2 / (f - n); - m[3*4+0] = - (r + l) / (r - l); - m[3*4+1] = - (t + b) / (t - b); - m[3*4+2] = - (f + n) / (f - n); + pod::Matrix4t m = uf::matrix::identity(); + m(0,0) = static_cast(2) / (r - l); + m(1,1) = static_cast(2) / (t - b); + m(2,2) = static_cast(-2) / (f - n); + + // Translation terms go in the last column (col = 3) + m(0,3) = - (r + l) / (r - l); + m(1,3) = - (t + b) / (t - b); + m(2,3) = - (f + n) / (f - n); return m; -/* - uf::stl::vector m = { - 2 / (r - l), 0, 0, 0, - 0, 2 / (t - b), 0, 0, - 0, 0, -2 / (f - n), 0, - -(r + l) / (r - l), -(t + b) / (t - b), -(f + n) / (f - n), 1, - }; - return uf::matrix::initialize(m); -*/ } template pod::Matrix4t /*UF_API*/ uf::matrix::orthographic( T l, T r, T b, T t ) { - return pod::Matrix4t({ - 2 / (r - l), 0, 0, 0, - 0, 2 / (t - b), 0, 0, - 0, 0, 1, 0, - -(r + l) / (r - l), -(t+b)/(t-b), 0, 1 - }); + pod::Matrix4t m = uf::matrix::identity(); + m(0,0) = static_cast(2) / (r - l); + m(1,1) = static_cast(2) / (t - b); + m(2,2) = static_cast(1); + + m(0,3) = - (r + l) / (r - l); + m(1,3) = - (t + b) / (t - b); } template pod::Matrix4t /*UF_API*/ uf::matrix::perspective( T fov, T raidou, T znear, T zfar ) { + if (uf::matrix::reverseInfiniteProjection) { + T f = static_cast(1) / tan(static_cast(0.5) * fov); + #if UF_USE_OPENGL + pod::Matrix4t m = uf::matrix::identity(); + m(0,0) = f / raidou; + m(1,1) = f; + m(2,2) = 0; + m(2,3) = znear; + m(3,2) = 1; + m(3,3) = 0; + return m; + #elif UF_USE_VULKAN + pod::Matrix4t m = uf::matrix::identity(); + m(0,0) = f / raidou; + m(1,1) = -f; // Vulkan flips Y + m(2,2) = 0; + m(2,3) = znear; + m(3,2) = 1; + m(3,3) = 0; + return m; + #endif + } else { + T range = znear - zfar; + T f = tan(static_cast(0.5) * fov); + + T Sx = static_cast(1) / (f * raidou); + T Sy = static_cast(1) / f; + T Sz = (zfar + znear) / range; + T Pz = (static_cast(2) * zfar * znear) / range; + + #if UF_USE_VULKAN + Sy = -Sy; // Vulkan NDC has inverted Y + #endif + + pod::Matrix4t m = uf::matrix::identity(); + m(0,0) = Sx; + m(1,1) = Sy; + m(2,2) = Sz; + m(2,3) = Pz; + m(3,2) = -1; + m(3,3) = 0; + return m; + } +#if 0 if ( uf::matrix::reverseInfiniteProjection ) { T f = static_cast(1) / tan( static_cast(0.5) * fov ); #if UF_USE_OPENGL return pod::Matrix4t({ - f / raidou, 0, 0, 0, - 0, f, 0, 0, - 0, 0, 0, 1, - 0, 0, znear, 0 + f / raidou, 0, 0, 0, + 0, f, 0, 0, + 0, 0, 0, 1, + 0, 0, znear, 0 }); #elif UF_USE_VULKAN return pod::Matrix4t({ - f / raidou, 0, 0, 0, - 0, -f, 0, 0, - 0, 0, 0, 1, - 0, 0, znear, 0 + f / raidou, 0, 0, 0, + 0, -f, 0, 0, + 0, 0, 0, 1, + 0, 0, znear, 0 }); #endif } else { @@ -618,17 +460,18 @@ pod::Matrix4t /*UF_API*/ uf::matrix::perspective( T fov, T raidou, T znear, T 0, 0, Pz, 0 }); } +#endif } template T& uf::matrix::copy( T& destination, const T& source ) { #pragma unroll // GCC unroll 16 - for ( uint_fast8_t i = 0; i < 16; ++i ) + for ( auto i = 0; i < 16; ++i ) destination[i] = source[i]; return destination; } template T& uf::matrix::copy( T& destination, typename T::type_t* const source ) { #pragma unroll // GCC unroll 16 - for ( uint_fast8_t i = 0; i < 16; ++i ) + for ( auto i = 0; i < 16; ++i ) destination[i] = source[i]; return destination; @@ -650,11 +493,11 @@ ext::json::Value /*UF_API*/ uf::matrix::encode( const pod::Matrix& m, con ext::json::Value json; if ( settings.quantize ) #pragma unroll // GCC unroll R*C - for ( uint_fast8_t i = 0; i < R*C; ++i ) + for ( auto i = 0; i < R*C; ++i ) json[i] = uf::math::quantizeShort( m[i] ); else #pragma unroll // GCC unroll R*C - for ( uint_fast8_t i = 0; i < R*C; ++i ) + for ( auto i = 0; i < R*C; ++i ) json[i] = m[i]; return json; @@ -663,10 +506,10 @@ template pod::Matrix& /*UF_API*/ uf::matrix::decode( const ext::json::Value& json, pod::Matrix& m ) { if ( ext::json::isArray(json) ) #pragma unroll // GCC unroll T::size - for ( uint_fast8_t i = 0; i < R*C && i < json.size(); ++i ) + for ( auto i = 0; i < R*C && i < json.size(); ++i ) m[i] = json[i].as(m[i]); else if ( ext::json::isObject(json) ) { - uint_fast8_t i = 0; + auto i = 0; ext::json::forEach(json, [&](const ext::json::Value& c){ if ( i >= R*C ) return; m[i] = c.as(m[i]); @@ -678,13 +521,13 @@ pod::Matrix& /*UF_API*/ uf::matrix::decode( const ext::json::Value& json, template pod::Matrix /*UF_API*/ uf::matrix::decode( const ext::json::Value& json, const pod::Matrix& _m ) { - ALIGN16 pod::Matrix m = _m; + pod::Matrix m = _m; if ( ext::json::isArray(json) ) #pragma unroll // GCC unroll T::size - for ( uint_fast8_t i = 0; i < R*C && i < json.size(); ++i ) + for ( auto i = 0; i < R*C && i < json.size(); ++i ) m[i] = json[i].as(_m[i]); else if ( ext::json::isObject(json) ) { - uint_fast8_t i = 0; + auto i = 0; ext::json::forEach(json, [&](const ext::json::Value& c){ if ( i >= R*C ) return; m[i] = c.as(_m[i]); @@ -699,17 +542,13 @@ uf::stl::string /*UF_API*/ uf::matrix::toString( const pod::Matrix& m ) { uf::stl::stringstream ss; ss << "Matrix(\n\t"; #pragma unroll // GCC unroll C - for ( uint_fast8_t c = 0; c < C; ++c ) { + for ( auto c = 0; c < C; ++c ) { #pragma unroll // GCC unroll R - for ( uint_fast8_t r = 0; r < R; ++r ) { + for ( auto r = 0; r < R; ++r ) { ss << m[r+c*C] << ", "; } if ( c + 1 < C ) ss << "\n\t"; } ss << "\n)"; return ss.str(); -} - -#if !__clang__ && __GNUC__ - #pragma GCC pop_options -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/impl.h b/engine/inc/uf/utils/math/physics/impl.h index 4b1eb797..0e367dd1 100644 --- a/engine/inc/uf/utils/math/physics/impl.h +++ b/engine/inc/uf/utils/math/physics/impl.h @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -27,9 +28,9 @@ namespace pod { }; struct SupportPoint { - pod::Vector3f p; - pod::Vector3f pA; - pod::Vector3f pB; + alignas(16) pod::Vector3f p; + alignas(16) pod::Vector3f pA; + alignas(16) pod::Vector3f pB; }; struct Simplex { @@ -38,16 +39,30 @@ namespace pod { struct Face { pod::SupportPoint a, b, c; - pod::Vector3f normal; + alignas(16) pod::Vector3f normal; float distance; }; struct BVH { typedef std::pair pair_t; - typedef uf::stl::vector pairs_t; + + struct PairHash { + size_t operator()( const pair_t& p ) const noexcept { + uint64_t a = (uint64_t) std::min(p.first, p.second); + uint64_t b = (uint64_t) std::max(p.first, p.second); + return (a << 32) ^ b; + } + }; + struct PairEq { + bool operator()( const pair_t& a, const pair_t& b ) const noexcept { + return (a.first == b.first && a.second == b.second) || (a.first == b.second && a.second == b.first); + } + }; + + typedef uf::stl::unordered_set pairs_t; struct Node { - pod::AABB bounds = {}; + alignas(16) pod::AABB bounds = {}; int32_t left = -1; int32_t right = -1; int32_t start = 0; @@ -56,7 +71,7 @@ namespace pod { bool asleep = false; }; struct FlatNode { - pod::AABB bounds = {}; + alignas(16) pod::AABB bounds = {}; int32_t start = -1; int32_t count = -1; int32_t skipIndex = -1; @@ -65,13 +80,13 @@ namespace pod { }; struct UpdatePolicy { enum class Decision { - NONE, // do nothing + NONE, // do nothing REFIT, // refit bounds REBUILD // rebuild from scratch }; float displacementThreshold = 0.25f; // 25% of AABB size - float overlapThreshold = 2.0f; // 2x growth in root surface area - float dirtyRatioThreshold = 0.3f; // 30% dirty bodies + float overlapThreshold = 2.0f; // 2x growth in root surface area + float dirtyRatioThreshold = 0.3f; // 30% dirty bodies int maxFramesBeforeRebuild = 60; // force rebuild every 60 frames }; @@ -92,27 +107,27 @@ namespace pod { struct Collider { // what it is enum CategoryMask : uint32_t { - CATEGORY_NONE = 0, - CATEGORY_STATIC = 1 << 0, - CATEGORY_DYNAMIC = 1 << 1, - CATEGORY_PLAYER = 1 << 2, - CATEGORY_NPC = 1 << 3, - CATEGORY_TRIGGER = 1 << 4, + CATEGORY_NONE = 0, + CATEGORY_STATIC = 1 << 0, + CATEGORY_DYNAMIC = 1 << 1, + CATEGORY_PLAYER = 1 << 2, + CATEGORY_NPC = 1 << 3, + CATEGORY_TRIGGER = 1 << 4, CATEGORY_PROJECTILE = 1 << 5, CATEGORY_CHARACTER = CATEGORY_PLAYER | CATEGORY_NPC, - CATEGORY_ALL = 0xFFFFFFFF + CATEGORY_ALL = 0xFFFFFFFF }; // what it collides with enum CollisionMask : uint32_t { - MASK_NONE = 0, - MASK_STATIC = CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC | CATEGORY_PROJECTILE, - MASK_DYNAMIC = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC, - MASK_PLAYER = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_NPC | CATEGORY_PROJECTILE, - MASK_NPC = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_PROJECTILE, - MASK_TRIGGER = CATEGORY_PLAYER | CATEGORY_NPC, + MASK_NONE = 0, + MASK_STATIC = CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC | CATEGORY_PROJECTILE, + MASK_DYNAMIC = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC, + MASK_PLAYER = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_NPC | CATEGORY_PROJECTILE, + MASK_NPC = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_PROJECTILE, + MASK_TRIGGER = CATEGORY_PLAYER | CATEGORY_NPC, MASK_PROJECTILE = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC, - MASK_CHARACTER = MASK_PLAYER | MASK_NPC, - MASK_ALL = 0xFFFFFFFF + MASK_CHARACTER = MASK_PLAYER | MASK_NPC, + MASK_ALL = 0xFFFFFFFF }; pod::ShapeType type; @@ -149,31 +164,30 @@ namespace pod { struct PhysicsBody { pod::World* world = NULL; uf::Object* object = NULL; - // pod::Transform<> transform = {}; - pod::Transform<>* transform = NULL; - pod::Vector3f offset = {}; bool isStatic = false; float mass = 1.0f; float inverseMass = 1.0f; - pod::Vector3f velocity = {}; - pod::Vector3f forceAccumulator = {}; + alignas(16) pod::Vector3f offset = {}; - pod::Vector3f angularVelocity = {}; - pod::Vector3f torqueAccumulator = {}; + alignas(16) pod::Vector3f velocity = {}; + alignas(16) pod::Vector3f forceAccumulator = {}; - pod::Vector3f inertiaTensor = { 1, 1, 1 }; - pod::Vector3f inverseInertiaTensor = { 1, 1, 1 }; + alignas(16) pod::Vector3f angularVelocity = {}; + alignas(16) pod::Vector3f torqueAccumulator = {}; - pod::Vector3f gravity = { NAN, NAN, NAN }; // an invalid gravity will fallback to world gravity + alignas(16) pod::Vector3f inertiaTensor = { 1, 1, 1 }; + alignas(16) pod::Vector3f inverseInertiaTensor = { 1, 1, 1 }; - pod::AABB bounds; - pod::Collider collider; - pod::PhysicsMaterial material; - pod::Activity activity; + alignas(16) pod::Vector3f gravity = { NAN, NAN, NAN }; // an invalid gravity will fallback to world gravity + + alignas(16) pod::AABB bounds; + alignas(16) pod::Collider collider; + alignas(16) pod::PhysicsMaterial material; + alignas(16) pod::Activity activity; }; struct Contact { @@ -210,7 +224,8 @@ namespace pod { uf::stl::vector bodies; pod::Vector3f gravity = { 0, -9.81f, 0 }; - pod::BVH bvh; + pod::BVH dynamicBvh; + pod::BVH staticBvh; }; } diff --git a/engine/inc/uf/utils/math/quaternion.h b/engine/inc/uf/utils/math/quaternion.h index a0bedf0b..e833ca13 100644 --- a/engine/inc/uf/utils/math/quaternion.h +++ b/engine/inc/uf/utils/math/quaternion.h @@ -14,48 +14,43 @@ #include "math.h" namespace pod { // Simple quaterions (designed [to store in arrays] with minimal headaches) - template using Quaternion = Vector4t; + template using Quaternion = Vector4t; } namespace uf { namespace quaternion { - // Equality checking - template std::size_t /*UF_API*/ compareTo( const T& left, const T& right ); // Equality check between two vectors (less than) - template bool /*UF_API*/ equals( const T& left, const T& right ); // Equality check between two vectors (equals) - // Basic arithmetic - template T /*UF_API*/ multiply( const T& left, const T& right ); // Multiplies two vectors of same type and size together - template pod::Quaternion /*UF_API*/ identity(); // Multiplies two vectors of same type and size together - template pod::Vector3t /*UF_API*/ rotate( const pod::Quaternion& left, const pod::Vector3t& right ); // Multiplies two vectors of same type and size together - template pod::Vector4t /*UF_API*/ rotate( const pod::Quaternion& left, const pod::Vector4t& right ); // Multiplies two vectors of same type and size together - template typename T::type_t /*UF_API*/ sum( const T& vector ); // Compute the sum of all components - template typename T::type_t /*UF_API*/ product( const T& vector ); // Compute the product of all components - template T /*UF_API*/ negate( const T& vector ); // Flip sign of all components - // Writes to first value - template T& /*UF_API*/ multiply( T& left, const T& right ); // Multiplies two vectors of same type and size together - template T& /*UF_API*/ negate( T& vector ); // Flip sign of all components - template T& /*UF_API*/ normalize( T& vector ); // Normalizes a vector - // Complex arithmetic - template typename T::type_t /*UF_API*/ dot( const T& left, const T& right ); // Compute the dot product between two vectors - template pod::Angle /*UF_API*/ angle( const T& a, const T& b ); // Compute the angle between two vectors - - template T /*UF_API*/ lerp( const T& from, const T& to, typename T::type_t delta ); // Linearly interpolate between two vectors - template T /*UF_API*/ slerp( const T& from, const T& to, typename T::type_t delta ); // Spherically interpolate between two vectors - - template typename T::type_t /*UF_API*/ distanceSquared( const T& a, const T& b ); // Gets the magnitude of the vector - template typename T::type_t /*UF_API*/ distance( const T& a, const T& b ); // Gets the magnitude of the vector - template typename T::type_t /*UF_API*/ magnitude( const T& vector ); // Gets the magnitude of the vector - template typename T::type_t /*UF_API*/ norm( const T& vector ); // Compute the norm of the vector - template T /*UF_API*/ normalize( const T& vector ); // Normalizes a vector - // Quaternion ops - template pod::Matrix4t matrix( const T& quaternion ); + template pod::Quaternion /*UF_API*/ identity(); + template T /*UF_API*/ multiply( const T& left, const T& right ); + template pod::Vector3t /*UF_API*/ rotate( const pod::Quaternion& left, const pod::Vector3t& right ); + template pod::Vector4t /*UF_API*/ rotate( const pod::Quaternion& left, const pod::Vector4t& right ); + template typename T::type_t /*UF_API*/ sum( const T& vector ); + template typename T::type_t /*UF_API*/ product( const T& vector ); + + + template typename T::type_t /*UF_API*/ dot( const T& left, const T& right ); + template pod::Angle /*UF_API*/ angle( const T& a, const T& b ); + + template T /*UF_API*/ lerp( const T& from, const T& to, typename T::type_t delta ); + template T /*UF_API*/ slerp( const T& from, const T& to, typename T::type_t delta ); + + template typename T::type_t /*UF_API*/ distanceSquared( const T& a, const T& b ); + template typename T::type_t /*UF_API*/ distance( const T& a, const T& b ); + template typename T::type_t /*UF_API*/ magnitude( const T& vector ); + template typename T::type_t /*UF_API*/ norm( const T& vector ); + template T /*UF_API*/ normalize( const T& vector ); + + template pod::Matrix4t matrix( const pod::Quaternion& quaternion ); template pod::Quaternion axisAngle( const pod::Vector3t& axis, T angle ); template pod::Quaternion unitVectors( const pod::Vector3t& u, const pod::Vector3t& v ); template pod::Quaternion lookAt( const pod::Vector3t& source, const pod::Vector3t& destination ); template T conjugate( const T& quaternion ); template T inverse( const T& quaternion ); - template T& conjugate( T& quaternion ); - template T& inverse( T& quaternion ); + + template T& /*UF_API*/ multiply_( T& left, const T& right ); + template T& /*UF_API*/ normalize_( T& vector ); + template T& conjugate_( T& quaternion ); + template T& inverse_( T& quaternion ); template pod::Vector3t eulerAngles( const pod::Quaternion& quaternion ); template T pitch( const pod::Quaternion& quaternion ); @@ -66,105 +61,4 @@ namespace uf { } } -#if UF_USE_CLASS_OF_PODS -namespace uf { - template - class /*UF_API*/ Quaternion { -public: - // Easily access POD's type - typedef pod::Quaternion pod_t; - // Replicate POD information - typedef T type_t; - typedef T* container_t; - static const std::size_t size = 4; - protected: - // POD storage - Quaternion::pod_t m_pod; - public: - T& x = m_pod.x; - T& y = m_pod.y; - T& z = m_pod.z; - T& w = m_pod.w; - public: - // C-tor - Quaternion(); // initializes POD to 'def' - Quaternion(T def); // initializes POD to 'def' - Quaternion(T x, T y, T z, T w); // initializes POD to 'def' - Quaternion(const Quaternion::pod_t& pod); // copies POD altogether - Quaternion(const T components[4]); // copies data into POD from 'components' (typed as C array) - Quaternion(const uf::stl::vector& components); // copies data into POD from 'components' (typed as uf::stl::vector) - // D-tor - // Unneccesary - // POD access - Quaternion::pod_t& data(); // Returns a reference of POD - const Quaternion::pod_t& data() const; // Returns a const-reference of POD - // Alternative POD access - T* get(); // Returns a pointer to the entire array - const T* get() const; // Returns a const-pointer to the entire array - T& getComponent( std::size_t i ); // Returns a reference to a single element - const T& getComponent( std::size_t i ) const; // Returns a const-reference to a single element - // POD manipulation - T* set(const T components[4]); // Sets the entire array - T& setComponent( std::size_t i, const T& value ); // Sets a single element - // Validation - bool isValid() const; // Checks if all components are valid (non NaN, inf, etc.) - // Basic arithmetic - inline uf::Quaternion& multiply( const Quaternion& quaternion ); // Multiplies two quaternions of same type and size together - inline uf::Quaternion multiply( const Quaternion& quaternion ) const; // Multiplies two quaternions of same type and size together - inline uf::Vector3t rotate( const Vector3t& quaternion ) const; // Multiplies a quaternion and a vector of same type and size together - inline uf::Vector4t rotate( const Vector4t& quaternion ) const; // Multiplies a quaternion and a vector of same type and size together - inline uf::Quaternion& negate(); // Flip sign of all components - // Complex arithmetic - inline T dot( const Quaternion right ) const; // Compute the dot product between two quaternions - inline pod::Angle angle( const Quaternion& b ) const; // Compute the angle between two quaternions - - inline uf::Quaternion lerp( const Quaternion to, typename T::type_t delta ) const; // Linearly interpolate between two quaternions - inline uf::Quaternion slerp( const Quaternion to, typename T::type_t delta ) const; // Spherically interpolate between two quaternions - - inline T distanceSquared( const Quaternion b ) const; // Compute the distance between two quaternions (doesn't sqrt) - inline T distance( const Quaternion b ) const; // Compute the distance between two quaternions - inline T magnitude() const; // Gets the magnitude of the quaternion - inline T norm() const; // Compute the norm of the quaternion - - inline uf::Quaternion& normalize(); // Normalizes a quaternion - uf::Quaternion getNormalized() const; // Return a normalized quaternion - // Quaternion ops - inline uf::Matrix4t matrix() const; - inline uf::Quaternion& axisAngle( const Vector3t& axis, T angle ); - inline uf::Quaternion& unitVectors( const Vector3t& u, const Vector3t& v ); - - inline uf::Quaternion& conjugate(); - inline uf::Quaternion& inverse(); - - inline uf::Quaternion getConjugate() const; - inline uf::Quaternion getInverse() const; - inline uf::stl::string toString() const; - // Overloaded ops - // Accessing via subscripts - T& operator[](std::size_t i); - const T& operator[](std::size_t i) const; - // Arithmetic - inline Quaternion operator-() const; // Negation - inline Quaternion operator*( const Quaternion& quaternion ) const; // Multiplication between two quaternions - inline Vector3t operator*( const Vector3t& vector ) const; // Multiplication between a quaternion and a vector (rotates vector) - inline Vector4t operator*( const Vector4t& vector ) const; // Multiplication between a quaternion and a vector (rotates vector) - inline Matrix4t operator*( const Matrix4t& matrix ) const; // Multiplication between a quaternion and a matrix - inline Quaternion& operator *=( const Quaternion& quaternion ); // Multiplication set between two quaternions - inline bool operator==( const Quaternion& quaternion ) const; // Equality check between two quaternions (equals) - inline bool operator!=( const Quaternion& quaternion ) const; // Equality check between two quaternions (not equals) - inline bool operator<( const Quaternion& quaternion ) const; // Equality check between two quaternions (less than) - inline bool operator<=( const Quaternion& quaternion ) const; // Equality check between two quaternions (less than or equals) - inline bool operator>( const Quaternion& quaternion ) const; // Equality check between two quaternions (greater than) - inline bool operator>=( const Quaternion& quaternion ) const; // Equality check between two quaternions (greater than or equals) - - inline operator pod_t&() { return this->m_pod; } - inline operator const pod_t&() const { return this->m_pod; } - }; -} -#endif - -#include "quaternion/quaternion.inl" -#ifdef UF_USE_GLM_TMP - #undef UF_USE_GLM - #undef UF_USE_GLM_TMP -#endif \ No newline at end of file +#include "quaternion/quaternion.inl" \ No newline at end of file diff --git a/engine/inc/uf/utils/math/quaternion/class.inl b/engine/inc/uf/utils/math/quaternion/class.inl deleted file mode 100644 index 0ab81ec0..00000000 --- a/engine/inc/uf/utils/math/quaternion/class.inl +++ /dev/null @@ -1,278 +0,0 @@ -// C-tor -// initializes POD to 'def' -template -uf::Quaternion::Quaternion() { - -} -// initializes POD to 'def' -template -uf::Quaternion::Quaternion(T def) : - m_pod( {def, def, def, 1} ) -{ - -} -// initializes POD to 'def' -template -uf::Quaternion::Quaternion(T x, T y, T z, T w) : - m_pod( {x, y, z, w} ) -{ - -} -// copies POD altogether -template -uf::Quaternion::Quaternion(const Quaternion::pod_t& pod) : - m_pod(pod) -{ - -} -// copies data into POD from 'components' (typed as C array) -template -uf::Quaternion::Quaternion(const T components[4] ) : - m_pod( { components[0], components[1], components[2], components[3] } ) -{ - -} -// copies data into POD from 'components' (typed as uf::stl::vector) -template -uf::Quaternion::Quaternion(const uf::stl::vector& components) { - memcpy( this->m_pod.components, &components[0], 4 ); -} -// D-tor -// Unneccesary -// POD access -// Returns a reference of POD -template -typename uf::Quaternion::pod_t& uf::Quaternion::data() { - return this->m_pod; -} -// Returns a const-reference of POD -template -const typename uf::Quaternion::pod_t& uf::Quaternion::data() const { - return this->m_pod; -} -// Alternative POD access -// Returns a pointer to the entire array -template -T* uf::Quaternion::get() { - return this->m_pod.components; -} -// Returns a const-pointer to the entire array -template -const T* uf::Quaternion::get() const { - return this->m_pod.components; -} -// Returns a reference to a single element -template -T& uf::Quaternion::getComponent( std::size_t i ) { - return this->m_pod.components[i]; -} -// Returns a const-reference to a single element -template -const T& uf::Quaternion::getComponent( std::size_t i ) const { - return this->m_pod.components[i]; -} -// POD manipulation -// Sets the entire array -template -T* uf::Quaternion::set(const T components[4]) { - for ( std::size_t i = 0; i < 4; ++i ) this->m_pod[i] = components[i]; -} -// Sets a single element -template -T& uf::Quaternion::setComponent( std::size_t i, const T& value ) { - this->m_pod[i] = value; -} -// Validation -// Checks if all components are valid (non NaN, inf, etc.) -template -bool uf::Quaternion::isValid() const { - for ( std::size_t i = 0; i < 4; ++i ) if ( this->m_pod[i] != this->m_pod[i] ) return false; - return true; -} -// Basic arithmetic -// Multiplies two quaternions of same type and size together -template -inline uf::Quaternion& uf::Quaternion::multiply( const Quaternion& b ) { - uf::quaternion::multiply(this->m_pod, b.m_pod); - return *this; -} -template -inline uf::Quaternion uf::Quaternion::multiply( const Quaternion& b ) const { - return uf::quaternion::multiply(this->m_pod, b.m_pod); -} -template -inline uf::Vector3t uf::Quaternion::rotate( const Vector3t& b ) const { - return uf::quaternion::rotate(this->m_pod, b.data()); -} -template -inline uf::Vector4t uf::Quaternion::rotate( const Vector4t& b ) const { - return uf::quaternion::rotate(this->m_pod, b.data()); -} -// Flip sign of all components -template -inline uf::Quaternion& uf::Quaternion::negate() { - uf::quaternion::negate(this->m_pod); - return *this; -} -// Complex arithmetic -// Compute the dot product between two quaternions -template -inline T uf::Quaternion::dot( const Quaternion right ) const { - return uf::quaternion::dot( this->m_pod, right.m_pod ); -} -// Compute the angle between two quaternions -template -inline pod::Angle uf::Quaternion::angle( const Quaternion& b ) const { - return uf::quaternion::angle( this->m_pod, b.m_pod ); -} - -// Linearly interpolate between two quaternions -template -inline uf::Quaternion uf::Quaternion::lerp( const Quaternion to, typename T::type_t delta ) const { - return uf::quaternion::lerp( this->m_pod, to.m_pod, delta ); -} -// Spherically interpolate between two quaternions -template -inline uf::Quaternion uf::Quaternion::slerp( const Quaternion to, typename T::type_t delta ) const { - return uf::quaternion::slerp( this->m_pod, to.m_pod, delta ); -} - -// Compute the distance between two quaternions (doesn't sqrt) -template -inline T uf::Quaternion::distanceSquared( const Quaternion b ) const { - return uf::quaternion::distanceSquared(this->m_pod, b.m_pod); -} -// Compute the distance between two quaternions -template -inline T uf::Quaternion::distance( const Quaternion b ) const { - return uf::quaternion::distance(this->m_pod, b.m_pod); -} -// Gets the magnitude of the quaternion -template -inline T uf::Quaternion::magnitude() const { - return uf::quaternion::magnitude(this->m_pod); -} -// Compute the norm of the quaternion -template -inline T uf::Quaternion::norm() const { - return uf::quaternion::norm(this->m_pod); -} - -// Normalizes a quaternion -template -inline uf::Quaternion& uf::Quaternion::normalize() { - uf::quaternion::normalize(this->m_pod); - return *this; -} -// Return a normalized quaternion -template -uf::Quaternion uf::Quaternion::getNormalized() const { - return uf::quaternion::normalize(this->m_pod); -} -// Quaternion ops -template -inline uf::Matrix4t uf::Quaternion::matrix() const { - return uf::quaternion::matrix(this->m_pod); -} -template -inline uf::Quaternion& uf::Quaternion::axisAngle( const Vector3t& axis, T angle ) { - this->m_pod = uf::quaternion::axisAngle(axis, angle); - return *this; -} -template -inline uf::Quaternion& uf::Quaternion::unitVectors( const Vector3t& u, const Vector3t& v ) { - this->m_pod = uf::quaternion::unitVectors(u, v); - return *this; -} - -template -inline uf::Quaternion& uf::Quaternion::conjugate() { - return uf::quaternion::conjugate(this->m_pod); -} -template -inline uf::Quaternion& uf::Quaternion::inverse() { - return uf::quaternion::inverse(this->m_pod); -} - -template -inline uf::Quaternion uf::Quaternion::getConjugate() const { - return uf::quaternion::conjugate(this->m_pod); -} -template -inline uf::Quaternion uf::Quaternion::getInverse() const { - return uf::quaternion::inverse(this->m_pod); -} -template -inline uf::stl::string uf::Quaternion::toString() const { - return uf::vector::toString(this->m_pod); -} -// Overloaded ops -// Accessing via subscripts -template -T& uf::Quaternion::operator[](std::size_t i) { - return this->m_pod[i]; -} -template -const T& uf::Quaternion::operator[](std::size_t i) const { - return this->m_pod[i]; -} -// Arithmetic -// Negation -template -inline uf::Quaternion uf::Quaternion::operator-() const { - return this->negate(); -} -// Multiplication between two quaternions -template -inline uf::Quaternion uf::Quaternion::operator*( const Quaternion& quaternion ) const { - return this->multiply(quaternion); -} -// Multiplication between a quaternion and a vector (rotates vector) -template -inline uf::Vector3t uf::Quaternion::operator*( const Vector3t& vector ) const { - return this->multiply(vector); -} -template -inline uf::Vector4t uf::Quaternion::operator*( const Vector4t& vector ) const { - return this->multiply(vector); -} -// Multiplication between a quaternion and a matrix -template -inline uf::Matrix4t uf::Quaternion::operator*( const Matrix4t& matrix ) const { - return this->multiply(matrix); -} -// Multiplication set between two quaternions -template -inline uf::Quaternion& uf::Quaternion::operator *=( const Quaternion& quaternion ) { - return this->multiply(quaternion); -} -// Equality check between two quaternions (equals) -template -inline bool uf::Quaternion::operator==( const Quaternion& quaternion ) const { - return uf::quaternion::equals(this->m_pod, quaternion.m_pod); -} -// Equality check between two quaternions (not equals) -template -inline bool uf::Quaternion::operator!=( const Quaternion& quaternion ) const { - return !uf::quaternion::equals(this->m_pod, quaternion.m_pod); -} -// Equality check between two quaternions (less than) -template -inline bool uf::Quaternion::operator<( const Quaternion& quaternion ) const { - return !(uf::quaternion::compareTo(this->m_pod, quaternion.m_pod) < 0); -} -// Equality check between two quaternions (less than or equals) -template -inline bool uf::Quaternion::operator<=( const Quaternion& quaternion ) const { - return !(uf::quaternion::compareTo(this->m_pod, quaternion.m_pod) <= 0); -} -// Equality check between two quaternions (greater than) -template -inline bool uf::Quaternion::operator>( const Quaternion& quaternion ) const { - return !(uf::quaternion::compareTo(this->m_pod, quaternion.m_pod) > 0); -} -// Equality check between two quaternions (greater than or equals) -template -inline bool uf::Quaternion::operator>=( const Quaternion& quaternion ) const { - return !(uf::quaternion::compareTo(this->m_pod, quaternion.m_pod) >= 0); -} \ No newline at end of file diff --git a/engine/inc/uf/utils/math/quaternion/pod.inl b/engine/inc/uf/utils/math/quaternion/pod.inl index ccb0f299..e791e123 100644 --- a/engine/inc/uf/utils/math/quaternion/pod.inl +++ b/engine/inc/uf/utils/math/quaternion/pod.inl @@ -1,69 +1,43 @@ -// Equality checking -// Equality check between two quaternions (less than) -template size_t uf::quaternion::compareTo( const T& left, const T& right ) { - return uf::vector::compareTo(left, right); -// return uf::quaternion::angle(left) > uf::quaternion::angle(right); +namespace pod { + // Simple quaterions (designed [to store in arrays] with minimal headaches) + template using Quaternion = Vector4t; } -// Equality check between two quaternions (equals) -template bool uf::quaternion::equals( const T& left, const T& right ) { - return uf::quaternion::compareTo( left, right ) == 0; -} -// Basic arithmetic -// Multiplies two quaternions of same type and size together -template T uf::quaternion::multiply( const T& left, const T& right ) { - T q1 = uf::quaternion::normalize(left); - T q2 = uf::quaternion::normalize(right); - T q; - - q.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y; - q.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z; - q.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x; - q.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z; - return uf::quaternion::normalize( q ); -} -// Multiplies this quaternion by a scalar -/* -template T uf::quaternion::multiply( const T& quaternion, const typename T::type_t& scalar ) { - return uf::vector::multiply( quaternion, scalar ); -} -*/ -// Flip sign of all components -template T uf::quaternion::negate( const T& quaternion ) { - return uf::quaternion::inverse(quaternion); -} +// snip header + template pod::Quaternion uf::quaternion::identity() { return pod::Quaternion{ 0, 0, 0, 1 }; } -// Writes to first value -// Multiplies two quaternions of same type and size together -template T& uf::quaternion::multiply( T& left, const T& right ) { - return left = uf::quaternion::multiply((const T&) left, right ); +template T uf::quaternion::multiply( const T& q1, const T& q2 ) { +#if 0 && UF_USE_SIMD + if constexpr (std::is_same_v) { + return uf::simd::quatMul( q1 , q2 ); + } +#endif + return { + q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y, + q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z, + q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x, + q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z, + }; } -// Multiplies a quaternion and a vector of same type and size together -template pod::Vector3t uf::quaternion::rotate( const pod::Quaternion& left, const pod::Vector3t& right ) { - pod::Vector3t qVec = { left.x, left.y, left.z }; - const T s = left.w; - return uf::vector::multiply( qVec, static_cast(2) * uf::vector::dot( qVec, right ) ) + uf::vector::multiply( right, s*s - uf::vector::dot( qVec, qVec )) + ( uf::vector::cross( qVec, right ) * static_cast(2) * s ); +template pod::Vector3t uf::quaternion::rotate( const pod::Quaternion& Q, const pod::Vector3t& v ) { +#if 0 && UF_USE_SIMD + if constexpr (std::is_same_v) { + return uf::simd::quatRot( Q, v ); + } +#endif + pod::Vector3t q = { Q.x, Q.y, Q.z }; + const T s = Q.w; + return uf::vector::multiply(q, static_cast(2) * uf::vector::dot(q, v)) + uf::vector::multiply(v, s*s - uf::vector::dot(q, q)) + (uf::vector::cross(q, v) * static_cast(2) * s); } -template pod::Vector4t uf::quaternion::rotate( const pod::Quaternion& left, const pod::Vector4t& right ) { - pod::Vector3t vector = uf::quaternion::rotate( left, {right.x, right.y, right.z} ); - return {vector.x, vector.y, vector.z, left.w}; +template pod::Vector4t uf::quaternion::rotate( const pod::Quaternion& q, const pod::Vector4t& v ) { + pod::Vector3t vector = uf::quaternion::rotate(q, { v.x, v.y, v.z }); + return { vector.x, vector.y, vector.z, v.w }; } -// Flip sign of all components -template T& uf::quaternion::negate( T& quaternion ) { - return quaternion = uf::quaternion::negate((const T&) quaternion); -} -// Normalizes a quaternion -template T& uf::quaternion::normalize( T& quaternion ) { - return quaternion = uf::quaternion::normalize((const T&) quaternion); -} -// Complex arithmetic -// Compute the dot product between two quaternions template typename T::type_t uf::quaternion::dot( const T& left, const T& right ) { return uf::vector::dot(left, right); } -// Compute the angle between two quaternions template pod::Angle uf::quaternion::angle( const T& a, const T& b ) { T tmp = b * uf::quaternion::inverse(a); return acosf(tmp.w) * static_cast(2); @@ -76,103 +50,80 @@ template pod::Vector3t uf::quaternion::eulerAngles( const pod::Qu }; } template T uf::quaternion::pitch( const pod::Quaternion& q ) { - T const y = static_cast(2) * (q.y * q.z + q.w * q.x); -#if UF_USE_SIMD - uf::simd::value Q = q; - pod::Quaternion s = uf::simd::mul( Q, Q ); - T const x = s.w - s.x - s.y - s.z; -#else - T const x = q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z; -#endif - + const T y = static_cast(2) * (q.y * q.z + q.w * q.x); + auto s = uf::vector::multiply( q, q ); + const T x = s.w - s.x - s.y - s.z; T epsilon = std::numeric_limits::epsilon(); - if ( fabs(x) < epsilon && fabs(y) < epsilon ) //avoid atan2(0,0) - handle singularity - Matiis - return static_cast(static_cast(2) * atan2(q.x, q.w)); - + if ( fabs(x) < epsilon && fabs(y) < epsilon ) return static_cast(static_cast(2) * atan2(q.x, q.w)); return static_cast(atan2(y, x)); } template T uf::quaternion::yaw( const pod::Quaternion& q ) { return asin(std::clamp(static_cast(-2) * (q.x * q.z - q.w * q.y), static_cast(-1), static_cast(1))); } template T uf::quaternion::roll( const pod::Quaternion& q ) { - T const y = static_cast(2) * (q.x * q.y + q.w * q.z); -#if UF_USE_SIMD - uf::simd::value Q = q; - pod::Quaternion s = uf::simd::mul( Q, Q ); - T const x = s.w - s.x - s.y - s.z; -#else - T const x = q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z; -#endif - + const T y = static_cast(2) * (q.x * q.y + q.w * q.z); + auto s = uf::vector::multiply( q, q ); + const T x = s.w - s.x - s.y - s.z; T epsilon = std::numeric_limits::epsilon(); - if ( fabs(x) < epsilon && fabs(y) < epsilon ) //avoid atan2(0,0) - handle singularity - Matiis - return static_cast(0); - + if ( fabs(x) < epsilon && fabs(y) < epsilon ) return static_cast(0); return static_cast(atan2(y, x)); } - -// Linearly interpolate between two quaternions template T uf::quaternion::lerp( const T& from, const T& to, typename T::type_t delta ) { return uf::vector::lerp( from, to, delta ); } -// Spherically interpolate between two quaternions template T uf::quaternion::slerp( const T& x, const T& y, typename T::type_t a ) { T z = y; - auto cosTheta = uf::quaternion::dot( x, y ); - if( cosTheta < 0 ) { + auto cosTheta = uf::quaternion::dot(x, y); + if ( cosTheta < 0 ) { z = -y; cosTheta = -cosTheta; } - if( cosTheta > 1 - std::numeric_limits::epsilon() ) return uf::vector::mix( x, z, a ); - typename T::type_t angle = acos(cosTheta); - return uf::vector::divide( uf::vector::add(uf::vector::multiply(x, sin(static_cast(1) - a * angle)), uf::vector::multiply(z, sin(a * angle))), sin(angle) ); -// return (x * sin((static_cast(1) - a) * angle) + z * sin(a * angle)) / sin(angle); -} + if (cosTheta > 1 - std::numeric_limits::epsilon()) return uf::vector::mix(x, z, a); -// Compute the distance between two quaternions (doesn't sqrt) + typename T::type_t angle = acos(cosTheta); + // return ( sin( ( 1 - a ) * angle) * x + sin( a * angle ) * y ) / sin( angle ); + return uf::vector::divide( uf::vector::add( uf::vector::multiply(x, sin((1 - a) * angle)), uf::vector::multiply(z, sin(a * angle)) ), sin( angle ) ); +} template typename T::type_t uf::quaternion::distanceSquared( const T& a, const T& b ) { return uf::vector::distanceSquared(a, b); } -// Compute the distance between two quaternions template typename T::type_t uf::quaternion::distance( const T& a, const T& b ) { return uf::vector::distance(a, b); } -// Gets the magnitude of the quaternion template typename T::type_t uf::quaternion::magnitude( const T& quaternion ) { return uf::vector::magnitude(quaternion); } -// Compute the norm of the quaternion template typename T::type_t uf::quaternion::norm( const T& quaternion ) { return uf::vector::norm(quaternion); } -// Normalizes a quaternion template T uf::quaternion::normalize( const T& quaternion ) { return uf::vector::normalize(quaternion); } +template pod::Matrix4t uf::quaternion::matrix( const pod::Quaternion& q ) { +#if UF_USE_SIMD + if constexpr ( std::is_same_v ) { + return uf::simd::quatMat( q ); + } +#endif + auto normal = uf::quaternion::normalize(q); -// Quaternion ops -template pod::Matrix4t uf::quaternion::matrix( const T& q ) { - T normal = uf::quaternion::normalize( q ); + const T xx = 2 * normal.x * normal.x; + const T xy = 2 * normal.x * normal.y; + const T xz = 2 * normal.x * normal.z; + const T xw = 2 * normal.x * normal.w; - const typename T::type_t xx = 2 * normal.x * normal.x; - const typename T::type_t xy = 2 * normal.x * normal.y; - const typename T::type_t xz = 2 * normal.x * normal.z; - const typename T::type_t xw = 2 * normal.x * -normal.w; + const T yy = 2 * normal.y * normal.y; + const T yz = 2 * normal.y * normal.z; + const T yw = 2 * normal.y * normal.w; - const typename T::type_t yy = 2 * normal.y * normal.y; - const typename T::type_t yz = 2 * normal.y * normal.z; - const typename T::type_t yw = 2 * normal.y * -normal.w; + const T zz = 2 * normal.z * normal.z; + const T zw = 2 * normal.z * normal.w; - const typename T::type_t zz = 2 * normal.z * normal.z; - const typename T::type_t zw = 2 * normal.z * -normal.w; - -// const typename T::type_t ww = w * w; - - return pod::Matrix4t({ - 1 - yy - zz, xy - zw, xz + yw, 0, - xy + zw, 1 - xx - zz, yz - xw, 0, - xz - yw, yz + xw, 1 - xx - yy, 0, - 0, 0, 0, 1 + return pod::Matrix4t({ + 1 - yy - zz, xy + zw, xz - yw, 0, + xy - zw, 1 - xx - zz, yz + xw, 0, + xz + yw, yz - xw, 1 - xx - yy, 0, + 0, 0, 0, 1 }); } template pod::Quaternion uf::quaternion::axisAngle( const pod::Vector3t& axis, T angle ) { @@ -180,112 +131,105 @@ template pod::Quaternion uf::quaternion::axisAngle( const pod::Ve T sinAngle = sin( angle * static_cast(0.5) ); T cosAngle = cos( angle * static_cast(0.5) ); -#if UF_USE_SIMD - q = uf::simd::mul( uf::simd::value(axis.x, axis.y, axis.z, static_cast(1) ), uf::simd::value(sinAngle, sinAngle, sinAngle, cosAngle) ); -#else - q.x = axis.x * sinAngle; - q.y = axis.y * sinAngle; - q.z = axis.z * sinAngle; - q.w = cosAngle; -#endif - uf::quaternion::normalize(q); - return q; + + q = pod::Vector4t{ axis.x, axis.y, axis.z, 1 } * pod::Vector4t{ sinAngle, sinAngle, sinAngle, cosAngle }; + return uf::quaternion::normalize( q ); } template pod::Quaternion uf::quaternion::unitVectors( const pod::Vector3t& u, const pod::Vector3t& v ) { - T dot = uf::vector::dot(u, v); - static const T EPSILON = static_cast(0.00001); - if ( dot + 1 < EPSILON ) return uf::quaternion::axisAngle( uf::vector::normalize(u), static_cast(3.1415926) ); - T mag = sqrt( static_cast(2) + static_cast(2) * dot ); - pod::Vector3t w = uf::vector::multiply(uf::vector::cross(u, v), (static_cast(1) / mag)); - return { - .x = w.x, - .y = w.y, - .z = w.z, - .w = mag * static_cast(0.5) - }; + static const T EPSILON = static_cast(1e-6); + + pod::Vector3t uNorm = uf::vector::normalize( u ); + pod::Vector3t vNorm = uf::vector::normalize( v ); + + T dot = uf::vector::dot( uNorm, vNorm ); + + if ( dot < -1 + EPSILON ) { + pod::Vector3t orthogonal = (fabs(uNorm.x) > fabs(uNorm.z)) ? pod::Vector3t{ -uNorm.y, uNorm.x, 0 } : pod::Vector3t{ 0, -uNorm.z, uNorm.y }; + orthogonal = uf::vector::normalize( orthogonal ); + return uf::quaternion::axisAngle( orthogonal, static_cast(M_PI) ); + } + + pod::Vector3t cross = uf::vector::cross(uNorm, vNorm); + T s = sqrt((1 + dot) * 2); + + return uf::quaternion::normalize({ + .x = cross.x / s, + .y = cross.y / s, + .z = cross.z / s, + .w = s * static_cast(0.5) + }); } template pod::Quaternion uf::quaternion::lookAt( const pod::Vector3t& at, const pod::Vector3t& _up ) { - pod::Vector3t up = _up; - pod::Vector3t forward = uf::vector::normalize( at ) ; - uf::vector::orthonormalize( up, forward ); - pod::Vector3t right = uf::vector::cross( up, forward ); - pod::Quaternion q; -#if UF_USE_SIMD - T w = sqrtf(static_cast(1) + right.x + up.y + forward.z) * static_cast(0.5); - float w4_recip = static_cast(1) / (static_cast(4) * w); - q = uf::simd::mul( uf::simd::sub( uf::simd::value( forward.y, right.z, up.x, static_cast(0) ), uf::simd::value( up.z, forward.x, right.y, static_cast(0) ) ), w4_recip ); - q.w = w; -#else - q.w = sqrtf(static_cast(1) + right.x + up.y + forward.z) * static_cast(0.5); - float w4_recip = static_cast(1) / (static_cast(4) * q.w); - q.x = (forward.y - up.z) * w4_recip; - q.y = (right.z - forward.x) * w4_recip; - q.z = (up.x - right.y) * w4_recip; -#endif - return uf::quaternion::inverse( uf::quaternion::normalize( q ) ); -// return q; + pod::Vector3t forward = uf::vector::normalize(at); + pod::Vector3t up = uf::vector::orthonormalize( _up, forward ); + pod::Vector3t right = uf::vector::cross(up, forward); + pod::Matrix4t m({ + right.x, up.x, forward.x, 0, + right.y, up.y, forward.y, 0, + right.z, up.z, forward.z, 0, + 0, 0, 0, 1 + }); + return uf::quaternion::normalize( uf::quaternion::fromMatrix( m ) ); } -template T& uf::quaternion::conjugate( T& q ) { -#if UF_USE_SIMD - return q = uf::simd::mul( q, static_cast(-1) ); -#endif - return q = { - .x = -q.x, - .y = -q.y, - .z = -q.z, - .w = q.w - }; -} + template T uf::quaternion::conjugate( const T& q ) { -#if UF_USE_SIMD - return uf::simd::mul( q, static_cast(-1) ); -#endif - return { - .x = -q.x, - .y = -q.y, - .z = -q.z, - .w = q.w - }; -} -template T& uf::quaternion::inverse( T& q ) { -#if UF_USE_SIMD - uf::simd::value Q = q; - return q = uf::simd::div( uf::simd::mul( Q, { static_cast(-1), static_cast(-1), static_cast(-1), static_cast(1) } ), uf::simd::dot( Q, Q ) ); -#endif - return q = uf::quaternion::conjugate( (const T&) q ) / uf::quaternion::dot( q, q ); + return uf::vector::multiply( q, { -1, -1, -1, 1 } ); } + template T uf::quaternion::inverse( const T& q ) { -#if UF_USE_SIMD - uf::simd::value Q = q; - return uf::simd::div( uf::simd::mul( Q, { static_cast(-1), static_cast(-1), static_cast(-1), static_cast(1) } ), uf::simd::dot( Q, Q ) ); -#endif return uf::quaternion::conjugate( q ) / uf::quaternion::dot( q, q ); } + +template T& uf::quaternion::multiply_( T& left, const T& right ) { + return left = uf::quaternion::multiply((const T&) left, right ); +} +template T& uf::quaternion::normalize_( T& q ) { + return q = uf::quaternion::normalize((const T&) q); +} +template T& uf::quaternion::conjugate_( T& q ) { + return q = uf::quaternion::conjugate((const T&) q); +} +template T& uf::quaternion::inverse_( T& q ) { + return q = uf::quaternion::inverse((const T&) q); +} + template pod::Quaternion uf::quaternion::fromMatrix( const pod::Matrix4t& m ) { pod::Quaternion q; - T m0 = m[(4*0)+0]; - T m5 = m[(4*1)+1]; - T m10 = m[(4*2)+2]; -#if UF_USE_SIMD - q = uf::simd::div( uf::simd::sqrt( uf::simd::max( static_cast(0), uf::simd::add( uf::simd::add( uf::simd::add( static_cast(1), uf::simd::value( m0, m0, -m0, -m0 ) ), uf::simd::value( m5, -m5, -m5, -m5 ) ), { m10, -m10, -m10, m10 } ) ) ), 2.0f ); - pod::Vector4f signs = uf::simd::sub( uf::simd::value( m[(4*1)+2], m[(4*2)+0], m[(4*0)+1], static_cast(0) ), uf::simd::value( m[(4*2)+1], m[(4*0)+2], m[(4*1)+0], 0.0f ) ); - return { - copysign( q.x, signs.x ), - copysign( q.y, signs.y ), - copysign( q.z, signs.z ), - q.w - }; -#else - q.w = sqrt(fmax(0, 1 + m0 + m5 + m10)) * static_cast(0.5); - q.x = sqrt(fmax(0, 1 + m0 - m5 - m10)) * static_cast(0.5); - q.y = sqrt(fmax(0, 1 - m0 + m5 - m10)) * static_cast(0.5); - q.z = sqrt(fmax(0, 1 - m0 - m5 + m10)) * static_cast(0.5); + T m00 = m[0], m01 = m[1], m02 = m[2]; + T m10 = m[4], m11 = m[5], m12 = m[6]; + T m20 = m[8], m21 = m[9], m22 = m[10]; - q.x = copysign(q.x, m[(4*1)+2] - m[(4*2)+1]); - q.y = copysign(q.y, m[(4*2)+0] - m[(4*0)+2]); - q.z = copysign(q.z, m[(4*0)+1] - m[(4*1)+0]); -#endif - return q; + T trace = m00 + m11 + m22; + if ( trace > 0 ) { + T s = sqrt(trace + 1) * static_cast(2); + q.w = static_cast(0.25) * s; + q.x = (m21 - m12) / s; + q.y = (m02 - m20) / s; + q.z = (m10 - m01) / s; + } + else if ( m00 > m11 && m00 > m22 ) { + T s = sqrt(1 + m00 - m11 - m22) * static_cast(2); + q.w = (m21 - m12) / s; + q.x = static_cast(0.25) * s; + q.y = (m01 + m10) / s; + q.z = (m02 + m20) / s; + } + else if ( m11 > m22 ) { + T s = sqrt(1 + m11 - m00 - m22) * static_cast(2); + q.w = (m02 - m20) / s; + q.x = (m01 + m10) / s; + q.y = static_cast(0.25) * s; + q.z = (m12 + m21) / s; + } + else { + T s = sqrt(1 + m22 - m00 - m11) * static_cast(2); + q.w = (m10 - m01) / s; + q.x = (m02 + m20) / s; + q.y = (m12 + m21) / s; + q.z = static_cast(0.25) * s; + } + + return uf::quaternion::normalize(q); } \ No newline at end of file diff --git a/engine/inc/uf/utils/math/quaternion/quaternion.inl b/engine/inc/uf/utils/math/quaternion/quaternion.inl index 7334596b..f29984c5 100644 --- a/engine/inc/uf/utils/math/quaternion/quaternion.inl +++ b/engine/inc/uf/utils/math/quaternion/quaternion.inl @@ -1,6 +1,7 @@ #pragma once -#include "pod.inl" -#if UF_USE_CLASS_OF_PODS - #include "class.inl" -#endif \ No newline at end of file +#if UF_USE_SIMD + #include "simd.inl" +#endif + +#include "pod.inl" \ No newline at end of file diff --git a/engine/inc/uf/utils/math/quaternion/simd.inl b/engine/inc/uf/utils/math/quaternion/simd.inl new file mode 100644 index 00000000..d504abbb --- /dev/null +++ b/engine/inc/uf/utils/math/quaternion/simd.inl @@ -0,0 +1,146 @@ +namespace uf { + namespace simd { + inline value /*UF_API*/ quatMul( value, value ); + inline value /*UF_API*/ quatRot( value, value ); + inline pod::Matrix4f /*UF_API*/ quatMat( value ); + } +} + +inline uf::simd::value uf::simd::quatMul( uf::simd::value Q1, uf::simd::value Q2 ) { + //__m128 Q1 = q1; + //__m128 Q2 = q2; + + // Broadcast q1.w, q1.x, q1.y, q1.z + __m128 q1w = _mm_shuffle_ps(Q1, Q1, _MM_SHUFFLE(3,3,3,3)); + __m128 q1x = _mm_shuffle_ps(Q1, Q1, _MM_SHUFFLE(0,0,0,0)); + __m128 q1y = _mm_shuffle_ps(Q1, Q1, _MM_SHUFFLE(1,1,1,1)); + __m128 q1z = _mm_shuffle_ps(Q1, Q1, _MM_SHUFFLE(2,2,2,2)); + + // Shuffle q2 into (x,y,z,w) permutations + __m128 q2xyzw = Q2; // (x,y,z,w) + __m128 q2wzyx = _mm_shuffle_ps(Q2, Q2, _MM_SHUFFLE(0,1,2,3)); // (w,z,y,x) + __m128 q2yzxw = _mm_shuffle_ps(Q2, Q2, _MM_SHUFFLE(3,0,2,1)); // (y,z,x,w) + __m128 q2zxyw = _mm_shuffle_ps(Q2, Q2, _MM_SHUFFLE(3,1,0,2)); // (z,x,y,w) + + // Compute terms + __m128 t0 = _mm_mul_ps(q1w, q2xyzw); // w1 * (x2,y2,z2,w2) + __m128 t1 = _mm_mul_ps(q1x, q2wzyx); // x1 * (w2,z2,y2,x2) + __m128 t2 = _mm_mul_ps(q1y, q2yzxw); // y1 * (y2,z2,x2,w2) + __m128 t3 = _mm_mul_ps(q1z, q2zxyw); // z1 * (z2,x2,y2,w2) + + // Signs: (+,+,+,+), (+,-,+,-), (-,+,-,+), (+,-,-,+) + const __m128 sign1 = _mm_set_ps( 1.f,-1.f, 1.f,-1.f); + const __m128 sign2 = _mm_set_ps(-1.f, 1.f,-1.f, 1.f); + const __m128 sign3 = _mm_set_ps( 1.f,-1.f,-1.f, 1.f); + + t1 = _mm_mul_ps(t1, sign1); + t2 = _mm_mul_ps(t2, sign2); + t3 = _mm_mul_ps(t3, sign3); + + __m128 result = _mm_add_ps(_mm_add_ps(t0, t1), _mm_add_ps(t2, t3)); + return result; +} +inline uf::simd::value uf::simd::quatRot( uf::simd::value Q, uf::simd::value V ) { + //__m128 Q = q; // (x,y,z,w) + //__m128 V = v; // (vx,vy,vz,0) + + // Extract q.xyz and q.w + __m128 qxyz = _mm_and_ps(Q, _mm_castsi128_ps(_mm_set_epi32(0, -1, -1, -1))); // mask out w + __m128 qw = _mm_shuffle_ps(Q, Q, _MM_SHUFFLE(3,3,3,3)); + + // dot(q.xyz, v) +#if SSE_INSTR_SET >= 4 + __m128 dot_qv = _mm_dp_ps(qxyz, V, 0x71); // result in lowest lane +#else + __m128 mul = _mm_mul_ps(qxyz, V); + __m128 shuf = _mm_movehdup_ps(mul); + __m128 sums = _mm_add_ps(mul, shuf); + shuf = _mm_movehl_ps(shuf, sums); + sums = _mm_add_ss(sums, shuf); + __m128 dot_qv = sums; +#endif + __m128 term1 = _mm_mul_ps(_mm_mul_ps(dot_qv, _mm_set1_ps(2.0f)), qxyz); + + // dot(q.xyz, q.xyz) +#if SSE_INSTR_SET >= 4 + __m128 dot_qq = _mm_dp_ps(qxyz, qxyz, 0x71); +#else + __m128 mul2 = _mm_mul_ps(qxyz, qxyz); + __m128 shuf2 = _mm_movehdup_ps(mul2); + __m128 sums2 = _mm_add_ps(mul2, shuf2); + shuf2 = _mm_movehl_ps(shuf2, sums2); + sums2 = _mm_add_ss(sums2, shuf2); + __m128 dot_qq = sums2; +#endif + __m128 w2 = _mm_mul_ps(qw, qw); + __m128 coeff = _mm_sub_ps(w2, dot_qq); + __m128 term2 = _mm_mul_ps(coeff, V); + + // cross(q.xyz, v) + __m128 q_yzx = _mm_shuffle_ps(qxyz, qxyz, _MM_SHUFFLE(3,0,2,1)); + __m128 v_yzx = _mm_shuffle_ps(V, V, _MM_SHUFFLE(3,0,2,1)); + __m128 cross = _mm_sub_ps(_mm_mul_ps(qxyz, v_yzx), _mm_mul_ps(q_yzx, V)); + cross = _mm_shuffle_ps(cross, cross, _MM_SHUFFLE(3,0,2,1)); + __m128 term3 = _mm_mul_ps(_mm_mul_ps(cross, qw), _mm_set1_ps(2.0f)); + + // Final result + __m128 result = _mm_add_ps(_mm_add_ps(term1, term2), term3); + + return result; +} +inline pod::Matrix4f uf::simd::quatMat( uf::simd::value Q ) { + // Shuffle out components + __m128 qx = _mm_shuffle_ps(Q, Q, _MM_SHUFFLE(0,0,0,0)); + __m128 qy = _mm_shuffle_ps(Q, Q, _MM_SHUFFLE(1,1,1,1)); + __m128 qz = _mm_shuffle_ps(Q, Q, _MM_SHUFFLE(2,2,2,2)); + __m128 qw = _mm_shuffle_ps(Q, Q, _MM_SHUFFLE(3,3,3,3)); + + // Compute squares + __m128 xx = _mm_mul_ps(qx, qx); + __m128 yy = _mm_mul_ps(qy, qy); + __m128 zz = _mm_mul_ps(qz, qz); + + // Cross terms + __m128 xy = _mm_mul_ps(qx, qy); + __m128 xz = _mm_mul_ps(qx, qz); + __m128 yz = _mm_mul_ps(qy, qz); + __m128 xw = _mm_mul_ps(qx, qw); + __m128 yw = _mm_mul_ps(qy, qw); + __m128 zw = _mm_mul_ps(qz, qw); + + __m128 two = _mm_set1_ps(2.0f); + + xx = _mm_mul_ps(xx, two); + yy = _mm_mul_ps(yy, two); + zz = _mm_mul_ps(zz, two); + xy = _mm_mul_ps(xy, two); + xz = _mm_mul_ps(xz, two); + yz = _mm_mul_ps(yz, two); + xw = _mm_mul_ps(xw, two); + yw = _mm_mul_ps(yw, two); + zw = _mm_mul_ps(zw, two); + + pod::Matrix4f M; + + M[0] = 1.0f - _mm_cvtss_f32(yy) - _mm_cvtss_f32(zz); + M[1] = _mm_cvtss_f32(xy) + _mm_cvtss_f32(zw); + M[2] = _mm_cvtss_f32(xz) - _mm_cvtss_f32(yw); + M[3] = 0.0f; + + M[4] = _mm_cvtss_f32(xy) - _mm_cvtss_f32(zw); + M[5] = 1.0f - _mm_cvtss_f32(xx) - _mm_cvtss_f32(zz); + M[6] = _mm_cvtss_f32(yz) + _mm_cvtss_f32(xw); + M[7] = 0.0f; + + M[8] = _mm_cvtss_f32(xz) + _mm_cvtss_f32(yw); + M[9] = _mm_cvtss_f32(yz) - _mm_cvtss_f32(xw); + M[10] = 1.0f - _mm_cvtss_f32(xx) - _mm_cvtss_f32(yy); + M[11] = 0.0f; + + M[12] = 0.0f; + M[13] = 0.0f; + M[14] = 0.0f; + M[15] = 1.0f; + + return M; +} \ No newline at end of file diff --git a/engine/inc/uf/utils/math/rayt.h b/engine/inc/uf/utils/math/rayt.h deleted file mode 100644 index 70e79bdb..00000000 --- a/engine/inc/uf/utils/math/rayt.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#if 0 -#include -#include - -namespace pod { - struct UF_API RTPrimitive { - static const uint32_t EMPTY = (uint32_t) -1; - static const uint32_t CUBE = 1; - static const uint32_t LEAF = 2; - static const uint32_t TREE = 3; - static const uint32_t ROOT = 4; - pod::Vector4f position; // 4 * 4 = 16 bytes - uint32_t type; // 4 * 1 = 4 bytes - }; - struct UF_API Light { - pod::Vector3f position; - pod::Vector3f color; - }; - struct UF_API Tree { - static const size_t TREE_SIZE = 8; - pod::Vector4f position; // 4 * 4 = 16 bytes - uint32_t type; // 4 * 1 = 4 bytes - uint32_t children[Tree::TREE_SIZE]; // 4 * 8 = 32 bytes - }; -} - -namespace uf { - namespace primitive { - uf::stl::vector UF_API populate( const uf::stl::vector& cubes ); - uf::stl::vector UF_API populateEntirely( const uf::stl::vector& cubes ); - uf::stl::vector UF_API populateEntirely( const uf::stl::vector& trees, bool = false ); - void UF_API test( const uf::stl::vector& cubes, const uf::stl::vector& trees ); - } -} -#endif \ No newline at end of file diff --git a/engine/inc/uf/utils/math/shapes.h b/engine/inc/uf/utils/math/shapes.h index fa447b72..509ea5a5 100644 --- a/engine/inc/uf/utils/math/shapes.h +++ b/engine/inc/uf/utils/math/shapes.h @@ -5,13 +5,13 @@ namespace pod { struct Plane { - pod::Vector3f normal; + alignas(16) pod::Vector3f normal; float offset; }; struct AABB { - pod::Vector3f min; - pod::Vector3f max; + alignas(16) pod::Vector3f min; + alignas(16) pod::Vector3f max; }; struct Sphere { @@ -24,19 +24,19 @@ namespace pod { }; struct Ray { - pod::Vector3f origin; - pod::Vector3f direction; + alignas(16) pod::Vector3f origin; + alignas(16) pod::Vector3f direction; }; struct Triangle { - pod::Vector3f points[3]; + alignas(16) pod::Vector3f points[3]; }; struct TriangleWithNormal : Triangle { - pod::Vector3f normal; + alignas(16) pod::Vector3f normal; }; struct TriangleWithNormals : Triangle { - pod::Vector3f normals[3]; + alignas(16) pod::Vector3f normals[3]; }; template diff --git a/engine/inc/uf/utils/math/transform/transform.inl b/engine/inc/uf/utils/math/transform/transform.inl index 0ffffdb1..e49806a2 100644 --- a/engine/inc/uf/utils/math/transform/transform.inl +++ b/engine/inc/uf/utils/math/transform/transform.inl @@ -65,13 +65,13 @@ template pod::Transform /*UF_API*/ uf::transform::reorient( const template pod::Transform& /*UF_API*/ uf::transform::rotate( pod::Transform& transform, const pod::Vector3t& axis, pod::Math::num_t delta ) { pod::Quaternion<> quat = uf::quaternion::axisAngle( axis, delta ); - transform.orientation = uf::vector::normalize(uf::quaternion::multiply(transform.orientation, quat)); + transform.orientation = uf::vector::normalize(uf::quaternion::multiply(quat, transform.orientation)); transform = uf::transform::reorient(transform); return transform; } template pod::Transform& /*UF_API*/ uf::transform::rotate( pod::Transform& transform, const pod::Quaternion& quat ) { - transform.orientation = uf::vector::normalize(uf::quaternion::multiply(transform.orientation, quat)); + transform.orientation = uf::vector::normalize(uf::quaternion::multiply(quat, transform.orientation)); transform = uf::transform::reorient(transform); return transform; diff --git a/engine/inc/uf/utils/math/vector.h b/engine/inc/uf/utils/math/vector.h index 71452e60..5c166523 100644 --- a/engine/inc/uf/utils/math/vector.h +++ b/engine/inc/uf/utils/math/vector.h @@ -5,11 +5,14 @@ #include "math.h" #include -#include #include #include +#include +#include +#include #include +#include #include #include #include @@ -19,51 +22,11 @@ #endif namespace pod { - // Simple vectors (designed [to store in arrays] with minimal headaches) - template - struct /*UF_API*/ Vector { - // n-dimensional/unspecialized vector access - T components[N]; - // POD information - typedef T type_t; - typedef T* container_t; - static const size_t size = N; - // Overload access - // Accessing via subscripts - T& operator[](size_t i); - const T& operator[](size_t i) const; - // Arithmetic - Vector operator()() const; // Negation - Vector operator-() const; // Negation - Vector operator+( const Vector& vector ) const; // Addition between two vectors - Vector operator-( const Vector& vector ) const; // Subtraction between two vectors - Vector operator*( const Vector& vector ) const; // Multiplication between two vectors - Vector operator/( const Vector& vector ) const; // Division between two vectors - Vector operator+( T scalar ) const; // Multiplication with scalar - Vector operator-( T scalar ) const; // Multiplication with scalar - Vector operator*( T scalar ) const; // Multiplication with scalar - Vector operator/( T scalar ) const; // Division with scalar - Vector& operator +=( const Vector& vector ); // Addition set between two vectors - Vector& operator -=( const Vector& vector ); // Subtraction set between two vectors - Vector& operator *=( const Vector& vector ); // Multiplication set between two vectors - Vector& operator /=( const Vector& vector ); // Division set between two vectors - Vector& operator +=( T scalar ); // Multiplication set with scalar - Vector& operator -=( T scalar ); // Multiplication set with scalar - Vector& operator *=( T scalar ); // Multiplication set with scalar - Vector& operator /=( T scalar ); // Division set with scalar - bool operator==( const Vector& vector ) const; // Equality check between two vectors (equals) - bool operator!=( const Vector& vector ) const; // Equality check between two vectors (not equals) - bool operator<( const Vector& vector ) const; // Equality check between two vectors (less than) - bool operator<=( const Vector& vector ) const; // Equality check between two vectors (less than or equals) - bool operator>( const Vector& vector ) const; // Equality check between two vectors (greater than) - bool operator>=( const Vector& vector ) const; // Equality check between two vectors (greater than or equals) + template + struct Vector; - template Vector& operator=( const Vector& vector ); - template operator Vector(); - explicit inline operator bool() const; - }; template using Vector1t = Vector; - typedef Vector1t Vector1; + typedef Vector1t Vector1; typedef Vector1t Vector1i; typedef Vector1t Vector1ui; @@ -72,7 +35,7 @@ namespace pod { typedef Vector1t Vector1d; template using Vector2t = Vector; - typedef Vector2t Vector2; + typedef Vector2t Vector2; typedef Vector2t Vector2i; typedef Vector2t Vector2ui; @@ -81,7 +44,7 @@ namespace pod { typedef Vector2t Vector2d; template using Vector3t = Vector; - typedef Vector3t Vector3; + typedef Vector3t Vector3; typedef Vector3t Vector3i; typedef Vector3t Vector3ui; typedef Vector3t ColorRGB; @@ -91,7 +54,7 @@ namespace pod { typedef Vector3t Vector3d; template using Vector4t = Vector; - typedef Vector4t Vector4; + typedef Vector4t Vector4; typedef Vector4t Vector4i; typedef Vector4t Vector4ui; typedef Vector4t ColorRgba; @@ -113,217 +76,167 @@ namespace pod { #endif } + // POD vector accessing/manipulation namespace uf { namespace vector { - template pod::Vector1t /*UF_API*/ create( T x ); - template pod::Vector2t /*UF_API*/ create( T x, T y ); - template pod::Vector3t /*UF_API*/ create( T x, T y, T z ); - template pod::Vector4t /*UF_API*/ create( T x, T y, T z, T w ); - template pod::Vector /*UF_API*/ copy( const pod::Vector& = {}); - template pod::Vector /*UF_API*/ cast( const U& from ); + template pod::Vector1t /*UF_API*/ create( T x ); // creates a 1D vector + template pod::Vector2t /*UF_API*/ create( T x, T y ); // creates a 2D vector + template pod::Vector3t /*UF_API*/ create( T x, T y, T z ); // creates a 3D vector + template pod::Vector4t /*UF_API*/ create( T x, T y, T z, T w ); // creates a 4D vector + template pod::Vector /*UF_API*/ copy( const pod::Vector& = {}); // creates a copy of a vector (for whatever reason) + template pod::Vector /*UF_API*/ cast( const U& from ); // casts one vector of one type to another (of the same size) // Equality checking - template int /*UF_API*/ compareTo( const T& left, const T& right ); // Equality check between two vectors (less than) - template bool /*UF_API*/ equals( const T& left, const T& right ); // Equality check between two vectors (equals) + template bool /*UF_API*/ equals( const T& left, const T& right ); // equality check between two vectors (==) + template bool /*UF_API*/ notEquals( const T& left, const T& right ); // equality check between two vectors (==) + template bool /*UF_API*/ less( const T& left, const T& right ); // equality check between two vectors (<) + template bool /*UF_API*/ lessEquals( const T& left, const T& right ); // equality check between two vectors (<=) + template bool /*UF_API*/ greater( const T& left, const T& right ); // equality check between two vectors (>) + template bool /*UF_API*/ greaterEquals( const T& left, const T& right ); // equality check between two vectors (>=) - template bool /*UF_API*/ isValid( const T& v ); // Checks if all components are valid (non NaN, inf, etc.) + template bool /*UF_API*/ isValid( const T& v ); // checks if all components are valid (non NaN, inf, etc.) // Basic arithmetic - template T /*UF_API*/ add( const T& left, const T& right ); // Adds two vectors of same type and size together - template T /*UF_API*/ add( const T& left, /*const typename T::type_t&*/ typename T::type_t scalar ); // Adds two vectors of same type and size together - template T /*UF_API*/ subtract( const T& left, const T& right ); // Subtracts two vectors of same type and size together - template T /*UF_API*/ subtract( const T& left, /*const typename T::type_t&*/ typename T::type_t scalar ); // Subtracts two vectors of same type and size together - template T /*UF_API*/ multiply( const T& left, const T& right ); // Multiplies two vectors of same type and size together - template T /*UF_API*/ multiply( const T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ); // Multiplies this vector by a scalar - template T /*UF_API*/ divide( const T& left, const T& right ); // Divides two vectors of same type and size together - template T /*UF_API*/ divide( const T& left, /*const typename T::type_t&*/ typename T::type_t scalar ); // Divides this vector by a scalar - template typename T::type_t /*UF_API*/ sum( const T& vector ); // Compute the sum of all components - template typename T::type_t /*UF_API*/ product( const T& vector ); // Compute the product of all components - template T /*UF_API*/ negate( const T& vector ); // Flip sign of all components - template T /*UF_API*/ abs( const T& vector ); - // Writes to first value - template T& /*UF_API*/ add_( T& left, const T& right ); // Adds two vectors of same type and size together - template T& /*UF_API*/ add_( T& left, /*const typename T::type_t&*/ typename T::type_t scalar ); // Adds two vectors of same type and size together - template T& /*UF_API*/ subtract_( T& left, const T& right ); // Subtracts two vectors of same type and size together - template T& /*UF_API*/ subtract_( T& left, /*const typename T::type_t&*/ typename T::type_t scalar ); // Subtracts two vectors of same type and size together - template T& /*UF_API*/ multiply_( T& left, const T& right ); // Multiplies two vectors of same type and size together - template T& /*UF_API*/ multiply_( T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ); // Multiplies this vector by a scalar - template T& /*UF_API*/ divide_( T& left, const T& right ); // Divides two vectors of same type and size together - template T& /*UF_API*/ divide_( T& left, /*const typename T::type_t&*/ typename T::type_t scalar ); // Divides this vector by a scalar - template T& /*UF_API*/ negate_( T& vector ); // Flip sign of all components - template T& /*UF_API*/ normalize_( T& vector ); // Normalizes a vector + template T /*UF_API*/ add( const T& left, const T& right ); // adds two vectors of same type and size together + template T /*UF_API*/ add( const T& left, typename T::type_t scalar ); // adds a scalar to every component of the vector + template T /*UF_API*/ add( typename T::type_t scalar, const T& vector ); // adds a scalar to every component of the vector (inverted) + template T /*UF_API*/ subtract( const T& left, const T& right ); // subtracts two vectors of same type and size together + template T /*UF_API*/ subtract( const T& left, typename T::type_t scalar ); // subtracts a scalar to every component of the vector + template T /*UF_API*/ subtract( typename T::type_t scalar, const T& vector ); // subtracts a scalar to every component of the vector (inverted) + template T /*UF_API*/ multiply( const T& left, const T& right ); // multiplies two vectors of same type and size together + template T /*UF_API*/ multiply( const T& vector, typename T::type_t scalar ); // multiplies a scalar to every component of the vector + template T /*UF_API*/ multiply( typename T::type_t scalar, const T& vector ); // multiplies a scalar to every component of the vector (inverted) + template T /*UF_API*/ divide( const T& left, const T& right ); // divides two vectors of same type and size together + template T /*UF_API*/ divide( const T& left, typename T::type_t scalar ); // divides a scalar to every component of the vector + template T /*UF_API*/ divide( typename T::type_t scalar, const T& vector ); // divides a scalar to every component of the vector (inverted) - template T /*UF_API*/ min( const T& left, const T& right ); // - template T /*UF_API*/ max( const T& left, const T& right ); // - template T /*UF_API*/ ceil( const T& vector ); // - template T /*UF_API*/ floor( const T& vector ); // - template T /*UF_API*/ round( const T& vector ); // + template T& /*UF_API*/ add_( T& left, const T& right ); // adds two vectors of same type and size together + template T& /*UF_API*/ add_( T& left, typename T::type_t scalar ); // adds a scalar to every component of the vector + template T& /*UF_API*/ add_( typename T::type_t scalar, T& vector ); // adds a scalar to every component of the vector (inverted) + template T& /*UF_API*/ subtract_( T& left, const T& right ); // subtracts two vectors of same type and size together + template T& /*UF_API*/ subtract_( T& left, typename T::type_t scalar ); // subtracts a scalar to every component of the vector + template T& /*UF_API*/ subtract_( typename T::type_t scalar, T& vector ); // subtracts a scalar to every component of the vector (inverted) + template T& /*UF_API*/ multiply_( T& left, const T& right ); // multiplies two vectors of same type and size together + template T& /*UF_API*/ multiply_( T& vector, typename T::type_t scalar ); // multiplies a scalar to every component of the vector + template T& /*UF_API*/ multiply_( typename T::type_t scalar, T& vector ); // multiplies a scalar to every component of the vector (inverted) + template T& /*UF_API*/ divide_( T& left, const T& right ); // divides two vectors of same type and size together + template T& /*UF_API*/ divide_( T& left, typename T::type_t scalar ); // divides a scalar to every component of the vector + template T& /*UF_API*/ divide_( typename T::type_t scalar, T& vector ); // divides a scalar to every component of the vector (inverted) + template T& /*UF_API*/ negate_( T& vector ); // flip sign of all components + template T& /*UF_API*/ normalize_( T& vector ); // normalizes a vector + + template typename T::type_t /*UF_API*/ sum( const T& vector ); // compute the sum of all components + template typename T::type_t /*UF_API*/ product( const T& vector ); // compute the product of all components + template T /*UF_API*/ negate( const T& vector ); // flip sign of all components + template T /*UF_API*/ abs( const T& vector ); // gets the absolute value of a vector + template T /*UF_API*/ min( const T& left, const T& right ); // returns the minimum of each component between two vectors + template T /*UF_API*/ max( const T& left, const T& right ); // returns the maximum of each component between two vectors + template T /*UF_API*/ clamp( const T& vector, const T& min, const T& max ); // clamps a vector between two bounds + template T /*UF_API*/ ceil( const T& vector ); // rounds each component of the the vector up + template T /*UF_API*/ floor( const T& vector ); // rounds each component of the vector down + template T /*UF_API*/ round( const T& vector ); // rounds each component of the vector // Complex arithmetic - template typename T::type_t /*UF_API*/ dot( const T& left, const T& right ); // Compute the dot product between two vectors - template float /*UF_API*/ angle( const T& a, const T& b ); // Compute the angle between two vectors - template float /*UF_API*/ signedAngle( const T& a, const T& b, const T& axis ); // Compute the signed angle between two vectors - template T /*UF_API*/ cross( const T& a, const T& b ); // Compute the cross product between two vectors + template typename T::type_t /*UF_API*/ dot( const T& left, const T& right ); // compute the dot product between two vectors + template float /*UF_API*/ angle( const T& a, const T& b ); // compute the angle between two vectors + template float /*UF_API*/ signedAngle( const T& a, const T& b, const T& axis ); // compute the signed angle between two vectors + template T /*UF_API*/ cross( const T& a, const T& b ); // compute the cross product between two vectors - template T /*UF_API*/ lerp( const T& from, const T& to, double, bool = true ); // Linearly interpolate between two vectors - template T /*UF_API*/ lerp( const T& from, const T& to, const T&, bool = true ); // Linearly interpolate between two vectors + template T /*UF_API*/ lerp( const T& from, const T& to, double, bool = true ); // linearly interpolate between two vectors + template T /*UF_API*/ lerp( const T& from, const T& to, const T&, bool = true ); // linearly interpolate between two vectors, component-wise - template T /*UF_API*/ slerp( const T& from, const T& to, double, bool = false); // Spherically interpolate between two vectors - template T /*UF_API*/ mix( const T& from, const T& to, double, bool = false ); // + template T /*UF_API*/ slerp( const T& from, const T& to, double, bool = false ); // spherically interpolate between two vectors + template T /*UF_API*/ mix( const T& from, const T& to, double, bool = false ); - template typename T::type_t /*UF_API*/ distanceSquared( const T& a, const T& b ); // Compute the distance between two vectors (doesn't sqrt) - template typename T::type_t /*UF_API*/ distance( const T& a, const T& b ); // Compute the distance between two vectors - template typename T::type_t /*UF_API*/ norm( const T& vector ); // Compute the norm of the vector - template typename T::type_t /*UF_API*/ magnitude( const T& vector ); // Gets the magnitude of the vector - template T /*UF_API*/ normalize( const T& vector ); // Normalizes a vector - template T /*UF_API*/ clampMagnitude( const T& vector ); // Clamps the magnitude of a vector - template void /*UF_API*/ orthonormalize( T& x, T& y ); // Orthonormalizes a vector against another vector - template T /*UF_API*/ orthonormalize( const T& x, const T& y ); // Orthonormalizes a vector against another vector + template typename T::type_t /*UF_API*/ distanceSquared( const T& a, const T& b ); // compute the distance between two vectors (doesn't sqrt) + template typename T::type_t /*UF_API*/ distance( const T& a, const T& b ); // compute the distance between two vectors + template typename T::type_t /*UF_API*/ magnitude( const T& vector ); // gets the magnitude of the vector + template typename T::type_t /*UF_API*/ norm( const T& vector ); // compute the norm (length) of the vector + template T /*UF_API*/ normalize( const T& vector ); // normalizes a vector + template T /*UF_API*/ clampMagnitude( const T& vector ); // clamps the magnitude of a vector + template void /*UF_API*/ orthonormalize( T& x, T& y ); // orthonormalizes a vector against another vector + template T /*UF_API*/ orthonormalize( const T& x, const T& y ); // orthonormalizes a vector against another vector - template uf::stl::string /*UF_API*/ toString( const T& vector ); // Parses a vector as a string - template ext::json::Value encode( const pod::Vector& v, const ext::json::EncodingSettings& = {} ); // Parses a vector into a JSON value + template uf::stl::string /*UF_API*/ toString( const T& vector ); // parses a vector as a string + template ext::json::Value encode( const pod::Vector& v, const ext::json::EncodingSettings& = {} ); // parses a vector into a JSON value - template pod::Vector& decode( const ext::json::Value& v, pod::Vector& ); // Parses a JSON value into a vector - template pod::Vector decode( const ext::json::Value& v, const pod::Vector& = {} ); // Parses a JSON value into a vector + template pod::Vector& decode( const ext::json::Value& v, pod::Vector& ); // parses a JSON value into a vector + template pod::Vector decode( const ext::json::Value& v, const pod::Vector& = {} ); // parses a JSON value into a vector - template typename T::type_t /*UF_API*/ mips( const T& size ); // Calculate amount of mips to use given a size + template typename T::type_t /*UF_API*/ mips( const T& size ); // calculate amount of mips to use given a size } } -#if UF_USE_CLASS_OF_PODS -namespace uf { - // Provides operations for POD vector - template - class /*UF_API*/ Vector { - public: - // Easily access POD's type - typedef pod::Vector pod_t; - // Replicate POD information - typedef T type_t; - typedef T* container_t; - static const size_t size = N; - protected: - // POD storage - Vector::pod_t m_pod; - public: - // C-tor - Vector(); // initializes POD to 'def' - Vector(T def); // initializes POD to 'def' - Vector(const Vector& v, T w); - Vector(const Vector::pod_t& pod); // copies POD altogether - Vector(const T components[N]); // copies data into POD from 'components' (typed as C array) - Vector(const uf::stl::vector& components); // copies data into POD from 'components' (typed as uf::stl::vector) - // D-tor - // Unneccesary - // POD access - Vector::pod_t& data(); // Returns a reference of POD - const Vector::pod_t& data() const; // Returns a const-reference of POD - // Alternative POD access - T* get(); // Returns a pointer to the entire array - const T* get() const; // Returns a const-pointer to the entire array - T& getComponent( size_t i ); // Returns a reference to a single element - const T& getComponent( size_t i ) const; // Returns a const-reference to a single element - // POD manipulation - T* set(const T components[N]); // Sets the entire array - T& setComponent( size_t i, const T& value ); // Sets a single element - // Validation - bool isValid() const; // Checks if all components are valid (non NaN, inf, etc.) - // Basic arithmetic - inline uf::Vector& add( const Vector& vector ); // Adds two vectors of same type and size together - inline uf::Vector& add( T scalar ); // Adds two vectors of same type and size together - inline uf::Vector& subtract( const Vector& vector ); // Subtracts two vectors of same type and size together - inline uf::Vector& subtract( T scalar ); // Subtracts two vectors of same type and size together - inline uf::Vector& multiply( const Vector& vector ); // Multiplies two vectors of same type and size together - inline uf::Vector& multiply( T scalar ); // Multiplies this vector by a scalar - inline uf::Vector& divide( const Vector& vector ); // Divides two vectors of same type and size together - inline uf::Vector& divide( T scalar ); // Divides this vector by a scalar - inline T sum() const; // Compute the sum of all components - inline T product() const; // Compute the product of all components - inline uf::Vector& negate(); // Flip sign of all components - // Complex arithmetic - inline T dot( const Vector right ) const; // Compute the dot product between two vectors - inline float angle( const Vector& b ) const; // Compute the angle between two vectors - - inline uf::Vector lerp( const Vector to, double delta ) const; // Linearly interpolate between two vectors - inline uf::Vector slerp( const Vector to, double delta ) const; // Spherically interpolate between two vectors - - inline T distanceSquared( const Vector b ) const; // Compute the distance between two vectors (doesn't sqrt) - inline T distance( const Vector b ) const; // Compute the distance between two vectors - inline T magnitude() const; // Gets the magnitude of the vector - inline T norm() const; // Compute the norm of the vector - - inline uf::Vector& normalize(); // Normalizes a vector - uf::Vector getNormalized() const; // Return a normalized vector - inline uf::stl::string toString() const; - // Overloaded ops - // Accessing via subscripts - T& operator[](size_t i); - const T& operator[](size_t i) const; - // Arithmetic - inline Vector operator-() const; // Negation - inline Vector operator+( const Vector& vector ) const; // Addition between two vectors - inline Vector operator-( const Vector& vector ) const; // Subtraction between two vectors - inline Vector operator*( const Vector& vector ) const; // Multiplication between two vectors - inline Vector operator/( const Vector& vector ) const; // Division between two vectors - inline Vector operator+( T scalar ) const; // Multiplication with scalar - inline Vector operator-( T scalar ) const; // Multiplication with scalar - inline Vector operator*( T scalar ) const; // Multiplication with scalar - inline Vector operator/( T scalar ) const; // Division with scalar - inline Vector& operator +=( const Vector& vector ); // Addition set between two vectors - inline Vector& operator -=( const Vector& vector ); // Subtraction set between two vectors - inline Vector& operator *=( const Vector& vector ); // Multiplication set between two vectors - inline Vector& operator /=( const Vector& vector ); // Division set between two vectors - inline Vector& operator +=( T scalar ); // Multiplication set with scalar - inline Vector& operator -=( T scalar ); // Multiplication set with scalar - inline Vector& operator *=( T scalar ); // Multiplication set with scalar - inline Vector& operator /=( T scalar ); // Division set with scalar - inline bool operator==( const Vector& vector ) const; // Equality check between two vectors (equals) - inline bool operator!=( const Vector& vector ) const; // Equality check between two vectors (not equals) - inline bool operator<( const Vector& vector ) const; // Equality check between two vectors (less than) - inline bool operator<=( const Vector& vector ) const; // Equality check between two vectors (less than or equals) - inline bool operator>( const Vector& vector ) const; // Equality check between two vectors (greater than) - inline bool operator>=( const Vector& vector ) const; // Equality check between two vectors (greater than or equals) - - inline operator pod_t&() { return this->m_pod; } - inline operator const pod_t&() const { return this->m_pod; } +#define DEFINE_VECTOR(T, N) \ + using type_t = T;\ + using container_t = T*;\ + static constexpr size_t size = N;\ + inline T& operator[](size_t i) { return components[i]; }\ + inline const T& operator[](size_t i) const { return components[i]; }\ + inline Vector operator-() const { return uf::vector::negate(*this); } \ + inline Vector operator+(const Vector& rhs) const { return uf::vector::add(*this, rhs); } \ + inline Vector operator-(const Vector& rhs) const { return uf::vector::subtract(*this, rhs); } \ + inline Vector operator*(const Vector& rhs) const { return uf::vector::multiply(*this, rhs); } \ + inline Vector operator/(const Vector& rhs) const { return uf::vector::divide(*this, rhs); } \ + inline Vector operator+(type_t scalar) const { return uf::vector::add(*this, scalar); } \ + inline Vector operator-(type_t scalar) const { return uf::vector::subtract(*this, scalar); } \ + inline Vector operator*(type_t scalar) const { return uf::vector::multiply(*this, scalar); } \ + inline Vector operator/(type_t scalar) const { return uf::vector::divide(*this, scalar); } \ + inline Vector& operator+=(const Vector& rhs) { return uf::vector::add_(*this, rhs); } \ + inline Vector& operator-=(const Vector& rhs) { return uf::vector::subtract_(*this, rhs); } \ + inline Vector& operator*=(const Vector& rhs) { return uf::vector::multiply_(*this, rhs); } \ + inline Vector& operator/=(const Vector& rhs) { return uf::vector::divide_(*this, rhs); } \ + inline Vector& operator+=(type_t scalar) { return uf::vector::add_(*this, scalar); } \ + inline Vector& operator-=(type_t scalar) { return uf::vector::subtract_(*this, scalar); } \ + inline Vector& operator*=(type_t scalar) { return uf::vector::multiply_(*this, scalar); } \ + inline Vector& operator/=(type_t scalar) { return uf::vector::divide_(*this, scalar); } \ + inline bool operator==(const Vector& rhs) const { return uf::vector::equals(*this, rhs); } \ + inline bool operator!=(const Vector& rhs) const { return uf::vector::notEquals(*this, rhs); } \ + inline bool operator<(const Vector& rhs) const { return uf::vector::less(*this, rhs); } \ + inline bool operator<=(const Vector& rhs) const { return uf::vector::lessEquals(*this, rhs); } \ + inline bool operator>(const Vector& rhs) const { return uf::vector::greater(*this, rhs); } \ + inline bool operator>=(const Vector& rhs) const { return uf::vector::greaterEquals(*this, rhs); } \ + inline explicit operator bool() const { return uf::vector::notEquals(*this, Vector{}); } \ + template inline operator Vector() const { return uf::vector::cast(*this); } + +namespace pod { + template + struct Vector { + union { + T components[N]; + }; + + DEFINE_VECTOR(T, N); }; - template using Vector1t = Vector; - typedef Vector1t Vector1; - typedef Vector1t Vector1i; - typedef Vector1t Vector1ui; + template + struct Vector { + union { + struct { T x, y; }; + T components[2]; + }; - typedef Vector1t Vector1l; - typedef Vector1t Vector1f; - typedef Vector1t Vector1d; - - template using Vector2t = Vector; - typedef Vector2t Vector2; - typedef Vector2t Vector2i; - typedef Vector2t Vector2ui; + DEFINE_VECTOR(T, 2); + }; + template + struct Vector { + union { + struct { T x, y, z; }; + T components[3]; + }; - typedef Vector2t Vector2l; - typedef Vector2t Vector2f; - typedef Vector2t Vector2d; + DEFINE_VECTOR(T, 3); + }; - template using Vector3t = Vector; - typedef Vector3t Vector3; - typedef Vector3t Vector3i; - typedef Vector3t Vector3ui; - typedef Vector3t ColorRGB; + template + struct Vector { + union { + struct { T x, y, z, w; }; + T components[4]; + }; - typedef Vector3t Vector3l; - typedef Vector3t Vector3f; - typedef Vector3t Vector3d; - - template using Vector4t = Vector; - typedef Vector4t Vector4; - typedef Vector4t Vector4i; - typedef Vector4t Vector4ui; - typedef Vector4t ColorRgba; - - typedef Vector4t Vector4l; - typedef Vector4t Vector4f; - typedef Vector4t Vector4d; + DEFINE_VECTOR(T, 4); + }; } -#endif + +// external functions //#include #include @@ -341,217 +254,6 @@ namespace ext { } } -namespace pod { - template - struct /*UF_API*/ Vector { - // XY access - T x; - // n-dimensional/unspecialized vector access - // T* components = (T*) this; - // POD information - typedef T type_t; - typedef T* container_t; - static const size_t size = 1; - // Overload access - // Accessing via subscripts - T& operator[](size_t i); - const T& operator[](size_t i) const; - // Arithmetic - inline Vector operator()() const; // Creation - inline Vector operator-() const; // Negation - inline Vector operator+( const Vector& vector ) const; // Addition between two vectors - inline Vector operator-( const Vector& vector ) const; // Subtraction between two vectors - inline Vector operator*( const Vector& vector ) const; // Multiplication between two vectors - inline Vector operator/( const Vector& vector ) const; // Division between two vectors - inline Vector operator+( T scalar ) const; // Multiplication with scalar - inline Vector operator-( T scalar ) const; // Multiplication with scalar - inline Vector operator*( T scalar ) const; // Multiplication with scalar - inline Vector operator/( T scalar ) const; // Division with scalar - inline Vector& operator +=( const Vector& vector ); // Addition set between two vectors - inline Vector& operator -=( const Vector& vector ); // Subtraction set between two vectors - inline Vector& operator *=( const Vector& vector ); // Multiplication set between two vectors - inline Vector& operator /=( const Vector& vector ); // Division set between two vectors - inline Vector& operator +=( T scalar ); // Multiplication set with scalar - inline Vector& operator -=( T scalar ); // Multiplication set with scalar - inline Vector& operator *=( T scalar ); // Multiplication set with scalar - inline Vector& operator /=( T scalar ); // Division set with scalar - inline bool operator==( const Vector& vector ) const; // Equality check between two vectors (equals) - inline bool operator!=( const Vector& vector ) const; // Equality check between two vectors (not equals) - inline bool operator<( const Vector& vector ) const; // Equality check between two vectors (less than) - inline bool operator<=( const Vector& vector ) const; // Equality check between two vectors (less than or equals) - inline bool operator>( const Vector& vector ) const; // Equality check between two vectors (greater than) - inline bool operator>=( const Vector& vector ) const; // Equality check between two vectors (greater than or equals) - template Vector& operator=( const Vector& vector ); - template operator Vector(); - explicit inline operator bool() const; - #if 0 - #if UF_USE_SIMD - Vector& operator=( const __m128 ); - operator __m128() const; - #endif - #endif - }; - template - struct /*UF_API*/ Vector { - // XY access - T x; - T y; - // n-dimensional/unspecialized vector access - // T* components = (T*) this; - // POD information - typedef T type_t; - typedef T* container_t; - static const size_t size = 2; - // Overload access - // Accessing via subscripts - T& operator[](size_t i); - const T& operator[](size_t i) const; - // Arithmetic - inline Vector operator()() const; // Creation - inline Vector operator-() const; // Negation - inline Vector operator+( const Vector& vector ) const; // Addition between two vectors - inline Vector operator-( const Vector& vector ) const; // Subtraction between two vectors - inline Vector operator*( const Vector& vector ) const; // Multiplication between two vectors - inline Vector operator/( const Vector& vector ) const; // Division between two vectors - inline Vector operator+( T scalar ) const; // Multiplication with scalar - inline Vector operator-( T scalar ) const; // Multiplication with scalar - inline Vector operator*( T scalar ) const; // Multiplication with scalar - inline Vector operator/( T scalar ) const; // Division with scalar - inline Vector& operator +=( const Vector& vector ); // Addition set between two vectors - inline Vector& operator -=( const Vector& vector ); // Subtraction set between two vectors - inline Vector& operator *=( const Vector& vector ); // Multiplication set between two vectors - inline Vector& operator /=( const Vector& vector ); // Division set between two vectors - inline Vector& operator +=( T scalar ); // Multiplication set with scalar - inline Vector& operator -=( T scalar ); // Multiplication set with scalar - inline Vector& operator *=( T scalar ); // Multiplication set with scalar - inline Vector& operator /=( T scalar ); // Division set with scalar - inline bool operator==( const Vector& vector ) const; // Equality check between two vectors (equals) - inline bool operator!=( const Vector& vector ) const; // Equality check between two vectors (not equals) - inline bool operator<( const Vector& vector ) const; // Equality check between two vectors (less than) - inline bool operator<=( const Vector& vector ) const; // Equality check between two vectors (less than or equals) - inline bool operator>( const Vector& vector ) const; // Equality check between two vectors (greater than) - inline bool operator>=( const Vector& vector ) const; // Equality check between two vectors (greater than or equals) - template Vector& operator=( const Vector& vector ); - template operator Vector(); - explicit inline operator bool() const; - #if 0 - #if UF_USE_SIMD - Vector& operator=( const __m128 ); - operator __m128() const; - #endif - #endif - }; - template - struct /*UF_API*/ Vector { - // XYZ access - T x; - T y; - T z; - // n-dimensional/unspecialized vector access - // T* components = (T*) this; - // POD information - typedef T type_t; - typedef T* container_t; - static const size_t size = 3; - // Overload access - // Accessing via subscripts - T& operator[](size_t i); - const T& operator[](size_t i) const; - // Arithmetic - inline Vector operator()() const; // Creation - inline Vector operator-() const; // Negation - inline Vector operator+( const Vector& vector ) const; // Addition between two vectors - inline Vector operator-( const Vector& vector ) const; // Subtraction between two vectors - inline Vector operator*( const Vector& vector ) const; // Multiplication between two vectors - inline Vector operator/( const Vector& vector ) const; // Division between two vectors - inline Vector operator+( T scalar ) const; // Multiplication with scalar - inline Vector operator-( T scalar ) const; // Multiplication with scalar - inline Vector operator*( T scalar ) const; // Multiplication with scalar - inline Vector operator/( T scalar ) const; // Division with scalar - inline Vector& operator +=( const Vector& vector ); // Addition set between two vectors - inline Vector& operator -=( const Vector& vector ); // Subtraction set between two vectors - inline Vector& operator *=( const Vector& vector ); // Multiplication set between two vectors - inline Vector& operator /=( const Vector& vector ); // Division set between two vectors - inline Vector& operator +=( T scalar ); // Multiplication set with scalar - inline Vector& operator -=( T scalar ); // Multiplication set with scalar - inline Vector& operator *=( T scalar ); // Multiplication set with scalar - inline Vector& operator /=( T scalar ); // Division set with scalar - inline bool operator==( const Vector& vector ) const; // Equality check between two vectors (equals) - inline bool operator!=( const Vector& vector ) const; // Equality check between two vectors (not equals) - inline bool operator<( const Vector& vector ) const; // Equality check between two vectors (less than) - inline bool operator<=( const Vector& vector ) const; // Equality check between two vectors (less than or equals) - inline bool operator>( const Vector& vector ) const; // Equality check between two vectors (greater than) - inline bool operator>=( const Vector& vector ) const; // Equality check between two vectors (greater than or equals) - - template Vector& operator=( const Vector& vector ); - template operator Vector(); - explicit inline operator bool() const; - #if 0 - #if UF_USE_SIMD - Vector& operator=( const __m128 ); - operator __m128() const; - #endif - #endif - }; - template -#if UF_VECTOR_ALIGNED - struct /*UF_API*/ alignas(16) Vector { -#else - struct /*UF_API*/ Vector { -#endif - // XYZW access - T x; - T y; - T z; - T w; - // n-dimensional/unspecialized vector access - // T* components = (T*) this; - // POD information - typedef T type_t; - typedef T* container_t; - static const size_t size = 4; - // Overload access - // Accessing via subscripts - T& operator[](size_t i); - const T& operator[](size_t i) const; - // Arithmetic - inline Vector operator()() const; // Creation - inline Vector operator-() const; // Negation - inline Vector operator+( const Vector& vector ) const; // Addition between two vectors - inline Vector operator-( const Vector& vector ) const; // Subtraction between two vectors - inline Vector operator*( const Vector& vector ) const; // Multiplication between two vectors - inline Vector operator/( const Vector& vector ) const; // Division between two vectors - inline Vector operator+( T scalar ) const; // Multiplication with scalar - inline Vector operator-( T scalar ) const; // Multiplication with scalar - inline Vector operator*( T scalar ) const; // Multiplication with scalar - inline Vector operator/( T scalar ) const; // Division with scalar - inline Vector& operator +=( const Vector& vector ); // Addition set between two vectors - inline Vector& operator -=( const Vector& vector ); // Subtraction set between two vectors - inline Vector& operator *=( const Vector& vector ); // Multiplication set between two vectors - inline Vector& operator /=( const Vector& vector ); // Division set between two vectors - inline Vector& operator +=( T scalar ); // Multiplication set with scalar - inline Vector& operator -=( T scalar ); // Multiplication set with scalar - inline Vector& operator *=( T scalar ); // Multiplication set with scalar - inline Vector& operator /=( T scalar ); // Division set with scalar - inline bool operator==( const Vector& vector ) const; // Equality check between two vectors (equals) - inline bool operator!=( const Vector& vector ) const; // Equality check between two vectors (not equals) - inline bool operator<( const Vector& vector ) const; // Equality check between two vectors (less than) - inline bool operator<=( const Vector& vector ) const; // Equality check between two vectors (less than or equals) - inline bool operator>( const Vector& vector ) const; // Equality check between two vectors (greater than) - inline bool operator>=( const Vector& vector ) const; // Equality check between two vectors (greater than or equals) - - template Vector& operator=( const Vector& vector ); - template operator Vector(); - explicit inline operator bool() const; - #if 0 - #if UF_USE_SIMD - Vector& operator=( const __m128 ); - operator __m128() const; - #endif - #endif - }; -} - namespace std { template struct hash> { diff --git a/engine/inc/uf/utils/math/vector/class.inl b/engine/inc/uf/utils/math/vector/class.inl deleted file mode 100644 index 3419974b..00000000 --- a/engine/inc/uf/utils/math/vector/class.inl +++ /dev/null @@ -1,256 +0,0 @@ -// C-tor -template // initializes POD to 'def' -uf::Vector::Vector() { -} -template // initializes POD to 'def' -uf::Vector::Vector(T def) { - for ( std::size_t i = 0; i < N; ++i ) this->m_pod[i] = def; -} -template // copies POD altogether -uf::Vector::Vector(const typename uf::Vector::pod_t& pod) : m_pod(pod) { -} -template // copies data into POD from 'components' (typed as C array) -uf::Vector::Vector(const T components[N]) { - this->set(&components[0]); -} -template // copies data into POD from 'components' (typed as uf::stl::vector) -uf::Vector::Vector(const uf::stl::vector& components) { - if ( components.size() >= N ) this->set(&components[0]); -} -// D-tor -// Unneccesary -// POD access -template // Returns a reference of POD -typename uf::Vector::pod_t& uf::Vector::data() { - return this->m_pod; -} -template // Returns a const-reference of POD -const typename uf::Vector::pod_t& uf::Vector::data() const { - return this->m_pod; -} -// Alternative POD access -template // Returns a pointer to the entire array -T* uf::Vector::get() { - return &this->m_pod[0]; -} -template // Returns a const-pointer to the entire array -const T* uf::Vector::get() const { - return &this->m_pod[0]; -} -template // Returns a reference to a single element -T& uf::Vector::getComponent( std::size_t i ) { - return this->m_pod[i]; -} -template // Returns a const-reference to a single element -const T& uf::Vector::getComponent( std::size_t i ) const { - return this->m_pod[i]; -} -// POD manipulation -template // Sets the entire array -T* uf::Vector::set(const T components[N]) { - for ( std::size_t i = 0; i < N; ++i ) this->m_pod[i] = components[i]; -} -template // Sets a single element -T& uf::Vector::setComponent( std::size_t i, const T& value ) { - this->m_pod[i] = value; -} -// Validation -template // Checks if all components are valid (non NaN, inf, etc.) -bool uf::Vector::isValid() const { - return uf::vector::isValid( this->m_pod ); -} -// Basic arithmetic -template // Adds two vectors of same type and size together -inline uf::Vector& uf::Vector::add( const Vector& vector ) { - return uf::vector::add( this->m_pod, vector.data() ); -} -template // Multiplies this vector by a scalar -inline uf::Vector& uf::Vector::add( T scalar ) { - return uf::vector::add( this->m_pod, scalar ); -} -template // Subtracts two vectors of same type and size together -inline uf::Vector& uf::Vector::subtract( const Vector& vector ) { - return uf::vector::subtract( this->m_pod, vector.data() ); -} -template // Multiplies this vector by a scalar -inline uf::Vector& uf::Vector::subtract( T scalar ) { - return uf::vector::subtract( this->m_pod, scalar ); -} -template // Multiplies two vectors of same type and size together -inline uf::Vector& uf::Vector::multiply( const Vector& vector ) { - return uf::vector::multiply( this->m_pod, vector.data() ); -} -template // Multiplies this vector by a scalar -inline uf::Vector& uf::Vector::multiply( T scalar ) { - return uf::vector::multiply( this->m_pod, scalar ); -} -template // Divides two vectors of same type and size together -inline uf::Vector& uf::Vector::divide( const Vector& vector ) { - return uf::vector::divide( this->m_pod, vector.data() ); -} -template // Divides this vector by a scalar -inline uf::Vector& uf::Vector::divide( T scalar ) { - return uf::vector::divide( this->m_pod, scalar ); -} -template // Compute the sum of all components -inline T uf::Vector::sum() const { - return uf::vector::sum( this->m_pod ); -} -template // Compute the product of all components -inline T uf::Vector::product() const { - return uf::vector::product( this->m_pod ); -} -template // Flip sign of all components -inline uf::Vector& uf::Vector::negate() { - return uf::vector::negate( this->m_pod ); -} -// Complex arithmetic -template // Compute the dot product between two vectors -inline T uf::Vector::dot( const Vector right ) const { - return uf::vector::dot( this->m_pod, right ); -} -template // Compute the angle between two vectors -inline float uf::Vector::angle( const Vector& b ) const { - return uf::vector::angle( this->m_pod, b ); -} - -template // Linearly interpolate between two vectors -inline uf::Vector uf::Vector::lerp( const Vector to, double delta ) const { - return uf::vector::lerp( this->m_pod, to, delta ); -} -template // Spherically interpolate between two vectors -inline uf::Vector uf::Vector::slerp( const Vector to, double delta ) const { - return uf::vector::slerp( this->m_pod, to, delta ); -} - -template // Compute the distance between two vectors (doesn't sqrt) -inline T uf::Vector::distanceSquared( const Vector b ) const { - return uf::vector::distanceSquared( this->m_pod, b ); -} -template // Compute the distance between two vectors -inline T uf::Vector::distance( const Vector b ) const { - return uf::vector::distance( this->m_pod, b ); -} -template // Gets the magnitude of the vector -inline T uf::Vector::magnitude() const { - return uf::vector::magnitude( this->m_pod ); -} -template // Compute the norm of the vector -inline T uf::Vector::norm() const { - return uf::vector::norm( this->m_pod ); -} - -template // Normalizes a vector -inline uf::Vector& uf::Vector::normalize() { - return uf::vector::normalize( this->m_pod ); -} -template // Return a normalized vector -uf::Vector uf::Vector::getNormalized() const { - return uf::vector::normalize( this->m_pod ); -} -template // Return a string -uf::stl::string uf::Vector::toString() const { - return uf::vector::toString( this->m_pod ); -} -// Overloaded ops -template -T& uf::Vector::operator[](std::size_t i) { - return this->m_pod[i]; -} -template -const T& uf::Vector::operator[](std::size_t i) const { - return this->m_pod[i]; -} -// Arithmetic -template // Negation -inline uf::Vector uf::Vector::operator-() const { - return uf::vector::negate( this->m_pod ); -} -template // Addition between two vectors -inline uf::Vector uf::Vector::operator+( const uf::Vector& vector ) const { - return uf::vector::add( this->m_pod, vector.data() ); -} -template // Subtraction between two vectors -inline uf::Vector uf::Vector::operator-( const uf::Vector& vector ) const { - return uf::vector::subtract( this->m_pod, vector.data() ); -} -template // Multiplication between two vectors -inline uf::Vector uf::Vector::operator*( const uf::Vector& vector ) const { - return uf::vector::multiply( this->m_pod, vector.data() ); -} -template // Division between two vectors -inline uf::Vector uf::Vector::operator/( const uf::Vector& vector ) const { - return uf::vector::divide( this->m_pod, vector.data() ); -} -template // Multiplication with scalar -inline uf::Vector uf::Vector::operator+( T scalar ) const { - return uf::vector::add( this->m_pod, scalar ); -} -template // Multiplication with scalar -inline uf::Vector uf::Vector::operator-( T scalar ) const { - return uf::vector::subtract( this->m_pod, scalar ); -} -template // Multiplication with scalar -inline uf::Vector uf::Vector::operator*( T scalar ) const { - return uf::vector::multiply( this->m_pod, scalar ); -} -template // Division with scalar -inline uf::Vector uf::Vector::operator/( T scalar ) const { - return uf::vector::divide( this->m_pod, scalar ); -} -template // Addition set between two vectors -inline uf::Vector& uf::Vector::operator +=( const uf::Vector& vector ) { - return uf::vector::add( this->m_pod, vector.data() ); -} -template // Subtraction set between two vectors -inline uf::Vector& uf::Vector::operator -=( const uf::Vector& vector ) { - return uf::vector::subtract( this->m_pod, vector.data() ); -} -template // Multiplication set between two vectors -inline uf::Vector& uf::Vector::operator *=( const uf::Vector& vector ) { - return uf::vector::multiply( this->m_pod, vector.data() ); -} -template // Division set between two vectors -inline uf::Vector& uf::Vector::operator /=( const uf::Vector& vector ) { - return uf::vector::divide( this->m_pod, vector.data() ); -} -template // Multiplication set with scalar -inline uf::Vector& uf::Vector::operator +=( T scalar ) { - return uf::vector::add( this->m_pod, scalar ); -} -template // Multiplication set with scalar -inline uf::Vector& uf::Vector::operator -=( T scalar ) { - return uf::vector::subtract( this->m_pod, scalar ); -} -template // Multiplication set with scalar -inline uf::Vector& uf::Vector::operator *=( T scalar ) { - return uf::vector::multiply( this->m_pod, scalar ); -} -template // Division set with scalar -inline uf::Vector& uf::Vector::operator /=( T scalar ) { - return uf::vector::divide( this->m_pod, scalar ); -} -template // Equality check between two vectors (equals) -inline bool uf::Vector::operator==( const uf::Vector& vector ) const { - return uf::vector::equals(this->m_pod, vector.data() ); -} -template // Equality check between two vectors (not equals) -inline bool uf::Vector::operator!=( const uf::Vector& vector ) const { - return !uf::vector::equals(this->m_pod, vector.data() ); -} -template // Equality check between two vectors (less than) -inline bool uf::Vector::operator<( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) < 0; -} -template // Equality check between two vectors (less than or equals) -inline bool uf::Vector::operator<=( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) <= 0; -} -template // Equality check between two vectors (greater than) -inline bool uf::Vector::operator>( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) > 0; -} -template // Equality check between two vectors (greater than or equals) -inline bool uf::Vector::operator>=( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) >= 0; -} \ No newline at end of file diff --git a/engine/inc/uf/utils/math/vector/pod.inl b/engine/inc/uf/utils/math/vector/pod.inl index e14bd0e9..370571ea 100644 --- a/engine/inc/uf/utils/math/vector/pod.inl +++ b/engine/inc/uf/utils/math/vector/pod.inl @@ -1,376 +1,567 @@ -#if !__clang__ && __GNUC__ - #pragma GCC push_options - #pragma GCC optimize ("unroll-loops") -#endif +template +constexpr bool simd_able_v = std::is_same_v || std::is_same_v || std::is_same_v; -// having this as an static const in-class variable doesn't work for some reason -#define SIMD_ABLE(T) std::is_same::value || std::is_same::value || std::is_same::value +template +constexpr void for_each_index(F&& f) { + [&](std::index_sequence) { + (f(std::integral_constant{}), ...); + }(std::make_index_sequence{}); +} #if UF_USE_SIMD #include "simd.h" #endif -#include "redundancy.inl" -// Equality checking + +// #define FOR_EACH( N, F ) for ( auto i = 0; i < N; ++i ) F; +#define FOR_EACH( N, F ) for_each_index([&](auto i) F ) + +template +T elementwise( const T& left, const T& right, Op&& op ) { + alignas(16) T res; + FOR_EACH(T::size, { + res[i] = op(left[i], right[i]); + }); + return res; +} + template -pod::Vector1t /*UF_API*/ uf::vector::create( T x ) { pod::Vector1t vec; vec.x = x; return vec; } +pod::Vector1t uf::vector::create( T x ) { + return pod::Vector1t{ x }; +} template -pod::Vector2t /*UF_API*/ uf::vector::create( T x, T y ) { pod::Vector2t vec; vec.x = x, vec.y = y; return vec; } +pod::Vector2t uf::vector::create( T x, T y ) { + return pod::Vector2t{ x, y }; +} template -pod::Vector3t /*UF_API*/ uf::vector::create( T x, T y, T z ) { pod::Vector3t vec; vec.x = x, vec.y = y, vec.z = z; return vec; } +pod::Vector3t uf::vector::create( T x, T y, T z ) { + return pod::Vector3t{ x, y, z }; +} template -pod::Vector4t /*UF_API*/ uf::vector::create( T x, T y, T z, T w ) { pod::Vector4t vec; vec.x = x, vec.y = y, vec.z = z, vec.w = w; return vec; } +pod::Vector4t uf::vector::create( T x, T y, T z, T w ) { + return pod::Vector4t{ x, y, z, w }; +} template -pod::Vector /*UF_API*/ uf::vector::copy( const pod::Vector& v ) { return v; } +pod::Vector uf::vector::copy( const pod::Vector& v ) { + return v; +} template -pod::Vector /*UF_API*/ uf::vector::cast( const U& from ) { - ALIGN16 pod::Vector to; +pod::Vector uf::vector::cast( const U& from ) { + alignas(16) pod::Vector to; #pragma unroll // GCC unroll N for ( auto i = 0; i < N && i < U::size; ++i ) to[i] = from[i]; return to; } -// Equality checking -template // Equality check between two vectors (less than) -int /*UF_API*/ uf::vector::compareTo( const T& left, const T& right ) { - return memcmp( &left, &right, T::size ); +template +bool uf::vector::equals( const T& left, const T& right ) { +#if UF_USE_SIMD + if constexpr ( simd_able_v ) { + return uf::simd::all( uf::simd::equals( left, right ) ); + } +#else + bool result = true; + FOR_EACH(T::size, { + if ( !(left[i] == right[i]) ) result = false; + }); + return result; +#endif } -template // Equality check between two vectors (equals) -bool /*UF_API*/ uf::vector::equals( const T& left, const T& right ) { -// return uf::vector::compareTo(left, right) == 0; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) - if ( left[i] != right[i] ) return false; - return true; +template +bool uf::vector::notEquals( const T& left, const T& right ) { +#if UF_USE_SIMD + if constexpr ( simd_able_v ) { + return uf::simd::all( uf::simd::notEquals( left, right ) ); + } +#else + bool result = true; + FOR_EACH(T::size, { + if ( !(left[i] != right[i]) ) result = false; + }); + return result; +#endif } -template // -bool /*UF_API*/ uf::vector::isValid( const T& v ) { +template +bool uf::vector::less( const T& left, const T& right ) { +#if UF_USE_SIMD + if constexpr ( simd_able_v ) { + return uf::simd::all( uf::simd::less( left, right ) ); + } +#else + bool result = true; + FOR_EACH(T::size, { + if ( !(left[i] < right[i]) ) result = false; + }); + return result; +#endif +} +template +bool uf::vector::lessEquals( const T& left, const T& right ) { +#if UF_USE_SIMD + if constexpr ( simd_able_v ) { + return uf::simd::all( uf::simd::lessEquals( left, right ) ); + } +#else + bool result = true; + FOR_EACH(T::size, { + if ( !(left[i] <= right[i]) ) result = false; + }); + return result; +#endif +} +template +bool uf::vector::greater( const T& left, const T& right ) { +#if UF_USE_SIMD + if constexpr ( simd_able_v ) { + return uf::simd::all( uf::simd::greater( left, right ) ); + } +#else + bool result = true; + FOR_EACH(T::size, { + if ( !(left[i] > right[i]) ) result = false; + }); + return result; +#endif +} +template +bool uf::vector::greaterEquals( const T& left, const T& right ) { +#if UF_USE_SIMD + if constexpr ( simd_able_v ) { + return uf::simd::all( uf::simd::greaterEquals( left, right ) ); + } +#else + bool result = true; + FOR_EACH(T::size, { + if ( !(left[i] >= right[i]) ) result = false; + }); + return result; +#endif +} +template +bool uf::vector::isValid( const T& v ) { return uf::vector::equals( v, v ); } -// Basic arithmetic -template // Adds two vectors of same type and size together -T /*UF_API*/ uf::vector::add( const T& left, const T& right ) { +template +T uf::vector::add( const T& left, const T& right ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return uf::simd::add( left, right ); } #endif - ALIGN16 T res; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + alignas(16) T res; + FOR_EACH(T::size, { res[i] = left[i] + right[i]; + }); return res; } -template // Multiplies this vector by a scalar -T /*UF_API*/ uf::vector::add( const T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ) { +template +T uf::vector::add( const T& vector, typename T::type_t scalar ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return uf::simd::add( vector, scalar ); } #endif - ALIGN16 T res; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + alignas(16) T res; + FOR_EACH(T::size, { res[i] = vector[i] + scalar; + }); return res; } -template // Subtracts two vectors of same type and size together -T /*UF_API*/ uf::vector::subtract( const T& left, const T& right ) { +template +T uf::vector::add( typename T::type_t scalar, const T& vector ) { + return uf::vector::add( vector, scalar ); +} +template +T uf::vector::subtract( const T& left, const T& right ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return uf::simd::sub( left, right ); } #endif - ALIGN16 T res; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + alignas(16) T res; + FOR_EACH(T::size, { res[i] = left[i] - right[i]; + }); return res; } -template // Multiplies this vector by a scalar -T /*UF_API*/ uf::vector::subtract( const T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ) { +template +T uf::vector::subtract( const T& vector, typename T::type_t scalar ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return uf::simd::sub( vector, scalar ); } #endif - ALIGN16 T res; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + alignas(16) T res; + FOR_EACH(T::size, { res[i] = vector[i] - scalar; + }); return res; } -template // Multiplies two vectors of same type and size together -T /*UF_API*/ uf::vector::multiply( const T& left, const T& right ) { +template +T uf::vector::subtract( typename T::type_t scalar, const T& vector ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { + return uf::simd::sub( scalar, vector ); + } +#endif + alignas(16) T res; + FOR_EACH(T::size, { + res[i] = scalar - vector[i]; + }); + return res; +} +template +T uf::vector::multiply( const T& left, const T& right ) { +#if UF_USE_SIMD + if constexpr ( simd_able_v ) { return uf::simd::mul( left, right ); } #endif - ALIGN16 T res; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + alignas(16) T res; + FOR_EACH(T::size, { res[i] = left[i] * right[i]; + }); return res; } -template // Multiplies this vector by a scalar -T /*UF_API*/ uf::vector::multiply( const T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ) { +template +T uf::vector::multiply( const T& vector, typename T::type_t scalar ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return uf::simd::mul( vector, scalar ); } #endif - ALIGN16 T res; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + alignas(16) T res; + FOR_EACH(T::size, { res[i] = vector[i] * scalar; + }); return res; } -template // Divides two vectors of same type and size together -T /*UF_API*/ uf::vector::divide( const T& left, const T& right ) { +template +T uf::vector::multiply( typename T::type_t scalar, const T& vector ) { + return uf::vector::multiply( vector, scalar ); +} +template +T uf::vector::divide( const T& left, const T& right ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return uf::simd::div( left, right ); } #elif UF_ENV_DREAMCAST && UF_ENV_DREAMCAST_SIMD - if ( SIMD_ABLE(T) ) { - ALIGN16 T res; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) - res[i] = MATH_Fast_Divide(left[i], right[i]); + if constexpr ( simd_able_v ) { + alignas(16) T res; + FOR_EACH(T::size, { + res[i] = MATH_Fast_Divide( left[i], right[i] ); + }); return res; } #endif - ALIGN16 T res; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + alignas(16) T res; + FOR_EACH(T::size, { res[i] = left[i] / right[i]; + }); return res; } -template // Divides this vector by a scalar -T /*UF_API*/ uf::vector::divide( const T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ) { +template +T uf::vector::divide( const T& vector, typename T::type_t scalar ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return uf::simd::div( vector, scalar ); } #elif UF_ENV_DREAMCAST && UF_ENV_DREAMCAST_SIMD - if ( SIMD_ABLE(T) ) { - ALIGN16 T res; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) - res[i] = MATH_Fast_Divide(vector[i], scalar); + if constexpr ( simd_able_v ) { + alignas(16) T res; + FOR_EACH(T::size, { + res[i] = MATH_Fast_Divide( vector[i], scalar ); + }); return res; } #endif - ALIGN16 T res; - scalar = 1.0 / scalar; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + alignas(16) T res; + scalar = static_cast(1) / scalar; + FOR_EACH(T::size, { res[i] = vector[i] * scalar; + }); return res; } -template // Compute the sum of all components -typename T::type_t /*UF_API*/ uf::vector::sum( const T& vector ) { - typename T::type_t res = 0; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) - res += vector[i]; - return res; -} -template // Compute the product of all components -typename T::type_t /*UF_API*/ uf::vector::product( const T& vector ) { - typename T::type_t res = 0; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) - res *= vector[i]; - return res; -} -template // Flip sign of all components -T /*UF_API*/ uf::vector::negate( const T& vector ) { +template +T uf::vector::divide( typename T::type_t scalar, const T& vector ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { + return uf::simd::div( scalar, vector ); + } +#elif UF_ENV_DREAMCAST && UF_ENV_DREAMCAST_SIMD + if constexpr ( simd_able_v ) { + alignas(16) T res; + FOR_EACH(T::size, { + res[i] = MATH_Fast_Divide( scalar, vector[i] ); + }); + return res; + } +#endif + alignas(16) T res; + scalar = static_cast(1) / scalar; + FOR_EACH(T::size, { + res[i] = scalar / vector[i]; + }); + return res; +} +template +typename T::type_t uf::vector::sum( const T& vector ) { + auto res = 0; + FOR_EACH(T::size, { + res += vector[i]; + }); + return res; +} +template +typename T::type_t uf::vector::product( const T& vector ) { + auto res = 1; + FOR_EACH(T::size, { + res *= vector[i]; + }); + return res; +} +template +T uf::vector::negate( const T& vector ) { +#if UF_USE_SIMD + if constexpr ( simd_able_v ) { return uf::simd::mul( vector, -1.f ); } #endif - ALIGN16 T res; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + alignas(16) T res; + FOR_EACH(T::size, { res[i] = -vector[i]; + }); return res; } -template // -T /*UF_API*/ uf::vector::abs( const T& vector ) { - T res; - for ( auto i = 0; i < T::size; ++i ) res[i] = std::abs( vector[i] ); +template +T uf::vector::abs( const T& vector ) { + alignas(16) T res; + FOR_EACH(T::size, { + res[i] = std::abs( vector[i] ); + }); return res; } -// Writes to first value -template // Adds two vectors of same type and size together -T& /*UF_API*/ uf::vector::add_( T& left, const T& right ) { +template +T& uf::vector::add_( T& left, const T& right ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return left = uf::vector::add( (const T&) left, right ); } #endif - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + FOR_EACH(T::size, { left[i] += right[i]; + }); return left; } -template // Multiplies this vector by a scalar -T& /*UF_API*/ uf::vector::add_( T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ) { +template +T& uf::vector::add_( T& vector, typename T::type_t scalar ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return vector = uf::vector::add( (const T&) vector, scalar ); } #endif - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + FOR_EACH(T::size, { vector[i] += scalar; + }); return vector; } -template // Subtracts two vectors of same type and size together -T& /*UF_API*/ uf::vector::subtract_( T& left, const T& right ) { +template +T& uf::vector::add_( typename T::type_t scalar, T& vector ) { + return uf::vector::add_( vector, scalar ); +} +template +T& uf::vector::subtract_( T& left, const T& right ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return left = uf::vector::subtract( (const T&) left, right ); } #endif - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + FOR_EACH(T::size, { left[i] -= right[i]; + }); return left; } -template // Multiplies this vector by a scalar -T& /*UF_API*/ uf::vector::subtract_( T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ) { +template +T& uf::vector::subtract_( T& vector, typename T::type_t scalar ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return vector = uf::vector::subtract( (const T&) vector, scalar ); } #endif - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + FOR_EACH(T::size, { vector[i] -= scalar; + }); return vector; } -template // Multiplies two vectors of same type and size together -T& /*UF_API*/ uf::vector::multiply_( T& left, const T& right ) { +template +T& uf::vector::subtract_( typename T::type_t scalar, T& vector ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { + return vector = uf::vector::subtract( scalar, (const T&) vector ); + } +#endif + FOR_EACH(T::size, { + vector[i] = scalar - vector[i]; + }); + return vector; +} +template +T& uf::vector::multiply_( T& left, const T& right ) { +#if UF_USE_SIMD + if constexpr ( simd_able_v ) { return left = uf::vector::multiply( (const T&) left, right ); } #endif - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + FOR_EACH(T::size, { left[i] *= right[i]; + }); return left; } -template // Multiplies this vector by a scalar -T& /*UF_API*/ uf::vector::multiply_( T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ) { +template +T& uf::vector::multiply_( T& vector, typename T::type_t scalar ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return vector = uf::vector::multiply( (const T&) vector, scalar ); } #endif - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + FOR_EACH(T::size, { vector[i] *= scalar; + }); return vector; } -template // Divides two vectors of same type and size together -T& /*UF_API*/ uf::vector::divide_( T& left, const T& right ) { +template +T& uf::vector::multiply_( typename T::type_t scalar, T& vector ) { + return uf::vector::multiply_( scalar, vector ); +} +template +T& uf::vector::divide_( T& left, const T& right ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return left = uf::vector::divide( (const T&) left, right ); } #endif - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + FOR_EACH(T::size, { left[i] /= right[i]; + }); return left; } -template // Divides this vector by a scalar -T& /*UF_API*/ uf::vector::divide_( T& vector, /*const typename T::type_t&*/ typename T::type_t scalar ) { +template +T& uf::vector::divide_( T& vector, typename T::type_t scalar ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return vector = uf::vector::divide( (const T&) vector, scalar ); } #endif - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + FOR_EACH(T::size, { vector[i] /= scalar; + }); return vector; } -template // Flip sign of all components -T& /*UF_API*/ uf::vector::negate_( T& vector ) { +template +T& uf::vector::divide_( typename T::type_t scalar, T& vector ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { + return vector = uf::vector::divide( scalar, (const T&) vector ); + } +#endif + FOR_EACH(T::size, { + vector[i] = scalar / vector[i]; + }); + return vector; +} +template +T& uf::vector::negate_( T& vector ) { +#if UF_USE_SIMD + if constexpr ( simd_able_v ) { return vector = uf::vector::negate( (const T&) vector ); } #endif - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + FOR_EACH(T::size, { vector[i] = -vector[i]; + }); return vector; } -template // Normalizes a vector -T& /*UF_API*/ uf::vector::normalize_( T& vector ) { +template +T& uf::vector::normalize_( T& vector ) { typename T::type_t norm = uf::vector::norm(vector); - if ( norm == 0 ) return vector; - return vector = uf::vector::divide((const T&) vector, norm); + return ( norm == 0 ) ? T{} : ( vector = uf::vector::divide((const T&) vector, norm) ); } -template // -T /*UF_API*/ uf::vector::min( const T& left, const T& right ) { +template +T uf::vector::min( const T& left, const T& right ) { +#if UF_USE_SIMD + if constexpr ( simd_able_v ) { + return uf::simd::min( left, right ); + } +#endif T res = left; - for ( auto i = 0; i < T::size; ++i ) res[i] = std::min( left[i], right[i] ); + FOR_EACH(T::size, { + res[i] = std::min( left[i], right[i] ); + }); return res; } -template // -T /*UF_API*/ uf::vector::max( const T& left, const T& right ) { +template +T uf::vector::max( const T& left, const T& right ) { +#if UF_USE_SIMD + if constexpr ( simd_able_v ) { + return uf::simd::max( left, right ); + } +#endif T res; - for ( auto i = 0; i < T::size; ++i ) res[i] = std::max( left[i], right[i] ); + FOR_EACH(T::size, { + res[i] = std::max( left[i], right[i] ); + }); return res; } -template // -T /*UF_API*/ uf::vector::ceil( const T& vector ) { +template +T uf::vector::clamp( const T& vector, const T& min, const T& max ) { + return uf::vector::max( min, uf::vector::min( vector, max ) ); +} +template +T uf::vector::ceil( const T& vector ) { T res; - for ( auto i = 0; i < T::size; ++i ) res[i] = std::ceil( vector[i] ); + FOR_EACH(T::size, { + res[i] = std::ceil( vector[i] ); + }); return res; } -template // -T /*UF_API*/ uf::vector::floor( const T& vector ) { +template +T uf::vector::floor( const T& vector ) { T res; - for ( auto i = 0; i < T::size; ++i ) res[i] = std::floor( vector[i] ); + FOR_EACH(T::size, { + res[i] = std::floor( vector[i] ); + }); return res; } -template // -T /*UF_API*/ uf::vector::round( const T& vector ) { +template +T uf::vector::round( const T& vector ) { T res; - for ( auto i = 0; i < T::size; ++i ) res[i] = ::round( vector[i] ); + FOR_EACH(T::size, { + res[i] = ::round( vector[i] ); + }); return res; } -// Complex arithmetic -template // Compute the dot product between two vectors -typename T::type_t /*UF_API*/ uf::vector::dot( const T& left, const T& right ) { +template +typename T::type_t uf::vector::dot( const T& left, const T& right ) { #if UF_ENV_DREAMCAST && UF_ENV_DREAMCAST_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return MATH_fipr( UF_EZ_VEC4(left, T::size), UF_EZ_VEC4(right, T::size) ); } #elif UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return uf::simd::dot( left, right ); } #endif return uf::vector::sum(uf::vector::multiply(left, right)); } -template // Compute the angle between two vectors -float /*UF_API*/ uf::vector::angle( const T& a, const T& b ) { +template +float uf::vector::angle( const T& a, const T& b ) { auto dot = uf::vector::dot(a, b); if ( dot < -1.0f ) dot = -1.0f; if ( dot > 1.0f ) dot = 1.0f; return acos(dot); } -template // Compute the angle between two vectors -float /*UF_API*/ uf::vector::signedAngle( const T& a, const T& b, const T& axis ) { +template +float uf::vector::signedAngle( const T& a, const T& b, const T& axis ) { auto unsignedAngle = uf::vector::angle(a, b); float cross_x = a.y * b.z - a.z * b.y; float cross_y = a.z * b.x - a.x * b.z; @@ -378,46 +569,46 @@ float /*UF_API*/ uf::vector::signedAngle( const T& a, const T& b, const T& axis float sign = (axis.x * cross_x + axis.y * cross_y + axis.z * cross_z) >= 0.0f ? 1.0f : -1.0f; return unsignedAngle * sign; } -template // Linearly interpolate between two vectors -T /*UF_API*/ uf::vector::lerp( const T& from, const T& to, double delta, bool clamp ) { +template +T uf::vector::lerp( const T& from, const T& to, double delta, bool clamp ) { delta = fmax( 0, fmin(1,delta) ); // from + ( ( to - from ) * delta ) #if UF_ENV_DREAMCAST && UF_ENV_DREAMCAST_SIMD - if ( SIMD_ABLE(T) ) { - ALIGN16 T res; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + if constexpr ( simd_able_v ) { + alignas(16) T res; + FOR_EACH(T::size, { res[i] = MATH_Lerp( from[i], to[i], delta ); + }); return res; } #elif UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return uf::simd::add(from, uf::simd::mul( uf::simd::sub(to, from), (float) delta) ); } #endif return uf::vector::add(from, uf::vector::multiply( uf::vector::subtract(to, from), delta ) ); } -template // Linearly interpolate between two vectors -T /*UF_API*/ uf::vector::lerp( const T& from, const T& to, const T& delta, bool clamp ) { +template +T uf::vector::lerp( const T& from, const T& to, const T& delta, bool clamp ) { //delta = fmax( 0, fmin(1,delta) ); // from + ( ( to - from ) * delta ) #if UF_ENV_DREAMCAST && UF_ENV_DREAMCAST_SIMD - if ( SIMD_ABLE(T) ) { - ALIGN16 T res; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) + if constexpr ( simd_able_v ) { + alignas(16) T res; + FOR_EACH(T::size, { res[i] = MATH_Lerp( from[i], to[i], delta[i] ); + }); return res; } #elif UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return uf::simd::add(from, uf::simd::mul( uf::simd::sub(to, from), delta) ); } #endif return uf::vector::add(from, uf::vector::multiply( uf::vector::subtract(to, from), delta ) ); } -template // Spherically interpolate between two vectors -T /*UF_API*/ uf::vector::slerp( const T& from, const T& to, double delta, bool clamp ) { +template +T uf::vector::slerp( const T& from, const T& to, double delta, bool clamp ) { if ( clamp ) delta = fmax( 0, fmin(1,delta) ); typename T::type_t dot = uf::vector::dot(from, to); typename T::type_t theta = acos(dot); @@ -426,81 +617,75 @@ T /*UF_API*/ uf::vector::slerp( const T& from, const T& to, double delta, bool c typename T::type_t w1 = sin((1.0f - delta) * theta / sTheta); typename T::type_t w2 = sin( delta * theta / sTheta ); #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return uf::simd::add( uf::simd::mul( from, w1 ), uf::simd::mul( to, w2 ) ); } #endif return uf::vector::add(uf::vector::multiply(from, w1), uf::vector::multiply(to, w2)); } -template // -T /*UF_API*/ uf::vector::mix( const T& x, const T& y, double a, bool clamp ) { +template +T uf::vector::mix( const T& x, const T& y, double a, bool clamp ) { if ( clamp ) a = fmax( 0, fmin(1,a) ); // x * (1.0 - a) + y * a #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return uf::simd::add( uf::simd::mul( x, 1.0f - (float) a ), uf::simd::mul( y, (float) a ) ); } #endif return uf::vector::add( uf::vector::multiply( x, 1 - a ), uf::vector::multiply( y, a ) ); } -template // Compute the distance between two vectors (doesn't sqrt) -typename T::type_t /*UF_API*/ uf::vector::distanceSquared( const T& a, const T& b ) { +template +typename T::type_t uf::vector::distanceSquared( const T& a, const T& b ) { #if UF_ENV_DREAMCAST && UF_ENV_DREAMCAST_SIMD - if ( SIMD_ABLE(T) ) { - ALIGN16 T delta = uf::vector::subtract(b, a); + if constexpr ( simd_able_v ) { + alignas(16) T delta = uf::vector::subtract(b, a); return MATH_Sum_of_Squares( UF_EZ_VEC4( delta, T::size ) ); } #elif UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { uf::simd::value delta = uf::simd::sub( b, a ); - // return uf::vector::sum( uf::simd::vector( uf::simd::mul( delta, delta ) ) ); return uf::simd::dot( delta, delta ); } #endif - ALIGN16 T delta = uf::vector::subtract(b, a); + alignas(16) T delta = uf::vector::subtract( b, a ); return uf::vector::dot( delta, delta ); -/* - ALIGN16 T delta = uf::vector::subtract(b, a); - uf::vector::multiply( delta, delta ); - return uf::vector::sum(delta); -*/ } -template // Compute the distance between two vectors -typename T::type_t /*UF_API*/ uf::vector::distance( const T& a, const T& b ) { +template +typename T::type_t uf::vector::distance( const T& a, const T& b ) { #if UF_ENV_DREAMCAST && UF_ENV_DREAMCAST_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return MATH_Fast_Sqrt(uf::vector::distanceSquared(a,b)); } #endif - return sqrt(uf::vector::distanceSquared(a,b)); + return sqrt( uf::vector::distanceSquared( a, b ) ); } -template // Gets the magnitude of the vector -typename T::type_t /*UF_API*/ uf::vector::magnitude( const T& vector ) { +template +typename T::type_t uf::vector::magnitude( const T& vector ) { return uf::vector::dot(vector, vector); } -template // Compute the norm of the vector -typename T::type_t /*UF_API*/ uf::vector::norm( const T& vector ) { +template +typename T::type_t uf::vector::norm( const T& vector ) { #if UF_ENV_DREAMCAST && UF_ENV_DREAMCAST_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return MATH_Fast_Sqrt( uf::vector::magnitude(vector) ); } #endif return sqrt( uf::vector::magnitude(vector) ); } -template // Normalizes a vector -T /*UF_API*/ uf::vector::normalize( const T& vector ) { +template +T uf::vector::normalize( const T& vector ) { typename T::type_t norm = uf::vector::norm(vector); if ( norm == 0 ) return vector; #if UF_ENV_DREAMCAST && UF_ENV_DREAMCAST_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { return uf::vector::multiply(vector, MATH_fsrra(norm)); } #endif return uf::vector::divide(vector, norm); } -template // Clamps the length of a vector -T /*UF_API*/ uf::vector::clampMagnitude( const T& v, float maxMag ) { +template +T uf::vector::clampMagnitude( const T& v, float maxMag ) { T res = v; float mag = uf::vector::magnitude( res ); if ( mag > maxMag ) { @@ -510,22 +695,22 @@ T /*UF_API*/ uf::vector::clampMagnitude( const T& v, float maxMag ) { return res; } -template // Normalizes a vector -void /*UF_API*/ uf::vector::orthonormalize( T& normal, T& tangent ) { +template +void uf::vector::orthonormalize( T& normal, T& tangent ) { normal = uf::vector::normalize( normal ); - ALIGN16 T norm = normal; - ALIGN16 T tan = uf::vector::normalize( tangent ); + alignas(16) T norm = normal; + alignas(16) T tan = uf::vector::normalize( tangent ); tangent = uf::vector::subtract( tan, uf::vector::multiply( norm, uf::vector::dot( norm, tan ) ) ); tangent = uf::vector::normalize( tangent ); } -template // Normalizes a vector -T /*UF_API*/ uf::vector::orthonormalize( const T& x, const T& y ) { +template +T uf::vector::orthonormalize( const T& x, const T& y ) { return uf::vector::normalize( uf::vector::subtract( x, uf::vector::multiply( y, uf::vector::dot( y, x ) ) ) ); } -template // Normalizes a vector -T /*UF_API*/ uf::vector::cross( const T& a, const T& b ) { +template +T uf::vector::cross( const T& a, const T& b ) { #if UF_USE_SIMD - if ( SIMD_ABLE(T) ) { + if constexpr ( simd_able_v ) { uf::simd::value x = a; uf::simd::value y = b; #if SSE_INSTR_SET >= 7 @@ -546,20 +731,29 @@ T /*UF_API*/ uf::vector::cross( const T& a, const T& b ) { #endif } #elif UF_ENV_DREAMCAST && UF_ENV_DREAMCAST_SIMD - if ( SIMD_ABLE(T) ) { - ALIGN16 auto res = MATH_Cross_Product( a.x, a.y, a.z, b.x, b.y, b.z ); + if constexpr ( simd_able_v ) { + alignas(16) auto res = MATH_Cross_Product( a.x, a.y, a.z, b.x, b.y, b.z ); return *((T*) &res); } #endif - ALIGN16 T res{ + alignas(16) T res{ a.y * b.z - b.y * a.z, a.z * b.x - b.z * a.x, a.x * b.y - b.x * a.y }; return res; } -template // Normalizes a vector -uf::stl::string /*UF_API*/ uf::vector::toString( const T& v ) { +template +typename T::type_t uf::vector::mips( const T& size ) { + uint32_t max = 0; + FOR_EACH(T::size, { + max = std::max( max, size[i] ); + }); + return static_cast(std::floor(std::log2(max))) + 1; +} + +template +uf::stl::string uf::vector::toString( const T& v ) { uf::stl::stringstream ss; ss << "Vector("; #pragma unroll // GCC unroll T::size @@ -572,7 +766,7 @@ uf::stl::string /*UF_API*/ uf::vector::toString( const T& v ) { } template -ext::json::Value /*UF_API*/ uf::vector::encode( const pod::Vector& v, const ext::json::EncodingSettings& settings ) { +ext::json::Value uf::vector::encode( const pod::Vector& v, const ext::json::EncodingSettings& settings ) { ext::json::Value json; if ( settings.quantize ) #pragma unroll // GCC unroll T::size @@ -585,7 +779,7 @@ ext::json::Value /*UF_API*/ uf::vector::encode( const pod::Vector& v, const return json; } template -pod::Vector& /*UF_API*/ uf::vector::decode( const ext::json::Value& json, pod::Vector& v ) { +pod::Vector& uf::vector::decode( const ext::json::Value& json, pod::Vector& v ) { if ( ext::json::isArray(json) ) #pragma unroll // GCC unroll T::size for ( auto i = 0; i < N && i < json.size(); ++i ) @@ -601,7 +795,7 @@ pod::Vector& /*UF_API*/ uf::vector::decode( const ext::json::Value& json, p return v; } template -pod::Vector /*UF_API*/ uf::vector::decode( const ext::json::Value& json, const pod::Vector& _v ) { +pod::Vector uf::vector::decode( const ext::json::Value& json, const pod::Vector& _v ) { pod::Vector v = _v; if ( ext::json::isArray(json) ) #pragma unroll // GCC unroll T::size @@ -616,16 +810,4 @@ pod::Vector /*UF_API*/ uf::vector::decode( const ext::json::Value& json, co }); } return v; -} - -template -typename T::type_t /*UF_API*/ uf::vector::mips( const T& size ) { - typename T::type_t max = 0; - #pragma unroll // GCC unroll T::size - for ( auto i = 0; i < T::size; ++i ) max = std::max(max, size[i]); - return static_cast(std::floor(std::log2(max))) + 1; -} - -#if !__clang__ && __GNUC__ - #pragma GCC pop_options -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/engine/inc/uf/utils/math/vector/redundancy.inl b/engine/inc/uf/utils/math/vector/redundancy.inl deleted file mode 100644 index 47c54313..00000000 --- a/engine/inc/uf/utils/math/vector/redundancy.inl +++ /dev/null @@ -1,1976 +0,0 @@ -// -// -template -T& pod::Vector::operator[](std::size_t i) { - return this->components[i]; -} -template -const T& pod::Vector::operator[](std::size_t i) const { - return this->components[i]; -} -// Arithmetic -template // Negation -inline pod::Vector pod::Vector::operator-() const { - return uf::vector::negate( *this ); -} -template // Addition between two vectors -inline pod::Vector pod::Vector::operator+( const pod::Vector& vector ) const { - return uf::vector::add( *this, vector ); -} -template // Subtraction between two vectors -inline pod::Vector pod::Vector::operator-( const pod::Vector& vector ) const { - return uf::vector::subtract( *this, vector ); -} -template // Multiplication between two vectors -inline pod::Vector pod::Vector::operator*( const pod::Vector& vector ) const { - return uf::vector::multiply( *this, vector ); -} -template // Division between two vectors -inline pod::Vector pod::Vector::operator/( const pod::Vector& vector ) const { - return uf::vector::divide( *this, vector ); -} -template // Multiplication with scalar -inline pod::Vector pod::Vector::operator+( T scalar ) const { - return uf::vector::add( *this, scalar ); -} -template // Multiplication with scalar -inline pod::Vector pod::Vector::operator-( T scalar ) const { - return uf::vector::subtract( *this, scalar ); -} -template // Multiplication with scalar -inline pod::Vector pod::Vector::operator*( T scalar ) const { - return uf::vector::multiply( *this, scalar ); -} -template // Division with scalar -inline pod::Vector pod::Vector::operator/( T scalar ) const { - return uf::vector::divide( *this, scalar ); -} -template // Addition set between two vectors -inline pod::Vector& pod::Vector::operator +=( const pod::Vector& vector ) { - return uf::vector::add_( *this, vector ); -} -template // Subtraction set between two vectors -inline pod::Vector& pod::Vector::operator -=( const pod::Vector& vector ) { - return uf::vector::subtract_( *this, vector ); -} -template // Multiplication set between two vectors -inline pod::Vector& pod::Vector::operator *=( const pod::Vector& vector ) { - return uf::vector::multiply_( *this, vector ); -} -template // Division set between two vectors -inline pod::Vector& pod::Vector::operator /=( const pod::Vector& vector ) { - return uf::vector::divide_( *this, vector ); -} -template // Multiplication set with scalar -inline pod::Vector& pod::Vector::operator +=( T scalar ) { - return uf::vector::add_( *this, scalar ); -} -template // Multiplication set with scalar -inline pod::Vector& pod::Vector::operator -=( T scalar ) { - return uf::vector::subtract_( *this, scalar ); -} -template // Multiplication set with scalar -inline pod::Vector& pod::Vector::operator *=( T scalar ) { - return uf::vector::multiply_( *this, scalar ); -} -template // Division set with scalar -inline pod::Vector& pod::Vector::operator /=( T scalar ) { - return uf::vector::divide_( *this, scalar ); -} -template // Equality check between two vectors (equals) -inline bool pod::Vector::operator==( const pod::Vector& vector ) const { - return uf::vector::equals(*this, vector); -} -template // Equality check between two vectors (not equals) -inline bool pod::Vector::operator!=( const pod::Vector& vector ) const { - return !uf::vector::equals(*this, vector); -} -template // Equality check between two vectors (less than) -inline bool pod::Vector::operator<( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) < 0; -} -template // Equality check between two vectors (less than or equals) -inline bool pod::Vector::operator<=( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) <= 0; -} -template // Equality check between two vectors (greater than) -inline bool pod::Vector::operator>( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) > 0; -} -template // Equality check between two vectors (greater than or equals) -inline bool pod::Vector::operator>=( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) >= 0; -} -template // Equality check between two vectors (greater than or equals) -inline pod::Vector::operator bool() const { - return !uf::vector::equals(*this, pod::Vector{}); -} - -template -template -pod::Vector::operator pod::Vector() { - return uf::vector::cast(*this); -} -template -template -pod::Vector& pod::Vector::operator=( const pod::Vector& vector ) { - return *this = uf::vector::cast(vector); -} -// -template -T& pod::Vector::operator[](std::size_t i) { - if ( i >= this->size ) i = this->size - 1; - return (&this->x)[i]; -} -template -const T& pod::Vector::operator[](std::size_t i) const { - if ( i >= this->size ) i = this->size - 1; - return (&this->x)[i]; -} -// Arithmetic -template // Negation -inline pod::Vector pod::Vector::operator()() const { - return uf::vector::create(0); -} -template // Negation -inline pod::Vector pod::Vector::operator-() const { - return uf::vector::negate( *this ); -} -template // Addition between two vectors -inline pod::Vector pod::Vector::operator+( const pod::Vector& vector ) const { - return uf::vector::add( *this, vector ); -} -template // Subtraction between two vectors -inline pod::Vector pod::Vector::operator-( const pod::Vector& vector ) const { - return uf::vector::subtract( *this, vector ); -} -template // Multiplication between two vectors -inline pod::Vector pod::Vector::operator*( const pod::Vector& vector ) const { - return uf::vector::multiply( *this, vector ); -} -template // Division between two vectors -inline pod::Vector pod::Vector::operator/( const pod::Vector& vector ) const { - return uf::vector::divide( *this, vector ); -} -template // Multiplication with scalar -inline pod::Vector pod::Vector::operator+( T scalar ) const { - return uf::vector::add( *this, scalar ); -} -template // Multiplication with scalar -inline pod::Vector pod::Vector::operator-( T scalar ) const { - return uf::vector::subtract( *this, scalar ); -} -template // Multiplication with scalar -inline pod::Vector pod::Vector::operator*( T scalar ) const { - return uf::vector::multiply( *this, scalar ); -} -template // Division with scalar -inline pod::Vector pod::Vector::operator/( T scalar ) const { - return uf::vector::divide( *this, scalar ); -} -template // Addition set between two vectors -inline pod::Vector& pod::Vector::operator +=( const pod::Vector& vector ) { - return uf::vector::add_( *this, vector ); -} -template // Subtraction set between two vectors -inline pod::Vector& pod::Vector::operator -=( const pod::Vector& vector ) { - return uf::vector::subtract_( *this, vector ); -} -template // Multiplication set between two vectors -inline pod::Vector& pod::Vector::operator *=( const pod::Vector& vector ) { - return uf::vector::multiply_( *this, vector ); -} -template // Division set between two vectors -inline pod::Vector& pod::Vector::operator /=( const pod::Vector& vector ) { - return uf::vector::divide_( *this, vector ); -} -template // Multiplication with scalar -inline pod::Vector& pod::Vector::operator +=( T scalar ) { - return uf::vector::add_( *this, scalar ); -} -template // Multiplication with scalar -inline pod::Vector& pod::Vector::operator -=( T scalar ) { - return uf::vector::subtract_( *this, scalar ); -} -template // Multiplication set with scalar -inline pod::Vector& pod::Vector::operator *=( T scalar ) { - return uf::vector::multiply_( *this, scalar ); -} -template // Division set with scalar -inline pod::Vector& pod::Vector::operator /=( T scalar ) { - return uf::vector::divide_( *this, scalar ); -} -template // Equality check between two vectors (equals) -inline bool pod::Vector::operator==( const pod::Vector& vector ) const { - return uf::vector::equals(*this, vector); -} -template // Equality check between two vectors (not equals) -inline bool pod::Vector::operator!=( const pod::Vector& vector ) const { - return !uf::vector::equals(*this, vector); -} -template // Equality check between two vectors (less than) -inline bool pod::Vector::operator<( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) < 0; -} -template // Equality check between two vectors (less than or equals) -inline bool pod::Vector::operator<=( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) <= 0; -} -template // Equality check between two vectors (greater than) -inline bool pod::Vector::operator>( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) > 0; -} -template // Equality check between two vectors (greater than or equals) -inline bool pod::Vector::operator>=( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) >= 0; -} -template -inline pod::Vector::operator bool() const { - return !uf::vector::equals(*this, pod::Vector{}); -} -template -template -pod::Vector::operator pod::Vector() { - return uf::vector::cast(*this); -} -template -template -pod::Vector& pod::Vector::operator=( const pod::Vector& vector ) { - return *this = uf::vector::cast(vector); -} -// -template -T& pod::Vector::operator[](std::size_t i) { - if ( i >= this->size ) i = this->size - 1; - return (&this->x)[i]; -} -template -const T& pod::Vector::operator[](std::size_t i) const { - if ( i >= this->size ) i = this->size - 1; - return (&this->x)[i]; -} -// Arithmetic -template // Negation -inline pod::Vector pod::Vector::operator()() const { - return uf::vector::create(0,0); -} -template // Negation -inline pod::Vector pod::Vector::operator-() const { - return uf::vector::negate( *this ); -} -template // Addition between two vectors -inline pod::Vector pod::Vector::operator+( const pod::Vector& vector ) const { - return uf::vector::add( *this, vector ); -} -template // Subtraction between two vectors -inline pod::Vector pod::Vector::operator-( const pod::Vector& vector ) const { - return uf::vector::subtract( *this, vector ); -} -template // Multiplication between two vectors -inline pod::Vector pod::Vector::operator*( const pod::Vector& vector ) const { - return uf::vector::multiply( *this, vector ); -} -template // Division between two vectors -inline pod::Vector pod::Vector::operator/( const pod::Vector& vector ) const { - return uf::vector::divide( *this, vector ); -} -template // Multiplication with scalar -inline pod::Vector pod::Vector::operator+( T scalar ) const { - return uf::vector::add( *this, scalar ); -} -template // Multiplication with scalar -inline pod::Vector pod::Vector::operator-( T scalar ) const { - return uf::vector::subtract( *this, scalar ); -} -template // Multiplication with scalar -inline pod::Vector pod::Vector::operator*( T scalar ) const { - return uf::vector::multiply( *this, scalar ); -} -template // Division with scalar -inline pod::Vector pod::Vector::operator/( T scalar ) const { - return uf::vector::divide( *this, scalar ); -} -template // Addition set between two vectors -inline pod::Vector& pod::Vector::operator +=( const pod::Vector& vector ) { - return uf::vector::add_( *this, vector ); -} -template // Subtraction set between two vectors -inline pod::Vector& pod::Vector::operator -=( const pod::Vector& vector ) { - return uf::vector::subtract_( *this, vector ); -} -template // Multiplication set between two vectors -inline pod::Vector& pod::Vector::operator *=( const pod::Vector& vector ) { - return uf::vector::multiply_( *this, vector ); -} -template // Division set between two vectors -inline pod::Vector& pod::Vector::operator /=( const pod::Vector& vector ) { - return uf::vector::divide_( *this, vector ); -} -template // Multiplication with scalar -inline pod::Vector& pod::Vector::operator+=( T scalar ) { - return uf::vector::add_( *this, scalar ); -} -template // Multiplication with scalar -inline pod::Vector& pod::Vector::operator-=( T scalar ) { - return uf::vector::subtract_( *this, scalar ); -} -template // Multiplication set with scalar -inline pod::Vector& pod::Vector::operator *=( T scalar ) { - return uf::vector::multiply_( *this, scalar ); -} -template // Division set with scalar -inline pod::Vector& pod::Vector::operator /=( T scalar ) { - return uf::vector::divide_( *this, scalar ); -} -template // Equality check between two vectors (equals) -inline bool pod::Vector::operator==( const pod::Vector& vector ) const { - return uf::vector::equals(*this, vector); -} -template // Equality check between two vectors (not equals) -inline bool pod::Vector::operator!=( const pod::Vector& vector ) const { - return !uf::vector::equals(*this, vector); -} -template // Equality check between two vectors (less than) -inline bool pod::Vector::operator<( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) < 0; -} -template // Equality check between two vectors (less than or equals) -inline bool pod::Vector::operator<=( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) <= 0; -} -template // Equality check between two vectors (greater than) -inline bool pod::Vector::operator>( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) > 0; -} -template // Equality check between two vectors (greater than or equals) -inline bool pod::Vector::operator>=( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) >= 0; -} -template -inline pod::Vector::operator bool() const { - return !uf::vector::equals(*this, pod::Vector{}); -} -template -template -pod::Vector::operator pod::Vector() { - return uf::vector::cast(*this); -} -template -template -pod::Vector& pod::Vector::operator=( const pod::Vector& vector ) { - return *this = uf::vector::cast(vector); -} -// -template -T& pod::Vector::operator[](std::size_t i) { - if ( i >= this->size ) i = this->size - 1; - return (&this->x)[i]; -} -template -const T& pod::Vector::operator[](std::size_t i) const { - if ( i >= this->size ) i = this->size - 1; - return (&this->x)[i]; -} -// Arithmetic -template // Negation -inline pod::Vector pod::Vector::operator()() const { - return uf::vector::create(0,0,0); -} -template // Negation -inline pod::Vector pod::Vector::operator-() const { - return uf::vector::negate( *this ); -} -template // Addition between two vectors -inline pod::Vector pod::Vector::operator+( const pod::Vector& vector ) const { - return uf::vector::add( *this, vector ); -} -template // Subtraction between two vectors -inline pod::Vector pod::Vector::operator-( const pod::Vector& vector ) const { - return uf::vector::subtract( *this, vector ); -} -template // Multiplication between two vectors -inline pod::Vector pod::Vector::operator*( const pod::Vector& vector ) const { - return uf::vector::multiply( *this, vector ); -} -template // Division between two vectors -inline pod::Vector pod::Vector::operator/( const pod::Vector& vector ) const { - return uf::vector::divide( *this, vector ); -} -template // Multiplication with scalar -inline pod::Vector pod::Vector::operator+( T scalar ) const { - return uf::vector::add( *this, scalar ); -} -template // Multiplication with scalar -inline pod::Vector pod::Vector::operator-( T scalar ) const { - return uf::vector::subtract( *this, scalar ); -} -template // Multiplication with scalar -inline pod::Vector pod::Vector::operator*( T scalar ) const { - return uf::vector::multiply( *this, scalar ); -} -template // Division with scalar -inline pod::Vector pod::Vector::operator/( T scalar ) const { - return uf::vector::divide( *this, scalar ); -} -template // Addition set between two vectors -inline pod::Vector& pod::Vector::operator +=( const pod::Vector& vector ) { - return uf::vector::add_( *this, vector ); -} -template // Subtraction set between two vectors -inline pod::Vector& pod::Vector::operator -=( const pod::Vector& vector ) { - return uf::vector::subtract_( *this, vector ); -} -template // Multiplication set between two vectors -inline pod::Vector& pod::Vector::operator *=( const pod::Vector& vector ) { - return uf::vector::multiply_( *this, vector ); -} -template // Division set between two vectors -inline pod::Vector& pod::Vector::operator /=( const pod::Vector& vector ) { - return uf::vector::divide_( *this, vector ); -} -template // Multiplication with scalar -inline pod::Vector& pod::Vector::operator +=( T scalar ) { - return uf::vector::add_( *this, scalar ); -} -template // Multiplication with scalar -inline pod::Vector& pod::Vector::operator -=( T scalar ) { - return uf::vector::subtract_( *this, scalar ); -} -template // Multiplication set with scalar -inline pod::Vector& pod::Vector::operator *=( T scalar ) { - return uf::vector::multiply_( *this, scalar ); -} -template // Division set with scalar -inline pod::Vector& pod::Vector::operator /=( T scalar ) { - return uf::vector::divide_( *this, scalar ); -} -template // Equality check between two vectors (equals) -inline bool pod::Vector::operator==( const pod::Vector& vector ) const { - return uf::vector::equals(*this, vector); -} -template // Equality check between two vectors (not equals) -inline bool pod::Vector::operator!=( const pod::Vector& vector ) const { - return !uf::vector::equals(*this, vector); -} -template // Equality check between two vectors (less than) -inline bool pod::Vector::operator<( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) < 0; -} -template // Equality check between two vectors (less than or equals) -inline bool pod::Vector::operator<=( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) <= 0; -} -template // Equality check between two vectors (greater than) -inline bool pod::Vector::operator>( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) > 0; -} -template // Equality check between two vectors (greater than or equals) -inline bool pod::Vector::operator>=( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) >= 0; -} -template -inline pod::Vector::operator bool() const { - return !uf::vector::equals(*this, pod::Vector{}); -} -template -template -pod::Vector::operator pod::Vector() { - return uf::vector::cast(*this); -/* - pod::Vector vector = {}; - for ( size_t i = 0; i < 3 && i < M; ++i ) { - vector[i] = (*this)[i]; - } - return vector; -*/ -} -template -template -pod::Vector& pod::Vector::operator=( const pod::Vector& vector ) { - return *this = uf::vector::cast(vector); -/* - for ( size_t i = 0; i < 3 && i < M; ++i ) { - (*this)[i] = vector[i]; - } - return *this; -*/ -} -// -template -T& pod::Vector::operator[](std::size_t i) { - if ( i >= this->size ) i = this->size - 1; - return (&this->x)[i]; -} -template -const T& pod::Vector::operator[](std::size_t i) const { - if ( i >= this->size ) i = this->size - 1; - return (&this->x)[i]; -} -// Arithmetic -template // Negation -inline pod::Vector pod::Vector::operator()() const { - return uf::vector::create(0,0,0,1); -} -template // Negation -inline pod::Vector pod::Vector::operator-() const { - return uf::vector::negate( *this ); -} -template // Addition between two vectors -inline pod::Vector pod::Vector::operator+( const pod::Vector& vector ) const { - return uf::vector::add( *this, vector ); -} -template // Subtraction between two vectors -inline pod::Vector pod::Vector::operator-( const pod::Vector& vector ) const { - return uf::vector::subtract( *this, vector ); -} -template // Multiplication with scalar -inline pod::Vector pod::Vector::operator+( T scalar ) const { - return uf::vector::add( *this, scalar ); -} -template // Multiplication with scalar -inline pod::Vector pod::Vector::operator-( T scalar ) const { - return uf::vector::subtract( *this, scalar ); -} -template // Multiplication between two vectors -inline pod::Vector pod::Vector::operator*( const pod::Vector& vector ) const { - return uf::vector::multiply( *this, vector ); -} -template // Division between two vectors -inline pod::Vector pod::Vector::operator/( const pod::Vector& vector ) const { - return uf::vector::divide( *this, vector ); -} -template // Multiplication with scalar -inline pod::Vector pod::Vector::operator*( T scalar ) const { - return uf::vector::multiply( *this, scalar ); -} -template // Division with scalar -inline pod::Vector pod::Vector::operator/( T scalar ) const { - return uf::vector::divide( *this, scalar ); -} -template // Addition set between two vectors -inline pod::Vector& pod::Vector::operator +=( const pod::Vector& vector ) { - return uf::vector::add_( *this, vector ); -} -template // Subtraction set between two vectors -inline pod::Vector& pod::Vector::operator -=( const pod::Vector& vector ) { - return uf::vector::subtract_( *this, vector ); -} -template // Multiplication set between two vectors -inline pod::Vector& pod::Vector::operator *=( const pod::Vector& vector ) { - return uf::vector::multiply_( *this, vector ); -} -template // Division set between two vectors -inline pod::Vector& pod::Vector::operator /=( const pod::Vector& vector ) { - return uf::vector::divide_( *this, vector ); -} -template // Multiplication with scalar -inline pod::Vector& pod::Vector::operator+=( T scalar ) { - return uf::vector::add_( *this, scalar ); -} -template // Multiplication with scalar -inline pod::Vector& pod::Vector::operator-=( T scalar ) { - return uf::vector::subtract_( *this, scalar ); -} -template // Multiplication set with scalar -inline pod::Vector& pod::Vector::operator *=( T scalar ) { - return uf::vector::multiply_( *this, scalar ); -} -template // Division set with scalar -inline pod::Vector& pod::Vector::operator /=( T scalar ) { - return uf::vector::divide_( *this, scalar ); -} -template // Equality check between two vectors (equals) -inline bool pod::Vector::operator==( const pod::Vector& vector ) const { - return uf::vector::equals(*this, vector); -} -template // Equality check between two vectors (not equals) -inline bool pod::Vector::operator!=( const pod::Vector& vector ) const { - return !uf::vector::equals(*this, vector); -} -template // Equality check between two vectors (less than) -inline bool pod::Vector::operator<( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) < 0; -} -template // Equality check between two vectors (less than or equals) -inline bool pod::Vector::operator<=( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) <= 0; -} -template // Equality check between two vectors (greater than) -inline bool pod::Vector::operator>( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) > 0; -} -template // Equality check between two vectors (greater than or equals) -inline bool pod::Vector::operator>=( const pod::Vector& vector ) const { - return uf::vector::compareTo(*this, vector) >= 0; -} -template -inline pod::Vector::operator bool() const { - return !uf::vector::equals(*this, pod::Vector{}); -} -template -template -pod::Vector::operator pod::Vector() { - return uf::vector::cast(*this); -} -template -template -pod::Vector& pod::Vector::operator=( const pod::Vector& vector ) { - return *this = uf::vector::cast(vector); -} -// -#if UF_USE_CLASS_OF_PODS -namespace uf { - template - struct /*UF_API*/ Vector { - public: - // Easily access POD's type - typedef pod::Vector pod_t; - // Replicate POD information - typedef T type_t; - typedef T* container_t; - static const std::size_t size = 1; - protected: - // POD storage - Vector::pod_t m_pod; - public: - T& x = m_pod.x; - public: - // C-tor - Vector(); // initializes POD to 'def' - Vector(T def); // initializes POD to 'def' - Vector(T x, T y); // initializes POD to 'def' - Vector(const Vector::pod_t& pod); // copies POD altogether - Vector(const T components[1]); // copies data into POD from 'components' (typed as C array) - Vector(const uf::stl::vector& components); // copies data into POD from 'components' (typed as uf::stl::vector) - // D-tor - // Unneccesary - // POD access - Vector::pod_t& data(); // Returns a reference of POD - const Vector::pod_t& data() const; // Returns a const-reference of POD - // Alternative POD access - T* get(); // Returns a pointer to the entire array - const T* get() const; // Returns a const-pointer to the entire array - T& getComponent( std::size_t i ); // Returns a reference to a single element - const T& getComponent( std::size_t i ) const; // Returns a const-reference to a single element - // POD manipulation - T* set(const T components[1]); // Sets the entire array - T& setComponent( std::size_t i, const T& value ); // Sets a single element - // Validation - bool isValid() const; // Checks if all components are valid (non NaN, inf, etc.) - // Basic arithmetic - inline uf::Vector& add( const Vector& vector ); // Adds two vectors of same type and size together - inline uf::Vector& subtract( const Vector& vector ); // Subtracts two vectors of same type and size together - inline uf::Vector& multiply( const Vector& vector ); // Multiplies two vectors of same type and size together - inline uf::Vector& multiply( T scalar ); // Multiplies this vector by a scalar - inline uf::Vector& divide( const Vector& vector ); // Divides two vectors of same type and size together - inline uf::Vector& divide( T scalar ); // Divides this vector by a scalar - inline T sum() const; // Compute the sum of all components - inline T product() const; // Compute the product of all components - inline uf::Vector& negate(); // Flip sign of all components - // Complex arithmetic - inline T dot( const Vector right ) const; // Compute the dot product between two vectors - inline pod::Angle angle( const Vector& b ) const; // Compute the angle between two vectors - - inline uf::Vector lerp( const Vector to, double delta ) const; // Linearly interpolate between two vectors - inline uf::Vector slerp( const Vector to, double delta ) const; // Spherically interpolate between two vectors - - inline T distanceSquared( const Vector b ) const; // Compute the distance between two vectors (doesn't sqrt) - inline T distance( const Vector b ) const; // Compute the distance between two vectors - inline T magnitude() const; // Gets the magnitude of the vector - inline T norm() const; // Compute the norm of the vector - - inline uf::Vector& normalize(); // Normalizes a vector - uf::Vector getNormalized() const; // Return a normalized vector - inline uf::stl::string toString() const; - // Overloaded ops - // Accessing via subscripts - T& operator[](std::size_t i); - const T& operator[](std::size_t i) const; - // Arithmetic - inline Vector operator-() const; // Negation - inline Vector operator+( const Vector& vector ) const; // Addition between two vectors - inline Vector operator-( const Vector& vector ) const; // Subtraction between two vectors - inline Vector operator*( const Vector& vector ) const; // Multiplication between two vectors - inline Vector operator/( const Vector& vector ) const; // Division between two vectors - inline Vector operator*( T scalar ) const; // Multiplication with scalar - inline Vector operator/( T scalar ) const; // Division with scalar - inline Vector& operator +=( const Vector& vector ); // Addition set between two vectors - inline Vector& operator -=( const Vector& vector ); // Subtraction set between two vectors - inline Vector& operator *=( const Vector& vector ); // Multiplication set between two vectors - inline Vector& operator /=( const Vector& vector ); // Division set between two vectors - inline Vector& operator *=( T scalar ); // Multiplication set with scalar - inline Vector& operator /=( T scalar ); // Division set with scalar - inline bool operator==( const Vector& vector ) const; // Equality check between two vectors (equals) - inline bool operator!=( const Vector& vector ) const; // Equality check between two vectors (not equals) - inline bool operator<( const Vector& vector ) const; // Equality check between two vectors (less than) - inline bool operator<=( const Vector& vector ) const; // Equality check between two vectors (less than or equals) - inline bool operator>( const Vector& vector ) const; // Equality check between two vectors (greater than) - inline bool operator>=( const Vector& vector ) const; // Equality check between two vectors (greater than or equals) - - inline operator pod_t&() { return this->m_pod; } - inline operator const pod_t&() const { return this->m_pod; } - }; - template - struct /*UF_API*/ Vector { - public: - // Easily access POD's type - typedef pod::Vector pod_t; - // Replicate POD information - typedef T type_t; - typedef T* container_t; - static const std::size_t size = 2; - protected: - // POD storage - Vector::pod_t m_pod; - public: - T& x = m_pod.x; - T& y = m_pod.y; - public: - // C-tor - Vector(); // initializes POD to 'def' - Vector(T def); // initializes POD to 'def' - Vector(T x, T y); // initializes POD to 'def' - Vector(const Vector::pod_t& pod); // copies POD altogether - Vector(const T components[2]); // copies data into POD from 'components' (typed as C array) - Vector(const uf::stl::vector& components); // copies data into POD from 'components' (typed as uf::stl::vector) - // D-tor - // Unneccesary - // POD access - Vector::pod_t& data(); // Returns a reference of POD - const Vector::pod_t& data() const; // Returns a const-reference of POD - // Alternative POD access - T* get(); // Returns a pointer to the entire array - const T* get() const; // Returns a const-pointer to the entire array - T& getComponent( std::size_t i ); // Returns a reference to a single element - const T& getComponent( std::size_t i ) const; // Returns a const-reference to a single element - // POD manipulation - T* set(const T components[2]); // Sets the entire array - T& setComponent( std::size_t i, const T& value ); // Sets a single element - // Validation - bool isValid() const; // Checks if all components are valid (non NaN, inf, etc.) - // Basic arithmetic - inline uf::Vector& add( const Vector& vector ); // Adds two vectors of same type and size together - inline uf::Vector& subtract( const Vector& vector ); // Subtracts two vectors of same type and size together - inline uf::Vector& multiply( const Vector& vector ); // Multiplies two vectors of same type and size together - inline uf::Vector& multiply( T scalar ); // Multiplies this vector by a scalar - inline uf::Vector& divide( const Vector& vector ); // Divides two vectors of same type and size together - inline uf::Vector& divide( T scalar ); // Divides this vector by a scalar - inline T sum() const; // Compute the sum of all components - inline T product() const; // Compute the product of all components - inline uf::Vector& negate(); // Flip sign of all components - // Complex arithmetic - inline T dot( const Vector right ) const; // Compute the dot product between two vectors - inline pod::Angle angle( const Vector& b ) const; // Compute the angle between two vectors - - inline uf::Vector lerp( const Vector to, double delta ) const; // Linearly interpolate between two vectors - inline uf::Vector slerp( const Vector to, double delta ) const; // Spherically interpolate between two vectors - - inline T distanceSquared( const Vector b ) const; // Compute the distance between two vectors (doesn't sqrt) - inline T distance( const Vector b ) const; // Compute the distance between two vectors - inline T magnitude() const; // Gets the magnitude of the vector - inline T norm() const; // Compute the norm of the vector - - inline uf::Vector& normalize(); // Normalizes a vector - uf::Vector getNormalized() const; // Return a normalized vector - inline uf::stl::string toString() const; - // Overloaded ops - // Accessing via subscripts - T& operator[](std::size_t i); - const T& operator[](std::size_t i) const; - // Arithmetic - inline Vector operator-() const; // Negation - inline Vector operator+( const Vector& vector ) const; // Addition between two vectors - inline Vector operator-( const Vector& vector ) const; // Subtraction between two vectors - inline Vector operator*( const Vector& vector ) const; // Multiplication between two vectors - inline Vector operator/( const Vector& vector ) const; // Division between two vectors - inline Vector operator*( T scalar ) const; // Multiplication with scalar - inline Vector operator/( T scalar ) const; // Division with scalar - inline Vector& operator +=( const Vector& vector ); // Addition set between two vectors - inline Vector& operator -=( const Vector& vector ); // Subtraction set between two vectors - inline Vector& operator *=( const Vector& vector ); // Multiplication set between two vectors - inline Vector& operator /=( const Vector& vector ); // Division set between two vectors - inline Vector& operator *=( T scalar ); // Multiplication set with scalar - inline Vector& operator /=( T scalar ); // Division set with scalar - inline bool operator==( const Vector& vector ) const; // Equality check between two vectors (equals) - inline bool operator!=( const Vector& vector ) const; // Equality check between two vectors (not equals) - inline bool operator<( const Vector& vector ) const; // Equality check between two vectors (less than) - inline bool operator<=( const Vector& vector ) const; // Equality check between two vectors (less than or equals) - inline bool operator>( const Vector& vector ) const; // Equality check between two vectors (greater than) - inline bool operator>=( const Vector& vector ) const; // Equality check between two vectors (greater than or equals) - - inline operator pod_t&() { return this->m_pod; } - inline operator const pod_t&() const { return this->m_pod; } - }; - template - struct /*UF_API*/ Vector { - public: - // Easily access POD's type - typedef pod::Vector pod_t; - // Replicate POD information - typedef T type_t; - typedef T* container_t; - static const std::size_t size = 3; - protected: - // POD storage - Vector::pod_t m_pod; - public: - T& x = m_pod.x; - T& y = m_pod.y; - T& z = m_pod.z; - - T& r = m_pod.x; - T& g = m_pod.y; - T& b = m_pod.z; - public: - // C-tor - Vector(); // initializes POD to 'def' - Vector(T def); // initializes POD to 'def' - Vector(T x, T y, T z); // initializes POD to 'def' - Vector(const Vector::pod_t& pod); // copies POD altogether - Vector(const T components[3]); // copies data into POD from 'components' (typed as C array) - Vector(const uf::stl::vector& components); // copies data into POD from 'components' (typed as uf::stl::vector) - // D-tor - // Unneccesary - // POD access - Vector::pod_t& data(); // Returns a reference of POD - const Vector::pod_t& data() const; // Returns a const-reference of POD - // Alternative POD access - T* get(); // Returns a pointer to the entire array - const T* get() const; // Returns a const-pointer to the entire array - T& getComponent( std::size_t i ); // Returns a reference to a single element - const T& getComponent( std::size_t i ) const; // Returns a const-reference to a single element - // POD manipulation - T* set(const T components[3]); // Sets the entire array - T& setComponent( std::size_t i, const T& value ); // Sets a single element - // Validation - bool isValid() const; // Checks if all components are valid (non NaN, inf, etc.) - // Basic arithmetic - inline uf::Vector& add( const Vector& vector ); // Adds two vectors of same type and size together - inline uf::Vector& subtract( const Vector& vector ); // Subtracts two vectors of same type and size together - inline uf::Vector& multiply( const Vector& vector ); // Multiplies two vectors of same type and size together - inline uf::Vector& multiply( T scalar ); // Multiplies this vector by a scalar - inline uf::Vector& divide( const Vector& vector ); // Divides two vectors of same type and size together - inline uf::Vector& divide( T scalar ); // Divides this vector by a scalar - inline T sum() const; // Compute the sum of all components - inline T product() const; // Compute the product of all components - inline uf::Vector& negate(); // Flip sign of all components - // Complex arithmetic - inline T dot( const Vector right ) const; // Compute the dot product between two vectors - inline pod::Angle angle( const Vector& b ) const; // Compute the angle between two vectors - - inline uf::Vector lerp( const Vector to, double delta ) const; // Linearly interpolate between two vectors - inline uf::Vector slerp( const Vector to, double delta ) const; // Spherically interpolate between two vectors - - inline T distanceSquared( const Vector b ) const; // Compute the distance between two vectors (doesn't sqrt) - inline T distance( const Vector b ) const; // Compute the distance between two vectors - inline T magnitude() const; // Gets the magnitude of the vector - inline T norm() const; // Compute the norm of the vector - - inline uf::Vector& normalize(); // Normalizes a vector - uf::Vector getNormalized() const; // Return a normalized vector - inline uf::stl::string toString() const; - // Overloaded ops - // Accessing via subscripts - T& operator[](std::size_t i); - const T& operator[](std::size_t i) const; - // Arithmetic - inline Vector operator-() const; // Negation - inline Vector operator+( const Vector& vector ) const; // Addition between two vectors - inline Vector operator-( const Vector& vector ) const; // Subtraction between two vectors - inline Vector operator*( const Vector& vector ) const; // Multiplication between two vectors - inline Vector operator/( const Vector& vector ) const; // Division between two vectors - inline Vector operator*( T scalar ) const; // Multiplication with scalar - inline Vector operator/( T scalar ) const; // Division with scalar - inline Vector& operator +=( const Vector& vector ); // Addition set between two vectors - inline Vector& operator -=( const Vector& vector ); // Subtraction set between two vectors - inline Vector& operator *=( const Vector& vector ); // Multiplication set between two vectors - inline Vector& operator /=( const Vector& vector ); // Division set between two vectors - inline Vector& operator *=( T scalar ); // Multiplication set with scalar - inline Vector& operator /=( T scalar ); // Division set with scalar - inline bool operator==( const Vector& vector ) const; // Equality check between two vectors (equals) - inline bool operator!=( const Vector& vector ) const; // Equality check between two vectors (not equals) - inline bool operator<( const Vector& vector ) const; // Equality check between two vectors (less than) - inline bool operator<=( const Vector& vector ) const; // Equality check between two vectors (less than or equals) - inline bool operator>( const Vector& vector ) const; // Equality check between two vectors (greater than) - inline bool operator>=( const Vector& vector ) const; // Equality check between two vectors (greater than or equals) - - inline operator pod_t&() { return this->m_pod; } - inline operator const pod_t&() const { return this->m_pod; } - }; - template - struct /*UF_API*/ Vector { - public: - // Easily access POD's type - typedef pod::Vector pod_t; - // Replicate POD information - typedef T type_t; - typedef T* container_t; - static const std::size_t size = 4; - protected: - // POD storage - Vector::pod_t m_pod; - public: - T& x = m_pod.x; - T& y = m_pod.y; - T& z = m_pod.z; - T& w = m_pod.w; - - T& r = m_pod.x; - T& g = m_pod.y; - T& b = m_pod.z; - T& a = m_pod.w; - public: - // C-tor - Vector(); // initializes POD to 'def' - Vector(T def); // initializes POD to 'def' - Vector(T x, T y, T z, T w); // initializes POD to 'def' - Vector(const Vector::pod_t& pod); // copies POD altogether - Vector(const T components[4]); // copies data into POD from 'components' (typed as C array) - Vector(const uf::stl::vector& components); // copies data into POD from 'components' (typed as uf::stl::vector) - // D-tor - // Unneccesary - // POD access - Vector::pod_t& data(); // Returns a reference of POD - const Vector::pod_t& data() const; // Returns a const-reference of POD - // Alternative POD access - T* get(); // Returns a pointer to the entire array - const T* get() const; // Returns a const-pointer to the entire array - T& getComponent( std::size_t i ); // Returns a reference to a single element - const T& getComponent( std::size_t i ) const; // Returns a const-reference to a single element - // POD manipulation - T* set(const T components[4]); // Sets the entire array - T& setComponent( std::size_t i, const T& value ); // Sets a single element - // Validation - bool isValid() const; // Checks if all components are valid (non NaN, inf, etc.) - // Basic arithmetic - inline uf::Vector& add( const Vector& vector ); // Adds two vectors of same type and size together - inline uf::Vector& subtract( const Vector& vector ); // Subtracts two vectors of same type and size together - inline uf::Vector& multiply( const Vector& vector ); // Multiplies two vectors of same type and size together - inline uf::Vector& multiply( T scalar ); // Multiplies this vector by a scalar - inline uf::Vector& divide( const Vector& vector ); // Divides two vectors of same type and size together - inline uf::Vector& divide( T scalar ); // Divides this vector by a scalar - inline T sum() const; // Compute the sum of all components - inline T product() const; // Compute the product of all components - inline uf::Vector& negate(); // Flip sign of all components - // Complex arithmetic - inline T dot( const Vector right ) const; // Compute the dot product between two vectors - inline pod::Angle angle( const Vector& b ) const; // Compute the angle between two vectors - - inline uf::Vector lerp( const Vector to, double delta ) const; // Linearly interpolate between two vectors - inline uf::Vector slerp( const Vector to, double delta ) const; // Spherically interpolate between two vectors - - inline T distanceSquared( const Vector b ) const; // Compute the distance between two vectors (doesn't sqrt) - inline T distance( const Vector b ) const; // Compute the distance between two vectors - inline T magnitude() const; // Gets the magnitude of the vector - inline T norm() const; // Compute the norm of the vector - - inline uf::Vector& normalize(); // Normalizes a vector - uf::Vector getNormalized() const; // Return a normalized vector - inline uf::stl::string toString() const; - // Overloaded ops - // Accessing via subscripts - T& operator[](std::size_t i); - const T& operator[](std::size_t i) const; - // Arithmetic - inline Vector operator-() const; // Negation - inline Vector operator+( const Vector& vector ) const; // Addition between two vectors - inline Vector operator-( const Vector& vector ) const; // Subtraction between two vectors - inline Vector operator*( const Vector& vector ) const; // Multiplication between two vectors - inline Vector operator/( const Vector& vector ) const; // Division between two vectors - inline Vector operator*( T scalar ) const; // Multiplication with scalar - inline Vector operator/( T scalar ) const; // Division with scalar - inline Vector& operator +=( const Vector& vector ); // Addition set between two vectors - inline Vector& operator -=( const Vector& vector ); // Subtraction set between two vectors - inline Vector& operator *=( const Vector& vector ); // Multiplication set between two vectors - inline Vector& operator /=( const Vector& vector ); // Division set between two vectors - inline Vector& operator *=( T scalar ); // Multiplication set with scalar - inline Vector& operator /=( T scalar ); // Division set with scalar - inline bool operator==( const Vector& vector ) const; // Equality check between two vectors (equals) - inline bool operator!=( const Vector& vector ) const; // Equality check between two vectors (not equals) - inline bool operator<( const Vector& vector ) const; // Equality check between two vectors (less than) - inline bool operator<=( const Vector& vector ) const; // Equality check between two vectors (less than or equals) - inline bool operator>( const Vector& vector ) const; // Equality check between two vectors (greater than) - inline bool operator>=( const Vector& vector ) const; // Equality check between two vectors (greater than or equals) - - inline operator pod_t&() { return this->m_pod; } - inline operator const pod_t&() const { return this->m_pod; } - }; -} -// C-tor -template // initializes POD to 'def' -uf::Vector::Vector() { -} -template // initializes POD to 'def' -uf::Vector::Vector(T def) { - for ( std::size_t i = 0; i < 1; ++i ) this->m_pod[i] = def; -} -template // initializes POD to 'def' -uf::Vector::Vector(T x, T y) { - this->m_pod.x = x; - this->m_pod.y = y; -} -template // copies POD altogether -uf::Vector::Vector(const typename uf::Vector::pod_t& pod) : m_pod(pod) { -} -template // copies data into POD from 'components' (typed as C array) -uf::Vector::Vector(const T components[1]) { - this->set(&components[0]); -} -template // copies data into POD from 'components' (typed as uf::stl::vector) -uf::Vector::Vector(const uf::stl::vector& components) { - if ( components.size() >= 1 ) this->set(&components[0]); -} -// D-tor -// Unneccesary -// POD access -template // Returns a reference of POD -typename uf::Vector::pod_t& uf::Vector::data() { - return this->m_pod; -} -template // Returns a const-reference of POD -const typename uf::Vector::pod_t& uf::Vector::data() const { - return this->m_pod; -} -// Alternative POD access -template // Returns a pointer to the entire array -T* uf::Vector::get() { - return &this->m_pod[0]; -} -template // Returns a const-pointer to the entire array -const T* uf::Vector::get() const { - return &this->m_pod[0]; -} -template // Returns a reference to a single element -T& uf::Vector::getComponent( std::size_t i ) { - if ( i >= 1 ) return NULL; - return this->m_pod[i]; -} -template // Returns a const-reference to a single element -const T& uf::Vector::getComponent( std::size_t i ) const { - if ( i >= 1 ) return NULL; - return this->m_pod[i]; -} -// POD manipulation -template // Sets the entire array -T* uf::Vector::set(const T components[1]) { - for ( std::size_t i = 0; i < 1; ++i ) this->m_pod[i] = components[i]; - return &this->m_pod[0]; -} -template // Sets a single element -T& uf::Vector::setComponent( std::size_t i, const T& value ) { - this->m_pod[i] = value; -} -// Validation -template // Checks if all components are valid (non NaN, inf, etc.) -bool uf::Vector::isValid() const { - for ( std::size_t i = 0; i < 1; ++i ) if ( this->m_pod[i] != this->m_pod[i] ) return false; - return true; -} -// Basic arithmetic -template // Adds two vectors of same type and size together -inline uf::Vector& uf::Vector::add( const uf::Vector& vector ) { - return uf::vector::add( this->m_pod, vector.data() ); -} -template // Subtracts two vectors of same type and size together -inline uf::Vector& uf::Vector::subtract( const uf::Vector& vector ) { - return uf::vector::subtract( this->m_pod, vector.data() ); -} -template // Multiplies two vectors of same type and size together -inline uf::Vector& uf::Vector::multiply( const uf::Vector& vector ) { - return uf::vector::multiply( this->m_pod, vector.data() ); -} -template // Multiplies this vector by a scalar -inline uf::Vector& uf::Vector::multiply( T scalar ) { - return uf::vector::multiply( this->m_pod, scalar ); -} -template // Divides two vectors of same type and size together -inline uf::Vector& uf::Vector::divide( const uf::Vector& vector ) { - return uf::vector::divide( this->m_pod, vector.data() ); -} -template // Divides this vector by a scalar -inline uf::Vector& uf::Vector::divide( T scalar ) { - return uf::vector::divide( this->m_pod, scalar ); -} -template // Compute the sum of all components -inline T uf::Vector::sum() const { - return uf::vector::sum( this->m_pod ); -} -template // Compute the product of all components -inline T uf::Vector::product() const { - return uf::vector::product( this->m_pod ); -} -template // Flip sign of all components -inline uf::Vector& uf::Vector::negate() { - return uf::vector::negate( this->m_pod ); -} -// Complex arithmetic -template // Compute the dot product between two vectors -inline T uf::Vector::dot( const uf::Vector right ) const { - return uf::vector::dot( this->m_pod, right ); -} -template // Compute the angle between two vectors -inline pod::Angle uf::Vector::angle( const uf::Vector& b ) const { - return uf::vector::angle( this->m_pod, b ); -} - -template // Linearly interpolate between two vectors -inline uf::Vector uf::Vector::lerp( const uf::Vector to, double delta ) const { - return uf::vector::lerp( this->m_pod, to, delta ); -} -template // Spherically interpolate between two vectors -inline uf::Vector uf::Vector::slerp( const uf::Vector to, double delta ) const { - return uf::vector::slerp( this->m_pod, to, delta ); -} - -template // Compute the distance between two vectors (doesn't sqrt) -inline T uf::Vector::distanceSquared( const uf::Vector b ) const { - return uf::vector::distanceSquared( this->m_pod, b ); -} -template // Compute the distance between two vectors -inline T uf::Vector::distance( const uf::Vector b ) const { - return uf::vector::distance( this->m_pod, b ); -} -template // Gets the magnitude of the vector -inline T uf::Vector::magnitude() const { - return uf::vector::magnitude( this->m_pod ); -} -template // Compute the norm of the vector -inline T uf::Vector::norm() const { - return uf::vector::norm( this->m_pod ); -} - -template // Normalizes a vector -inline uf::Vector& uf::Vector::normalize() { - return uf::vector::normalize( this->m_pod ); -} -template // Return a normalized vector -uf::Vector uf::Vector::getNormalized() const { - return uf::vector::normalize( this->m_pod ); -} -template // Return a string -uf::stl::string uf::Vector::toString() const { - return uf::vector::toString( this->m_pod ); -} -// Overloaded ops -template -T& uf::Vector::operator[](std::size_t i) { - if ( i >= 1 ) return NULL; - return this->m_pod[i]; -} -template -const T& uf::Vector::operator[](std::size_t i) const { - if ( i >= 1 ) return NULL; - return this->m_pod[i]; -} -// Arithmetic -template // Negation -inline uf::Vector uf::Vector::operator-() const { - return uf::vector::negate( this->m_pod ); -} -template // Addition between two vectors -inline uf::Vector uf::Vector::operator+( const uf::Vector& vector ) const { - return uf::vector::add( this->m_pod, vector.data() ); -} -template // Subtraction between two vectors -inline uf::Vector uf::Vector::operator-( const uf::Vector& vector ) const { - return uf::vector::subtract( this->m_pod, vector.data() ); -} -template // Multiplication between two vectors -inline uf::Vector uf::Vector::operator*( const uf::Vector& vector ) const { - return uf::vector::multiply( this->m_pod, vector.data() ); -} -template // Division between two vectors -inline uf::Vector uf::Vector::operator/( const uf::Vector& vector ) const { - return uf::vector::divide( this->m_pod, vector.data() ); -} -template // Multiplication with scalar -inline uf::Vector uf::Vector::operator*( T scalar ) const { - return uf::vector::multiply( this->m_pod, scalar ); -} -template // Division with scalar -inline uf::Vector uf::Vector::operator/( T scalar ) const { - return uf::vector::divide( this->m_pod, scalar ); -} -template // Addition set between two vectors -inline uf::Vector& uf::Vector::operator +=( const uf::Vector& vector ) { - return uf::vector::add( this->m_pod, vector.data() ); -} -template // Subtraction set between two vectors -inline uf::Vector& uf::Vector::operator -=( const uf::Vector& vector ) { - return uf::vector::subtract( this->m_pod, vector.data() ); -} -template // Multiplication set between two vectors -inline uf::Vector& uf::Vector::operator *=( const uf::Vector& vector ) { - return uf::vector::multiply( this->m_pod, vector.data() ); -} -template // Division set between two vectors -inline uf::Vector& uf::Vector::operator /=( const uf::Vector& vector ) { - return uf::vector::divide( this->m_pod, vector.data() ); -} -template // Multiplication set with scalar -inline uf::Vector& uf::Vector::operator *=( T scalar ) { - return uf::vector::multiply( this->m_pod, scalar ); -} -template // Division set with scalar -inline uf::Vector& uf::Vector::operator /=( T scalar ) { - return uf::vector::divide( this->m_pod, scalar ); -} -template // Equality check between two vectors (equals) -inline bool uf::Vector::operator==( const uf::Vector& vector ) const { - return uf::vector::equals(this->m_pod, vector.data() ); -} -template // Equality check between two vectors (not equals) -inline bool uf::Vector::operator!=( const uf::Vector& vector ) const { - return !uf::vector::equals(this->m_pod, vector.data() ); -} -template // Equality check between two vectors (less than) -inline bool uf::Vector::operator<( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) < 0; -} -template // Equality check between two vectors (less than or equals) -inline bool uf::Vector::operator<=( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) <= 0; -} -template // Equality check between two vectors (greater than) -inline bool uf::Vector::operator>( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) > 0; -} -template // Equality check between two vectors (greater than or equals) -inline bool uf::Vector::operator>=( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) >= 0; -} -// C-tor -template // initializes POD to 'def' -uf::Vector::Vector() { -} -template // initializes POD to 'def' -uf::Vector::Vector(T def) { - for ( std::size_t i = 0; i < 2; ++i ) this->m_pod[i] = def; -} -template // initializes POD to 'def' -uf::Vector::Vector(T x, T y) { - this->m_pod.x = x; - this->m_pod.y = y; -} -template // copies POD altogether -uf::Vector::Vector(const typename uf::Vector::pod_t& pod) : m_pod(pod) { -} -template // copies data into POD from 'components' (typed as C array) -uf::Vector::Vector(const T components[2]) { - this->set(&components[0]); -} -template // copies data into POD from 'components' (typed as uf::stl::vector) -uf::Vector::Vector(const uf::stl::vector& components) { - if ( components.size() >= 2 ) this->set(&components[0]); -} -// D-tor -// Unneccesary -// POD access -template // Returns a reference of POD -typename uf::Vector::pod_t& uf::Vector::data() { - return this->m_pod; -} -template // Returns a const-reference of POD -const typename uf::Vector::pod_t& uf::Vector::data() const { - return this->m_pod; -} -// Alternative POD access -template // Returns a pointer to the entire array -T* uf::Vector::get() { - return &this->m_pod[0]; -} -template // Returns a const-pointer to the entire array -const T* uf::Vector::get() const { - return &this->m_pod[0]; -} -template // Returns a reference to a single element -T& uf::Vector::getComponent( std::size_t i ) { - if ( i >= 2 ) return NULL; - return this->m_pod[i]; -} -template // Returns a const-reference to a single element -const T& uf::Vector::getComponent( std::size_t i ) const { - if ( i >= 2 ) return NULL; - return this->m_pod[i]; -} -// POD manipulation -template // Sets the entire array -T* uf::Vector::set(const T components[2]) { - for ( std::size_t i = 0; i < 2; ++i ) this->m_pod[i] = components[i]; - return &this->m_pod[0]; -} -template // Sets a single element -T& uf::Vector::setComponent( std::size_t i, const T& value ) { - this->m_pod[i] = value; -} -// Validation -template // Checks if all components are valid (non NaN, inf, etc.) -bool uf::Vector::isValid() const { - for ( std::size_t i = 0; i < 2; ++i ) if ( this->m_pod[i] != this->m_pod[i] ) return false; - return true; -} -// Basic arithmetic -template // Adds two vectors of same type and size together -inline uf::Vector& uf::Vector::add( const uf::Vector& vector ) { - return uf::vector::add( this->m_pod, vector.data() ); -} -template // Subtracts two vectors of same type and size together -inline uf::Vector& uf::Vector::subtract( const uf::Vector& vector ) { - return uf::vector::subtract( this->m_pod, vector.data() ); -} -template // Multiplies two vectors of same type and size together -inline uf::Vector& uf::Vector::multiply( const uf::Vector& vector ) { - return uf::vector::multiply( this->m_pod, vector.data() ); -} -template // Multiplies this vector by a scalar -inline uf::Vector& uf::Vector::multiply( T scalar ) { - return uf::vector::multiply( this->m_pod, scalar ); -} -template // Divides two vectors of same type and size together -inline uf::Vector& uf::Vector::divide( const uf::Vector& vector ) { - return uf::vector::divide( this->m_pod, vector.data() ); -} -template // Divides this vector by a scalar -inline uf::Vector& uf::Vector::divide( T scalar ) { - return uf::vector::divide( this->m_pod, scalar ); -} -template // Compute the sum of all components -inline T uf::Vector::sum() const { - return uf::vector::sum( this->m_pod ); -} -template // Compute the product of all components -inline T uf::Vector::product() const { - return uf::vector::product( this->m_pod ); -} -template // Flip sign of all components -inline uf::Vector& uf::Vector::negate() { - return uf::vector::negate( this->m_pod ); -} -// Complex arithmetic -template // Compute the dot product between two vectors -inline T uf::Vector::dot( const uf::Vector right ) const { - return uf::vector::dot( this->m_pod, right ); -} -template // Compute the angle between two vectors -inline pod::Angle uf::Vector::angle( const uf::Vector& b ) const { - return uf::vector::angle( this->m_pod, b ); -} - -template // Linearly interpolate between two vectors -inline uf::Vector uf::Vector::lerp( const uf::Vector to, double delta ) const { - return uf::vector::lerp( this->m_pod, to, delta ); -} -template // Spherically interpolate between two vectors -inline uf::Vector uf::Vector::slerp( const uf::Vector to, double delta ) const { - return uf::vector::slerp( this->m_pod, to, delta ); -} - -template // Compute the distance between two vectors (doesn't sqrt) -inline T uf::Vector::distanceSquared( const uf::Vector b ) const { - return uf::vector::distanceSquared( this->m_pod, b ); -} -template // Compute the distance between two vectors -inline T uf::Vector::distance( const uf::Vector b ) const { - return uf::vector::distance( this->m_pod, b ); -} -template // Gets the magnitude of the vector -inline T uf::Vector::magnitude() const { - return uf::vector::magnitude( this->m_pod ); -} -template // Compute the norm of the vector -inline T uf::Vector::norm() const { - return uf::vector::norm( this->m_pod ); -} - -template // Normalizes a vector -inline uf::Vector& uf::Vector::normalize() { - return uf::vector::normalize( this->m_pod ); -} -template // Return a normalized vector -uf::Vector uf::Vector::getNormalized() const { - return uf::vector::normalize( this->m_pod ); -} -template // Return a string -uf::stl::string uf::Vector::toString() const { - return uf::vector::toString( this->m_pod ); -} -// Overloaded ops -template -T& uf::Vector::operator[](std::size_t i) { - if ( i >= 2 ) return NULL; - return this->m_pod[i]; -} -template -const T& uf::Vector::operator[](std::size_t i) const { - if ( i >= 2 ) return NULL; - return this->m_pod[i]; -} -// Arithmetic -template // Negation -inline uf::Vector uf::Vector::operator-() const { - return uf::vector::negate( this->m_pod ); -} -template // Addition between two vectors -inline uf::Vector uf::Vector::operator+( const uf::Vector& vector ) const { - return uf::vector::add( this->m_pod, vector.data() ); -} -template // Subtraction between two vectors -inline uf::Vector uf::Vector::operator-( const uf::Vector& vector ) const { - return uf::vector::subtract( this->m_pod, vector.data() ); -} -template // Multiplication between two vectors -inline uf::Vector uf::Vector::operator*( const uf::Vector& vector ) const { - return uf::vector::multiply( this->m_pod, vector.data() ); -} -template // Division between two vectors -inline uf::Vector uf::Vector::operator/( const uf::Vector& vector ) const { - return uf::vector::divide( this->m_pod, vector.data() ); -} -template // Multiplication with scalar -inline uf::Vector uf::Vector::operator*( T scalar ) const { - return uf::vector::multiply( this->m_pod, scalar ); -} -template // Division with scalar -inline uf::Vector uf::Vector::operator/( T scalar ) const { - return uf::vector::divide( this->m_pod, scalar ); -} -template // Addition set between two vectors -inline uf::Vector& uf::Vector::operator +=( const uf::Vector& vector ) { - return uf::vector::add( this->m_pod, vector.data() ); -} -template // Subtraction set between two vectors -inline uf::Vector& uf::Vector::operator -=( const uf::Vector& vector ) { - return uf::vector::subtract( this->m_pod, vector.data() ); -} -template // Multiplication set between two vectors -inline uf::Vector& uf::Vector::operator *=( const uf::Vector& vector ) { - return uf::vector::multiply( this->m_pod, vector.data() ); -} -template // Division set between two vectors -inline uf::Vector& uf::Vector::operator /=( const uf::Vector& vector ) { - return uf::vector::divide( this->m_pod, vector.data() ); -} -template // Multiplication set with scalar -inline uf::Vector& uf::Vector::operator *=( T scalar ) { - return uf::vector::multiply( this->m_pod, scalar ); -} -template // Division set with scalar -inline uf::Vector& uf::Vector::operator /=( T scalar ) { - return uf::vector::divide( this->m_pod, scalar ); -} -template // Equality check between two vectors (equals) -inline bool uf::Vector::operator==( const uf::Vector& vector ) const { - return uf::vector::equals(this->m_pod, vector.data() ); -} -template // Equality check between two vectors (not equals) -inline bool uf::Vector::operator!=( const uf::Vector& vector ) const { - return !uf::vector::equals(this->m_pod, vector.data() ); -} -template // Equality check between two vectors (less than) -inline bool uf::Vector::operator<( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) < 0; -} -template // Equality check between two vectors (less than or equals) -inline bool uf::Vector::operator<=( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) <= 0; -} -template // Equality check between two vectors (greater than) -inline bool uf::Vector::operator>( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) > 0; -} -template // Equality check between two vectors (greater than or equals) -inline bool uf::Vector::operator>=( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) >= 0; -} -// -// C-tor -template // initializes POD to 'def' -uf::Vector::Vector() { -} -template // initializes POD to 'def' -uf::Vector::Vector(T def) { - for ( std::size_t i = 0; i < 3; ++i ) this->m_pod[i] = def; -} -template // initializes POD to 'def' -uf::Vector::Vector(T x, T y, T z) { - this->m_pod.x = x; - this->m_pod.y = y; - this->m_pod.z = z; -} -template // copies POD altogether -uf::Vector::Vector(const typename uf::Vector::pod_t& pod) : m_pod(pod) { -} -template // copies data into POD from 'components' (typed as C array) -uf::Vector::Vector(const T components[3]) { - this->set(&components[0]); -} -template // copies data into POD from 'components' (typed as uf::stl::vector) -uf::Vector::Vector(const uf::stl::vector& components) { - if ( components.size() >= 3 ) this->set(&components[0]); -} -// D-tor -// Unneccesary -// POD access -template // Returns a reference of POD -typename uf::Vector::pod_t& uf::Vector::data() { - return this->m_pod; -} -template // Returns a const-reference of POD -const typename uf::Vector::pod_t& uf::Vector::data() const { - return this->m_pod; -} -// Alternative POD access -template // Returns a pointer to the entire array -T* uf::Vector::get() { - return &this->m_pod[0]; -} -template // Returns a const-pointer to the entire array -const T* uf::Vector::get() const { - return &this->m_pod[0]; -} -template // Returns a reference to a single element -T& uf::Vector::getComponent( std::size_t i ) { - if ( i >= 3 ) return NULL; - return this->m_pod[i]; -} -template // Returns a const-reference to a single element -const T& uf::Vector::getComponent( std::size_t i ) const { - if ( i >= 3 ) return NULL; - return this->m_pod[i]; -} -// POD manipulation -template // Sets the entire array -T* uf::Vector::set(const T components[3]) { - for ( std::size_t i = 0; i < 3; ++i ) this->m_pod[i] = components[i]; - return &this->m_pod[0]; -} -template // Sets a single element -T& uf::Vector::setComponent( std::size_t i, const T& value ) { - this->m_pod[i] = value; -} -// Validation -template // Checks if all components are valid (non NaN, inf, etc.) -bool uf::Vector::isValid() const { - for ( std::size_t i = 0; i < 3; ++i ) if ( this->m_pod[i] != this->m_pod[i] ) return false; - return true; -} -// Basic arithmetic -template // Adds two vectors of same type and size together -inline uf::Vector& uf::Vector::add( const uf::Vector& vector ) { - return uf::vector::add( this->m_pod, vector.data() ); -} -template // Subtracts two vectors of same type and size together -inline uf::Vector& uf::Vector::subtract( const uf::Vector& vector ) { - return uf::vector::subtract( this->m_pod, vector.data() ); -} -template // Multiplies two vectors of same type and size together -inline uf::Vector& uf::Vector::multiply( const uf::Vector& vector ) { - return uf::vector::multiply( this->m_pod, vector.data() ); -} -template // Multiplies this vector by a scalar -inline uf::Vector& uf::Vector::multiply( T scalar ) { - return uf::vector::multiply( this->m_pod, scalar ); -} -template // Divides two vectors of same type and size together -inline uf::Vector& uf::Vector::divide( const uf::Vector& vector ) { - return uf::vector::divide( this->m_pod, vector.data() ); -} -template // Divides this vector by a scalar -inline uf::Vector& uf::Vector::divide( T scalar ) { - return uf::vector::divide( this->m_pod, scalar ); -} -template // Compute the sum of all components -inline T uf::Vector::sum() const { - return uf::vector::sum( this->m_pod ); -} -template // Compute the product of all components -inline T uf::Vector::product() const { - return uf::vector::product( this->m_pod ); -} -template // Flip sign of all components -inline uf::Vector& uf::Vector::negate() { - return uf::vector::negate( this->m_pod ); -} -// Complex arithmetic -template // Compute the dot product between two vectors -inline T uf::Vector::dot( const uf::Vector right ) const { - return uf::vector::dot( this->m_pod, right ); -} -template // Compute the angle between two vectors -inline pod::Angle uf::Vector::angle( const uf::Vector& b ) const { - return uf::vector::angle( this->m_pod, b ); -} - -template // Linearly interpolate between two vectors -inline uf::Vector uf::Vector::lerp( const uf::Vector to, double delta ) const { - return uf::vector::lerp( this->m_pod, to, delta ); -} -template // Spherically interpolate between two vectors -inline uf::Vector uf::Vector::slerp( const uf::Vector to, double delta ) const { - return uf::vector::slerp( this->m_pod, to, delta ); -} - -template // Compute the distance between two vectors (doesn't sqrt) -inline T uf::Vector::distanceSquared( const uf::Vector b ) const { - return uf::vector::distanceSquared( this->m_pod, b ); -} -template // Compute the distance between two vectors -inline T uf::Vector::distance( const uf::Vector b ) const { - return uf::vector::distance( this->m_pod, b ); -} -template // Gets the magnitude of the vector -inline T uf::Vector::magnitude() const { - return uf::vector::magnitude( this->m_pod ); -} -template // Compute the norm of the vector -inline T uf::Vector::norm() const { - return uf::vector::norm( this->m_pod ); -} - -template // Normalizes a vector -inline uf::Vector& uf::Vector::normalize() { - return uf::vector::normalize( this->m_pod ); -} -template // Return a normalized vector -uf::Vector uf::Vector::getNormalized() const { - return uf::vector::normalize( this->m_pod ); -} -template // Return a string -uf::stl::string uf::Vector::toString() const { - return uf::vector::toString( this->m_pod ); -} -// Overloaded ops -template -T& uf::Vector::operator[](std::size_t i) { - if ( i >= 3 ) return NULL; - return this->m_pod[i]; -} -template -const T& uf::Vector::operator[](std::size_t i) const { - if ( i >= 3 ) return NULL; - return this->m_pod[i]; -} -// Arithmetic -template // Negation -inline uf::Vector uf::Vector::operator-() const { - return uf::vector::negate( this->m_pod ); -} -template // Addition between two vectors -inline uf::Vector uf::Vector::operator+( const uf::Vector& vector ) const { - return uf::vector::add( this->m_pod, vector.data() ); -} -template // Subtraction between two vectors -inline uf::Vector uf::Vector::operator-( const uf::Vector& vector ) const { - return uf::vector::subtract( this->m_pod, vector.data() ); -} -template // Multiplication between two vectors -inline uf::Vector uf::Vector::operator*( const uf::Vector& vector ) const { - return uf::vector::multiply( this->m_pod, vector.data() ); -} -template // Division between two vectors -inline uf::Vector uf::Vector::operator/( const uf::Vector& vector ) const { - return uf::vector::divide( this->m_pod, vector.data() ); -} -template // Multiplication with scalar -inline uf::Vector uf::Vector::operator*( T scalar ) const { - return uf::vector::multiply( this->m_pod, scalar ); -} -template // Division with scalar -inline uf::Vector uf::Vector::operator/( T scalar ) const { - return uf::vector::divide( this->m_pod, scalar ); -} -template // Addition set between two vectors -inline uf::Vector& uf::Vector::operator +=( const uf::Vector& vector ) { - return uf::vector::add( this->m_pod, vector.data() ); -} -template // Subtraction set between two vectors -inline uf::Vector& uf::Vector::operator -=( const uf::Vector& vector ) { - return uf::vector::subtract( this->m_pod, vector.data() ); -} -template // Multiplication set between two vectors -inline uf::Vector& uf::Vector::operator *=( const uf::Vector& vector ) { - return uf::vector::multiply( this->m_pod, vector.data() ); -} -template // Division set between two vectors -inline uf::Vector& uf::Vector::operator /=( const uf::Vector& vector ) { - return uf::vector::divide( this->m_pod, vector.data() ); -} -template // Multiplication set with scalar -inline uf::Vector& uf::Vector::operator *=( T scalar ) { - return uf::vector::multiply( this->m_pod, scalar ); -} -template // Division set with scalar -inline uf::Vector& uf::Vector::operator /=( T scalar ) { - return uf::vector::divide( this->m_pod, scalar ); -} -template // Equality check between two vectors (equals) -inline bool uf::Vector::operator==( const uf::Vector& vector ) const { - return uf::vector::equals(this->m_pod, vector.data() ); -} -template // Equality check between two vectors (not equals) -inline bool uf::Vector::operator!=( const uf::Vector& vector ) const { - return !uf::vector::equals(this->m_pod, vector.data() ); -} -template // Equality check between two vectors (less than) -inline bool uf::Vector::operator<( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) < 0; -} -template // Equality check between two vectors (less than or equals) -inline bool uf::Vector::operator<=( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) <= 0; -} -template // Equality check between two vectors (greater than) -inline bool uf::Vector::operator>( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) > 0; -} -template // Equality check between two vectors (greater than or equals) -inline bool uf::Vector::operator>=( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) >= 0; -} -// -// C-tor -template // initializes POD to 'def' -uf::Vector::Vector() { -} -template // initializes POD to 'def' -uf::Vector::Vector(T def) { - for ( std::size_t i = 0; i < 4; ++i ) this->m_pod[i] = def; -} -template // initializes POD to 'def' -uf::Vector::Vector(T x, T y, T z, T w) { - this->m_pod.x = x; - this->m_pod.y = y; - this->m_pod.z = z; - this->m_pod.w = w; -} -template // copies POD altogether -uf::Vector::Vector(const typename uf::Vector::pod_t& pod) : m_pod(pod) { -} -template // copies data into POD from 'components' (typed as C array) -uf::Vector::Vector(const T components[4]) { - this->set(&components[0]); -} -template // copies data into POD from 'components' (typed as uf::stl::vector) -uf::Vector::Vector(const uf::stl::vector& components) { - if ( components.size() >= 4 ) this->set(&components[0]); -} -// D-tor -// Unneccesary -// POD access -template // Returns a reference of POD -typename uf::Vector::pod_t& uf::Vector::data() { - return this->m_pod; -} -template // Returns a const-reference of POD -const typename uf::Vector::pod_t& uf::Vector::data() const { - return this->m_pod; -} -// Alternative POD access -template // Returns a pointer to the entire array -T* uf::Vector::get() { - return &this->m_pod[0]; -} -template // Returns a const-pointer to the entire array -const T* uf::Vector::get() const { - return &this->m_pod[0]; -} -template // Returns a reference to a single element -T& uf::Vector::getComponent( std::size_t i ) { - if ( i >= 4 ) return NULL; - return this->m_pod[i]; -} -template // Returns a const-reference to a single element -const T& uf::Vector::getComponent( std::size_t i ) const { - if ( i >= 4 ) return NULL; - return this->m_pod[i]; -} -// POD manipulation -template // Sets the entire array -T* uf::Vector::set(const T components[4]) { - for ( std::size_t i = 0; i < 4; ++i ) this->m_pod[i] = components[i]; - return &this->m_pod[0]; -} -template // Sets a single element -T& uf::Vector::setComponent( std::size_t i, const T& value ) { - this->m_pod[i] = value; -} -// Validation -template // Checks if all components are valid (non NaN, inf, etc.) -bool uf::Vector::isValid() const { - for ( std::size_t i = 0; i < 4; ++i ) if ( this->m_pod[i] != this->m_pod[i] ) return false; - return true; -} -// Basic arithmetic -template // Adds two vectors of same type and size together -inline uf::Vector& uf::Vector::add( const uf::Vector& vector ) { - return uf::vector::add( this->m_pod, vector.data() ); -} -template // Subtracts two vectors of same type and size together -inline uf::Vector& uf::Vector::subtract( const uf::Vector& vector ) { - return uf::vector::subtract( this->m_pod, vector.data() ); -} -template // Multiplies two vectors of same type and size together -inline uf::Vector& uf::Vector::multiply( const uf::Vector& vector ) { - return uf::vector::multiply( this->m_pod, vector.data() ); -} -template // Multiplies this vector by a scalar -inline uf::Vector& uf::Vector::multiply( T scalar ) { - return uf::vector::multiply( this->m_pod, scalar ); -} -template // Divides two vectors of same type and size together -inline uf::Vector& uf::Vector::divide( const uf::Vector& vector ) { - return uf::vector::divide( this->m_pod, vector.data() ); -} -template // Divides this vector by a scalar -inline uf::Vector& uf::Vector::divide( T scalar ) { - return uf::vector::divide( this->m_pod, scalar ); -} -template // Compute the sum of all components -inline T uf::Vector::sum() const { - return uf::vector::sum( this->m_pod ); -} -template // Compute the product of all components -inline T uf::Vector::product() const { - return uf::vector::product( this->m_pod ); -} -template // Flip sign of all components -inline uf::Vector& uf::Vector::negate() { - return uf::vector::negate( this->m_pod ); -} -// Complex arithmetic -template // Compute the dot product between two vectors -inline T uf::Vector::dot( const uf::Vector right ) const { - return uf::vector::dot( this->m_pod, right ); -} -template // Compute the angle between two vectors -inline pod::Angle uf::Vector::angle( const uf::Vector& b ) const { - return uf::vector::angle( this->m_pod, b ); -} - -template // Linearly interpolate between two vectors -inline uf::Vector uf::Vector::lerp( const uf::Vector to, double delta ) const { - return uf::vector::lerp( this->m_pod, to, delta ); -} -template // Spherically interpolate between two vectors -inline uf::Vector uf::Vector::slerp( const uf::Vector to, double delta ) const { - return uf::vector::slerp( this->m_pod, to, delta ); -} - -template // Compute the distance between two vectors (doesn't sqrt) -inline T uf::Vector::distanceSquared( const uf::Vector b ) const { - return uf::vector::distanceSquared( this->m_pod, b ); -} -template // Compute the distance between two vectors -inline T uf::Vector::distance( const uf::Vector b ) const { - return uf::vector::distance( this->m_pod, b ); -} -template // Gets the magnitude of the vector -inline T uf::Vector::magnitude() const { - return uf::vector::magnitude( this->m_pod ); -} -template // Compute the norm of the vector -inline T uf::Vector::norm() const { - return uf::vector::norm( this->m_pod ); -} - -template // Normalizes a vector -inline uf::Vector& uf::Vector::normalize() { - return uf::vector::normalize( this->m_pod ); -} -template // Return a normalized vector -uf::Vector uf::Vector::getNormalized() const { - return uf::vector::normalize( this->m_pod ); -} -template // Return a string -uf::stl::string uf::Vector::toString() const { - return uf::vector::toString( this->m_pod ); -} -// Overloaded ops -template -T& uf::Vector::operator[](std::size_t i) { - if ( i >= 4 ) return NULL; - return this->m_pod[i]; -} -template -const T& uf::Vector::operator[](std::size_t i) const { - if ( i >= 4 ) return NULL; - return this->m_pod[i]; -} -// Arithmetic -template // Negation -inline uf::Vector uf::Vector::operator-() const { - return uf::vector::negate( this->m_pod ); -} -template // Addition between two vectors -inline uf::Vector uf::Vector::operator+( const uf::Vector& vector ) const { - return uf::vector::add( this->m_pod, vector.data() ); -} -template // Subtraction between two vectors -inline uf::Vector uf::Vector::operator-( const uf::Vector& vector ) const { - return uf::vector::subtract( this->m_pod, vector.data() ); -} -template // Multiplication between two vectors -inline uf::Vector uf::Vector::operator*( const uf::Vector& vector ) const { - return uf::vector::multiply( this->m_pod, vector.data() ); -} -template // Division between two vectors -inline uf::Vector uf::Vector::operator/( const uf::Vector& vector ) const { - return uf::vector::divide( this->m_pod, vector.data() ); -} -template // Multiplication with scalar -inline uf::Vector uf::Vector::operator*( T scalar ) const { - return uf::vector::multiply( this->m_pod, scalar ); -} -template // Division with scalar -inline uf::Vector uf::Vector::operator/( T scalar ) const { - return uf::vector::divide( this->m_pod, scalar ); -} -template // Addition set between two vectors -inline uf::Vector& uf::Vector::operator +=( const uf::Vector& vector ) { - return uf::vector::add( this->m_pod, vector.data() ); -} -template // Subtraction set between two vectors -inline uf::Vector& uf::Vector::operator -=( const uf::Vector& vector ) { - return uf::vector::subtract( this->m_pod, vector.data() ); -} -template // Multiplication set between two vectors -inline uf::Vector& uf::Vector::operator *=( const uf::Vector& vector ) { - return uf::vector::multiply( this->m_pod, vector.data() ); -} -template // Division set between two vectors -inline uf::Vector& uf::Vector::operator /=( const uf::Vector& vector ) { - return uf::vector::divide( this->m_pod, vector.data() ); -} -template // Multiplication set with scalar -inline uf::Vector& uf::Vector::operator *=( T scalar ) { - return uf::vector::multiply( this->m_pod, scalar ); -} -template // Division set with scalar -inline uf::Vector& uf::Vector::operator /=( T scalar ) { - return uf::vector::divide( this->m_pod, scalar ); -} -template // Equality check between two vectors (equals) -inline bool uf::Vector::operator==( const uf::Vector& vector ) const { - return uf::vector::equals(this->m_pod, vector.data() ); -} -template // Equality check between two vectors (not equals) -inline bool uf::Vector::operator!=( const uf::Vector& vector ) const { - return !uf::vector::equals(this->m_pod, vector.data() ); -} -template // Equality check between two vectors (less than) -inline bool uf::Vector::operator<( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) < 0; -} -template // Equality check between two vectors (less than or equals) -inline bool uf::Vector::operator<=( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) <= 0; -} -template // Equality check between two vectors (greater than) -inline bool uf::Vector::operator>( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) > 0; -} -template // Equality check between two vectors (greater than or equals) -inline bool uf::Vector::operator>=( const uf::Vector& vector ) const { - return uf::vector::compareTo(this->m_pod, vector.data() ) >= 0; -} -#endif \ No newline at end of file diff --git a/engine/inc/uf/utils/math/vector/simd.h b/engine/inc/uf/utils/math/vector/simd.h index d71039a1..6359eedc 100644 --- a/engine/inc/uf/utils/math/vector/simd.h +++ b/engine/inc/uf/utils/math/vector/simd.h @@ -6,6 +6,30 @@ #include #endif +#define DEFINE_SIMD(T)\ + inline value /*UF_API*/ load( const T* );\ + inline void /*UF_API*/ store( value, T* );\ + inline value /*UF_API*/ set( T );\ + inline value /*UF_API*/ set( T, T, T, T );\ + inline value /*UF_API*/ add( value, value );\ + inline value /*UF_API*/ sub( value, value );\ + inline value /*UF_API*/ mul( value, value );\ + inline value /*UF_API*/ div( value, value );\ + inline value /*UF_API*/ min( value, value );\ + inline value /*UF_API*/ max( value, value );\ + inline bool /*UF_API*/ all( value );\ + inline bool /*UF_API*/ any( value );\ + inline value /*UF_API*/ less( value, value );\ + inline value /*UF_API*/ lessEquals( value, value );\ + inline value /*UF_API*/ greater( value, value );\ + inline value /*UF_API*/ greaterEquals( value, value );\ + inline value /*UF_API*/ equals( value, value );\ + inline value /*UF_API*/ notEquals( value, value );\ + inline value /*UF_API*/ sqrt( value );\ + inline value /*UF_API*/ hadd( value, value );\ + inline T /*UF_API*/ dot( value, value );\ + template inline pod::Vector vector( const value );\ + namespace uf { namespace simd { template @@ -39,7 +63,7 @@ namespace uf { }; template - class /**UF_API**/ alignas(16) value { + class /*UF_API*/ alignas(16) value { private: // __m128 m_value; typedef typename traits::value value_type; @@ -57,100 +81,39 @@ namespace uf { inline value(const pod::Vector& rhs); inline value(const pod::Vector& rhs); - inline value operator+( const value& y ); - inline value operator-( const value& y ); - inline value operator*( const value& y ); - inline value operator/( const value& y ); + inline value operator+( const value& rhs ); + inline value operator-( const value& rhs ); + inline value operator*( const value& rhs ); + inline value operator/( const value& rhs ); + + inline value operator<( const value& rhs ); + inline value operator<=( const value& rhs ); + inline value operator>( const value& rhs ); + inline value operator>=( const value& rhs ); + inline value operator==( const value& rhs ); + inline value operator!=( const value& rhs ); + inline value& operator=(const value_type& rhs); inline value& operator=(const value& rhs); - inline value& operator=(const pod::Vector4f& rhs); + inline value& operator=(const pod::Vector& rhs); + inline operator value_type() const; template inline operator pod::Vector() const; }; - inline value /**UF_API**/ load( const float* ); - inline void /**UF_API**/ store( value, float* ); - inline value /**UF_API**/ set( float ); - inline value /**UF_API**/ set( float, float, float, float ); - inline value /**UF_API**/ add( value, value ); - inline value /**UF_API**/ sub( value, value ); - inline value /**UF_API**/ mul( value, value ); - inline value /**UF_API**/ div( value, value ); - inline value /**UF_API**/ min( value, value ); - inline value /**UF_API**/ max( value, value ); - inline value /**UF_API**/ sqrt( value ); - // inline value /**UF_API**/ hadd( value, value ); - inline float /**UF_API**/ dot( value, value ); - template inline pod::Vector vector( const value ); - - inline value /**UF_API**/ load( const int32_t* ); - inline void /**UF_API**/ store( value, int32_t* ); - inline value /**UF_API**/ set( int32_t ); - inline value /**UF_API**/ set( int32_t, int32_t, int32_t, int32_t ); - inline value /**UF_API**/ add( value, value ); - inline value /**UF_API**/ sub( value, value ); - inline value /**UF_API**/ mul( value, value ); - inline value /**UF_API**/ div( value, value ); - inline value /**UF_API**/ min( value, value ); - inline value /**UF_API**/ max( value, value ); - inline value /**UF_API**/ sqrt( value ); - // inline value /**UF_API**/ hadd( value, value ); - inline int32_t /**UF_API**/ dot( value, value ); - template inline pod::Vector vector( const value ); - - inline value /**UF_API**/ load( const uint* ); - inline void /**UF_API**/ store( value, uint* ); - inline value /**UF_API**/ set( uint ); - inline value /**UF_API**/ set( uint, uint, uint, uint ); - inline value /**UF_API**/ add( value, value ); - inline value /**UF_API**/ sub( value, value ); - inline value /**UF_API**/ mul( value, value ); - inline value /**UF_API**/ div( value, value ); - inline value /**UF_API**/ min( value, value ); - inline value /**UF_API**/ max( value, value ); - inline value /**UF_API**/ sqrt( value ); - // inline value /**UF_API**/ hadd( value, value ); - inline uint /**UF_API**/ dot( value, value ); - template inline pod::Vector vector( const value ); + DEFINE_SIMD(float); + DEFINE_SIMD(int32_t); + DEFINE_SIMD(uint32_t); // these are effectively NOPs #if UF_USE_FLOAT16 - inline value /**UF_API**/ load( const std::float16_t* ) { return {}; } - inline void /**UF_API**/ store( value, std::float16_t* ) { return; } - inline value /**UF_API**/ set( std::float16_t ) { return {}; } - inline value /**UF_API**/ set( std::float16_t, std::float16_t, std::float16_t, std::float16_t ) { return {}; } - inline value /**UF_API**/ add( value, value ) { return {}; } - inline value /**UF_API**/ sub( value, value ) { return {}; } - inline value /**UF_API**/ mul( value, value ) { return {}; } - inline value /**UF_API**/ div( value, value ) { return {}; } - inline value /**UF_API**/ min( value, value ) { return {}; } - inline value /**UF_API**/ max( value, value ) { return {}; } - inline value /**UF_API**/ sqrt( value ) { return {}; } - // inline value /**UF_API**/ hadd( value, value ) { return {}; } - inline std::float16_t /**UF_API**/ dot( value, value ) { return {}; } - template inline pod::Vector vector( const value ) { return {}; } + DEFINE_SIMD(std::float16_t) #endif #if UF_USE_BFLOAT16 - inline value /**UF_API**/ load( const std::bfloat16_t* ) { return {}; } - inline void /**UF_API**/ store( value, std::bfloat16_t* ) { return; } - inline value /**UF_API**/ set( std::bfloat16_t ) { return {}; } - inline value /**UF_API**/ set( std::bfloat16_t, std::bfloat16_t, std::bfloat16_t, std::bfloat16_t ) { return {}; } - inline value /**UF_API**/ add( value, value ) { return {}; } - inline value /**UF_API**/ sub( value, value ) { return {}; } - inline value /**UF_API**/ mul( value, value ) { return {}; } - inline value /**UF_API**/ div( value, value ) { return {}; } - inline value /**UF_API**/ min( value, value ) { return {}; } - inline value /**UF_API**/ max( value, value ) { return {}; } - inline value /**UF_API**/ sqrt( value ) { return {}; } - // inline value /**UF_API**/ hadd( value, value ) { return {}; } - inline std::bfloat16_t /**UF_API**/ dot( value, value ) { return {}; } - template inline pod::Vector vector( const value ) { return {}; } - - + DEFINE_SIMD(std::bfloat16_t) #endif } - } #include "simd.inl" \ No newline at end of file diff --git a/engine/inc/uf/utils/math/vector/simd.inl b/engine/inc/uf/utils/math/vector/simd.inl index 2c00d536..4717bced 100644 --- a/engine/inc/uf/utils/math/vector/simd.inl +++ b/engine/inc/uf/utils/math/vector/simd.inl @@ -1,5 +1,12 @@ #include +namespace { + inline __m128i bias_unsigned(__m128i v) { + const __m128i signbit = _mm_set1_epi32(0x80000000); + return _mm_xor_si128(v, signbit); + } +} + template inline uf::simd::value::value() {} template @@ -39,6 +46,30 @@ inline uf::simd::value uf::simd::value::operator/( const value& rhs ) { return uf::simd::div( *this, rhs ); } template +inline uf::simd::value uf::simd::value::operator<( const value& rhs ) { + return uf::simd::less( *this, rhs ); +} +template +inline uf::simd::value uf::simd::value::operator<=( const value& rhs ) { + return uf::simd::lessEquals( *this, rhs ); +} +template +inline uf::simd::value uf::simd::value::operator>( const value& rhs ) { + return uf::simd::greater( *this, rhs ); +} +template +inline uf::simd::value uf::simd::value::operator>=( const value& rhs ) { + return uf::simd::greaterEquals( *this, rhs ); +} +template +inline uf::simd::value uf::simd::value::operator==( const value& rhs ) { + return uf::simd::equals( *this, rhs ); +} +template +inline uf::simd::value uf::simd::value::operator!=( const value& rhs ) { + return uf::simd::notEquals( *this, rhs ); +} +template inline uf::simd::value& uf::simd::value::operator=(const uf::simd::value::value_type& rhs) { m_value = rhs; return *this; @@ -49,7 +80,7 @@ inline uf::simd::value& uf::simd::value::operator=(const value& rhs) { return *this; } template -inline uf::simd::value& uf::simd::value::operator=(const pod::Vector4f& rhs) { +inline uf::simd::value& uf::simd::value::operator=(const pod::Vector& rhs) { m_value = uf::simd::load(&rhs[0]); return *this; } @@ -71,121 +102,120 @@ inline pod::Vector uf::simd::vector( const uf::simd::value v ){ return uf::vector::cast(r); } template -inline pod::Vector uf::simd::vector( const uf::simd::value v ){ +inline pod::Vector uf::simd::vector( const uf::simd::value v ){ pod::Vector4i r; uf::simd::store( v, &r[0] ); - return uf::vector::cast(r); + return uf::vector::cast(r); } template -inline pod::Vector uf::simd::vector( const uf::simd::value v ){ +inline pod::Vector uf::simd::vector( const uf::simd::value v ){ pod::Vector4ui r; uf::simd::store( v, &r[0] ); - return uf::vector::cast(r); + return uf::vector::cast(r); } -inline uf::simd::value /*UF_API*/ uf::simd::load( const float* f ) { -#if UF_VECTOR_ALIGNED - return _mm_load_ps(f); -#else - if ( uf::aligned(f, 16) ) return _mm_load_ps(f); - - alignas(16) float s[4]; - memcpy( &s[0], f, sizeof(float) * 4 ); - return _mm_loadu_ps(s); -#endif +inline uf::simd::value uf::simd::load( const float* f ) { + // if ( uf::aligned(f, 16) ) return _mm_load_ps(f); + return _mm_loadu_ps(f); } -inline void /*UF_API*/ uf::simd::store( uf::simd::value v, float* f ) { -#if UF_VECTOR_ALIGNED - return _mm_store_ps(f, v); -#else - if ( uf::aligned(f, 16) ) return _mm_store_ps(f, v); - - alignas(16) float s[4]; - _mm_store_ps(&s[0], v); - memcpy( f, &s[0], sizeof(float) * 4 ); -#endif +inline void uf::simd::store( uf::simd::value v, float* f ) { + /* if ( uf::aligned(f, 16) ) _mm_store_ps(f, v); + else */ _mm_storeu_ps(f, v); } -inline uf::simd::value /*UF_API*/ uf::simd::set( float f ) { +inline uf::simd::value uf::simd::set( float f ) { return _mm_set1_ps(f); } -inline uf::simd::value /*UF_API*/ uf::simd::set( float x, float y, float z, float w ) { +inline uf::simd::value uf::simd::set( float x, float y, float z, float w ) { return _mm_setr_ps(x, y, z, w); } -inline uf::simd::value /*UF_API*/ uf::simd::add( uf::simd::value x, uf::simd::value y ) { +inline uf::simd::value uf::simd::add( uf::simd::value x, uf::simd::value y ) { return _mm_add_ps( x, y ); } -inline uf::simd::value /*UF_API*/ uf::simd::sub( uf::simd::value x, uf::simd::value y ) { +inline uf::simd::value uf::simd::sub( uf::simd::value x, uf::simd::value y ) { return _mm_sub_ps( x, y ); } -inline uf::simd::value /*UF_API*/ uf::simd::mul( uf::simd::value x, uf::simd::value y ) { +inline uf::simd::value uf::simd::mul( uf::simd::value x, uf::simd::value y ) { return _mm_mul_ps( x, y ); } -inline uf::simd::value /*UF_API*/ uf::simd::div( uf::simd::value x, uf::simd::value y ) { +inline uf::simd::value uf::simd::div( uf::simd::value x, uf::simd::value y ) { return _mm_div_ps( x, y ); } /* inline uf::simd::value uf::simd::hadd( uf::simd::value x, uf::simd::value y ) { +#if 0 return _mm_hadd_ps( x, y ); +#else + __m128 shuf = _mm_movehdup_ps(v); + __m128 sums = _mm_add_ps(v, shuf); + shuf = _mm_movehl_ps(shuf, sums); + sums = _mm_add_ss(sums, shuf); + return _mm_cvtss_f32(sums); +#endif } */ -inline uf::simd::value /*UF_API*/ uf::simd::min( uf::simd::value x, uf::simd::value y ) { + +inline uf::simd::value uf::simd::min( uf::simd::value x, uf::simd::value y ) { return _mm_min_ps( x, y ); } -inline uf::simd::value /*UF_API*/ uf::simd::max( uf::simd::value x, uf::simd::value y ) { +inline uf::simd::value uf::simd::max( uf::simd::value x, uf::simd::value y ) { return _mm_max_ps( x, y ); } -inline uf::simd::value /*UF_API*/ uf::simd::sqrt( uf::simd::value v ) { +inline bool uf::simd::all( uf::simd::value mask) { + return _mm_movemask_ps(mask) == 0xF; // all 4 bits set +} +inline bool uf::simd::any( uf::simd::value mask) { + return _mm_movemask_ps(mask) != 0x0; // any bit set +} +inline uf::simd::value uf::simd::less( uf::simd::value x, uf::simd::value y ) { + return _mm_cmplt_ps( x, y ); +} +inline uf::simd::value uf::simd::lessEquals( uf::simd::value x, uf::simd::value y ) { + return _mm_cmple_ps( x, y ); +} +inline uf::simd::value uf::simd::greater( uf::simd::value x, uf::simd::value y ) { + return _mm_cmpgt_ps( x, y ); +} +inline uf::simd::value uf::simd::greaterEquals( uf::simd::value x, uf::simd::value y ) { + return _mm_cmpge_ps( x, y ); +} +inline uf::simd::value uf::simd::equals( uf::simd::value x, uf::simd::value y ) { + return _mm_cmpeq_ps( x, y ); +} +inline uf::simd::value uf::simd::notEquals( uf::simd::value x, uf::simd::value y ) { + return _mm_cmpneq_ps( x, y ); +} +inline uf::simd::value uf::simd::sqrt( uf::simd::value v ) { return _mm_sqrt_ps( v ); } -inline float /*UF_API*/ uf::simd::dot( uf::simd::value x, uf::simd::value y ) { +inline float uf::simd::dot( uf::simd::value x, uf::simd::value y ) { #if SSE_INSTR_SET >= 5 - float res; - __m128 result = _mm_dp_ps(x, y, 0xFF); - _mm_store_ss(&res, result); - return res; -// return uf::simd::vector( result )[0]; + __m128 result = _mm_dp_ps(x, y, 0xF1); + return _mm_cvtss_f32(result); #elif SSE_INSTR_SET >= 3 __m128 mulRes = _mm_mul_ps(x, y); __m128 shufReg = _mm_movehdup_ps(mulRes); __m128 sumsReg = _mm_add_ps(mulRes, shufReg); - shufReg = _mm_movehl_ps(shufReg, sumsReg); - sumsReg = _mm_add_ss(sumsReg, shufReg); - return _mm_cvtss_f32(sumsReg); + shufReg = _mm_movehl_ps(shufReg, sumsReg); + sumsReg = _mm_add_ss(sumsReg, shufReg); + return _mm_cvtss_f32(sumsReg); #else return uf::vector::sum( uf::simd::vector( uf::simd::mul( x, y ) ) ); #endif } -inline uf::simd::value /*UF_API*/ uf::simd::load( const int32_t* f ) { +inline uf::simd::value uf::simd::load( const int32_t* f ) { #if SSE_INSTR_SET >= 3 -#if UF_VECTOR_ALIGNED - return _mm_load_si128((__m128i*) f); -#else - if ( uf::aligned(f, 16) ) return _mm_load_si128((__m128i*) f); - - alignas(16) int32_t s[4]; - memcpy( &s[0], f, sizeof(int32_t) * 4 ); - return _mm_load_si128((__m128i*) s); -#endif + // if ( uf::aligned(f, 16) ) return _mm_load_si128(reinterpret_cast(f)); + return _mm_loadu_si128(reinterpret_cast(f)); #else return uf::simd::value( f[0], f[1], f[2], f[3] ); #endif } -inline void /*UF_API*/ uf::simd::store( uf::simd::value v, int32_t* f ) { +inline void uf::simd::store( uf::simd::value v, int32_t* f ) { #if SSE_INSTR_SET >= 3 -#if UF_VECTOR_ALIGNED - return _mm_store_si128((__m128i*) f, v); + /*if ( uf::aligned(f, 16) ) _mm_store_si128(reinterpret_cast<__m128i*>(f), v); + else*/ _mm_storeu_si128(reinterpret_cast<__m128i*>(f), v); #else - if ( uf::aligned(f, 16) ) return _mm_store_si128((__m128i*) f, v); - - alignas(16) int32_t s[4]; - _mm_store_si128((__m128i*) &s[0], v); - memcpy( f, &s[0], sizeof(int32_t) * 4 ); -#endif -#else - union { - __m128i x; - int32_t y[4]; - } kludge; + union { __m128i x; int32_t y[4]; } kludge; kludge.x = v; f[0] = kludge.y[0]; f[1] = kludge.y[1]; @@ -193,28 +223,28 @@ inline void /*UF_API*/ uf::simd::store( uf::simd::value v, int32_t* f ) f[3] = kludge.y[3]; #endif } -inline uf::simd::value /*UF_API*/ uf::simd::set( int32_t f ) { +inline uf::simd::value uf::simd::set( int32_t f ) { return _mm_set1_epi32(f); } -inline uf::simd::value /*UF_API*/ uf::simd::set( int32_t x, int32_t y, int32_t z, int32_t w ) { +inline uf::simd::value uf::simd::set( int32_t x, int32_t y, int32_t z, int32_t w ) { return _mm_setr_epi32(x, y, z, w); } -inline uf::simd::value /*UF_API*/ uf::simd::add( uf::simd::value x, uf::simd::value y ) { - auto X = uf::simd::vector( x ); - auto Y = uf::simd::vector( y ); - return uf::simd::set( X[0] + Y[0], X[1] + Y[1], X[2] + Y[2], X[3] + Y[3] ); +inline uf::simd::value uf::simd::add( uf::simd::value x, uf::simd::value y ) { + return _mm_add_epi32(x, y); } -inline uf::simd::value /*UF_API*/ uf::simd::sub( uf::simd::value x, uf::simd::value y ) { - auto X = uf::simd::vector( x ); - auto Y = uf::simd::vector( y ); - return uf::simd::set( X[0] - Y[0], X[1] - Y[1], X[2] - Y[2], X[3] - Y[3] ); +inline uf::simd::value uf::simd::sub( uf::simd::value x, uf::simd::value y ) { + return _mm_sub_epi32(x, y); } -inline uf::simd::value /*UF_API*/ uf::simd::mul( uf::simd::value x, uf::simd::value y ) { - auto X = uf::simd::vector( x ); - auto Y = uf::simd::vector( y ); - return uf::simd::set( X[0] * Y[0], X[1] * Y[1], X[2] * Y[2], X[3] * Y[3] ); +inline uf::simd::value uf::simd::mul( uf::simd::value x, uf::simd::value y ) { +#if SSE_INSTR_SET >= 4 + return _mm_mullo_epi32(x, y); +#else + auto X = uf::simd::vector(x); + auto Y = uf::simd::vector(y); + return uf::simd::set(X[0]*Y[0], X[1]*Y[1], X[2]*Y[2], X[3]*Y[3]); +#endif } -inline uf::simd::value /*UF_API*/ uf::simd::div( uf::simd::value x, uf::simd::value y ) { +inline uf::simd::value uf::simd::div( uf::simd::value x, uf::simd::value y ) { auto X = uf::simd::vector( x ); auto Y = uf::simd::vector( y ); return uf::simd::set( X[0] / Y[0], X[1] / Y[1], X[2] / Y[2], X[3] / Y[3] ); @@ -226,57 +256,94 @@ inline uf::simd::value uf::simd::hadd( uf::simd::value x, uf:: return uf::simd::set( X[0] + Y[0], X[1] + Y[1], X[2] + Y[2], X[3] + Y[3] ); } */ -inline uf::simd::value /*UF_API*/ uf::simd::min( uf::simd::value x, uf::simd::value y ) { - auto X = uf::simd::vector( x ); - auto Y = uf::simd::vector( y ); - return uf::simd::set( std::min(X[0], Y[0]), std::min(X[1], Y[1]), std::min(X[2], Y[2]), std::min(X[3], Y[3]) ); +inline uf::simd::value uf::simd::min( uf::simd::value x, uf::simd::value y ) { +#if SSE_INSTR_SET >= 4 + return _mm_min_epi32(x, y); +#else + auto X = uf::simd::vector(x); + auto Y = uf::simd::vector(y); + return uf::simd::set(std::min(X[0],Y[0]), std::min(X[1],Y[1]), std::min(X[2],Y[2]), std::min(X[3],Y[3])); +#endif } -inline uf::simd::value /*UF_API*/ uf::simd::max( uf::simd::value x, uf::simd::value y ) { - auto X = uf::simd::vector( x ); - auto Y = uf::simd::vector( y ); - return uf::simd::set( std::max(X[0], Y[0]), std::max(X[1], Y[1]), std::max(X[2], Y[2]), std::max(X[3], Y[3]) ); +inline uf::simd::value uf::simd::max( uf::simd::value x, uf::simd::value y ) { +#if SSE_INSTR_SET >= 4 + return _mm_max_epi32(x, y); +#else + auto X = uf::simd::vector(x); + auto Y = uf::simd::vector(y); + return uf::simd::set(std::max(X[0],Y[0]), std::max(X[1],Y[1]), std::max(X[2],Y[2]), std::max(X[3],Y[3])); +#endif } -inline uf::simd::value /*UF_API*/ uf::simd::sqrt( uf::simd::value v ) { +inline bool uf::simd::all( uf::simd::value mask) { + return _mm_movemask_epi8( mask ) == 0xFFFF; // all 4 bits set +} +inline bool uf::simd::any( uf::simd::value mask) { + return _mm_movemask_epi8( mask ) != 0x0; // any bit set +} +inline uf::simd::value uf::simd::less( uf::simd::value x, uf::simd::value y ) { +#if SSE_INSTR_SET >= 4 + return _mm_cmplt_epi32( x, y ); +#else + auto X = vector( x ), Y = vector( y ); + return set(X[0] < Y[0], X[1] < Y[1], X[2] < Y[2], X[3] < Y[3]); +#endif +} +inline uf::simd::value uf::simd::lessEquals( uf::simd::value x, uf::simd::value y ) { +#if SSE_INSTR_SET >= 4 + __m128i gt = _mm_cmpgt_epi32(x, y); + return _mm_xor_si128(gt, _mm_set1_epi32(-1)); +#else + auto X = vector( x ), Y = vector( y ); + return uf::simd::set(X[0] <= Y[0], X[1] <= Y[1], X[2] <= Y[2], X[3] <= Y[3]); +#endif +} +inline uf::simd::value uf::simd::greater( uf::simd::value x, uf::simd::value y ) { +#if SSE_INSTR_SET >= 4 + return _mm_cmpgt_epi32( x, y ); +#else + auto X = vector( x ), Y = vector( y ); + return uf::simd::set(X[0] > Y[0], X[1] > Y[1], X[2] > Y[2], X[3] > Y[3]); +#endif +} +inline uf::simd::value uf::simd::greaterEquals( uf::simd::value x, uf::simd::value y ) { +#if SSE_INSTR_SET >= 4 + __m128i gt = _mm_cmplt_epi32(x, y); + return _mm_xor_si128(gt, _mm_set1_epi32(-1)); +#else + auto X = vector( x ), Y = vector( y ); + return uf::simd::set(X[0] >= Y[0], X[1] >= Y[1], X[2] >= Y[2], X[3] >= Y[3]); +#endif +} +inline uf::simd::value uf::simd::equals( uf::simd::value x, uf::simd::value y ) { + return _mm_cmpeq_epi32(x, y); +} +inline uf::simd::value uf::simd::notEquals( uf::simd::value x, uf::simd::value y ) { + return _mm_xor_si128(_mm_cmpeq_epi32(x, y), _mm_set1_epi32(-1)); +} +inline uf::simd::value uf::simd::sqrt( uf::simd::value v ) { auto V = uf::simd::vector( v ); return uf::simd::set( (int32_t) std::sqrt(V[0]), (int32_t) std::sqrt(V[1]), (int32_t) std::sqrt(V[2]), (int32_t) std::sqrt(V[3]) ); } -inline int32_t /*UF_API*/ uf::simd::dot( uf::simd::value x, uf::simd::value y ) { +inline int32_t uf::simd::dot( uf::simd::value x, uf::simd::value y ) { auto X = uf::simd::vector( x ); auto Y = uf::simd::vector( y ); return X[0] * Y[0] + X[1] * Y[1] + X[2] * Y[2] + X[3] * Y[3]; } -inline uf::simd::value /*UF_API*/ uf::simd::load( const uint32_t* f ) { +inline uf::simd::value uf::simd::load( const uint32_t* f ) { #if SSE_INSTR_SET >= 3 -#if UF_VECTOR_ALIGNED - return _mm_load_si128((__m128i*) f); -#else - if ( uf::aligned(f, 16) ) return _mm_load_si128((__m128i*) f); - - alignas(16) uint32_t s[4]; - memcpy( &s[0], f, sizeof(uint32_t) * 4 ); - return _mm_load_si128((__m128i*) &s[0]); -#endif + // if ( uf::aligned(f, 16) ) return _mm_load_si128(reinterpret_cast(f)); + return _mm_loadu_si128(reinterpret_cast(f)); #else return uf::simd::value( f[0], f[1], f[2], f[3] ); #endif } -inline void /*UF_API*/ uf::simd::store( uf::simd::value v, uint32_t* f ) { +inline void uf::simd::store( uf::simd::value v, uint32_t* f ) { #if SSE_INSTR_SET >= 3 -#if UF_VECTOR_ALIGNED - return _mm_store_si128((__m128i*) f, v); + /*if ( uf::aligned(f, 16) ) _mm_store_si128(reinterpret_cast<__m128i*>(f), v); + else*/ _mm_storeu_si128(reinterpret_cast<__m128i*>(f), v); #else - if ( uf::aligned(f, 16) ) return _mm_store_si128((__m128i*) f, v); - - alignas(16) uint32_t s[4]; - _mm_store_si128((__m128i*) &s[0], v); - memcpy( f, &s[0], sizeof(uint32_t) * 4 ); -#endif -#else - union { - __m128i x; - uint32_t y[4]; - } kludge; + union { __m128i x; uint32_t y[4]; } kludge; kludge.x = v; f[0] = kludge.y[0]; f[1] = kludge.y[1]; @@ -284,50 +351,28 @@ inline void /*UF_API*/ uf::simd::store( uf::simd::value v, uint32_t* f f[3] = kludge.y[3]; #endif } -inline uf::simd::value /*UF_API*/ uf::simd::set( uint32_t f ) { -#if 0 - union { - __m128i x; - uint32_t y[4]; - } kludge; - kludge.y[0] = f; - kludge.y[1] = f; - kludge.y[2] = f; - kludge.y[3] = f; -#else +inline uf::simd::value uf::simd::set( uint32_t f ) { return _mm_set1_epi32(f); -#endif } -inline uf::simd::value /*UF_API*/ uf::simd::set( uint32_t x, uint32_t y, uint32_t z, uint32_t w ) { -#if 0 - union { - __m128i x; - uint32_t y[4]; - } kludge; - kludge.y[0] = x; - kludge.y[1] = y; - kludge.y[2] = z; - kludge.y[3] = w; -#else +inline uf::simd::value uf::simd::set( uint32_t x, uint32_t y, uint32_t z, uint32_t w ) { return _mm_setr_epi32(x, y, z, w); +} +inline uf::simd::value uf::simd::add( uf::simd::value x, uf::simd::value y ) { + return _mm_add_epi32(x, y); +} +inline uf::simd::value uf::simd::sub( uf::simd::value x, uf::simd::value y ) { + return _mm_sub_epi32(x, y); +} +inline uf::simd::value uf::simd::mul( uf::simd::value x, uf::simd::value y ) { +#if SSE_INSTR_SET >= 4 + return _mm_mullo_epi32(x, y); +#else + auto X = uf::simd::vector(x); + auto Y = uf::simd::vector(y); + return uf::simd::set(X[0]*Y[0], X[1]*Y[1], X[2]*Y[2], X[3]*Y[3]); #endif } -inline uf::simd::value /*UF_API*/ uf::simd::add( uf::simd::value x, uf::simd::value y ) { - auto X = uf::simd::vector( x ); - auto Y = uf::simd::vector( y ); - return uf::simd::set( X[0] + Y[0], X[1] + Y[1], X[2] + Y[2], X[3] + Y[3] ); -} -inline uf::simd::value /*UF_API*/ uf::simd::sub( uf::simd::value x, uf::simd::value y ) { - auto X = uf::simd::vector( x ); - auto Y = uf::simd::vector( y ); - return uf::simd::set( X[0] - Y[0], X[1] - Y[1], X[2] - Y[2], X[3] - Y[3] ); -} -inline uf::simd::value /*UF_API*/ uf::simd::mul( uf::simd::value x, uf::simd::value y ) { - auto X = uf::simd::vector( x ); - auto Y = uf::simd::vector( y ); - return uf::simd::set( X[0] * Y[0], X[1] * Y[1], X[2] * Y[2], X[3] * Y[3] ); -} -inline uf::simd::value /*UF_API*/ uf::simd::div( uf::simd::value x, uf::simd::value y ) { +inline uf::simd::value uf::simd::div( uf::simd::value x, uf::simd::value y ) { auto X = uf::simd::vector( x ); auto Y = uf::simd::vector( y ); return uf::simd::set( X[0] / Y[0], X[1] / Y[1], X[2] / Y[2], X[3] / Y[3] ); @@ -339,21 +384,81 @@ inline uf::simd::value uf::simd::hadd( uf::simd::value x, uf return uf::simd::set( X[0] + Y[0], X[1] + Y[1], X[2] + Y[2], X[3] + Y[3] ); } */ -inline uf::simd::value /*UF_API*/ uf::simd::min( uf::simd::value x, uf::simd::value y ) { - auto X = uf::simd::vector( x ); - auto Y = uf::simd::vector( y ); - return uf::simd::set( std::min(X[0], Y[0]), std::min(X[1], Y[1]), std::min(X[2], Y[2]), std::min(X[3], Y[3]) ); +inline uf::simd::value uf::simd::min( uf::simd::value x, uf::simd::value y ) { +#if SSE_INSTR_SET >= 4 + return _mm_min_epu32(x, y); // unsigned min +#else + auto X = uf::simd::vector(x); + auto Y = uf::simd::vector(y); + return uf::simd::set(std::min(X[0],Y[0]), std::min(X[1],Y[1]), std::min(X[2],Y[2]), std::min(X[3],Y[3])); +#endif } -inline uf::simd::value /*UF_API*/ uf::simd::max( uf::simd::value x, uf::simd::value y ) { - auto X = uf::simd::vector( x ); - auto Y = uf::simd::vector( y ); - return uf::simd::set( std::max(X[0], Y[0]), std::max(X[1], Y[1]), std::max(X[2], Y[2]), std::max(X[3], Y[3]) ); +inline uf::simd::value uf::simd::max( uf::simd::value x, uf::simd::value y ) { +#if SSE_INSTR_SET >= 4 + return _mm_max_epu32(x, y); // unsigned max +#else + auto X = uf::simd::vector(x); + auto Y = uf::simd::vector(y); + return uf::simd::set(std::max(X[0],Y[0]), std::max(X[1],Y[1]), std::max(X[2],Y[2]), std::max(X[3],Y[3])); +#endif } -inline uf::simd::value /*UF_API*/ uf::simd::sqrt( uf::simd::value v ) { +inline bool uf::simd::all( uf::simd::value mask) { + return _mm_movemask_epi8( mask ) == 0xFFFF; // all 4 bits set +} +inline bool uf::simd::any( uf::simd::value mask) { + return _mm_movemask_epi8( mask ) != 0x0; // any bit set +} +inline uf::simd::value uf::simd::less( uf::simd::value x, uf::simd::value y ) { +#if SSE_INSTR_SET >= 4 + return _mm_cmplt_epi32( ::bias_unsigned( x ), ::bias_unsigned( y ) ); +#else + auto X = vector( x ), Y = vector( y ); + return set(X[0] < Y[0], X[1] < Y[1], X[2] < Y[2], X[3] < Y[3]); +#endif +} +inline uf::simd::value uf::simd::lessEquals(value x, value y) { +#if SSE_INSTR_SET >= 2 + // a <= b <=> !(a > b) + __m128i bx = ::bias_unsigned(x); + __m128i by = ::bias_unsigned(y); + __m128i gt = _mm_cmpgt_epi32(bx, by); // signed compare + return _mm_xor_si128(gt, _mm_set1_epi32(-1)); // invert mask +#else + auto X = vector(x), Y = vector(y); + return set(X[0] <= Y[0], X[1] <= Y[1], X[2] <= Y[2], X[3] <= Y[3]); +#endif +} +inline uf::simd::value uf::simd::greater( uf::simd::value x, uf::simd::value y ) { +#if SSE_INSTR_SET >= 4 + return _mm_cmpgt_epi32( ::bias_unsigned( x ), ::bias_unsigned( y ) ); +#else + auto X = vector( x ), Y = vector( y ); + return uf::simd::set(X[0] > Y[0], X[1] > Y[1], X[2] > Y[2], X[3] > Y[3]); +#endif +} +inline uf::simd::value uf::simd::greaterEquals(value x, value y) { +#if SSE_INSTR_SET >= 2 + // a >= b <=> !(a < b) + __m128i bx = ::bias_unsigned(x); + __m128i by = ::bias_unsigned(y); + __m128i lt = _mm_cmplt_epi32(bx, by); // signed compare + return _mm_xor_si128(lt, _mm_set1_epi32(-1)); // invert mask +#else + auto X = vector(x), Y = vector(y); + return set(X[0] >= Y[0], X[1] >= Y[1], X[2] >= Y[2], X[3] >= Y[3]); +#endif +} +inline uf::simd::value uf::simd::equals( uf::simd::value x, uf::simd::value y ) { + return _mm_cmpeq_epi32(x, y); +} +inline uf::simd::value uf::simd::notEquals( uf::simd::value x, uf::simd::value y ) { + return _mm_xor_si128(_mm_cmpeq_epi32(x, y), _mm_set1_epi32(-1)); +} +inline uf::simd::value uf::simd::sqrt( uf::simd::value v ) { auto V = uf::simd::vector( v ); return uf::simd::set( (uint32_t) std::sqrt(V[0]), (uint32_t) std::sqrt(V[1]), (uint32_t) std::sqrt(V[2]), (uint32_t) std::sqrt(V[3]) ); } -inline uint32_t /*UF_API*/ uf::simd::dot( uf::simd::value x, uf::simd::value y ) { +inline uint32_t uf::simd::dot( uf::simd::value x, uf::simd::value y ) { auto X = uf::simd::vector( x ); auto Y = uf::simd::vector( y ); return X[0] * Y[0] + X[1] * Y[1] + X[2] * Y[2] + X[3] * Y[3]; diff --git a/engine/inc/uf/utils/math/vector/vector.inl b/engine/inc/uf/utils/math/vector/vector.inl index d2038492..d2c0cd06 100644 --- a/engine/inc/uf/utils/math/vector/vector.inl +++ b/engine/inc/uf/utils/math/vector/vector.inl @@ -1,7 +1,4 @@ #include "pod.inl" -#if UF_USE_CLASS_OF_PODS - #include "class.inl" -#endif template uf::stl::string /*UF_API*/ uf::string::toString( const pod::Vector& v ) { diff --git a/engine/inc/uf/utils/memory/unordered_set.h b/engine/inc/uf/utils/memory/unordered_set.h new file mode 100644 index 00000000..d1c96e3b --- /dev/null +++ b/engine/inc/uf/utils/memory/unordered_set.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include "./allocator.h" + +#include +#include "vector.h" + +namespace uf { + namespace stl { + template< + class Key, + class Hash = std::hash, + class KeyEqual = std::equal_to, + #if UF_MEMORYPOOL_USE_STL_ALLOCATOR + class Allocator = std::allocator + #else + class Allocator = uf::Allocator + #endif + > + using unordered_set = std::unordered_set; + } +} \ No newline at end of file diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index 80106b1f..1a128d3a 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -1297,7 +1297,7 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) if ( tag["transform"]["offset"].as() ) { auto parsed = uf::transform::decode( tag["transform"], pod::Transform<>{} ); transform.position += parsed.position; - transform.orientation = uf::quaternion::multiply( transform.orientation, parsed.orientation ); + transform.orientation = uf::quaternion::multiply( parsed.orientation, transform.orientation ); } else { transform = uf::transform::decode( tag["transform"], transform ); if ( tag["transform"]["parent"].is() ) { diff --git a/engine/src/ext/lua/usertypes/vector.cpp b/engine/src/ext/lua/usertypes/vector.cpp index 25ec1e68..c01c55e4 100644 --- a/engine/src/ext/lua/usertypes/vector.cpp +++ b/engine/src/ext/lua/usertypes/vector.cpp @@ -191,7 +191,7 @@ namespace binds { return uf::quaternion::axisAngle( arg.as(), angle ); } else if ( arg.is() ) { sol::table table = arg.as(); - return uf::quaternion::axisAngle( pod::Vector3f{ table[0], table[1], table[2] }, angle ); + return uf::quaternion::axisAngle( pod::Vector3f{ (float) table[0], table[1], table[2] }, angle ); } return ::Quaternion{}; } diff --git a/engine/src/ext/vulkan/graphic.cpp b/engine/src/ext/vulkan/graphic.cpp index 5ef281ad..dd0bbc95 100644 --- a/engine/src/ext/vulkan/graphic.cpp +++ b/engine/src/ext/vulkan/graphic.cpp @@ -1588,7 +1588,7 @@ void ext::vulkan::Graphic::generateTopAccelerationStructure( const uf::stl::vect for ( auto& blas : graphic->accelerationStructures.bottoms ) { auto& instance = instances[blas.instanceID]; auto mat = modelMatrices[instance.objectID]; - mat = uf::matrix::transpose(mat); + mat = uf::matrix::transpose(mat); // might need to not do this auto& instanceVK = instancesVK.emplace_back(); memcpy(&instanceVK.transform, &mat, sizeof(instanceVK.transform)); diff --git a/engine/src/utils/math/physics/aabb.inl b/engine/src/utils/math/physics/aabb.inl index a2028307..bee07c8d 100644 --- a/engine/src/utils/math/physics/aabb.inl +++ b/engine/src/utils/math/physics/aabb.inl @@ -1,15 +1,6 @@ namespace { - bool aabbOverlap( const pod::AABB& a, const pod::AABB& b, float eps ) { - for (int axis=0; axis<3; ++axis) { - if (a.max[axis] + eps < b.min[axis] - eps) return false; - if (a.min[axis] - eps > b.max[axis] + eps) return false; - } - return true; - /* - return !(a.max.x < b.min.x + eps || a.min.x > b.max.x - eps || - a.max.y < b.min.y + eps || a.min.y > b.max.y - eps || - a.max.z < b.min.z + eps || a.min.z > b.max.z - eps); - */ + inline bool aabbOverlap( const pod::AABB& a, const pod::AABB& b, float eps ) { + return ( a.min - eps ) <= ( b.max + eps ) && ( a.max + eps ) >= ( b.min - eps ); } inline float aabbSurfaceArea(const pod::AABB& aabb) { @@ -25,11 +16,7 @@ namespace { } pod::Vector3f closestPointOnAABB(const pod::Vector3f& p, const pod::AABB& box) { - return { - std::max(box.min.x, std::min(p.x, box.max.x)), - std::max(box.min.y, std::min(p.y, box.max.y)), - std::max(box.min.z, std::min(p.z, box.max.z)) - }; + return uf::vector::clamp( p, box.min, box.max ); } std::pair getCapsuleSegment( const pod::PhysicsBody& body ) { @@ -78,16 +65,8 @@ namespace { pod::AABB computeTriangleAABB( const pod::Triangle& tri ) { return { - { - std::min({tri.points[0].x, tri.points[1].x, tri.points[2].x}), - std::min({tri.points[0].y, tri.points[1].y, tri.points[2].y}), - std::min({tri.points[0].z, tri.points[1].z, tri.points[2].z}), - }, - { - std::max({tri.points[0].x, tri.points[1].x, tri.points[2].x}), - std::max({tri.points[0].y, tri.points[1].y, tri.points[2].y}), - std::max({tri.points[0].z, tri.points[1].z, tri.points[2].z}), - }, + uf::vector::min( uf::vector::min( tri.points[0], tri.points[1] ), tri.points[2] ), + uf::vector::max( uf::vector::max( tri.points[0], tri.points[1] ), tri.points[2] ), }; } @@ -211,17 +190,13 @@ namespace { if ( !::aabbOverlap( A, B ) ) return false; // calculate overlap extents - float overlaps[3] = { - std::min(A.max.x, B.max.x) - std::max(A.min.x, B.min.x), - std::min(A.max.y, B.max.y) - std::max(A.min.y, B.min.y), - std::min(A.max.z, B.max.z) - std::max(A.min.z, B.min.z) - }; + auto overlaps = uf::vector::min( A.max, B.max ) - uf::vector::max( A.min, B.min ); // determine collision axis = smallest overlap int axis = -1; float minOverlap = FLT_MAX; - for (int i = 0; i < 3; ++i) { - if (overlaps[i] < minOverlap) { + for ( auto i = 0; i < 3; ++i ) { + if ( overlaps[i] < minOverlap ) { minOverlap = overlaps[i]; axis = i; } @@ -232,31 +207,27 @@ namespace { normal[axis] = (delta[axis] < 0 ? -1.0f : 1.0f); // build manifold contacts: overlap region corners on the separating axis - float xMin = std::max(A.min.x, B.min.x); - float xMax = std::min(A.max.x, B.max.x); - float yMin = std::max(A.min.y, B.min.y); - float yMax = std::min(A.max.y, B.max.y); - float zMin = std::max(A.min.z, B.min.z); - float zMax = std::min(A.max.z, B.max.z); + auto Min = uf::vector::max( A.min, B.min ); + auto Max = uf::vector::min( A.max, B.max ); // on chosen axis, clamp to overlapped rectangle -> 4 potential points if (axis == 0) { // x-axis separation, so face-on overlap in YZ plane - manifold.points.emplace_back(pod::Contact{ { (normal.x > 0 ? A.max.x : A.min.x), yMin, zMin }, normal, minOverlap }); - manifold.points.emplace_back(pod::Contact{ { (normal.x > 0 ? A.max.x : A.min.x), yMin, zMax }, normal, minOverlap }); - manifold.points.emplace_back(pod::Contact{ { (normal.x > 0 ? A.max.x : A.min.x), yMax, zMin }, normal, minOverlap }); - manifold.points.emplace_back(pod::Contact{ { (normal.x > 0 ? A.max.x : A.min.x), yMax, zMax }, normal, minOverlap }); + manifold.points.emplace_back(pod::Contact{ { (normal.x > 0 ? A.max.x : A.min.x), Min.y, Min.z }, normal, minOverlap }); + manifold.points.emplace_back(pod::Contact{ { (normal.x > 0 ? A.max.x : A.min.x), Min.y, Max.z }, normal, minOverlap }); + manifold.points.emplace_back(pod::Contact{ { (normal.x > 0 ? A.max.x : A.min.x), Max.y, Min.z }, normal, minOverlap }); + manifold.points.emplace_back(pod::Contact{ { (normal.x > 0 ? A.max.x : A.min.x), Max.y, Max.z }, normal, minOverlap }); } else if (axis == 1) { // y-axis separation, overlap in XZ plane - manifold.points.emplace_back(pod::Contact{ { xMin, (normal.y > 0 ? A.max.y : A.min.y), zMin }, normal, minOverlap }); - manifold.points.emplace_back(pod::Contact{ { xMin, (normal.y > 0 ? A.max.y : A.min.y), zMax }, normal, minOverlap }); - manifold.points.emplace_back(pod::Contact{ { xMax, (normal.y > 0 ? A.max.y : A.min.y), zMin }, normal, minOverlap }); - manifold.points.emplace_back(pod::Contact{ { xMax, (normal.y > 0 ? A.max.y : A.min.y), zMax }, normal, minOverlap }); + manifold.points.emplace_back(pod::Contact{ { Min.x, (normal.y > 0 ? A.max.y : A.min.y), Min.z }, normal, minOverlap }); + manifold.points.emplace_back(pod::Contact{ { Min.x, (normal.y > 0 ? A.max.y : A.min.y), Max.z }, normal, minOverlap }); + manifold.points.emplace_back(pod::Contact{ { Max.x, (normal.y > 0 ? A.max.y : A.min.y), Min.z }, normal, minOverlap }); + manifold.points.emplace_back(pod::Contact{ { Max.x, (normal.y > 0 ? A.max.y : A.min.y), Max.z }, normal, minOverlap }); } else if (axis == 2) { // z-axis separation, overlap in XY plane - manifold.points.emplace_back(pod::Contact{ { xMin, yMin, (normal.z > 0 ? A.max.z : A.min.z) }, normal, minOverlap }); - manifold.points.emplace_back(pod::Contact{ { xMin, yMax, (normal.z > 0 ? A.max.z : A.min.z) }, normal, minOverlap }); - manifold.points.emplace_back(pod::Contact{ { xMax, yMin, (normal.z > 0 ? A.max.z : A.min.z) }, normal, minOverlap }); - manifold.points.emplace_back(pod::Contact{ { xMax, yMax, (normal.z > 0 ? A.max.z : A.min.z) }, normal, minOverlap }); + manifold.points.emplace_back(pod::Contact{ { Min.x, Min.y, (normal.z > 0 ? A.max.z : A.min.z) }, normal, minOverlap }); + manifold.points.emplace_back(pod::Contact{ { Min.x, Max.y, (normal.z > 0 ? A.max.z : A.min.z) }, normal, minOverlap }); + manifold.points.emplace_back(pod::Contact{ { Max.x, Min.y, (normal.z > 0 ? A.max.z : A.min.z) }, normal, minOverlap }); + manifold.points.emplace_back(pod::Contact{ { Max.x, Max.y, (normal.z > 0 ? A.max.z : A.min.z) }, normal, minOverlap }); } return true; diff --git a/engine/src/utils/math/physics/bvh.inl b/engine/src/utils/math/physics/bvh.inl index f4e010e7..82b21d6c 100644 --- a/engine/src/utils/math/physics/bvh.inl +++ b/engine/src/utils/math/physics/bvh.inl @@ -162,6 +162,8 @@ namespace { } void buildBroadphaseBVH( pod::BVH& bvh, const uf::stl::vector& bodies, int capacity = 2 ) { + if ( bodies.empty() ) return; + bvh.indices.clear(); bvh.nodes.clear(); bvh.indices.reserve(bodies.size()); @@ -207,7 +209,8 @@ namespace { auto tris = view.index.count / 3; for ( auto triIndexID = 0; triIndexID < tris; ++triIndexID ) { - auto aabb = ::computeTriangleAABB( positions.data(view.vertex.first), positions.stride(), indices.data(view.index.first), mesh.index.size, triIndexID ); + auto tri = ::fetchTriangle( positions.data(view.vertex.first), positions.stride(), indices.data(view.index.first), mesh.index.size, triIndexID ); + auto aabb = ::computeTriangleAABB( tri ); auto triID = triIndexID + (view.index.first / 3); if ( triID != bounds.size() ) UF_MSG_DEBUG("triID={}, bounds.size()={}", triID, bounds.size()); @@ -349,7 +352,8 @@ namespace { auto tris = view.index.count / 3; for ( auto triIndexID = 0; triIndexID < tris; ++triIndexID ) { - auto aabb = ::computeTriangleAABB( positions.data(view.vertex.first), positions.stride(), indices.data(view.index.first), mesh.index.size, triIndexID ); + auto tri = ::fetchTriangle( positions.data(view.vertex.first), positions.stride(), indices.data(view.index.first), mesh.index.size, triIndexID ); + auto aabb = ::computeTriangleAABB( tri ); bounds.emplace_back(aabb); } } @@ -414,7 +418,7 @@ namespace { if ( bodyA == bodyB ) continue; if ( bodyA > bodyB ) std::swap( bodyA, bodyB ); - pairs.emplace_back(bodyA, bodyB); + pairs.emplace(bodyA, bodyB); } } return; @@ -442,7 +446,7 @@ namespace { int bodyA = bvhA.indices[nodeA.start + i]; int bodyB = bvhB.indices[nodeB.start + j]; - pairs.emplace_back(bodyA, bodyB); + pairs.emplace(bodyA, bodyB); } } return; @@ -470,7 +474,7 @@ namespace { if ( bodyA == bodyB ) continue; if ( bodyA > bodyB ) std::swap( bodyA, bodyB ); - pairs.emplace_back(bodyA, bodyB); + pairs.emplace(bodyA, bodyB); } } return; @@ -499,12 +503,12 @@ namespace { namespace { // query a BVH with an AABB via a stack void queryBVH( const pod::BVH& bvh, const pod::AABB& bounds, uf::stl::vector& outIndices ) { + if ( bvh.nodes.empty() ) return; + if ( !bvh.flattened.empty() ) return ::queryFlatBVH( bvh, bounds, outIndices ); outIndices.reserve(::reserveCount); - if ( bvh.nodes.empty() ) return; - uf::stl::stack stack; stack.push(0); @@ -598,7 +602,6 @@ namespace { auto& nodes = bvh.flattened; auto& indices = bvh.indices; - outPairs.clear(); outPairs.reserve(::reserveCount); for ( auto i = 0; i < (int) nodes.size(); ++i ) { @@ -619,7 +622,7 @@ namespace { if ( indexA == indexB ) continue; if ( indexA > indexB ) std::swap( indexA, indexB ); - outPairs.emplace_back( indexA, indexB ); + outPairs.emplace( indexA, indexB ); } } } @@ -634,7 +637,6 @@ namespace { if ( nodesA.empty() || nodesB.empty() ) return; - outPairs.clear(); outPairs.reserve(::reserveCount); for ( auto i = 0; i < (int) nodesA.size(); ++i ) { @@ -652,7 +654,7 @@ namespace { auto indexA = indicesA[nodeA.start + ia]; auto indexB = indicesB[nodeB.start + ib]; - outPairs.emplace_back( indexA, indexB ); + outPairs.emplace( indexA, indexB ); } } } diff --git a/engine/src/utils/math/physics/helpers.inl b/engine/src/utils/math/physics/helpers.inl index 5378b1d8..86a24d60 100644 --- a/engine/src/utils/math/physics/helpers.inl +++ b/engine/src/utils/math/physics/helpers.inl @@ -73,13 +73,6 @@ namespace { return (idA << 32) ^ idB; } - void deduplicatePairs( pod::BVH::pairs_t& pairs ) { - // should already be swapped - for (auto& [a, b] : pairs) if (a > b) std::swap(a, b); - std::sort(pairs.begin(), pairs.end()); - pairs.erase(std::unique(pairs.begin(), pairs.end()), pairs.end()); - } - // marks a body as asleep void wakeBody( pod::PhysicsBody& body ) { body.activity.awake = true; diff --git a/engine/src/utils/math/physics/impl.cpp b/engine/src/utils/math/physics/impl.cpp index a5cacb92..bec58ea8 100644 --- a/engine/src/utils/math/physics/impl.cpp +++ b/engine/src/utils/math/physics/impl.cpp @@ -25,8 +25,10 @@ namespace { bool useBvhSahBodies = false; bool useBvhSahMeshes = false; + bool useSplitBvhs = false; // currently bugged if enabled + int solverIterations = 10; - float baumgarteCorrectionPercent = 0.2f; + float baumgarteCorrectionPercent = 0.02f; float baumgarteCorrectionSlop = 0.01f; uf::stl::unordered_map manifoldsCache; @@ -117,21 +119,34 @@ void uf::physics::impl::substep( pod::World& world, float dt, int substeps ) { } void uf::physics::impl::step( pod::World& world, float dt ) { auto& bodies = world.bodies; - auto& bvh = world.bvh; + auto& dynamicBvh = world.dynamicBvh; + auto& staticBvh = world.staticBvh; + + uf::stl::vector staticBodies; + uf::stl::vector dynamicBodies; if ( bodies.empty() ) return; + ++::frameCounter; + for ( auto* body : bodies ) { + ( body->isStatic ? staticBodies : dynamicBodies ).emplace_back(body); + if ( !body->activity.awake ) continue; ::integrate( *body, dt ); } - switch ( ::decideBVHUpdate( bvh, bodies, ::bvhUpdatePolicy, ::frameCounter++ ) ) { + // rebuild static bvh if diry + if ( staticBvh.dirty && ::useSplitBvhs ) { + ::buildBroadphaseBVH( staticBvh, staticBodies, ::broadphaseBvhCapacity ); // (re)build + } + + switch ( ::decideBVHUpdate( dynamicBvh, ::useSplitBvhs ? dynamicBodies : bodies, ::bvhUpdatePolicy, ::frameCounter ) ) { case pod::BVH::UpdatePolicy::Decision::REBUILD: { - ::buildBroadphaseBVH( bvh, bodies, ::broadphaseBvhCapacity ); // (re)build + ::buildBroadphaseBVH( dynamicBvh, ::useSplitBvhs ? dynamicBodies : bodies, ::broadphaseBvhCapacity ); // (re)build } break; case pod::BVH::UpdatePolicy::Decision::REFIT: { - ::refitBVH( bvh, bodies ); // refit + ::refitBVH( dynamicBvh, ::useSplitBvhs ? dynamicBodies : bodies ); // refit } break; case pod::BVH::UpdatePolicy::Decision::NONE: default: @@ -141,12 +156,12 @@ void uf::physics::impl::step( pod::World& world, float dt ) { // query for overlaps pod::BVH::pairs_t pairs; - ::queryOverlaps( bvh, pairs ); - ::deduplicatePairs( pairs ); + ::queryOverlaps( dynamicBvh, pairs ); + if ( ::useSplitBvhs ) ::queryOverlaps( dynamicBvh, staticBvh, pairs ); // build islands uf::stl::vector islands; - ::buildIslands( pairs, world.bodies, islands ); + ::buildIslands( pairs, bodies, islands ); // update sleep state per island for ( auto& island : islands ) ::updateIsland( island, dt ); @@ -194,7 +209,7 @@ void uf::physics::impl::step( pod::World& world, float dt ) { if ( ::warmupSolver ) ::storeManifolds( manifolds, ::manifoldsCache ); // recompute bounds for further queries - for ( auto* body : bodies ) { + for ( auto* body : dynamicBodies ) { body->bounds = ::computeAABB( *body ); } } @@ -330,13 +345,14 @@ pod::PhysicsBody& uf::physics::impl::create( pod::World& world, uf::Object& obje if ( body.isStatic ) { uf::physics::impl::setColliderCategory(body, "STATIC"); uf::physics::impl::setColliderMask(body, "STATIC"); + world.staticBvh.dirty = true; // mark as dirty } else { uf::physics::impl::setColliderCategory(body, "DYNAMIC"); uf::physics::impl::setColliderMask(body, "DYNAMIC"); + world.dynamicBvh.dirty = true; // mark as dirty } world.bodies.emplace_back(&body); // insert into world - world.bvh.dirty = true; // mark as dirty return body; } @@ -459,11 +475,13 @@ pod::RayQuery uf::physics::impl::rayCast( const pod::Ray& ray, const pod::World& pod::RayQuery rayHit; rayHit.contact.penetration = maxDistance; - auto& bvh = world.bvh; + auto& dynamicBvh = world.dynamicBvh; + auto& staticBvh = world.dynamicBvh; auto& bodies = world.bodies; uf::stl::vector candidates; - ::queryBVH( bvh, ray, candidates ); + ::queryBVH( dynamicBvh, ray, candidates ); + if ( ::useSplitBvhs ) ::queryBVH( staticBvh, ray, candidates ); for ( auto i : candidates ) { auto* b = bodies[i]; diff --git a/engine/src/utils/math/physics/mesh.inl b/engine/src/utils/math/physics/mesh.inl index 0b8edfa6..7016089e 100644 --- a/engine/src/utils/math/physics/mesh.inl +++ b/engine/src/utils/math/physics/mesh.inl @@ -122,7 +122,6 @@ namespace { // compute overlaps between one BVH and another BVH pod::BVH::pairs_t pairs; ::queryOverlaps( bvhA, bvhB, pairs ); - ::deduplicatePairs( pairs ); bool hit = false; // do collision per triangle diff --git a/engine/src/utils/math/physics/solvers.inl b/engine/src/utils/math/physics/solvers.inl index 02a38e00..e440c5b6 100644 --- a/engine/src/utils/math/physics/solvers.inl +++ b/engine/src/utils/math/physics/solvers.inl @@ -148,7 +148,7 @@ namespace { } residual = rhs - uf::matrix::multiply( K, lambda ); - pod::Matrix Kinv = uf::matrix::invert( K ); + pod::Matrix Kinv = uf::matrix::inverse( K ); pod::Vector dLambda = uf::matrix::multiply( Kinv, residual ); for ( auto i = 0; i < N; i++ ) { diff --git a/engine/src/utils/math/physics/triangle.inl b/engine/src/utils/math/physics/triangle.inl index d5e26cd1..48a7e090 100644 --- a/engine/src/utils/math/physics/triangle.inl +++ b/engine/src/utils/math/physics/triangle.inl @@ -29,28 +29,11 @@ namespace { //return uf::vector::normalize( tri.normals[0] + tri.normals[1] + tri.normals[2] ); } - pod::AABB computeTriangleAABB( const void* vertices, size_t vertexStride, const void* indexData, size_t indexSize, size_t triID ) { - auto triIndexID = triID * 3; - - uint32_t i0 = ::getIndex( indexData, indexSize, triIndexID + 0 ); - uint32_t i1 = ::getIndex( indexData, indexSize, triIndexID + 1 ); - uint32_t i2 = ::getIndex( indexData, indexSize, triIndexID + 2 ); - - auto& v0 = *reinterpret_cast(reinterpret_cast(vertices) + i0 * vertexStride); - auto& v1 = *reinterpret_cast(reinterpret_cast(vertices) + i1 * vertexStride); - auto& v2 = *reinterpret_cast(reinterpret_cast(vertices) + i2 * vertexStride); - + pod::Triangle fetchTriangle( const void* vertices, size_t vertexStride, const void* indexData, size_t indexSize, size_t triID ) { return { - { - std::min({v0.x, v1.x, v2.x}), - std::min({v0.y, v1.y, v2.y}), - std::min({v0.z, v1.z, v2.z}), - }, - { - std::max({v0.x, v1.x, v2.x}), - std::max({v0.y, v1.y, v2.y}), - std::max({v0.z, v1.z, v2.z}), - } + *reinterpret_cast(reinterpret_cast(vertices) + ::getIndex( indexData, indexSize, (triID * 3) + 0 ) * vertexStride), + *reinterpret_cast(reinterpret_cast(vertices) + ::getIndex( indexData, indexSize, (triID * 3) + 1 ) * vertexStride), + *reinterpret_cast(reinterpret_cast(vertices) + ::getIndex( indexData, indexSize, (triID * 3) + 2 ) * vertexStride), }; } @@ -71,28 +54,12 @@ namespace { triBase += trisInView; } UF_ASSERT( found ); - uint32_t triIndexID = triID * 3; // remap triangle ID to index ID - - pod::TriangleWithNormal tri; auto& positions = (*found)["position"]; auto& normals = (*found)["normal"]; auto& indices = (*found)["index"]; - - const void* indexBase = indices.data(found->index.first); - size_t indexSize = mesh.index.size; - - uint32_t idxs[3]; - // to-do: just make this a macro that could have a parallel hint - for ( auto i = 0; i < 3; ++i ) idxs[i] = getIndex(indexBase, indexSize, triIndexID + i); - - { - auto* base = reinterpret_cast(positions.data(found->vertex.first)); - size_t stride = positions.stride(); - - for ( auto i = 0; i < 3; ++i ) tri.points[i] = *reinterpret_cast(base + idxs[i] * stride); - } - + + pod::TriangleWithNormal tri = { ::fetchTriangle( positions.data(found->vertex.first), positions.stride(), indices.data(found->index.first), mesh.index.size, triID ) }; tri.normal = uf::vector::normalize(uf::vector::cross(tri.points[1] - tri.points[0], tri.points[2] - tri.points[0])); /* @@ -373,7 +340,7 @@ namespace { auto bounds = ::computeSegmentAABB( p1, p2, r ); // to-do: derive proper delta - pod::Vector3f closestSeg, closest; + pod::Vector3f closestSeg = {}, closest = {}; float dist2 = ::segmentTriangleDistanceSq( p1, p2, tri, closestSeg, closest ); if ( !uf::vector::isValid( closest ) ) return false; diff --git a/engine/src/utils/math/rayt.cpp b/engine/src/utils/math/rayt.cpp deleted file mode 100644 index fbd12763..00000000 --- a/engine/src/utils/math/rayt.cpp +++ /dev/null @@ -1,338 +0,0 @@ -#if 0 -#include -#include -#include - -// compile-time assert to ensure objects are of same size, if using multiple types of objects - -// takes a vector of primitives and groups them under leaves (end point of a tree) -uf::stl::vector uf::primitive::populate( const uf::stl::vector& cubes ) { // assert(cubes.size() > 0); - uf::stl::vector trees; - uf::stl::vector copy; - uf::stl::vector alloced; - copy.reserve( cubes.size() ); -// std::cout << "Size: " << cubes.size() << std::endl; - for ( const auto& cube : cubes ) { - copy.push_back( &cube ); - } - - trees.reserve( copy.size() / pod::Tree::TREE_SIZE ); - alloced.reserve( copy.size() ); - const float cubeRoot = std::cbrt(pod::Tree::TREE_SIZE); - for ( const auto& cube : cubes ) { - // already allocated, skip - if ( std::find( alloced.begin(), alloced.end(), &cube ) != alloced.end() ) continue; - size_t index = 0; - pod::Tree tree; - // sort by closest cube - std::sort( copy.begin(), copy.end(), [&]( const pod::Primitive* l, const pod::Primitive* r ) { - return uf::vector::distanceSquared( cube.position, l->position ) < uf::vector::distanceSquared( cube.position, r->position ); - } ); -// std::cout << trees.size() << ": " << alloced.size() << std::endl; - while ( index < pod::Tree::TREE_SIZE && copy.begin() != copy.end() ) { - const pod::Primitive* ptr = *copy.begin(); - copy.erase( copy.begin() ); - tree.children[index++] = (ptr - &cubes[0]); - } - for ( size_t i = index; i < pod::Tree::TREE_SIZE; ++i ) { - tree.children[i] = pod::Primitive::EMPTY; - } - // mark children as allocated - /* - for ( int i = 0; i < pod::Tree::TREE_SIZE && i < index; ++i ) { - const auto& cube = cubes.at(tree.children[i]); - alloced.push_back(&cube); - tree.primitive.position.x += cube.position.x; tree.primitive.position.y += cube.position.y; tree.primitive.position.z += cube.position.z; - } - tree.primitive.position.x /= pod::Tree::TREE_SIZE; - tree.primitive.position.y /= pod::Tree::TREE_SIZE; - tree.primitive.position.z /= pod::Tree::TREE_SIZE; - */ - pod::Vector3f min = { 0, 0, 0 }, max = { 0, 0, 0 }; - for ( int i = 0; i < pod::Tree::TREE_SIZE && i < index; ++i ) { - const auto& cube = cubes.at(tree.children[i]); - alloced.push_back(&cube); - if ( i == 0 ) { - min.x = cube.position.x - cube.position.w; - min.y = cube.position.y - cube.position.w; - min.z = cube.position.z - cube.position.w; - max.x = cube.position.x + cube.position.w; - max.y = cube.position.y + cube.position.w; - max.z = cube.position.z + cube.position.w; - continue; - } - min.x = std::min( cube.position.x - cube.position.w, min.x ); min.y = std::min( cube.position.y - cube.position.w, min.y ); min.z = std::min( cube.position.z - cube.position.w, min.z ); - max.x = std::max( cube.position.x + cube.position.w, max.x ); max.y = std::max( cube.position.y + cube.position.w, max.y ); max.z = std::max( cube.position.z + cube.position.w, max.z ); - } - tree.position.x = (max.x + min.x) * 0.5f; - tree.position.y = (max.y + min.y) * 0.5f; - tree.position.z = (max.z + min.z) * 0.5f; - - tree.position.w = std::max( tree.position.w, (max.x - min.x) * 0.5f ); - tree.position.w = std::max( tree.position.w, (max.y - min.y) * 0.5f ); - tree.position.w = std::max( tree.position.w, (max.z - min.z) * 0.5f ); - // tree.position.w = 0.5; - tree.type = pod::Primitive::LEAF; // leaves point to cubes - trees.push_back(tree); - } - return trees; -} - -// takes a list of leaves (ends of trees) and properly populate an entire tree -uf::stl::vector uf::primitive::populateEntirely( const uf::stl::vector& trees, bool rooted ) { // assert(trees.size() > 0); - // generate first layer - uf::stl::vector tree = trees; - uf::stl::vector referred; - uf::stl::vector queue; - uint32_t iteration = 0; - uint32_t start = 0; -/* - std::cout << "Primitives:\n\t"; - for ( auto& prim : primitives ) { - size_t i = &prim - &primitives[0]; - std::cout << (i < 10 ? "0" : "" ) << i << " "; - if ( (i+1) % 8 == 0 ) std::cout << "\n\t"; - } - std::cout << std::endl; -*/ -loop: { -// std::cout << "Iteration #" << ++iteration << std::endl; - referred.clear(); - // grab all unreferenced trees - for ( auto& branch : tree ) { - if ( branch.type != pod::Primitive::TREE ) continue; - referred.insert( referred.end(), &branch.children[0], &branch.children[7] ); -// std::cout << "Tree #" << (&branch - &tree[0]) << " refers to:\n"; - for ( uint i = 0; i < pod::Tree::TREE_SIZE; ++i ) { -// std::cout << "\t" << branch.children[i] << " "; - referred.push_back(branch.children[i]); - } -// std::cout << std::endl; - } - queue.clear(); - // check if referred -// std::cout << "Queueing:\n\t"; - for ( auto& branch : tree ) { - size_t i = &branch - &tree[0]; - if ( std::find( referred.begin(), referred.end(), i ) != referred.end() ) continue; -// std::cout << i << " "; - queue.push_back( &branch - &tree[0] ); - } -// std::cout << std::endl; - // grab the branches' primitives - uf::stl::vector enqueued; enqueued.reserve( queue.size() ); - for ( uint32_t i : queue ) { - pod::Tree t = tree.at(i); - pod::Primitive primitive; - primitive.position = t.position; - primitive.position.w = t.position.w; - primitive.type = i; - enqueued.push_back( primitive ); - } - // create a parent tree - uf::stl::vector newTree = populate( enqueued ); - // convert indices and type - for ( auto& branch : newTree ) { - branch.type = pod::Primitive::TREE; - branch.position.w = (iteration+1.0f) * 0.5f; - for ( size_t i = 0; i < pod::Tree::TREE_SIZE; ++i ) { - size_t index = branch.children[i]; - if ( index == pod::Primitive::EMPTY ) continue; - branch.children[i] = enqueued.at(index).type; - } - } - // copy new tree to beginning of tree list - tree.insert( tree.end(), newTree.begin(), newTree.end() ); - start = tree.size(); - // cannot divide furter - if ( newTree.size() <= 1 ) goto finished; -} - goto loop; -finished: - if ( rooted ) tree.at(tree.size()-1).type = pod::Primitive::ROOT; - -// std::cout << "Full tree:\n"; - for ( auto& branch : tree ) { -// std::cout << "\t" << (&branch - &tree[0]) << " (type: " << (branch.type) << ") has children:\n\t\t"; - for ( size_t i = 0; i < pod::Tree::TREE_SIZE; ++i ) { -// std::cout << branch.children[i] << " "; - } -// std::cout << std::endl; - } -// std::cout << std::endl; - for ( auto& branch : tree ) { -// std::cout << (&branch - &tree[0]) << " (type: " << (branch.type) << ") primitive:\n"; -// std::cout << "\tPosition: " << branch.position.x << ", " << branch.position.y << ", " << branch.position.z << "\n\tSize: " << branch.position.w << "\n\t\t"; - for ( size_t i = 0; i < pod::Tree::TREE_SIZE; ++i ) { -// std::cout << branch.children[i] << " "; - } -// std::cout << std::endl; - /* - if ( branch.type == pod::Primitive::LEAF ) { - for ( size_t i = 0; i < pod::Tree::TREE_SIZE; ++i ) { - if ( branch.children[i] == pod::Primitive::EMPTY ) continue; - auto& pr = primitives.at(branch.children[i]); -// std::cout << "\t\tPosition: " << pr.position.x << ", " << pr.position.y << ", " << pr.position.z << "\n\t\tSize: " << pr.position.w << std::endl; - } - } else { - for ( size_t i = 0; i < pod::Tree::TREE_SIZE; ++i ) { - if ( branch.children[i] == pod::Primitive::EMPTY ) continue; - auto& pr = tree.at(branch.children[i]); -// std::cout << "\t\tPosition: " << pr.position.x << ", " << pr.position.y << ", " << pr.position.z << "\n\t\tSize: " << pr.position.w << std::endl; - } - } - */ - } -// std::cout << std::endl; - - return tree; -} - - - - - - - - - - - - -//////////////////////// -namespace { - #define EPSILON 0.0001f - #define MAXLEN 1000.0f - #define SHADOW 0.5f - - #define TREE_SIZE 8 - #define TREE_STACK 8 - #define PRIMITIVE_TYPE_EMPTY UINT32_MAX - #define PRIMITIVE_TYPE_CUBE 1 - #define PRIMITIVE_TYPE_LEAF 2 - #define PRIMITIVE_TYPE_TREE 3 - #define PRIMITIVE_TYPE_ROOT 4 - struct StackIterator { - uint tree; - uint child; - }; - struct Stack { - int pointer; - StackIterator container[TREE_STACK]; - } stack; - void printStack( ) { - std::cout << "[*] Pointer @ " << stack.pointer << std::endl; - for ( int i = stack.pointer; i >= 0; --i ) { - std::cout << "[*] " << stack.container[i].tree << ", " << stack.container[i].child << std::endl; - } - std::cout << std::endl; - } - StackIterator popStack( ) { - StackIterator top = stack.container[stack.pointer]; - stack.container[stack.pointer--] = { UINT32_MAX, UINT32_MAX }; - std::cout << "[?] popped stack" << std::endl; - printStack(); - return top; - } - StackIterator topStack( ) { - StackIterator pointer = stack.container[stack.pointer]; - printStack(); - return pointer; - } - void pushStack( StackIterator item ) { - stack.container[++stack.pointer] = item; - std::cout << "[?] pushed to stack" << std::endl; - printStack(); - } - float cubeIntersect( const pod::Vector3f& rayO, const pod::Vector3f& rayD, const pod::Vector3f& rayDRecip, const pod::Primitive& cube) { - float t[10]; - t[1] = ( cube.position.x - cube.position.w - rayO.x) / rayD.x; - t[2] = ( cube.position.x + cube.position.w - rayO.x) / rayD.x; - t[3] = ( cube.position.y - cube.position.w - rayO.y) / rayD.y; - t[4] = ( cube.position.y + cube.position.w - rayO.y) / rayD.y; - t[5] = ( cube.position.z - cube.position.w - rayO.z) / rayD.z; - t[6] = ( cube.position.z + cube.position.w - rayO.z) / rayD.z; - t[7] = std::max(std::max(std::min(t[1], t[2]), std::min(t[3], t[4])), std::min(t[5], t[6])); - t[8] = std::min(std::min(std::max(t[1], t[2]), std::max(t[3], t[4])), std::max(t[5], t[6])); - t[9] = (t[8] < 0 || t[7] > t[8]) ? 0.0 : t[7]; - return t[9]; - } - float treeIntersect( const pod::Vector3f& rayO, const pod::Vector3f& rayD, const pod::Vector3f& rayDRecip, const pod::Tree& tree ) { - pod::Primitive treecube; - treecube.type = tree.type; - treecube.position = tree.position; - return cubeIntersect( rayO, rayD, rayDRecip, treecube ); - } -} - -void uf::primitive::test( const uf::stl::vector& cubes, const uf::stl::vector& trees ) { - pod::Vector3f rayO = { 0, 5, 0 }; - pod::Vector3f rayD = uf::vector::normalize( pod::Vector3f{ 0, -1, -0.25 } ); - pod::Vector3f rayDRecip = { 1.0f / rayD.x, 1.0f / rayD.y, 1.0f / rayD.z }; - float resT = MAXLEN; - uint root = trees.size() - 1; - uint id = UINT32_MAX; - if ( root == UINT32_MAX ) return; - - // set up stack - stack.pointer = -1; - for ( uint i = 0; i < TREE_STACK; ++i ) stack.container[i] = {UINT32_MAX, UINT32_MAX}; - pushStack({ root, UINT32_MAX }); - - while ( true ) { - StackIterator it = popStack(); - // end of stack - if ( it.tree == UINT32_MAX ) break; - pod::Tree tree = trees[it.tree]; - // invalid tree - if ( tree.type == PRIMITIVE_TYPE_EMPTY ) break; - // new tree, parse collision - if ( it.child == UINT32_MAX ) { - float t = treeIntersect( rayO, rayD, rayDRecip, tree ); - // bad intersection with this tree, continue with next iteration - std::cout << "[?] Collision: 0 < " << t << " < " << resT << std::endl; - if ( t <= EPSILON || t >= resT ) continue; - // push back with new stack - it.child = 0; - pushStack( it ); - // continue with next iteration - continue; - } else if ( it.child >= TREE_SIZE ) { - // no new children, continue with next iteration - continue; - } else { - // is leaf - if ( tree.type == PRIMITIVE_TYPE_LEAF ) { - // check children for a match - for ( uint i = 0; i < TREE_SIZE; ++i ) { - uint branchId = tree.children[i]; - // unallocated, skip - if ( branchId == UINT32_MAX ) continue; - pod::Primitive primitive = cubes[branchId]; - if ( primitive.type == PRIMITIVE_TYPE_EMPTY ) continue; - float t = cubeIntersect( rayO, rayD, rayDRecip, primitive ); - // branch intersects with ray, set as new parent - if ( (t <= EPSILON) || (t >= resT) ) continue; - id = branchId; - resT = t; - } - // continue with next iteration - continue; - } - // parse children - uint branchId = tree.children[it.child++]; - // add new iterator to the stack - pushStack( it ); - // unused child, continue with next iteration - if ( branchId == UINT32_MAX ) continue; - // tree branch, push to stack - // the first if block will check its collision - it.tree = branchId; - it.child = UINT32_MAX; - pushStack( it ); - continue; - } - } - std::cout << "ID: " << id << std::endl; -} -#endif \ No newline at end of file