I guess I'll try and do some work (something about trying to force inline the vector operators but failing, and ensuring the internal physics system should work for the dreamcast with its quantized meshes (maybe, it's still quite underperforming compared to RP3D), probably some other things from a week or so ago)

This commit is contained in:
ecker 2025-09-14 20:37:34 -05:00
parent 36612f9ce9
commit 8dd83f7f49
16 changed files with 425 additions and 362 deletions

View File

@ -7,8 +7,7 @@
"physics": { "physics": {
"mass": 0, "mass": 0,
"inertia": [0, 0, 0], "inertia": [0, 0, 0],
"type": "bounding box", "type": "mesh" // "bounding box"
"recenter": true
} }
} }
} }

View File

@ -8,6 +8,7 @@
"physics": { "physics": {
"mass": 0, "mass": 0,
"type": "bounding box" "type": "bounding box"
// "type": "mesh"
} }
} }
} }

View File

@ -8,10 +8,16 @@ namespace pod {
template<typename T = NUM, size_t R = 4, size_t C = R> template<typename T = NUM, size_t R = 4, size_t C = R>
struct /*UF_API*/ Matrix { struct /*UF_API*/ Matrix {
// n-dimensional/unspecialized matrix access // n-dimensional/unspecialized matrix access
T components[R*C] = {}; union {
T components[R*C] = {};
pod::Vector<T, C> _rows[R]; // to-do: better name
pod::Vector<T, R> _columns[C]; // to-do: better name
};
// POD information // POD information
typedef T type_t; typedef T type_t;
typedef T* container_t; typedef T* container_t;
typedef pod::Vector<T, R> row_t;
typedef pod::Vector<T, C> col_t;
static const size_t rows = R; static const size_t rows = R;
static const size_t columns = C; static const size_t columns = C;
// Overload access // Overload access
@ -23,12 +29,12 @@ namespace pod {
FORCE_INLINE const T& operator()(size_t r, size_t c) const; FORCE_INLINE const T& operator()(size_t r, size_t c) const;
// Arithmetic // Arithmetic
Matrix<T,R,C> operator*( const Matrix<T,R,C>& matrix ) const; FORCE_INLINE Matrix<T,R,C> operator*( const Matrix<T,R,C>& matrix ) const;
Matrix<T,R,C> operator*( T scalar ) const; FORCE_INLINE Matrix<T,R,C> operator*( T scalar ) const;
Matrix<T,R,C> operator+( const Matrix<T,R,C>& matrix ) const; FORCE_INLINE Matrix<T,R,C> operator+( const Matrix<T,R,C>& matrix ) const;
Matrix<T,R,C>& operator *=( const Matrix<T,R,C>& matrix ); FORCE_INLINE Matrix<T,R,C>& operator *=( const Matrix<T,R,C>& matrix );
bool operator==( const Matrix<T,R,C>& matrix ) const; FORCE_INLINE bool operator==( const Matrix<T,R,C>& matrix ) const;
bool operator!=( const Matrix<T,R,C>& matrix ) const; FORCE_INLINE bool operator!=( const Matrix<T,R,C>& matrix ) const;
}; };
template<typename T = NUM> using Matrix2t = Matrix<T,2>; template<typename T = NUM> using Matrix2t = Matrix<T,2>;
@ -48,66 +54,66 @@ namespace uf {
namespace matrix { namespace matrix {
extern bool UF_API reverseInfiniteProjection; extern bool UF_API reverseInfiniteProjection;
template<typename T=NUM> pod::Matrix4t<T> /*UF_API*/ identity(); template<typename T=NUM> /*FORCE_INLINE*/ pod::Matrix4t<T> /*UF_API*/ identity();
template<typename T=NUM> pod::Matrix4t<T> /*UF_API*/ initialize( const T* ); template<typename T=NUM> /*FORCE_INLINE*/ pod::Matrix4t<T> /*UF_API*/ initialize( const T* );
template<typename T=NUM> pod::Matrix4t<T> /*UF_API*/ initialize( const uf::stl::vector<T>& ); template<typename T=NUM> /*FORCE_INLINE*/ pod::Matrix4t<T> /*UF_API*/ initialize( const uf::stl::vector<T>& );
template<typename T> pod::Matrix<typename T::type_t, T::columns, T::columns> /*UF_API*/ identityi(); template<typename T> /*FORCE_INLINE*/ pod::Matrix<typename T::type_t, T::columns, T::columns> /*UF_API*/ identityi();
template<typename T=pod::Matrix4> bool /*UF_API*/ equals( const T& left, const T& right, float eps = 1.0e-6f ); template<typename T=pod::Matrix4> /*FORCE_INLINE*/ bool /*UF_API*/ equals( const T& left, const T& right, float eps = 1.0e-6f );
template<typename T, typename U> pod::Matrix<typename T::type_t, T::columns, T::columns> multiply( const T& left, const U& right ); template<typename T, typename U> /*FORCE_INLINE*/ pod::Matrix<typename T::type_t, T::columns, T::columns> multiply( const T& left, const U& right );
template<typename T> pod::Matrix4t<T> multiply( const pod::Matrix4t<T>& left, const pod::Matrix4t<T>& right ); template<typename T> /*FORCE_INLINE*/ pod::Matrix4t<T> multiply( const pod::Matrix4t<T>& left, const pod::Matrix4t<T>& right );
template<typename T=pod::Matrix4> T /*UF_API*/ transpose( const T& matrix ); template<typename T=pod::Matrix4> /*FORCE_INLINE*/ T /*UF_API*/ transpose( const T& matrix );
template<typename T=NUM> pod::Matrix2t<T> inverse(const pod::Matrix2t<T>& mat ); template<typename T=NUM> /*FORCE_INLINE*/ pod::Matrix2t<T> inverse(const pod::Matrix2t<T>& mat );
template<typename T=NUM> pod::Matrix3t<T> inverse(const pod::Matrix3t<T>& mat ); template<typename T=NUM> /*FORCE_INLINE*/ pod::Matrix3t<T> inverse(const pod::Matrix3t<T>& mat );
template<typename T=NUM> pod::Matrix4t<T> inverse(const pod::Matrix4t<T>& mat ); template<typename T=NUM> /*FORCE_INLINE*/ pod::Matrix4t<T> inverse(const pod::Matrix4t<T>& mat );
template<typename T=NUM> pod::Vector2t<T> multiply(const pod::Matrix2t<T>& mat, const pod::Vector2t<T>& v ); template<typename T=NUM> /*FORCE_INLINE*/ pod::Vector2t<T> multiply(const pod::Matrix2t<T>& mat, const pod::Vector2t<T>& v );
template<typename T=NUM> pod::Vector3t<T> multiply(const pod::Matrix3t<T>& mat, const pod::Vector3t<T>& v ); template<typename T=NUM> /*FORCE_INLINE*/ pod::Vector3t<T> multiply(const pod::Matrix3t<T>& mat, const pod::Vector3t<T>& v );
template<typename T=NUM> pod::Vector3t<T> multiply( const pod::Matrix4t<T>& mat, const pod::Vector3t<T>& vector, T w = 1, bool = false ); template<typename T=NUM> /*FORCE_INLINE*/ pod::Vector3t<T> multiply( const pod::Matrix4t<T>& mat, const pod::Vector3t<T>& vector, T w = 1, bool = false );
template<typename T=NUM> pod::Vector4t<T> multiply( const pod::Matrix4t<T>& mat, const pod::Vector4t<T>& vector, bool = false ); template<typename T=NUM> /*FORCE_INLINE*/ pod::Vector4t<T> multiply( const pod::Matrix4t<T>& mat, const pod::Vector4t<T>& vector, bool = false );
template<typename T=pod::Matrix4> T /*UF_API*/ multiplyAll( const T& matrix, typename T::type_t scalar ); template<typename T=pod::Matrix4> /*FORCE_INLINE*/ T /*UF_API*/ multiplyAll( const T& matrix, typename T::type_t scalar );
template<typename T=pod::Matrix4> T /*UF_API*/ add( const T& lhs, const T& rhs ); template<typename T=pod::Matrix4> /*FORCE_INLINE*/ T /*UF_API*/ add( const T& lhs, const T& rhs );
template<typename T=pod::Matrix4> T& /*UF_API*/ inverse_( T& matrix ); template<typename T=pod::Matrix4> /*FORCE_INLINE*/ T& /*UF_API*/ inverse_( T& matrix );
template<typename T, typename U> pod::Matrix<typename T::type_t, T::columns, T::columns> multiply_( T& left, const U& right ); template<typename T, typename U> /*FORCE_INLINE*/ pod::Matrix<typename T::type_t, T::columns, T::columns> multiply_( T& left, const U& right );
template<typename T> pod::Matrix<typename T::type_t, T::columns, T::columns> multiply_( T& left, const T& right ); template<typename T> /*FORCE_INLINE*/ pod::Matrix<typename T::type_t, T::columns, T::columns> multiply_( T& left, const T& right );
template<typename T=pod::Matrix4> T& /*UF_API*/ translate_( T& matrix, const pod::Vector3t<typename T::type_t>& vector ); template<typename T=pod::Matrix4> /*FORCE_INLINE*/ T& /*UF_API*/ translate_( T& matrix, const pod::Vector3t<typename T::type_t>& vector );
template<typename T=pod::Matrix4> T& /*UF_API*/ rotate_( T& matrix, const pod::Vector3t<typename T::type_t>& vector ); template<typename T=pod::Matrix4> /*FORCE_INLINE*/ T& /*UF_API*/ rotate_( T& matrix, const pod::Vector3t<typename T::type_t>& vector );
template<typename T=pod::Matrix4> T& /*UF_API*/ scale_( T& matrix, const pod::Vector3t<typename T::type_t>& vector ); template<typename T=pod::Matrix4> /*FORCE_INLINE*/ T& /*UF_API*/ scale_( T& matrix, const pod::Vector3t<typename T::type_t>& vector );
template<typename T=pod::Matrix4> T /*UF_API*/ translate( const T& matrix, const pod::Vector3t<typename T::type_t>& vector ); template<typename T=pod::Matrix4> /*FORCE_INLINE*/ T /*UF_API*/ translate( const T& matrix, const pod::Vector3t<typename T::type_t>& vector );
template<typename T=pod::Matrix4> T /*UF_API*/ rotate( const T& matrix, const pod::Vector3t<typename T::type_t>& vector ); template<typename T=pod::Matrix4> /*FORCE_INLINE*/ T /*UF_API*/ rotate( const T& matrix, const pod::Vector3t<typename T::type_t>& vector );
template<typename T=pod::Matrix4> T /*UF_API*/ scale( const T& matrix, const pod::Vector3t<typename T::type_t>& vector ); template<typename T=pod::Matrix4> /*FORCE_INLINE*/ T /*UF_API*/ scale( const T& matrix, const pod::Vector3t<typename T::type_t>& vector );
template<typename T=pod::Matrix4> pod::Vector3t<typename T::type_t> /*UF_API*/ eulerAngles( const T& matrix ); template<typename T=pod::Matrix4> /*FORCE_INLINE*/ pod::Vector3t<typename T::type_t> /*UF_API*/ eulerAngles( const T& matrix );
template<typename T=NUM> pod::Matrix4t<T> /*UF_API*/ orthographic( T, T, T, T, T, T ); template<typename T=NUM> /*FORCE_INLINE*/ pod::Matrix4t<T> /*UF_API*/ orthographic( T, T, T, T, T, T );
template<typename T=NUM> pod::Matrix4t<T> /*UF_API*/ orthographic( T, T, T, T ); template<typename T=NUM> /*FORCE_INLINE*/ pod::Matrix4t<T> /*UF_API*/ orthographic( T, T, T, T );
template<typename T=NUM> pod::Matrix4t<T> FORCE_INLINE /*UF_API*/ orthographic( const pod::Vector2t<T>& lr, const pod::Vector2t<T>& bt, const pod::Vector2t<T>& nf ) { template<typename T=NUM> /*FORCE_INLINE*/ pod::Matrix4t<T> /*UF_API*/ orthographic( const pod::Vector2t<T>& lr, const pod::Vector2t<T>& bt, const pod::Vector2t<T>& nf ) {
return orthographic<T>( lr.x, lr.y, bt.x, bt.y, nf.x, nf.y ); return orthographic<T>( lr.x, lr.y, bt.x, bt.y, nf.x, nf.y );
} }
template<typename T=NUM> pod::Matrix4t<T> FORCE_INLINE /*UF_API*/ orthographic( const pod::Vector2t<T>& lr, const pod::Vector2t<T>& bt ) { template<typename T=NUM> /*FORCE_INLINE*/ pod::Matrix4t<T> /*UF_API*/ orthographic( const pod::Vector2t<T>& lr, const pod::Vector2t<T>& bt ) {
return orthographic<T>( lr.x, lr.y, bt.x, bt.y ); return orthographic<T>( lr.x, lr.y, bt.x, bt.y );
} }
template<typename T=NUM> pod::Matrix4t<T> /*UF_API*/ perspective( T, T, T, T ); template<typename T=NUM> /*FORCE_INLINE*/ pod::Matrix4t<T> /*UF_API*/ perspective( T, T, T, T );
template<typename T=NUM> pod::Matrix4t<T> FORCE_INLINE /*UF_API*/ perspective( T fov, T raidou, const pod::Vector2f& range ) { template<typename T=NUM> /*FORCE_INLINE*/ pod::Matrix4t<T> /*UF_API*/ perspective( T fov, T raidou, const pod::Vector2f& range ) {
return perspective( fov, raidou, range.x, range.y ); return perspective( fov, raidou, range.x, range.y );
} }
template<typename T=NUM> pod::Matrix4t<T> FORCE_INLINE /*UF_API*/ perspective( T fov, const pod::Vector2ui& size, const pod::Vector2f& range ) { template<typename T=NUM> /*FORCE_INLINE*/ pod::Matrix4t<T> /*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 ); return perspective( fov, (T) size.x / (T) size.y, range.x, range.y );
} }
// Setting // Setting
template<typename T=pod::Matrix4> T& /*UF_API*/ copy( T& destination, const T& source ); template<typename T=pod::Matrix4> /*FORCE_INLINE*/ T& /*UF_API*/ copy( T& destination, const T& source );
template<typename T=pod::Matrix4> T& /*UF_API*/ copy( T& destination, typename T::type_t* const source ); template<typename T=pod::Matrix4> /*FORCE_INLINE*/ T& /*UF_API*/ copy( T& destination, typename T::type_t* const source );
template<typename T, size_t R, size_t C = R> uf::stl::string /*UF_API*/ toString( const pod::Matrix<T,R,C>& v ); template<typename T, size_t R, size_t C = R> /*FORCE_INLINE*/ uf::stl::string /*UF_API*/ toString( const pod::Matrix<T,R,C>& v );
template<typename T, size_t R, size_t C> ext::json::Value /*UF_API*/ encode( const pod::Matrix<T,R,C>& v, const ext::json::EncodingSettings& = {} ); template<typename T, size_t R, size_t C> /*FORCE_INLINE*/ ext::json::Value /*UF_API*/ encode( const pod::Matrix<T,R,C>& v, const ext::json::EncodingSettings& = {} );
template<typename T, size_t R, size_t C> pod::Matrix<T,R,C>& /*UF_API*/ decode( const ext::json::Value& v, pod::Matrix<T,R,C>& ); template<typename T, size_t R, size_t C> /*FORCE_INLINE*/ pod::Matrix<T,R,C>& /*UF_API*/ decode( const ext::json::Value& v, pod::Matrix<T,R,C>& );
template<typename T, size_t R, size_t C> pod::Matrix<T,R,C> /*UF_API*/ decode( const ext::json::Value& v, const pod::Matrix<T,R,C>& = uf::matrix::identity() ); template<typename T, size_t R, size_t C> /*FORCE_INLINE*/ pod::Matrix<T,R,C> /*UF_API*/ decode( const ext::json::Value& v, const pod::Matrix<T,R,C>& = uf::matrix::identity() );
} }
} }
@ -115,14 +121,14 @@ namespace uf {
namespace uf { namespace uf {
namespace string { namespace string {
template<typename T, size_t R, size_t C> template<typename T, size_t R, size_t C>
uf::stl::string /*UF_API*/ toString( const pod::Matrix<T,R,C>& v ); FORCE_INLINE uf::stl::string /*UF_API*/ toString( const pod::Matrix<T,R,C>& v );
} }
} }
namespace ext { namespace ext {
namespace json { namespace json {
template<typename T, size_t R, size_t C = R> ext::json::Value /*UF_API*/ encode( const pod::Matrix<T,R,C>& v ); template<typename T, size_t R, size_t C = R> FORCE_INLINE ext::json::Value /*UF_API*/ encode( const pod::Matrix<T,R,C>& v );
template<typename T, size_t R, size_t C = R> pod::Matrix<T,R,C>& /*UF_API*/ decode( const ext::json::Value& v, pod::Matrix<T,R,C>& ); template<typename T, size_t R, size_t C = R> FORCE_INLINE pod::Matrix<T,R,C>& /*UF_API*/ decode( const ext::json::Value& v, pod::Matrix<T,R,C>& );
template<typename T, size_t R, size_t C = R> pod::Matrix<T,R,C> /*UF_API*/ decode( const ext::json::Value& v, const pod::Matrix<T,R,C>& = uf::matrix::identity() ); template<typename T, size_t R, size_t C = R> FORCE_INLINE pod::Matrix<T,R,C> /*UF_API*/ decode( const ext::json::Value& v, const pod::Matrix<T,R,C>& = uf::matrix::identity() );
} }
} }

View File

@ -19,45 +19,45 @@ namespace pod {
namespace uf { namespace uf {
namespace quaternion { namespace quaternion {
template<typename T = NUM> pod::Quaternion<T> /*UF_API*/ identity(); template<typename T = NUM> /*FORCE_INLINE*/ pod::Quaternion<T> /*UF_API*/ identity();
template<typename T> T /*UF_API*/ multiply( const T& left, const T& right ); template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ multiply( const T& left, const T& right );
template<typename T> pod::Vector3t<T> /*UF_API*/ rotate( const pod::Quaternion<T>& left, const pod::Vector3t<T>& right ); template<typename T> /*FORCE_INLINE*/ pod::Vector3t<T> /*UF_API*/ rotate( const pod::Quaternion<T>& left, const pod::Vector3t<T>& right );
template<typename T> pod::Vector4t<T> /*UF_API*/ rotate( const pod::Quaternion<T>& left, const pod::Vector4t<T>& right ); template<typename T> /*FORCE_INLINE*/ pod::Vector4t<T> /*UF_API*/ rotate( const pod::Quaternion<T>& left, const pod::Vector4t<T>& right );
template<typename T> typename T::type_t /*UF_API*/ sum( const T& vector ); template<typename T> /*FORCE_INLINE*/ typename T::type_t /*UF_API*/ sum( const T& vector );
template<typename T> typename T::type_t /*UF_API*/ product( const T& vector ); template<typename T> /*FORCE_INLINE*/ typename T::type_t /*UF_API*/ product( const T& vector );
template<typename T> typename T::type_t /*UF_API*/ dot( const T& left, const T& right ); template<typename T> /*FORCE_INLINE*/ typename T::type_t /*UF_API*/ dot( const T& left, const T& right );
template<typename T> pod::Angle /*UF_API*/ angle( const T& a, const T& b ); template<typename T> /*FORCE_INLINE*/ pod::Angle /*UF_API*/ angle( const T& a, const T& b );
template<typename T> T /*UF_API*/ lerp( const T& from, const T& to, typename T::type_t delta ); template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ lerp( const T& from, const T& to, typename T::type_t delta );
template<typename T> T /*UF_API*/ slerp( const T& from, const T& to, typename T::type_t delta ); template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ slerp( const T& from, const T& to, typename T::type_t delta );
template<typename T> typename T::type_t /*UF_API*/ distanceSquared( const T& a, const T& b ); template<typename T> /*FORCE_INLINE*/ typename T::type_t /*UF_API*/ distanceSquared( const T& a, const T& b );
template<typename T> typename T::type_t /*UF_API*/ distance( const T& a, const T& b ); template<typename T> /*FORCE_INLINE*/ typename T::type_t /*UF_API*/ distance( const T& a, const T& b );
template<typename T> typename T::type_t /*UF_API*/ magnitude( const T& vector ); template<typename T> /*FORCE_INLINE*/ typename T::type_t /*UF_API*/ magnitude( const T& vector );
template<typename T> typename T::type_t /*UF_API*/ norm( const T& vector ); template<typename T> /*FORCE_INLINE*/ typename T::type_t /*UF_API*/ norm( const T& vector );
template<typename T> T /*UF_API*/ normalize( const T& vector ); template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ normalize( const T& vector );
template<typename T> pod::Matrix4t<T> matrix( const pod::Quaternion<T>& quaternion ); template<typename T> /*FORCE_INLINE*/ pod::Matrix4t<T> matrix( const pod::Quaternion<T>& quaternion );
template<typename T> pod::Quaternion<T> axisAngle( const pod::Vector3t<T>& axis, T angle ); template<typename T> /*FORCE_INLINE*/ pod::Quaternion<T> axisAngle( const pod::Vector3t<T>& axis, T angle );
template<typename T> pod::Quaternion<T> unitVectors( const pod::Vector3t<T>& u, const pod::Vector3t<T>& v ); template<typename T> /*FORCE_INLINE*/ pod::Quaternion<T> unitVectors( const pod::Vector3t<T>& u, const pod::Vector3t<T>& v );
template<typename T> pod::Quaternion<T> lookAt( const pod::Vector3t<T>& source, const pod::Vector3t<T>& destination ); template<typename T> /*FORCE_INLINE*/ pod::Quaternion<T> lookAt( const pod::Vector3t<T>& source, const pod::Vector3t<T>& destination );
template<typename T> T conjugate( const T& quaternion ); template<typename T> /*FORCE_INLINE*/ T conjugate( const T& quaternion );
template<typename T> T inverse( const T& quaternion ); template<typename T> /*FORCE_INLINE*/ T inverse( const T& quaternion );
template<typename T> T& /*UF_API*/ multiply_( T& left, const T& right ); template<typename T> /*FORCE_INLINE*/ T& /*UF_API*/ multiply_( T& left, const T& right );
template<typename T> T& /*UF_API*/ normalize_( T& vector ); template<typename T> /*FORCE_INLINE*/ T& /*UF_API*/ normalize_( T& vector );
template<typename T> T& conjugate_( T& quaternion ); template<typename T> /*FORCE_INLINE*/ T& conjugate_( T& quaternion );
template<typename T> T& inverse_( T& quaternion ); template<typename T> /*FORCE_INLINE*/ T& inverse_( T& quaternion );
template<typename T> pod::Vector3t<T> eulerAngles( const pod::Quaternion<T>& quaternion ); template<typename T> /*FORCE_INLINE*/ pod::Vector3t<T> eulerAngles( const pod::Quaternion<T>& quaternion );
template<typename T> T pitch( const pod::Quaternion<T>& quaternion ); template<typename T> /*FORCE_INLINE*/ T pitch( const pod::Quaternion<T>& quaternion );
template<typename T> T yaw( const pod::Quaternion<T>& quaternion ); template<typename T> /*FORCE_INLINE*/ T yaw( const pod::Quaternion<T>& quaternion );
template<typename T> T roll( const pod::Quaternion<T>& quaternion ); template<typename T> /*FORCE_INLINE*/ T roll( const pod::Quaternion<T>& quaternion );
template<typename T> pod::Quaternion<T> fromMatrix( const pod::Matrix4t<T>& matrix ); template<typename T> /*FORCE_INLINE*/ pod::Quaternion<T> fromMatrix( const pod::Matrix4t<T>& matrix );
} }
} }

View File

@ -80,88 +80,89 @@ namespace pod {
// POD vector accessing/manipulation // POD vector accessing/manipulation
namespace uf { namespace uf {
namespace vector { namespace vector {
template<typename T> pod::Vector1t<T> /*UF_API*/ create( T x ); // creates a 1D vector template<typename T> /*FORCE_INLINE*/ pod::Vector1t<T> /*UF_API*/ create( T x ); // creates a 1D vector
template<typename T> pod::Vector2t<T> /*UF_API*/ create( T x, T y ); // creates a 2D vector template<typename T> /*FORCE_INLINE*/ pod::Vector2t<T> /*UF_API*/ create( T x, T y ); // creates a 2D vector
template<typename T> pod::Vector3t<T> /*UF_API*/ create( T x, T y, T z ); // creates a 3D vector template<typename T> /*FORCE_INLINE*/ pod::Vector3t<T> /*UF_API*/ create( T x, T y, T z ); // creates a 3D vector
template<typename T> pod::Vector4t<T> /*UF_API*/ create( T x, T y, T z, T w ); // creates a 4D vector template<typename T> /*FORCE_INLINE*/ pod::Vector4t<T> /*UF_API*/ create( T x, T y, T z, T w ); // creates a 4D vector
template<typename T, size_t N> pod::Vector<T, N> /*UF_API*/ copy( const pod::Vector<T, N>& = {}); // creates a copy of a vector (for whatever reason) template<typename T, size_t N> /*FORCE_INLINE*/ pod::Vector<T, N> /*UF_API*/ copy( const pod::Vector<T, N>& = {}); // creates a copy of a vector (for whatever reason)
template<typename T, size_t N, typename U> pod::Vector<T, N> /*UF_API*/ cast( const U& from ); // casts one vector of one type to another (of the same size) template<typename T, size_t N, typename U> /*FORCE_INLINE*/ pod::Vector<T, N> /*UF_API*/ cast( const U& from ); // casts one vector of one type to another (of the same size)
// Equality checking // Equality checking
template<typename T> bool /*UF_API*/ equals( const T& left, const T& right ); // equality check between two vectors (==) template<typename T> /*FORCE_INLINE*/ bool /*UF_API*/ equals( const T& left, const T& right ); // equality check between two vectors (==)
template<typename T> bool /*UF_API*/ notEquals( const T& left, const T& right ); // equality check between two vectors (==) template<typename T> /*FORCE_INLINE*/ bool /*UF_API*/ notEquals( const T& left, const T& right ); // equality check between two vectors (==)
template<typename T> bool /*UF_API*/ less( const T& left, const T& right ); // equality check between two vectors (<) template<typename T> /*FORCE_INLINE*/ bool /*UF_API*/ less( const T& left, const T& right ); // equality check between two vectors (<)
template<typename T> bool /*UF_API*/ lessEquals( const T& left, const T& right ); // equality check between two vectors (<=) template<typename T> /*FORCE_INLINE*/ bool /*UF_API*/ lessEquals( const T& left, const T& right ); // equality check between two vectors (<=)
template<typename T> bool /*UF_API*/ greater( const T& left, const T& right ); // equality check between two vectors (>) template<typename T> /*FORCE_INLINE*/ bool /*UF_API*/ greater( const T& left, const T& right ); // equality check between two vectors (>)
template<typename T> bool /*UF_API*/ greaterEquals( const T& left, const T& right ); // equality check between two vectors (>=) template<typename T> /*FORCE_INLINE*/ bool /*UF_API*/ greaterEquals( const T& left, const T& right ); // equality check between two vectors (>=)
template<typename T> bool /*UF_API*/ isValid( const T& v ); // checks if all components are valid (non NaN, inf, etc.) template<typename T> /*FORCE_INLINE*/ bool /*UF_API*/ isValid( const T& v ); // checks if all components are valid (non NaN, inf, etc.)
// Basic arithmetic // Basic arithmetic
template<typename T> T /*UF_API*/ add( const T& left, const T& right ); // adds two vectors of same type and size together template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ add( const T& left, const T& right ); // adds two vectors of same type and size together
template<typename T> T /*UF_API*/ add( const T& left, typename T::type_t scalar ); // adds a scalar to every component of the vector template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ add( const T& left, typename T::type_t scalar ); // adds a scalar to every component of the vector
template<typename T> T /*UF_API*/ add( typename T::type_t scalar, const T& vector ); // adds a scalar to every component of the vector (inverted) template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ add( typename T::type_t scalar, const T& vector ); // adds a scalar to every component of the vector (inverted)
template<typename T> T /*UF_API*/ subtract( const T& left, const T& right ); // subtracts two vectors of same type and size together template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ subtract( const T& left, const T& right ); // subtracts two vectors of same type and size together
template<typename T> T /*UF_API*/ subtract( const T& left, typename T::type_t scalar ); // subtracts a scalar to every component of the vector template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ subtract( const T& left, typename T::type_t scalar ); // subtracts a scalar to every component of the vector
template<typename T> T /*UF_API*/ subtract( typename T::type_t scalar, const T& vector ); // subtracts a scalar to every component of the vector (inverted) template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ subtract( typename T::type_t scalar, const T& vector ); // subtracts a scalar to every component of the vector (inverted)
template<typename T> T /*UF_API*/ multiply( const T& left, const T& right ); // multiplies two vectors of same type and size together template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ multiply( const T& left, const T& right ); // multiplies two vectors of same type and size together
template<typename T> T /*UF_API*/ multiply( const T& vector, typename T::type_t scalar ); // multiplies a scalar to every component of the vector template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ multiply( const T& vector, typename T::type_t scalar ); // multiplies a scalar to every component of the vector
template<typename T> T /*UF_API*/ multiply( typename T::type_t scalar, const T& vector ); // multiplies a scalar to every component of the vector (inverted) template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ multiply( typename T::type_t scalar, const T& vector ); // multiplies a scalar to every component of the vector (inverted)
template<typename T> T /*UF_API*/ divide( const T& left, const T& right ); // divides two vectors of same type and size together template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ divide( const T& left, const T& right ); // divides two vectors of same type and size together
template<typename T> T /*UF_API*/ divide( const T& left, typename T::type_t scalar ); // divides a scalar to every component of the vector template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ divide( const T& left, typename T::type_t scalar ); // divides a scalar to every component of the vector
template<typename T> T /*UF_API*/ divide( typename T::type_t scalar, const T& vector ); // divides a scalar to every component of the vector (inverted) template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ divide( typename T::type_t scalar, const T& vector ); // divides a scalar to every component of the vector (inverted)
template<typename T> T& /*UF_API*/ add_( T& left, const T& right ); // adds two vectors of same type and size together template<typename T> /*FORCE_INLINE*/ T& /*UF_API*/ add_( T& left, const T& right ); // adds two vectors of same type and size together
template<typename T> T& /*UF_API*/ add_( T& left, typename T::type_t scalar ); // adds a scalar to every component of the vector template<typename T> /*FORCE_INLINE*/ T& /*UF_API*/ add_( T& left, typename T::type_t scalar ); // adds a scalar to every component of the vector
template<typename T> T& /*UF_API*/ add_( typename T::type_t scalar, T& vector ); // adds a scalar to every component of the vector (inverted) template<typename T> /*FORCE_INLINE*/ T& /*UF_API*/ add_( typename T::type_t scalar, T& vector ); // adds a scalar to every component of the vector (inverted)
template<typename T> T& /*UF_API*/ subtract_( T& left, const T& right ); // subtracts two vectors of same type and size together template<typename T> /*FORCE_INLINE*/ T& /*UF_API*/ subtract_( T& left, const T& right ); // subtracts two vectors of same type and size together
template<typename T> T& /*UF_API*/ subtract_( T& left, typename T::type_t scalar ); // subtracts a scalar to every component of the vector template<typename T> /*FORCE_INLINE*/ T& /*UF_API*/ subtract_( T& left, typename T::type_t scalar ); // subtracts a scalar to every component of the vector
template<typename T> T& /*UF_API*/ subtract_( typename T::type_t scalar, T& vector ); // subtracts a scalar to every component of the vector (inverted) template<typename T> /*FORCE_INLINE*/ T& /*UF_API*/ subtract_( typename T::type_t scalar, T& vector ); // subtracts a scalar to every component of the vector (inverted)
template<typename T> T& /*UF_API*/ multiply_( T& left, const T& right ); // multiplies two vectors of same type and size together template<typename T> /*FORCE_INLINE*/ T& /*UF_API*/ multiply_( T& left, const T& right ); // multiplies two vectors of same type and size together
template<typename T> T& /*UF_API*/ multiply_( T& vector, typename T::type_t scalar ); // multiplies a scalar to every component of the vector template<typename T> /*FORCE_INLINE*/ T& /*UF_API*/ multiply_( T& vector, typename T::type_t scalar ); // multiplies a scalar to every component of the vector
template<typename T> T& /*UF_API*/ multiply_( typename T::type_t scalar, T& vector ); // multiplies a scalar to every component of the vector (inverted) template<typename T> /*FORCE_INLINE*/ T& /*UF_API*/ multiply_( typename T::type_t scalar, T& vector ); // multiplies a scalar to every component of the vector (inverted)
template<typename T> T& /*UF_API*/ divide_( T& left, const T& right ); // divides two vectors of same type and size together template<typename T> /*FORCE_INLINE*/ T& /*UF_API*/ divide_( T& left, const T& right ); // divides two vectors of same type and size together
template<typename T> T& /*UF_API*/ divide_( T& left, typename T::type_t scalar ); // divides a scalar to every component of the vector template<typename T> /*FORCE_INLINE*/ T& /*UF_API*/ divide_( T& left, typename T::type_t scalar ); // divides a scalar to every component of the vector
template<typename T> T& /*UF_API*/ divide_( typename T::type_t scalar, T& vector ); // divides a scalar to every component of the vector (inverted) template<typename T> /*FORCE_INLINE*/ T& /*UF_API*/ divide_( typename T::type_t scalar, T& vector ); // divides a scalar to every component of the vector (inverted)
template<typename T> T& /*UF_API*/ negate_( T& vector ); // flip sign of all components template<typename T> /*FORCE_INLINE*/ T& /*UF_API*/ negate_( T& vector ); // flip sign of all components
template<typename T> T& /*UF_API*/ normalize_( T& vector ); // normalizes a vector template<typename T> /*FORCE_INLINE*/ T& /*UF_API*/ normalize_( T& vector ); // normalizes a vector
template<typename T> typename T::type_t /*UF_API*/ sum( const T& vector ); // compute the sum of all components template<typename T> /*FORCE_INLINE*/ typename T::type_t /*UF_API*/ sum( const T& vector ); // compute the sum of all components
template<typename T> typename T::type_t /*UF_API*/ product( const T& vector ); // compute the product of all components template<typename T> /*FORCE_INLINE*/ typename T::type_t /*UF_API*/ product( const T& vector ); // compute the product of all components
template<typename T> T /*UF_API*/ negate( const T& vector ); // flip sign of all components template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ negate( const T& vector ); // flip sign of all components
template<typename T> T /*UF_API*/ abs( const T& vector ); // gets the absolute value of a vector template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ abs( const T& vector ); // gets the absolute value of a vector
template<typename T> T /*UF_API*/ min( const T& left, const T& right ); // returns the minimum of each component between two vectors template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ min( const T& left, const T& right ); // returns the minimum of each component between two vectors
template<typename T> T /*UF_API*/ max( const T& left, const T& right ); // returns the maximum of each component between two vectors template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ max( const T& left, const T& right ); // returns the maximum of each component between two vectors
template<typename T> T /*UF_API*/ clamp( const T& vector, const T& min, const T& max ); // clamps a vector between two bounds template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ clamp( const T& vector, const T& min, const T& max ); // clamps a vector between two bounds
template<typename T> T /*UF_API*/ ceil( const T& vector ); // rounds each component of the the vector up template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ ceil( const T& vector ); // rounds each component of the the vector up
template<typename T> T /*UF_API*/ floor( const T& vector ); // rounds each component of the vector down template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ floor( const T& vector ); // rounds each component of the vector down
template<typename T> T /*UF_API*/ round( const T& vector ); // rounds each component of the vector template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ round( const T& vector ); // rounds each component of the vector
// Complex arithmetic // Complex arithmetic
template<typename T> typename T::type_t /*UF_API*/ dot( const T& left, const T& right ); // compute the dot product between two vectors template<typename T> /*FORCE_INLINE*/ typename T::type_t /*UF_API*/ dot( const T& left, const T& right ); // compute the dot product between two vectors
template<typename T> float /*UF_API*/ angle( const T& a, const T& b ); // compute the angle between two vectors template<typename T> /*FORCE_INLINE*/ float /*UF_API*/ angle( const T& a, const T& b ); // compute the angle between two vectors
template<typename T> float /*UF_API*/ signedAngle( const T& a, const T& b, const T& axis ); // compute the signed angle between two vectors template<typename T> /*FORCE_INLINE*/ float /*UF_API*/ signedAngle( const T& a, const T& b, const T& axis ); // compute the signed angle between two vectors
template<typename T> T /*UF_API*/ cross( const T& a, const T& b ); // compute the cross product between two vectors template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ cross( const T& a, const T& b ); // compute the cross product between two vectors
template<typename T> T /*UF_API*/ lerp( const T& from, const T& to, double, bool = true ); // linearly interpolate between two vectors template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ lerp( const T& from, const T& to, double, bool = true ); // linearly interpolate between two vectors
template<typename T> T /*UF_API*/ lerp( const T& from, const T& to, const T&, bool = true ); // linearly interpolate between two vectors, component-wise template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ lerp( const T& from, const T& to, const T&, bool = true ); // linearly interpolate between two vectors, component-wise
template<typename T> T /*UF_API*/ slerp( const T& from, const T& to, double, bool = false ); // spherically interpolate between two vectors template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ slerp( const T& from, const T& to, double, bool = false ); // spherically interpolate between two vectors
template<typename T> T /*UF_API*/ mix( const T& from, const T& to, double, bool = false ); template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ mix( const T& from, const T& to, double, bool = false );
template<typename T> 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> /*FORCE_INLINE*/ 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> typename T::type_t /*UF_API*/ distance( const T& a, const T& b ); // compute the distance between two vectors template<typename T> /*FORCE_INLINE*/ typename T::type_t /*UF_API*/ distance( const T& a, const T& b ); // compute the distance between two vectors
template<typename T> typename T::type_t /*UF_API*/ magnitude( const T& vector ); // gets the magnitude of the vector template<typename T> /*FORCE_INLINE*/ typename T::type_t /*UF_API*/ magnitude( const T& vector ); // gets the magnitude of the vector
template<typename T> typename T::type_t /*UF_API*/ norm( const T& vector ); // compute the norm (length) of the vector template<typename T> /*FORCE_INLINE*/ typename T::type_t /*UF_API*/ norm( const T& vector ); // compute the norm (length) of the vector
template<typename T> T /*UF_API*/ normalize( const T& vector ); // normalizes a vector template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ normalize( const T& vector ); // normalizes a vector
template<typename T> T /*UF_API*/ clampMagnitude( const T& vector ); // clamps the magnitude of a vector template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ clampMagnitude( const T& vector ); // clamps the magnitude of a vector
template<typename T> void /*UF_API*/ orthonormalize( T& x, T& y ); // orthonormalizes a vector against another vector template<typename T> /*FORCE_INLINE*/ void /*UF_API*/ orthonormalize( T& x, T& y ); // orthonormalizes a vector against another vector
template<typename T> T /*UF_API*/ orthonormalize( const T& x, const T& y ); // orthonormalizes a vector against another vector template<typename T> /*FORCE_INLINE*/ T /*UF_API*/ orthonormalize( const T& x, const T& y ); // orthonormalizes a vector against another vector
template<typename T> uf::stl::string /*UF_API*/ toString( const T& vector ); // parses a vector as a string template<typename T> /*FORCE_INLINE*/ size_t /*UF_API*/ hash( const T& vector ); // hashes a vector
template<typename T, size_t N> ext::json::Value encode( const pod::Vector<T,N>& v, const ext::json::EncodingSettings& = {} ); // parses a vector into a JSON value template<typename T> /*FORCE_INLINE*/ uf::stl::string /*UF_API*/ toString( const T& vector ); // parses a vector as a string
template<typename T, size_t N> /*FORCE_INLINE*/ ext::json::Value encode( const pod::Vector<T,N>& v, const ext::json::EncodingSettings& = {} ); // parses a vector into a JSON value
template<typename T, size_t N> pod::Vector<T,N>& decode( const ext::json::Value& v, pod::Vector<T,N>& ); // parses a JSON value into a vector template<typename T, size_t N> /*FORCE_INLINE*/ pod::Vector<T,N>& decode( const ext::json::Value& v, pod::Vector<T,N>& ); // parses a JSON value into a vector
template<typename T, size_t N> pod::Vector<T,N> decode( const ext::json::Value& v, const pod::Vector<T,N>& = {} ); // parses a JSON value into a vector template<typename T, size_t N> /*FORCE_INLINE*/ pod::Vector<T,N> decode( const ext::json::Value& v, const pod::Vector<T,N>& = {} ); // parses a JSON value into a vector
template<typename T> typename T::type_t /*UF_API*/ mips( const T& size ); // calculate amount of mips to use given a size template<typename T> /*FORCE_INLINE*/ typename T::type_t /*UF_API*/ mips( const T& size ); // calculate amount of mips to use given a size
} }
} }
@ -197,6 +198,12 @@ namespace uf {
FORCE_INLINE explicit operator bool() const { return uf::vector::notEquals(*this, Vector<T,N>{}); } \ FORCE_INLINE explicit operator bool() const { return uf::vector::notEquals(*this, Vector<T,N>{}); } \
template<typename U, size_t M> FORCE_INLINE operator Vector<U,M>() const { return uf::vector::cast<U,M>(*this); } template<typename U, size_t M> FORCE_INLINE operator Vector<U,M>() const { return uf::vector::cast<U,M>(*this); }
#define DEFINE_VECTOR_EXT(T, N) \
template<typename T> FORCE_INLINE pod::Vector<T,N> operator+( T scalar, const pod::Vector<T,N>& v ) { return uf::vector::add(scalar, v); }\
template<typename T> FORCE_INLINE pod::Vector<T,N> operator-( T scalar, const pod::Vector<T,N>& v ) { return uf::vector::subtract(scalar, v); }\
template<typename T> FORCE_INLINE pod::Vector<T,N> operator*( T scalar, const pod::Vector<T,N>& v ) { return uf::vector::multiply(scalar, v); }\
template<typename T> FORCE_INLINE pod::Vector<T,N> operator/( T scalar, const pod::Vector<T,N>& v ) { return uf::vector::divide(scalar, v); }\
namespace pod { namespace pod {
template<typename T, size_t N> template<typename T, size_t N>
struct Vector { struct Vector {
@ -238,30 +245,35 @@ namespace pod {
// external functions // external functions
//#include <uf/utils/string/ext.h> // scalar operator vector
#include <sstream> template<typename T, size_t N> FORCE_INLINE pod::Vector<T,N> operator+( T scalar, const pod::Vector<T,N>& v ) { return uf::vector::add(scalar, v); }
template<typename T, size_t N> FORCE_INLINE pod::Vector<T,N> operator-( T scalar, const pod::Vector<T,N>& v ) { return uf::vector::subtract(scalar, v); }
template<typename T, size_t N> FORCE_INLINE pod::Vector<T,N> operator*( T scalar, const pod::Vector<T,N>& v ) { return uf::vector::multiply(scalar, v); }
template<typename T, size_t N> FORCE_INLINE pod::Vector<T,N> operator/( T scalar, const pod::Vector<T,N>& v ) { return uf::vector::divide(scalar, v); }
DEFINE_VECTOR_EXT(T, 2);
DEFINE_VECTOR_EXT(T, 3);
DEFINE_VECTOR_EXT(T, 4);
// stringify
namespace uf { namespace uf {
namespace string { namespace string {
template<typename T, size_t N> template<typename T, size_t N> FORCE_INLINE uf::stl::string toString( const pod::Vector<T,N>& v );
uf::stl::string toString( const pod::Vector<T,N>& v );
} }
} }
// jsonify
namespace ext { namespace ext {
namespace json { namespace json {
template<typename T, size_t N> ext::json::Value encode( const pod::Vector<T,N>& v ); template<typename T, size_t N> FORCE_INLINE ext::json::Value encode( const pod::Vector<T,N>& v );
template<typename T, size_t N> pod::Vector<T,N>& decode( const ext::json::Value&, pod::Vector<T,N>& ); template<typename T, size_t N> FORCE_INLINE pod::Vector<T,N>& decode( const ext::json::Value&, pod::Vector<T,N>& );
template<typename T, size_t N> pod::Vector<T,N> decode( const ext::json::Value&, const pod::Vector<T,N>& = {} ); template<typename T, size_t N> FORCE_INLINE pod::Vector<T,N> decode( const ext::json::Value&, const pod::Vector<T,N>& = {} );
} }
} }
// hash
namespace std { namespace std {
template<typename T, size_t N> template<typename T, size_t N>
struct hash<pod::Vector<T,N>> { struct hash<pod::Vector<T,N>> {
size_t operator()(const pod::Vector<T,N>& v) const { FORCE_INLINE size_t operator()(const pod::Vector<T,N>& v) const;
size_t hash = 0;
for ( size_t i = 0; i < N; ++i ) hash ^= v[i];
return hash;
}
}; };
} }

View File

@ -276,9 +276,9 @@ T uf::vector::divide( const T& vector, typename T::type_t scalar ) {
} }
#endif #endif
T res; T res;
scalar = static_cast<typename T::type_t>(1) / scalar; float recip = static_cast<typename T::type_t>(1) / scalar;
FOR_EACH(T::size, { FOR_EACH(T::size, {
res[i] = vector[i] * scalar; res[i] = vector[i] * recip;
}); });
return res; return res;
} }
@ -298,9 +298,9 @@ T uf::vector::divide( typename T::type_t scalar, const T& vector ) {
} }
#endif #endif
T res; T res;
scalar = static_cast<T>(1) / scalar; float recip = static_cast<typename T::type_t>(1) / scalar;
FOR_EACH(T::size, { FOR_EACH(T::size, {
res[i] = scalar / vector[i]; res[i] = vector[i] * recip;
}); });
return res; return res;
} }
@ -740,6 +740,15 @@ typename T::type_t uf::vector::mips( const T& size ) {
return static_cast<uint32_t>(std::floor(std::log2(max))) + 1; return static_cast<uint32_t>(std::floor(std::log2(max))) + 1;
} }
template<typename T>
size_t uf::vector::hash( const T& v ) {
size_t hash = 0;
FOR_EACH(T::size, {
hash ^= v[i];
});
return hash;
}
template<typename T> template<typename T>
uf::stl::string uf::vector::toString( const T& v ) { uf::stl::string uf::vector::toString( const T& v ) {
uf::stl::stringstream ss; uf::stl::stringstream ss;

View File

@ -18,3 +18,8 @@ template<typename T, size_t N>
pod::Vector<T,N> /*UF_API*/ ext::json::decode( const ext::json::Value& json, const pod::Vector<T,N>& v ) { pod::Vector<T,N> /*UF_API*/ ext::json::decode( const ext::json::Value& json, const pod::Vector<T,N>& v ) {
return uf::vector::decode<T,N>(json, v); return uf::vector::decode<T,N>(json, v);
} }
template<typename T, size_t N>
size_t std::hash<pod::Vector<T,N>>::operator()( const pod::Vector<T,N>& v ) const {
return uf::vector::hash( v );
}

View File

@ -191,15 +191,10 @@ namespace uf {
return null; return null;
} }
}; };
/*
struct Bounds {
pod::Vector3f min = { std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
pod::Vector3f max = { -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max() };
} bounds;
*/
uf::stl::vector<buffer_t> buffers; uf::stl::vector<buffer_t> buffers;
// crunge, but it's better this way // crunge, but it's better this way for streaming in mesh data
uf::stl::vector<uf::stl::string> buffer_paths; uf::stl::vector<uf::stl::string> buffer_paths;
protected: protected:
void _destroy( uf::Mesh::Input& input ); void _destroy( uf::Mesh::Input& input );

View File

@ -1,24 +1,74 @@
namespace { namespace {
inline bool aabbOverlap( const pod::AABB& a, const pod::AABB& b, float eps ) { FORCE_INLINE bool aabbOverlap( const pod::AABB& a, const pod::AABB& b, float eps ) {
#if UF_USE_SIMD
return uf::simd::all( uf::simd::lessEquals( a.min, b.max ) ) && uf::simd::all( uf::simd::greaterEquals( a.max, b.min ) );
#else
return ( a.min - eps ) <= ( b.max + eps ) && ( a.max + eps ) >= ( b.min - eps ); return ( a.min - eps ) <= ( b.max + eps ) && ( a.max + eps ) >= ( b.min - eps );
#endif
} }
inline float aabbSurfaceArea(const pod::AABB& aabb) { FORCE_INLINE float aabbSurfaceArea(const pod::AABB& aabb) {
auto d = uf::vector::max( ( aabb.max - aabb.min ), pod::Vector3f{} ); auto d = uf::vector::max( ( aabb.max - aabb.min ), pod::Vector3f{} );
return 2.0f * (d.x * d.y + d.y * d.z + d.z * d.x); return 2.0f * (d.x * d.y + d.y * d.z + d.z * d.x);
} }
pod::AABB computeSegmentAABB( const pod::Vector3f& p1, const pod::Vector3f p2, float r ) { FORCE_INLINE pod::AABB computeSegmentAABB( const pod::Vector3f& p1, const pod::Vector3f p2, float r ) {
return { return {
uf::vector::min( p1, p2 ) - r, uf::vector::min( p1, p2 ) - r,
uf::vector::max( p1, p2 ) + r, uf::vector::max( p1, p2 ) + r,
}; };
} }
pod::Vector3f closestPointOnAABB(const pod::Vector3f& p, const pod::AABB& box) { FORCE_INLINE pod::Vector3f closestPointOnAABB(const pod::Vector3f& p, const pod::AABB& box) {
return uf::vector::clamp( p, box.min, box.max ); return uf::vector::clamp( p, box.min, box.max );
} }
FORCE_INLINE pod::AABB computeTriangleAABB( const pod::Triangle& tri ) {
return {
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] ),
};
}
FORCE_INLINE pod::AABB mergeAabb( const pod::AABB& a, const pod::AABB& b ) {
return {
uf::vector::min( a.min, b.min ),
uf::vector::max( a.max, b.max ),
};
}
FORCE_INLINE pod::Vector3f aabbCenter( const pod::AABB& aabb ) {
return ( aabb.max + aabb.min ) * 0.5f;
}
FORCE_INLINE pod::Vector3f aabbExtent( const pod::AABB& aabb ) {
return ( aabb.max - aabb.min ) * 0.5f;
}
pod::AABB transformAabbToWorld( const pod::AABB& localBox, const pod::Transform<>& transform ) {
const auto& q = transform.orientation;
const auto& p = transform.position;
pod::Vector3f center = (localBox.min + localBox.max) * 0.5f;
pod::Vector3f extents = (localBox.max - localBox.min) * 0.5f;
pod::Vector3f axisX = uf::quaternion::rotate(q, pod::Vector3f{1,0,0});
pod::Vector3f axisY = uf::quaternion::rotate(q, pod::Vector3f{0,1,0});
pod::Vector3f axisZ = uf::quaternion::rotate(q, pod::Vector3f{0,0,1});
pod::Vector3f worldCenter = uf::quaternion::rotate(q, center) + p;
pod::Vector3f worldExtents = {
fabs(axisX.x) * extents.x + fabs(axisY.x) * extents.y + fabs(axisZ.x) * extents.z,
fabs(axisX.y) * extents.x + fabs(axisY.y) * extents.y + fabs(axisZ.y) * extents.z,
fabs(axisX.z) * extents.x + fabs(axisY.z) * extents.y + fabs(axisZ.z) * extents.z
};
return {
worldCenter - worldExtents,
worldCenter + worldExtents
};
}
std::pair<pod::Vector3f, pod::Vector3f> getCapsuleSegment( const pod::PhysicsBody& body ) { std::pair<pod::Vector3f, pod::Vector3f> getCapsuleSegment( const pod::PhysicsBody& body ) {
const auto transform = ::getTransform( body ); const auto transform = ::getTransform( body );
const auto& capsule = body.collider.capsule; const auto& capsule = body.collider.capsule;
@ -34,10 +84,13 @@ namespace {
const auto transform = ::getTransform( body ); const auto transform = ::getTransform( body );
switch ( body.collider.type ) { switch ( body.collider.type ) {
case pod::ShapeType::AABB: { case pod::ShapeType::AABB: {
/*
return { return {
transform.position + body.collider.aabb.min, transform.position + body.collider.aabb.min,
transform.position + body.collider.aabb.max, transform.position + body.collider.aabb.max,
}; };
*/
return ::transformAabbToWorld( body.collider.aabb, *body.transform );
} break; } break;
case pod::ShapeType::SPHERE: { case pod::ShapeType::SPHERE: {
return { return {
@ -63,20 +116,13 @@ namespace {
return {}; return {};
} }
pod::AABB computeTriangleAABB( const pod::Triangle& tri ) {
return {
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] ),
};
}
float triAabbDistanceSq( const pod::Triangle& tri, const pod::AABB& box ) { float triAabbDistanceSq( const pod::Triangle& tri, const pod::AABB& box ) {
float minDistSq = FLT_MAX; float minDistSq = FLT_MAX;
for ( auto i = 0; i < 3; ++i ) { FOR_EACH(3, {
auto cp = ::closestPointOnAABB( tri.points[i], box ); auto cp = ::closestPointOnAABB( tri.points[i], box );
auto d = tri.points[i] - cp; auto d = tri.points[i] - cp;
minDistSq = std::min( minDistSq, uf::vector::dot( d, d ) ); minDistSq = std::min( minDistSq, uf::vector::dot( d, d ) );
} });
return minDistSq; return minDistSq;
} }
@ -124,11 +170,11 @@ namespace {
if ( !axisTest( {-f2.y, f2.x, 0} ) ) return false; if ( !axisTest( {-f2.y, f2.x, 0} ) ) return false;
// test AABB face axes // test AABB face axes
for ( auto i = 0; i < 3; ++i ) { FOR_EACH(3, {
float minVal = std::min({v0[i], v1[i], v2[i]}); float minVal = std::min({v0[i], v1[i], v2[i]});
float maxVal = std::max({v0[i], v1[i], v2[i]}); float maxVal = std::max({v0[i], v1[i], v2[i]});
if ( minVal > e[i] || maxVal < -e[i] ) return false; if ( minVal > e[i] || maxVal < -e[i] ) return false;
} });
// test triangle normal axis // test triangle normal axis
auto n = uf::vector::cross( f0, f1 ); auto n = uf::vector::cross( f0, f1 );
@ -139,13 +185,6 @@ namespace {
return true; return true;
} }
pod::AABB mergeAabb( const pod::AABB& a, const pod::AABB& b ) {
return {
uf::vector::min( a.min, b.min ),
uf::vector::max( a.max, b.max ),
};
}
pod::AABB transformAabbToLocal( const pod::AABB& box, const pod::Transform<>& transform ) { pod::AABB transformAabbToLocal( const pod::AABB& box, const pod::Transform<>& transform ) {
auto inv = uf::transform::inverse( transform ); auto inv = uf::transform::inverse( transform );
@ -166,21 +205,14 @@ namespace {
{ -FLT_MAX, -FLT_MAX, -FLT_MAX }, { -FLT_MAX, -FLT_MAX, -FLT_MAX },
}; };
for ( auto i = 0; i < 8; ++i ) { FOR_EACH(8, {
auto local = uf::transform::apply( inv, corners[i] ); auto local = uf::transform::apply( inv, corners[i] );
out.min = uf::vector::min( out.min, local ); out.min = uf::vector::min( out.min, local );
out.max = uf::vector::max( out.max, local ); out.max = uf::vector::max( out.max, local );
} });
return out; return out;
} }
pod::Vector3f aabbCenter( const pod::AABB& aabb ) {
return ( aabb.max + aabb.min ) * 0.5f;
}
pod::Vector3f aabbExtent( const pod::AABB& aabb ) {
return ( aabb.max - aabb.min ) * 0.5f;
}
bool aabbAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) { bool aabbAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES(AABB, AABB); ASSERT_COLLIDER_TYPES(AABB, AABB);
@ -195,12 +227,12 @@ namespace {
// determine collision axis = smallest overlap // determine collision axis = smallest overlap
auto axis = -1; auto axis = -1;
float minOverlap = FLT_MAX; float minOverlap = FLT_MAX;
for ( auto i = 0; i < 3; ++i ) { FOR_EACH(3, {
if ( overlaps[i] < minOverlap ) { if ( overlaps[i] < minOverlap ) {
minOverlap = overlaps[i]; minOverlap = overlaps[i];
axis = i; axis = i;
} }
} });
pod::Vector3f delta = ::getPosition( b ) - ::getPosition( a ); pod::Vector3f delta = ::getPosition( b ) - ::getPosition( a );
pod::Vector3f normal{0,0,0}; pod::Vector3f normal{0,0,0};
@ -211,13 +243,13 @@ namespace {
auto Max = uf::vector::min( A.max, B.max ); auto Max = uf::vector::min( A.max, B.max );
// on chosen axis, clamp to overlapped rectangle -> 4 potential points // on chosen axis, clamp to overlapped rectangle -> 4 potential points
if (axis == 0) { // x-axis separation, so face-on overlap in YZ plane 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), Min.y, Min.z }, 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), 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, 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 }); 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 else if ( axis == 1 ) { // y-axis separation, overlap in XZ plane
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), 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{ { 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), Min.z }, normal, minOverlap });
@ -235,30 +267,18 @@ namespace {
bool aabbSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) { bool aabbSphere( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( AABB, SPHERE ); ASSERT_COLLIDER_TYPES( AABB, SPHERE );
auto start = manifold.points.size(); REVERSE_COLLIDER( a, b, sphereAabb );
if ( !::sphereAabb( b, a, manifold, eps ) ) return false;
for ( auto i = start; i < manifold.points.size(); ++i ) manifold.points[i].normal = -manifold.points[i].normal;
return true;
} }
bool aabbPlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) { bool aabbPlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( AABB, PLANE ); ASSERT_COLLIDER_TYPES( AABB, PLANE );
auto start = manifold.points.size(); REVERSE_COLLIDER( a, b, planeAabb );
if ( !::planeAabb( b, a, manifold, eps ) ) return false;
for ( auto i = start; i < manifold.points.size(); ++i ) manifold.points[i].normal = -manifold.points[i].normal;
return true;
} }
bool aabbCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) { bool aabbCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( AABB, CAPSULE ); ASSERT_COLLIDER_TYPES( AABB, CAPSULE );
auto start = manifold.points.size(); REVERSE_COLLIDER( a, b, capsuleAabb );
if ( !::capsuleAabb( b, a, manifold, eps ) ) return false;
for ( auto i = start; i < manifold.points.size(); ++i ) manifold.points[i].normal = -manifold.points[i].normal;
return true;
} }
bool aabbMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) { bool aabbMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( AABB, MESH ); ASSERT_COLLIDER_TYPES( AABB, MESH );
auto start = manifold.points.size(); REVERSE_COLLIDER( a, b, meshAabb );
if ( !::meshAabb( b, a, manifold, eps ) ) return false;
for ( auto i = start; i < manifold.points.size(); ++i ) manifold.points[i].normal = -manifold.points[i].normal;
return true;
} }
} }

