#pragma once #include #include #include #include #include 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 struct VectorAlignmentHelper { static constexpr size_t Alignment = (Size % 4zu == 0 && sizeof(T) == 4zu) ? Max(16zu, alignof(T)) : alignof(T); }; template struct Vec : public Swizzle::Alignment, Size> { static constexpr size_t Alignment = VectorAlignmentHelper::Alignment; using DefaultLengthType = DefaultLengthTypeResolver::LengthType; using DefaultLengthVec = Vec; using Swizzle::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 constexpr Vec TransformResult(UnaryOperation op) const { return Util::TransformResult(begin(), end(), op); } template constexpr Vec TransformResult(const T *other, BinaryOperation op) const { return Util::TransformResult(begin(), end(), other, op); } template constexpr Vec TransformResult(const Vec& other, BinaryOperation op) const { return TransformResult(other.begin(), op); } template constexpr Vec& TransformInPlace(UnaryOperation op) { Util::Transform(begin(), end(), begin(), op); return *this; } template constexpr Vec& TransformInPlace(const T *other, BinaryOperation op) { Util::Transform(begin(), end(), other, begin(), op); return *this; } template constexpr Vec& TransformInPlace(const Vec& other, BinaryOperation op) { return TransformInPlace(other.begin(), op); } constexpr Vec operator-() const { return TransformResult(Math::Negate); } constexpr Vec operator+(const Vec& other) const { return TransformResult(other, Math::Add); } constexpr Vec operator-(const Vec& other) const { return TransformResult(other, Math::Subtract); } constexpr Vec operator*(const Vec& other) const { return TransformResult(other, Math::Multiply); } 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); } 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); } 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); } constexpr Vec& operator-=(const Vec& other) { return TransformInPlace(other, Math::Subtract); } constexpr Vec& operator*=(const Vec& other) { return TransformInPlace(other, Math::Multiply); } 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); } 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); } 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 constexpr Vec operator*(T scalar, const Vec& Vec) { return Vec.TransformResult([scalar](T value) { return scalar * value; }); } template constexpr Vec operator/(T scalar, const Vec& Vec) { return Vec.TransformResult([scalar](T value) { return scalar / value; }); } template constexpr Vec operator%(T scalar, const Vec& Vec) { return Vec.TransformResult([scalar](T value) { return scalar % value; }); } template constexpr T accumulate(const Vec& a, T init = T{}) { return Accumulate(a.begin(), a.end(), init); } template constexpr T dot(const Vec& a, const Vec& b) { return accumulate(a * b); } template constexpr T lengthSqr(const Vec& a) { return dot(a, a); } template ::DefaultLengthType> constexpr J length(const Vec& a) { return sqrtf(J{ lengthSqr(a) }); } template ::DefaultLengthType> constexpr Vec normalize(const Vec& a) { return a * J{ rcp( length(a) ) }; } template ::DefaultLengthType> constexpr Vec rcp(const Vec& a) { return TransformResult>(a.begin(), a.end(), [](T value){ return rcp(value); }); } template constexpr bool empty(const Vec& a) { return a == Vec::Zero; } template constexpr bool identity(const Vec& a) { return a == Vec::Identity; } template constexpr Vec Min(const Vec& a, const Vec& b) { return Util::TransformResult>(a.begin(), a.end(), b.begin(), [](T val_a, T val_b){ return Min(val_a, val_b); }); } template constexpr Vec Max(const Vec& a, const Vec& b) { return Util::TransformResult>(a.begin(), a.end(), b.begin(), [](T val_a, T val_b){ return Max(val_a, val_b); }); } using vec1 = Vec; using vec2 = Vec; using vec3 = Vec; using vec4 = Vec; constexpr vec1 operator"" _vec1(long double value) { return vec1{static_cast(value)}; } constexpr vec1 operator"" _vec1(unsigned long long value) { return vec1{static_cast(value)}; } constexpr vec2 operator"" _vec2(long double value) { return vec2{static_cast(value)}; } constexpr vec2 operator"" _vec2(unsigned long long value) { return vec2{static_cast(value)}; } constexpr vec3 operator"" _vec3(long double value) { return vec3{static_cast(value)}; } constexpr vec3 operator"" _vec3(unsigned long long value) { return vec3{static_cast(value)}; } constexpr vec4 operator"" _vec4(long double value) { return vec4{static_cast(value)}; } constexpr vec4 operator"" _vec4(unsigned long long value) { return vec4{static_cast(value)}; } constexpr float cross(const vec2& a, const vec2& b) { return a.x * b.y - b.x * a.y; } constexpr 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 }; } }