Orange/include/Orange/Math/Vector.h

314 lines
8.7 KiB
C
Raw Normal View History

2022-08-07 00:15:47 +01:00
#pragma once
#include <Orange/Core/Types.h>
#include <Orange/Core/Traits.h>
#include <Orange/Core/Array.h>
#include <Orange/Math/Basic.h>
namespace orange
{
template <typename T, size_t Size>
struct Vec
{
using DefaultLengthType = DefaultLengthTypeResolver<T>::LengthType;
using DefaultLengthVec = Vec<DefaultLengthType, Size>;
constexpr Vec()
: data{ } {}
constexpr explicit Vec(T splat)
{
Fill(data.begin(), data.end(), splat);
}
constexpr Vec(const T components[Size])
{
Copy(&components[0], &components[Size], data.begin());
}
template <typename... Args>
constexpr Vec(const Args&... args)
: data {{ args... }}
{
static_assert(sizeof...(Args) == Size);
}
constexpr Vec(const Vec& other) = default;
constexpr T& operator[](size_t index) { return data[index]; }
constexpr const T& operator[](size_t index) const { return data[index]; }
constexpr const T* begin() const { return data.begin(); }
constexpr T* begin() { return data.begin(); }
constexpr const T* end() const { return data.end(); }
constexpr T* end() { return data.end(); }
constexpr bool operator==(const Vec& other) const
{
return Equal(begin(), end(), other.begin());
}
constexpr bool operator!=(const Vec& other) const
{
return !operator==(other);
}
template <typename UnaryOperation>
constexpr Vec TransformResult(UnaryOperation op) const
{
2022-08-13 10:21:35 +01:00
return Util::TransformResult<Vec>(begin(), end(), op);
2022-08-07 00:15:47 +01:00
}
template <typename BinaryOperation>
constexpr Vec TransformResult(const T *other, BinaryOperation op) const
{
2022-08-13 10:21:35 +01:00
return Util::TransformResult<Vec>(begin(), end(), other, op);
2022-08-07 00:15:47 +01:00
}
template <typename BinaryOperation>
constexpr Vec TransformResult(const Vec& other, BinaryOperation op) const
{
return TransformResult(other.begin(), op);
}
template <typename UnaryOperation>
constexpr Vec& TransformInPlace(UnaryOperation op)
{
2022-08-13 10:21:35 +01:00
Util::Transform(begin(), end(), begin(), op);
2022-08-07 00:15:47 +01:00
return *this;
}
template <typename BinaryOperation>
constexpr Vec& TransformInPlace(const T *other, BinaryOperation op)
{
2022-08-13 10:21:35 +01:00
Util::Transform(begin(), end(), other, begin(), op);
2022-08-07 00:15:47 +01:00
return *this;
}
template <typename BinaryOperation>
constexpr Vec& TransformInPlace(const Vec& other, BinaryOperation op)
{
return TransformInPlace(other.begin(), op);
}
constexpr Vec operator-() const
{
2022-08-13 10:21:35 +01:00
return TransformResult(Math::Negate<T>);
2022-08-07 00:15:47 +01:00
}
constexpr Vec operator+(const Vec& other) const
{
2022-08-13 10:21:35 +01:00
return TransformResult(other, Math::Add<T>);
2022-08-07 00:15:47 +01:00
}
constexpr Vec operator-(const Vec& other) const
{
2022-08-13 10:21:35 +01:00
return TransformResult(other, Math::Subtract<T>);
2022-08-07 00:15:47 +01:00
}
constexpr Vec operator*(const Vec& other) const
{
2022-08-13 10:21:35 +01:00
return TransformResult(other, Math::Multiply<T>);
2022-08-07 00:15:47 +01:00
}
constexpr Vec operator*(const T& scalar) const
{
return TransformResult([scalar](T value) { return value * scalar; });
}
constexpr Vec operator/(const Vec& other) const
{
2022-08-13 10:21:35 +01:00
return TransformResult(other, Math::Divide<T>);
2022-08-07 00:15:47 +01:00
}
constexpr Vec operator/(const T& scalar) const
{
return TransformResult([scalar](T value) { return value / scalar; });
}
constexpr Vec operator%(const Vec& other) const
{
2022-08-13 10:21:35 +01:00
return TransformResult(other, Math::Modulo<T>);
2022-08-07 00:15:47 +01:00
}
constexpr Vec operator%(const T& scalar) const
{
return TransformResult([scalar](T value) { return value % scalar; });
}
constexpr Vec& operator+=(const Vec& other)
{
2022-08-13 10:21:35 +01:00
return TransformInPlace(Math::Add<T>);
2022-08-07 00:15:47 +01:00
}
constexpr Vec& operator-=(const Vec& other)
{
2022-08-13 10:21:35 +01:00
return TransformInPlace(Math::Subtract<T>);
2022-08-07 00:15:47 +01:00
}
constexpr Vec& operator*=(const Vec& other)
{
2022-08-13 10:21:35 +01:00
return TransformInPlace(Math::Multiply<T>);
2022-08-07 00:15:47 +01:00
}
constexpr Vec& operator*=(const T& scalar)
{
return TransformInPlace([scalar](T value) { return value * scalar; });
}
constexpr Vec& operator/=(const Vec& other)
{
2022-08-13 10:21:35 +01:00
return TransformInPlace(Math::Divide<T>);
2022-08-07 00:15:47 +01:00
}
constexpr Vec& operator/=(const T& scalar)
{
return TransformInPlace([scalar](T value) { return value / scalar; });
}
constexpr Vec& operator%=(const Vec& other)
{
2022-08-13 10:21:35 +01:00
return TransformInPlace(Math::Modulo<T>);
2022-08-07 00:15:47 +01:00
}
constexpr Vec& operator%=(const T& scalar)
{
return TransformInPlace([scalar](T value) { return value % scalar; });
}
static constexpr Vec Zero = Vec{ T{ 0 } };
static constexpr Vec Identity = Vec{ T{ 1 } };
// Align to 16 if the size is a multiple of 4 and T is 4 bytes in size.
// to take advantage of aligned load/stores.
static constexpr size_t Alignment =
(Size % 4zu == 0 && sizeof(T) == 4zu)
? Max<size_t>(16zu, alignof(T))
: alignof(T);
2022-08-13 10:21:35 +01:00
union
{
alignas(Alignment) Array<T, Size> data;
struct
{
alignas(Alignment) float x;
float y;
float z;
float w;
};
};
2022-08-07 00:15:47 +01:00
};
template <typename T, size_t Size>
constexpr Vec<T, Size> operator*(T scalar, const Vec<T, Size>& Vec)
{
return Vec.TransformResult([scalar](T value) { return scalar * value; });
}
template <typename T, size_t Size>
constexpr Vec<T, Size> operator/(T scalar, const Vec<T, Size>& Vec)
{
return Vec.TransformResult([scalar](T value) { return scalar / value; });
}
template <typename T, size_t Size>
constexpr Vec<T, Size> operator%(T scalar, const Vec<T, Size>& Vec)
{
return Vec.TransformResult([scalar](T value) { return scalar % value; });
}
template <typename T, size_t Size>
constexpr T accumulate(const Vec<T, Size>& a, T init = T{})
{
return Accumulate(a.begin(), a.end(), init);
}
template <typename T, size_t Size>
constexpr T dot(const Vec<T, Size>& a, const Vec<T, Size>& b)
{
return accumulate(a * b);
}
template <typename T, size_t Size>
constexpr T lengthSqr(const Vec<T, Size>& a)
{
return dot(a, a);
}
template <typename T, size_t Size, typename J = Vec<T, Size>::DefaultLengthType>
constexpr J length(const Vec<T, Size>& a)
{
2022-08-13 10:21:35 +01:00
return sqrtf(J{ lengthSqr(a) });
2022-08-07 00:15:47 +01:00
}
template <typename T, size_t Size, typename J = Vec<T, Size>::DefaultLengthType>
constexpr Vec<J, Size> normalize(const Vec<T, Size>& a)
{
return a * J{ rcp( length<T, Size>(a) ) };
}
template <typename T, size_t Size, typename J = Vec<T, Size>::DefaultLengthType>
constexpr Vec<J, Size> rcp(const Vec<T, Size>& a)
{
return TransformResult<Vec<J, Size>>(a.begin(), a.end(), [](T value){ return rcp<T, J>(value); });
}
template <typename T, size_t Size>
constexpr bool empty(const Vec<T, Size>& a)
{
return a == Vec<T, Size>::Zero;
}
template <typename T, size_t Size>
constexpr bool identity(const Vec<T, Size>& a)
{
return a == Vec<T, Size>::Identity;
}
2022-08-07 00:59:25 +01:00
template <typename T, size_t Size>
constexpr Vec<T, Size> Min(const Vec<T, Size>& a, const Vec<T, Size>& b)
{
2022-08-13 10:21:35 +01:00
return Util::TransformResult<Vec<T, Size>>(a.begin(), a.end(), b.begin(), [](T val_a, T val_b){ return Min(val_a, val_b); });
2022-08-07 00:59:25 +01:00
}
template <typename T, size_t Size>
constexpr Vec<T, Size> Max(const Vec<T, Size>& a, const Vec<T, Size>& b)
{
2022-08-13 10:21:35 +01:00
return Util::TransformResult<Vec<T, Size>>(a.begin(), a.end(), b.begin(), [](T val_a, T val_b){ return Max(val_a, val_b); });
2022-08-07 00:59:25 +01:00
}
2022-08-13 10:21:35 +01:00
2022-08-07 00:59:25 +01:00
using vec1 = Vec<float, 1>;
using vec2 = Vec<float, 2>;
using vec3 = Vec<float, 3>;
using vec4 = Vec<float, 4>;
2022-08-07 00:15:47 +01:00
2022-08-13 10:21:35 +01:00
float cross(const vec2& a, const vec2& b)
{
return a.x * b.y - b.x * a.y;
}
vec3 cross(const vec3& a, const vec3& b)
{
return
{
a.y * b.z - b.y * a.z,
a.z * b.x - b.z * a.x,
a.x * b.y - b.x * a.y
};
}
2022-08-07 00:15:47 +01:00
}