View File

@ -1,3 +1,13 @@
namespace {
int32_t flattenBVH( pod::BVH& bvh, int32_t nodeID );
void queryFlatBVH( const pod::BVH&, const pod::AABB& bounds, uf::stl::vector<int32_t>& out );
void queryFlatBVH( const pod::BVH&, const pod::Ray& ray, uf::stl::vector<int32_t>& out, float maxDist = FLT_MAX );
void queryFlatOverlaps( const pod::BVH& bvh, pod::BVH::pairs_t& outPairs );
void queryFlatOverlaps( const pod::BVH& bvhA, const pod::BVH& bvhB, pod::BVH::pairs_t& outPairs );
}
// BVH // BVH
namespace { namespace {
int32_t buildBVHNode( pod::BVH& bvh, const uf::stl::vector<pod::AABB>& bounds, int32_t start, int32_t end, int32_t capacity = 2 ) { int32_t buildBVHNode( pod::BVH& bvh, const uf::stl::vector<pod::AABB>& bounds, int32_t start, int32_t end, int32_t capacity = 2 ) {
@ -212,7 +222,7 @@ namespace {
auto tris = view.index.count / 3; auto tris = view.index.count / 3;
for ( auto triIndexID = 0; triIndexID < tris; ++triIndexID ) { for ( auto triIndexID = 0; triIndexID < tris; ++triIndexID ) {
auto tri = ::fetchTriangle( positions.data(view.vertex.first), positions.stride(), indices.data(view.index.first), mesh.index.size, triIndexID ); auto tri = ::fetchTriangle( view, indices, positions, triIndexID );
auto aabb = ::computeTriangleAABB( tri ); auto aabb = ::computeTriangleAABB( tri );
auto triID = triIndexID + (view.index.first / 3); auto triID = triIndexID + (view.index.first / 3);
@ -363,7 +373,7 @@ namespace {
auto tris = view.index.count / 3; auto tris = view.index.count / 3;
for ( auto triIndexID = 0; triIndexID < tris; ++triIndexID ) { for ( auto triIndexID = 0; triIndexID < tris; ++triIndexID ) {
auto tri = ::fetchTriangle( positions.data(view.vertex.first), positions.stride(), indices.data(view.index.first), mesh.index.size, triIndexID ); auto tri = ::fetchTriangle( view, indices, positions, triIndexID );
auto aabb = ::computeTriangleAABB( tri ); auto aabb = ::computeTriangleAABB( tri );
bounds.emplace_back(aabb); bounds.emplace_back(aabb);
} }

View File

@ -104,9 +104,6 @@ namespace {
} }
bool capsuleMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) { bool capsuleMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( CAPSULE, MESH ); ASSERT_COLLIDER_TYPES( CAPSULE, MESH );
auto start = manifold.points.size(); REVERSE_COLLIDER( a, b, meshCapsule );
if ( !::meshCapsule( b, a, manifold, eps ) ) return false;
for ( auto i = start; i < manifold.points.size(); ++i ) manifold.points[i].normal = -manifold.points[i].normal;
return true;
} }
} }

View File

@ -1,3 +1,9 @@
#define REVERSE_COLLIDER( a, b, fun )\
auto start = manifold.points.size();\
if ( !::fun( b, a, manifold, eps ) ) return false;\
for ( auto i = start; i < manifold.points.size(); ++i ) manifold.points[i].normal = -manifold.points[i].normal;\
return true;
// forward declare // forward declare
namespace { namespace {
bool aabbAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) ); bool aabbAabb( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
@ -37,31 +43,16 @@ namespace {
bool triangleCapsule( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold, float eps = EPS(1.0e-6f) ); bool triangleCapsule( const pod::TriangleWithNormal& tri, const pod::PhysicsBody& body, pod::Manifold& manifold, float eps = EPS(1.0e-6f) );
// ugh // ugh
FORCE_INLINE bool aabbOverlap( const pod::AABB& a, const pod::AABB& b, float eps = EPS(1.0e-6f) );
pod::Vector3f aabbCenter( const pod::AABB& aabb ); pod::Vector3f aabbCenter( const pod::AABB& aabb );
bool aabbOverlap( const pod::AABB& a, const pod::AABB& b, float eps = EPS(1.0e-6f) );
pod::AABB computeTriangleAABB( const pod::Triangle& tri );
void solveContacts( uf::stl::vector<pod::Manifold>& manifolds, float dt );
int32_t flattenBVH( pod::BVH& bvh, int32_t nodeID );
void traverseNodePair( const pod::BVH& bvh, int32_t leftID, int32_t rightID, pod::BVH::pairs_t& pairs );
void traverseNodePair( const pod::BVH& a, int32_t nodeA, const pod::BVH& b, int32_t nodeB, pod::BVH::pairs_t& out );
void queryBVH( const pod::BVH& bvh, const pod::AABB& bounds, uf::stl::vector<int32_t>& indices ); void queryBVH( const pod::BVH& bvh, const pod::AABB& bounds, uf::stl::vector<int32_t>& indices );
void queryBVH( const pod::BVH& bvh, const pod::AABB& bounds, uf::stl::vector<int32_t>& indices, int32_t nodeID ); void queryBVH( const pod::BVH& bvh, const pod::AABB& bounds, uf::stl::vector<int32_t>& indices, int32_t nodeID );
void queryBVH( const pod::BVH& bvh, const pod::Ray& ray, uf::stl::vector<int32_t>& indices, float maxDist = FLT_MAX ); void queryBVH( const pod::BVH& bvh, const pod::Ray& ray, uf::stl::vector<int32_t>& indices, float maxDist = FLT_MAX );
void queryBVH( const pod::BVH& bvh, const pod::Ray& ray, uf::stl::vector<int32_t>& indices, int32_t nodeID, float maxDist = FLT_MAX ); void queryBVH( const pod::BVH& bvh, const pod::Ray& ray, uf::stl::vector<int32_t>& indices, int32_t nodeID, float maxDist = FLT_MAX );
void queryFlatBVH( const pod::BVH&, const pod::AABB& bounds, uf::stl::vector<int32_t>& out );
void queryFlatBVH( const pod::BVH&, const pod::Ray& ray, uf::stl::vector<int32_t>& out, float maxDist = FLT_MAX );
void queryOverlaps( const pod::BVH& bvh, pod::BVH::pairs_t& outPairs ); void queryOverlaps( const pod::BVH& bvh, pod::BVH::pairs_t& outPairs );
void queryOverlaps( const pod::BVH& bvhA, const pod::BVH& bvhB, pod::BVH::pairs_t& outPairs ); void queryOverlaps( const pod::BVH& bvhA, const pod::BVH& bvhB, pod::BVH::pairs_t& outPairs );
void queryFlatOverlaps( const pod::BVH& bvh, pod::BVH::pairs_t& outPairs );
void queryFlatOverlaps( const pod::BVH& bvhA, const pod::BVH& bvhB, pod::BVH::pairs_t& outPairs );
} }
namespace { namespace {
@ -381,22 +372,4 @@ namespace {
return best; return best;
} }
bool triangleTriangleIntersect( const pod::Triangle& a, const pod::Triangle& b, float eps = EPS(1e-6f) ) {
auto boxA = ::computeTriangleAABB( a );
auto boxB = ::computeTriangleAABB( b );
if ( !::aabbOverlap( boxA, boxB ) ) return false;
// check vertices of a inside b or vice versa
for ( auto i = 0; i < 3; i++ ) {
auto q = ::closestPointOnTriangle( a.points[i], b );
if ( uf::vector::magnitude( q - a.points[i] ) < eps ) return true;
}
for ( auto i = 0; i < 3; i++ ) {
auto q = ::closestPointOnTriangle( b.points[i], a );
if ( uf::vector::magnitude( q - b.points[i] ) < eps ) return true;
}
return false;
}
} }

View File

@ -5,41 +5,45 @@
#include <uf/utils/memory/stack.h> #include <uf/utils/memory/stack.h>
namespace { namespace {
bool warmupSolver = true; bool warmupSolver = true; // cache manifold data to warm up the solver
bool blockContactSolver = true; bool blockContactSolver = true; // use BlockNxN solvers (where N = number of contacts for a manifold)
bool psgContactSolver = true; // iterative solver is flawed bool psgContactSolver = true; // use PSG contact solver
bool useGjk = false; // currently don't have a way to broadphase mesh => narrowphase tri via GJK bool useGjk = false; // currently don't have a way to broadphase mesh => narrowphase tri via GJK
bool fixedStep = true; bool fixedStep = true; // run physics simulation with a fixed delta time (with accumulation), rather than rely on actual engine deltatime
int32_t substeps = 0; // number of substeps per frame tick
int32_t reserveCount = 32; // amount of elements to reserve for vectors used in this system, to-do: have it tie to a memory pool allocator
int32_t substeps = 0; // increasing these make things lag for reasons I can imagine why
int32_t reserveCount = 32; int32_t broadphaseBvhCapacity = 1; // number of bodies per leaf node
int32_t meshBvhCapacity = 1; // number of triangles per leaf node
// increasing these make things lag // additionally flattens a BVH for linear iteration, rather than a recursive / stack-based traversal
int32_t broadphaseBvhCapacity = 1; bool flattenBvhBodies = true;
int32_t meshBvhCapacity = 1;
bool flattenBvhBodies = false; // bugged
bool flattenBvhMeshes = true; bool flattenBvhMeshes = true;
// it actually seems slower to use these...... // use surface area heuristics for building the BVH, rather than naive splits
bool useBvhSahBodies = false; bool useBvhSahBodies = false; // it actually seems slower to use these......
bool useBvhSahMeshes = false; bool useBvhSahMeshes = true;
bool useSplitBvhs = true; // currently bugged if enabled bool useSplitBvhs = true; // creates separate BVHs for static / dynamic objects
// to-do: find possibly better values for this
int32_t solverIterations = 10; int32_t solverIterations = 10;
float baumgarteCorrectionPercent = 0.2f; float baumgarteCorrectionPercent = 0.2f;
float baumgarteCorrectionSlop = 0.01f; float baumgarteCorrectionSlop = 0.01f;
uf::stl::unordered_map<size_t, pod::Manifold> manifoldsCache; uf::stl::unordered_map<size_t, pod::Manifold> manifoldsCache;
int32_t manifoldCacheLifetime = 6; int32_t manifoldCacheLifetime = 6; // to-do: find a good value for this
uint32_t frameCounter = 0; uint32_t frameCounter = 0;
// to-do: tweak this to not be annoying
// currently seems only reliable when it hits its TTL, but too long of a wait is gross, and too frequent of an update causes lag
pod::BVH::UpdatePolicy bvhUpdatePolicy = { pod::BVH::UpdatePolicy bvhUpdatePolicy = {
.displacementThreshold = 0.25f, .displacementThreshold = 0.25f,
.overlapThreshold = 2.0f, .overlapThreshold = 2.0f,
.dirtyRatioThreshold = 0.3f, .dirtyRatioThreshold = 0.3f,
.maxFramesBeforeRebuild = 60, .maxFramesBeforeRebuild = 120,
}; };
} }
@ -61,7 +65,7 @@ namespace {
#include "integration.inl" #include "integration.inl"
#include "solvers.inl" #include "solvers.inl"
// unused // unused, as these are from reactphysics
float uf::physics::impl::timescale = 1.0f / 60.0f; float uf::physics::impl::timescale = 1.0f / 60.0f;
bool uf::physics::impl::interpolate = false; bool uf::physics::impl::interpolate = false;
bool uf::physics::impl::shared = false; bool uf::physics::impl::shared = false;
@ -264,9 +268,7 @@ void uf::physics::impl::updateInertia( pod::PhysicsBody& body ) {
extents *= extents; // square it; extents *= extents; // square it;
body.inertiaTensor = extents * (body.mass / 12.0f); body.inertiaTensor = extents * (body.mass / 12.0f);
// to-do: add overloaded inverse order arithmetic operators body.inverseInertiaTensor = 1.0f / body.inertiaTensor;
//body.inverseInertiaTensor = 1.0f / body.inertiaTensor;
body.inverseInertiaTensor = { 1.0f / body.inertiaTensor.x, 1.0f / body.inertiaTensor.y, 1.0f / body.inertiaTensor.z };
} break; } break;
case pod::ShapeType::SPHERE: { case pod::ShapeType::SPHERE: {
float I = 0.4f * body.mass * body.collider.sphere.radius * body.collider.sphere.radius; float I = 0.4f * body.mass * body.collider.sphere.radius * body.collider.sphere.radius;

View File

@ -48,16 +48,10 @@ namespace {
} }
bool planeCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) { bool planeCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( PLANE, CAPSULE ); ASSERT_COLLIDER_TYPES( PLANE, CAPSULE );
auto start = manifold.points.size(); REVERSE_COLLIDER( a, b, capsulePlane );
if ( !::capsulePlane( b, a, manifold, eps ) ) return false;
for ( auto i = start; i < manifold.points.size(); ++i ) manifold.points[i].normal = -manifold.points[i].normal;
return true;
} }
bool planeMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) { bool planeMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( PLANE, MESH ); ASSERT_COLLIDER_TYPES( PLANE, MESH );
auto start = manifold.points.size(); REVERSE_COLLIDER( a, b, meshPlane );
if ( !::meshPlane( b, a, manifold, eps ) ) return false;
for ( auto i = start; i < manifold.points.size(); ++i ) manifold.points[i].normal = -manifold.points[i].normal;
return true;
} }
} }

