Orange/include/Orange/Math/Vector.h

298 lines
9.1 KiB
C++

#pragma once
#include <Orange/Core/Types.h>
#include <Orange/Core/Traits.h>
#include <Orange/Core/Array.h>
#include <Orange/Math/Basic.h>
#include <Orange/Math/Swizzle.h>
namespace orange
{
// 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.
template <typename T, size_t Size>
struct VectorAlignmentHelper
{
static constexpr size_t Alignment =
(Size % 4zu == 0 && sizeof(T) == 4zu)
? Max<size_t>(16zu, alignof(T))
: alignof(T);
};
template <typename T, size_t Size>
struct Vec : public Swizzle<T, VectorAlignmentHelper<T, Size>::Alignment, Size>
{
static constexpr size_t Alignment = VectorAlignmentHelper<T, Size>::Alignment;
using DefaultLengthType = DefaultLengthTypeResolver<T>::LengthType;
using DefaultLengthVec = Vec<DefaultLengthType, Size>;
using Swizzle<T, Alignment, Size>::Swizzle;
constexpr T& operator[](size_t index) { return this->data[index]; }
constexpr const T& operator[](size_t index) const { return this->data[index]; }
constexpr const T* begin() const { return this->data.begin(); }
constexpr T* begin() { return this->data.begin(); }
constexpr const T* end() const { return this->data.end(); }
constexpr T* end() { return this->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
{
return Util::TransformResult<Vec>(begin(), end(), op);
}
template <typename BinaryOperation>
constexpr Vec TransformResult(const T *other, BinaryOperation op) const
{
return Util::TransformResult<Vec>(begin(), end(), other, op);
}
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)
{
Util::Transform(begin(), end(), begin(), op);
return *this;
}
template <typename BinaryOperation>
constexpr Vec& TransformInPlace(const T *other, BinaryOperation op)
{
Util::Transform(begin(), end(), other, begin(), op);
return *this;
}
template <typename BinaryOperation>
constexpr Vec& TransformInPlace(const Vec& other, BinaryOperation op)
{
return TransformInPlace(other.begin(), op);
}
constexpr Vec operator-() const
{
return TransformResult(Math::Negate<T>);
}
constexpr Vec operator+(const Vec& other) const
{
return TransformResult(other, Math::Add<T>);
}
constexpr Vec operator-(const Vec& other) const
{
return TransformResult(other, Math::Subtract<T>);
}
constexpr Vec operator*(const Vec& other) const
{
return TransformResult(other, Math::Multiply<T>);
}
constexpr Vec operator*(const T& scalar) const
{
return TransformResult([scalar](T value) { return value * scalar; });
}
constexpr Vec operator/(const Vec& other) const
{
return TransformResult(other, Math::Divide<T>);
}
constexpr Vec operator/(const T& scalar) const
{
return TransformResult([scalar](T value) { return value / scalar; });
}
constexpr Vec operator%(const Vec& other) const
{
return TransformResult(other, Math::Modulo<T>);
}
constexpr Vec operator%(const T& scalar) const
{
return TransformResult([scalar](T value) { return value % scalar; });
}
constexpr Vec& operator+=(const Vec& other)
{
return TransformInPlace(other, Math::Add<T>);
}
constexpr Vec& operator-=(const Vec& other)
{
return TransformInPlace(other, Math::Subtract<T>);
}
constexpr Vec& operator*=(const Vec& other)
{
return TransformInPlace(other, Math::Multiply<T>);
}
constexpr Vec& operator*=(const T& scalar)
{
return TransformInPlace([scalar](T value) { return value * scalar; });
}
constexpr Vec& operator/=(const Vec& other)
{
return TransformInPlace(other, Math::Divide<T>);
}
constexpr Vec& operator/=(const T& scalar)
{
return TransformInPlace([scalar](T value) { return value / scalar; });
}
constexpr Vec& operator%=(const Vec& other)
{
return TransformInPlace(other, Math::Modulo<T>);
}
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 } };
};
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)
{
return sqrtf(J{ lengthSqr(a) });
}
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;
}
template <typename T, size_t Size>
constexpr Vec<T, Size> Min(const Vec<T, Size>& a, const Vec<T, Size>& b)
{
return Util::TransformResult<Vec<T, Size>>(a.begin(), a.end(), b.begin(), [](T val_a, T val_b){ return Min(val_a, val_b); });
}
template <typename T, size_t Size>
constexpr Vec<T, Size> Max(const Vec<T, Size>& a, const Vec<T, Size>& b)
{
return Util::TransformResult<Vec<T, Size>>(a.begin(), a.end(), b.begin(), [](T val_a, T val_b){ return Max(val_a, val_b); });
}
using vec1 = Vec<float, 1>;
using vec2 = Vec<float, 2>;
using vec3 = Vec<float, 3>;
using vec4 = Vec<float, 4>;
constexpr vec1 operator"" _vec1(long double value) { return vec1{static_cast<float>(value)}; }
constexpr vec1 operator"" _vec1(unsigned long long value) { return vec1{static_cast<float>(value)}; }
constexpr vec2 operator"" _vec2(long double value) { return vec2{static_cast<float>(value)}; }
constexpr vec2 operator"" _vec2(unsigned long long value) { return vec2{static_cast<float>(value)}; }
constexpr vec3 operator"" _vec3(long double value) { return vec3{static_cast<float>(value)}; }
constexpr vec3 operator"" _vec3(unsigned long long value) { return vec3{static_cast<float>(value)}; }
constexpr vec4 operator"" _vec4(long double value) { return vec4{static_cast<float>(value)}; }
constexpr vec4 operator"" _vec4(unsigned long long value) { return vec4{static_cast<float>(value)}; }
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
};
}
}