298 lines
9.1 KiB
C++
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(Math::Add<T>);
|
|
}
|
|
|
|
constexpr Vec& operator-=(const Vec& other)
|
|
{
|
|
return TransformInPlace(Math::Subtract<T>);
|
|
}
|
|
|
|
constexpr Vec& operator*=(const Vec& other)
|
|
{
|
|
return TransformInPlace(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(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(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
|
|
};
|
|
}
|
|
|
|
}
|