View File

@ -53,23 +53,14 @@ namespace {
} }
bool spherePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) { bool spherePlane( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( SPHERE, PLANE ); ASSERT_COLLIDER_TYPES( SPHERE, PLANE );
auto start = manifold.points.size(); REVERSE_COLLIDER( a, b, planeSphere );
if ( !::planeSphere( b, a, manifold, eps ) ) return false;
for ( auto i = start; i < manifold.points.size(); ++i ) manifold.points[i].normal = -manifold.points[i].normal;
return true;
} }
bool sphereCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) { bool sphereCapsule( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( SPHERE, CAPSULE ); ASSERT_COLLIDER_TYPES( SPHERE, CAPSULE );
auto start = manifold.points.size(); REVERSE_COLLIDER( a, b, capsuleSphere );
if ( !::capsuleSphere( b, a, manifold, eps ) ) return false;
for ( auto i = start; i < manifold.points.size(); ++i ) manifold.points[i].normal = -manifold.points[i].normal;
return true;
} }
bool sphereMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) { bool sphereMesh( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::Manifold& manifold, float eps ) {
ASSERT_COLLIDER_TYPES( SPHERE, MESH ); ASSERT_COLLIDER_TYPES( SPHERE, MESH );
auto start = manifold.points.size(); REVERSE_COLLIDER( a, b, meshSphere );
if ( !::meshSphere( b, a, manifold, eps ) ) return false;
for ( auto i = start; i < manifold.points.size(); ++i ) manifold.points[i].normal = -manifold.points[i].normal;
return true;
} }
} }

View File

@ -1,23 +1,9 @@
#define REORIENT_NORMALS_ON_FETCH 0 #define REORIENT_NORMALS_ON_FETCH 0
#define REORIENT_NORMALS_ON_CONTACT 1 #define REORIENT_NORMALS_ON_CONTACT 1
// mesh BVH #include <uf/utils/math/quant.h>
namespace {
// to-do: clean this up
uint32_t getIndex( const void* indexData, size_t indexSize, size_t idx ) {
if ( indexSize == sizeof(uint8_t) ) {
auto* ptr = reinterpret_cast<const uint8_t*>(indexData);
return static_cast<uint32_t>(ptr[idx]);
} else if ( indexSize == sizeof(uint16_t) ) {
auto* ptr = reinterpret_cast<const uint16_t*>(indexData);
return static_cast<uint32_t>(ptr[idx]);
} else if ( indexSize == sizeof(uint32_t) ) {
auto* ptr = reinterpret_cast<const uint32_t*>(indexData);
return ptr[idx];
}
UF_EXCEPTION("Unsupported index type of size {}", indexSize);
}
namespace {
pod::Vector3f triangleCenter( const pod::Triangle& tri ) { pod::Vector3f triangleCenter( const pod::Triangle& tri ) {
return ( tri.points[0] + tri.points[1] + tri.points[2] ) / 3.0f; return ( tri.points[0] + tri.points[1] + tri.points[2] ) / 3.0f;
} }
@ -29,12 +15,80 @@ namespace {
//return uf::vector::normalize( tri.normals[0] + tri.normals[1] + tri.normals[2] ); //return uf::vector::normalize( tri.normals[0] + tri.normals[1] + tri.normals[2] );
} }
pod::Triangle fetchTriangle( const void* vertices, size_t vertexStride, const void* indexData, size_t indexSize, size_t triID ) { bool triangleTriangleIntersect( const pod::Triangle& a, const pod::Triangle& b, float eps = EPS(1e-6f) ) {
return { auto boxA = ::computeTriangleAABB( a );
*reinterpret_cast<const pod::Vector3f*>(reinterpret_cast<const uint8_t*>(vertices) + ::getIndex( indexData, indexSize, (triID * 3) + 0 ) * vertexStride), auto boxB = ::computeTriangleAABB( b );
*reinterpret_cast<const pod::Vector3f*>(reinterpret_cast<const uint8_t*>(vertices) + ::getIndex( indexData, indexSize, (triID * 3) + 1 ) * vertexStride),
*reinterpret_cast<const pod::Vector3f*>(reinterpret_cast<const uint8_t*>(vertices) + ::getIndex( indexData, indexSize, (triID * 3) + 2 ) * vertexStride), if ( !::aabbOverlap( boxA, boxB ) ) return false;
};
// check vertices of a inside b or vice versa
FOR_EACH(3, {
auto q = ::closestPointOnTriangle( a.points[i], b );
if ( uf::vector::magnitude( q - a.points[i] ) < eps ) return true;
});
FOR_EACH(3, {
auto q = ::closestPointOnTriangle( b.points[i], a );
if ( uf::vector::magnitude( q - b.points[i] ) < eps ) return true;
});
return false;
}
size_t getIndex( const void* pointer, size_t stride, size_t index ) {
#define CAST_INDEX(T) case sizeof(T): return ((T*) pointer)[index];
switch ( stride ) {
CAST_INDEX(uint8_t);
CAST_INDEX(uint16_t);
CAST_INDEX(uint32_t);
default: {
UF_EXCEPTION("invalid stride type: {}", stride);
} break;
}
}
size_t getIndex( const uf::Mesh::View& view, const uf::Mesh::AttributeView& indices, size_t index ) {
return ::getIndex( indices.data(view.index.first), indices.stride(), index );
}
pod::Vector3f getVertex( const uf::Mesh::View& view, const uf::Mesh::AttributeView& positions, size_t index ) {
const auto stride = positions.stride();
#define CAST_VERTEX(T) {\
const T* vertices = (T*) positions.data(view.vertex.first + index);\
return { vertices[0], vertices[1], vertices[2], };\
}
#define DEQUANTIZE_VERTEX(T) {\
const T* vertices = (T*) positions.data(view.vertex.first + index);\
return { uf::quant::dequantize(vertices[0]), uf::quant::dequantize(vertices[1]), uf::quant::dequantize(vertices[2]), };\
}
switch ( positions.attribute.descriptor.type ) {
// dequantize
case uf::renderer::enums::Type::USHORT:
case uf::renderer::enums::Type::SHORT: {
DEQUANTIZE_VERTEX(uint16_t);
} break;
case uf::renderer::enums::Type::FLOAT: {
CAST_VERTEX(float);
} break;
#if UF_USE_FLOAT16
case uf::renderer::enums::Type::HALF: {
CAST_VERTEX(std::float16_t);
} break;
#endif
#if UF_USE_BFLOAT16
case uf::renderer::enums::Type::BFLOAT: {
CAST_VERTEX(std::bfloat16_t);
} break;
#endif
default: UF_EXCEPTION("unsupported vertex type: {}", positions.attribute.descriptor.type); break;
}
// return ::getVertex( positions.data(view.vertex.first), positions.stride(), index );
}
pod::Triangle fetchTriangle( const uf::Mesh::View& view, const uf::Mesh::AttributeView& indices, const uf::Mesh::AttributeView& positions, size_t triID ) {
auto index = triID * 3;
pod::Triangle tri;
FOR_EACH(3, {
tri.points[i] = ::getVertex( view, positions, ::getIndex( view, indices, index + i ) );
});
return tri;
} }
pod::TriangleWithNormal fetchTriangle( const uf::Mesh& mesh, size_t triID ) { pod::TriangleWithNormal fetchTriangle( const uf::Mesh& mesh, size_t triID ) {
@ -43,49 +97,42 @@ namespace {
// find which view contains this triangle index. // find which view contains this triangle index.
size_t triBase = 0; size_t triBase = 0;
const uf::Mesh::View* found = nullptr; const uf::Mesh::View* view = nullptr;
for ( auto& v : views ) { for ( auto& v : views ) {
auto trisInView = v.index.count / 3; auto trisInView = v.index.count / 3;
if (triID < triBase + trisInView) { if (triID < triBase + trisInView) {
found = &v; view = &v;
triID -= triBase; // local triangle index inside this view triID -= triBase; // local triangle index inside this view
break; break;
} }
triBase += trisInView; triBase += trisInView;
} }
UF_ASSERT( found ); UF_ASSERT( view );
auto& positions = (*found)["position"]; auto& positions = (*view)["position"];
auto& normals = (*found)["normal"]; auto& normals = (*view)["normal"];
auto& indices = (*found)["index"]; auto& indices = (*view)["index"];
pod::TriangleWithNormal tri = { ::fetchTriangle( positions.data(found->vertex.first), positions.stride(), indices.data(found->index.first), mesh.index.size, triID ) }; pod::TriangleWithNormal tri = { ::fetchTriangle( *view, indices, positions, triID ) };
tri.normal = uf::vector::normalize(uf::vector::cross(tri.points[1] - tri.points[0], tri.points[2] - tri.points[0])); tri.normal = uf::vector::normalize(uf::vector::cross(tri.points[1] - tri.points[0], tri.points[2] - tri.points[0]));
/*
if ( false && normals.valid() ) {
auto* base = reinterpret_cast<const uint8_t*>(normals.data(found->vertex.first));
size_t stride = normals.stride();
for ( auto i = 0; i < 3; ++i ) tri.normals[i] = *reinterpret_cast<const pod::Vector3f*>(base + idxs[i] * stride);
} else {
auto normal = ::triangleNormal( (pod::Triangle&) tri );
for ( auto i = 0; i < 3; ++i ) tri.normals[i] = normal;
}
*/
return tri; return tri;
} }
// if body is a mesh, apply its transform to the triangles, else reorient the normal with respect to the body // if body is a mesh, apply its transform to the triangles, else reorient the normal with respect to the body
pod::TriangleWithNormal fetchTriangle( const uf::Mesh& mesh, size_t triID, const pod::PhysicsBody& body, bool fast = true ) { pod::TriangleWithNormal fetchTriangle( const uf::Mesh& mesh, size_t triID, const pod::PhysicsBody& body, bool fast = false ) {
auto tri = ::fetchTriangle( mesh, triID ); auto tri = ::fetchTriangle( mesh, triID );
auto transform = ::getTransform( body ); auto transform = ::getTransform( body );
if ( body.collider.type == pod::ShapeType::MESH ) { if ( body.collider.type == pod::ShapeType::MESH ) {
if ( fast ) { if ( fast ) {
for ( auto i = 0; i < 3; ++i ) tri.points[i] += transform.position; FOR_EACH(3, {
tri.points[i] += transform.position;
});
} else { } else {
for ( auto i = 0; i < 3; ++i ) tri.points[i] = uf::transform::apply( transform, tri.points[i] ); FOR_EACH(3, {
tri.points[i] = uf::transform::apply( transform, tri.points[i] );
});
tri.normal = uf::quaternion::rotate( transform.orientation, tri.normal ); tri.normal = uf::quaternion::rotate( transform.orientation, tri.normal );
} }
} }
@ -132,24 +179,24 @@ namespace {
// clip edges of A against plane of B // clip edges of A against plane of B
const pod::Vector3f At[3] = { A.points[0], A.points[1], A.points[2] }; const pod::Vector3f At[3] = { A.points[0], A.points[1], A.points[2] };
for ( auto i = 0; i < 3; ++i ) { FOR_EACH(3, {
auto j = ( i + 1 ) % 3; auto j = ( i + 1 ) % 3;
pod::Vector3f p; pod::Vector3f p;
if ( intersectSegmentPlane( At[i], At[j], nB, dB, p ) ) { if ( intersectSegmentPlane( At[i], At[j], nB, dB, p ) ) {
// check if intersection lies inside triangle B // check if intersection lies inside triangle B
if ( ::pointInTriangle( p, B ) ) checkAndPush(p); if ( ::pointInTriangle( p, B ) ) checkAndPush(p);
} }
} });
// clip edges of B against plane of A // clip edges of B against plane of A
const pod::Vector3f Bt[3] = { B.points[0], B.points[1], B.points[2] }; const pod::Vector3f Bt[3] = { B.points[0], B.points[1], B.points[2] };
for ( auto i = 0; i < 3; ++i ) { FOR_EACH(3, {
auto j = ( i + 1 ) % 3; auto j = ( i + 1 ) % 3;
pod::Vector3f p; pod::Vector3f p;
if ( intersectSegmentPlane( Bt[i], Bt[j], nA, dA, p ) ) { if ( intersectSegmentPlane( Bt[i], Bt[j], nA, dA, p ) ) {
if ( ::pointInTriangle( p, A ) ) checkAndPush(p); if ( ::pointInTriangle( p, A ) ) checkAndPush(p);
} }
} });
if ( intersections.empty() ) return false; if ( intersections.empty() ) return false;
@ -295,7 +342,9 @@ namespace {
bool hit = false; bool hit = false;
pod::Vector3f dist; pod::Vector3f dist;
for ( auto i = 0; i < 3; i++ ) dist[i] = uf::vector::dot(normal, tri.points[i] ) - d; FOR_EACH(3, {
dist[i] = uf::vector::dot(normal, tri.points[i] ) - d;
});
// completely on one side // completely on one side
bool allAbove = ( dist.x > eps && dist.y > eps && dist.z > eps ); bool allAbove = ( dist.x > eps && dist.y > eps && dist.z > eps );
@ -305,10 +354,10 @@ namespace {
if ( allBelow ) { if ( allBelow ) {
hit = true; hit = true;
for ( auto i = 0; i < 3; i++ ) { FOR_EACH(3, {
float penetration = -dist[i]; float penetration = -dist[i];
manifold.points.emplace_back(pod::Contact{tri.points[i], normal, penetration}); manifold.points.emplace_back(pod::Contact{tri.points[i], normal, -dist[i]});
} });
return hit; return hit;
} }