diff options
Diffstat (limited to 'gfx/angle/checkout/src/common/vector_utils.h')
-rw-r--r-- | gfx/angle/checkout/src/common/vector_utils.h | 523 |
1 files changed, 523 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/common/vector_utils.h b/gfx/angle/checkout/src/common/vector_utils.h new file mode 100644 index 0000000000..d23a836288 --- /dev/null +++ b/gfx/angle/checkout/src/common/vector_utils.h @@ -0,0 +1,523 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// vector_utils.h: Utility classes implementing various vector operations + +#ifndef COMMON_VECTOR_UTILS_H_ +#define COMMON_VECTOR_UTILS_H_ + +#include <cmath> +#include <cstddef> +#include <ostream> +#include <type_traits> + +namespace angle +{ + +template <size_t Dimension, typename Type> +class Vector; + +using Vector2 = Vector<2, float>; +using Vector3 = Vector<3, float>; +using Vector4 = Vector<4, float>; + +using Vector2I = Vector<2, int>; +using Vector3I = Vector<3, int>; +using Vector4I = Vector<4, int>; + +using Vector2U = Vector<2, unsigned int>; +using Vector3U = Vector<3, unsigned int>; +using Vector4U = Vector<4, unsigned int>; + +template <size_t Dimension, typename Type> +class VectorBase +{ + public: + using VectorN = Vector<Dimension, Type>; + + // Constructors + VectorBase() = default; + explicit VectorBase(Type element); + + template <typename Type2> + VectorBase(const VectorBase<Dimension, Type2> &other); + + template <typename Arg1, typename Arg2, typename... Args> + VectorBase(const Arg1 &arg1, const Arg2 &arg2, const Args &... args); + + // Access the vector backing storage directly + const Type *data() const { return mData; } + Type *data() { return mData; } + constexpr size_t size() const { return Dimension; } + + // Load or store the pointer from / to raw data + static VectorN Load(const Type *source); + static void Store(const VectorN &source, Type *destination); + + // Index the vector + Type &operator[](size_t i) { return mData[i]; } + const Type &operator[](size_t i) const { return mData[i]; } + + // Basic arithmetic operations + VectorN operator+() const; + VectorN operator-() const; + VectorN operator+(const VectorN &other) const; + VectorN operator-(const VectorN &other) const; + VectorN operator*(const VectorN &other) const; + VectorN operator/(const VectorN &other) const; + VectorN operator*(Type other) const; + VectorN operator/(Type other) const; + friend VectorN operator*(Type a, const VectorN &b) { return b * a; } + + // Compound arithmetic operations + VectorN &operator+=(const VectorN &other); + VectorN &operator-=(const VectorN &other); + VectorN &operator*=(const VectorN &other); + VectorN &operator/=(const VectorN &other); + VectorN &operator*=(Type other); + VectorN &operator/=(Type other); + + // Comparison operators + bool operator==(const VectorN &other) const; + bool operator!=(const VectorN &other) const; + + // Other arithmetic operations + Type length() const; + Type lengthSquared() const; + Type dot(const VectorBase<Dimension, Type> &other) const; + VectorN normalized() const; + + protected: + template <size_t CurrentIndex, size_t OtherDimension, typename OtherType, typename... Args> + void initWithList(const Vector<OtherDimension, OtherType> &arg1, const Args &... args); + + // Some old compilers consider this function an alternative for initWithList(Vector) + // when the variant above is more precise. Use SFINAE on the return value to hide + // this variant for non-arithmetic types. The return value is still void. + template <size_t CurrentIndex, typename OtherType, typename... Args> + typename std::enable_if<std::is_arithmetic<OtherType>::value>::type initWithList( + OtherType arg1, + const Args &... args); + + template <size_t CurrentIndex> + void initWithList() const; + + template <size_t Dimension2, typename Type2> + friend class VectorBase; + + Type mData[Dimension]; +}; + +template <size_t Dimension, typename Type> +std::ostream &operator<<(std::ostream &ostream, const VectorBase<Dimension, Type> &vector); + +template <typename Type> +class Vector<2, Type> : public VectorBase<2, Type> +{ + public: + // Import the constructors defined in VectorBase + using VectorBase<2, Type>::VectorBase; + + // Element shorthands + Type &x() { return this->mData[0]; } + Type &y() { return this->mData[1]; } + + const Type &x() const { return this->mData[0]; } + const Type &y() const { return this->mData[1]; } +}; + +template <typename Type> +std::ostream &operator<<(std::ostream &ostream, const Vector<2, Type> &vector); + +template <typename Type> +class Vector<3, Type> : public VectorBase<3, Type> +{ + public: + // Import the constructors defined in VectorBase + using VectorBase<3, Type>::VectorBase; + + // Additional operations + Vector<3, Type> cross(const Vector<3, Type> &other) const; + + // Element shorthands + Type &x() { return this->mData[0]; } + Type &y() { return this->mData[1]; } + Type &z() { return this->mData[2]; } + + const Type &x() const { return this->mData[0]; } + const Type &y() const { return this->mData[1]; } + const Type &z() const { return this->mData[2]; } +}; + +template <typename Type> +std::ostream &operator<<(std::ostream &ostream, const Vector<3, Type> &vector); + +template <typename Type> +class Vector<4, Type> : public VectorBase<4, Type> +{ + public: + // Import the constructors defined in VectorBase + using VectorBase<4, Type>::VectorBase; + + // Element shorthands + Type &x() { return this->mData[0]; } + Type &y() { return this->mData[1]; } + Type &z() { return this->mData[2]; } + Type &w() { return this->mData[3]; } + + const Type &x() const { return this->mData[0]; } + const Type &y() const { return this->mData[1]; } + const Type &z() const { return this->mData[2]; } + const Type &w() const { return this->mData[3]; } +}; + +template <typename Type> +std::ostream &operator<<(std::ostream &ostream, const Vector<4, Type> &vector); + +// Implementation of constructors and misc operations + +template <size_t Dimension, typename Type> +VectorBase<Dimension, Type>::VectorBase(Type element) +{ + for (size_t i = 0; i < Dimension; ++i) + { + mData[i] = element; + } +} + +template <size_t Dimension, typename Type> +template <typename Type2> +VectorBase<Dimension, Type>::VectorBase(const VectorBase<Dimension, Type2> &other) +{ + for (size_t i = 0; i < Dimension; ++i) + { + mData[i] = static_cast<Type>(other.mData[i]); + } +} + +// Ideally we would like to have only two constructors: +// - a scalar constructor that takes Type as a parameter +// - a compound constructor +// However if we define the compound constructor for when it has a single arguments, then calling +// Vector2(0.0) will be ambiguous. To solve this we take advantage of there being a single compound +// constructor with a single argument, which is the copy constructor. We end up with three +// constructors: +// - the scalar constructor +// - the copy constructor +// - the compound constructor for two or more arguments, hence the arg1, and arg2 here. +template <size_t Dimension, typename Type> +template <typename Arg1, typename Arg2, typename... Args> +VectorBase<Dimension, Type>::VectorBase(const Arg1 &arg1, const Arg2 &arg2, const Args &... args) +{ + initWithList<0>(arg1, arg2, args...); +} + +template <size_t Dimension, typename Type> +template <size_t CurrentIndex, size_t OtherDimension, typename OtherType, typename... Args> +void VectorBase<Dimension, Type>::initWithList(const Vector<OtherDimension, OtherType> &arg1, + const Args &... args) +{ + static_assert(CurrentIndex + OtherDimension <= Dimension, + "Too much data in the vector constructor."); + for (size_t i = 0; i < OtherDimension; ++i) + { + mData[CurrentIndex + i] = static_cast<Type>(arg1.mData[i]); + } + initWithList<CurrentIndex + OtherDimension>(args...); +} + +template <size_t Dimension, typename Type> +template <size_t CurrentIndex, typename OtherType, typename... Args> +typename std::enable_if<std::is_arithmetic<OtherType>::value>::type +VectorBase<Dimension, Type>::initWithList(OtherType arg1, const Args &... args) +{ + static_assert(CurrentIndex + 1 <= Dimension, "Too much data in the vector constructor."); + mData[CurrentIndex] = static_cast<Type>(arg1); + initWithList<CurrentIndex + 1>(args...); +} + +template <size_t Dimension, typename Type> +template <size_t CurrentIndex> +void VectorBase<Dimension, Type>::initWithList() const +{ + static_assert(CurrentIndex == Dimension, "Not enough data in the vector constructor."); +} + +template <size_t Dimension, typename Type> +Vector<Dimension, Type> VectorBase<Dimension, Type>::Load(const Type *source) +{ + Vector<Dimension, Type> result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = source[i]; + } + return result; +} + +template <size_t Dimension, typename Type> +void VectorBase<Dimension, Type>::Store(const Vector<Dimension, Type> &source, Type *destination) +{ + for (size_t i = 0; i < Dimension; ++i) + { + destination[i] = source.mData[i]; + } +} + +// Implementation of basic arithmetic operations +template <size_t Dimension, typename Type> +Vector<Dimension, Type> VectorBase<Dimension, Type>::operator+() const +{ + Vector<Dimension, Type> result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = +mData[i]; + } + return result; +} + +template <size_t Dimension, typename Type> +Vector<Dimension, Type> VectorBase<Dimension, Type>::operator-() const +{ + Vector<Dimension, Type> result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = -mData[i]; + } + return result; +} + +template <size_t Dimension, typename Type> +Vector<Dimension, Type> VectorBase<Dimension, Type>::operator+( + const Vector<Dimension, Type> &other) const +{ + Vector<Dimension, Type> result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = mData[i] + other.mData[i]; + } + return result; +} + +template <size_t Dimension, typename Type> +Vector<Dimension, Type> VectorBase<Dimension, Type>::operator-( + const Vector<Dimension, Type> &other) const +{ + Vector<Dimension, Type> result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = mData[i] - other.mData[i]; + } + return result; +} + +template <size_t Dimension, typename Type> +Vector<Dimension, Type> VectorBase<Dimension, Type>::operator*( + const Vector<Dimension, Type> &other) const +{ + Vector<Dimension, Type> result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = mData[i] * other.mData[i]; + } + return result; +} + +template <size_t Dimension, typename Type> +Vector<Dimension, Type> VectorBase<Dimension, Type>::operator/( + const Vector<Dimension, Type> &other) const +{ + Vector<Dimension, Type> result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = mData[i] / other.mData[i]; + } + return result; +} + +template <size_t Dimension, typename Type> +Vector<Dimension, Type> VectorBase<Dimension, Type>::operator*(Type other) const +{ + Vector<Dimension, Type> result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = mData[i] * other; + } + return result; +} + +template <size_t Dimension, typename Type> +Vector<Dimension, Type> VectorBase<Dimension, Type>::operator/(Type other) const +{ + Vector<Dimension, Type> result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = mData[i] / other; + } + return result; +} + +// Implementation of compound arithmetic operations +template <size_t Dimension, typename Type> +Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator+=( + const Vector<Dimension, Type> &other) +{ + for (size_t i = 0; i < Dimension; ++i) + { + mData[i] += other.mData[i]; + } + return *static_cast<Vector<Dimension, Type> *>(this); +} + +template <size_t Dimension, typename Type> +Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator-=( + const Vector<Dimension, Type> &other) +{ + for (size_t i = 0; i < Dimension; ++i) + { + mData[i] -= other.mData[i]; + } + return *static_cast<Vector<Dimension, Type> *>(this); +} + +template <size_t Dimension, typename Type> +Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator*=( + const Vector<Dimension, Type> &other) +{ + for (size_t i = 0; i < Dimension; ++i) + { + mData[i] *= other.mData[i]; + } + return *static_cast<Vector<Dimension, Type> *>(this); +} + +template <size_t Dimension, typename Type> +Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator/=( + const Vector<Dimension, Type> &other) +{ + for (size_t i = 0; i < Dimension; ++i) + { + mData[i] /= other.mData[i]; + } + return *static_cast<Vector<Dimension, Type> *>(this); +} + +template <size_t Dimension, typename Type> +Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator*=(Type other) +{ + for (size_t i = 0; i < Dimension; ++i) + { + mData[i] *= other; + } + return *static_cast<Vector<Dimension, Type> *>(this); +} + +template <size_t Dimension, typename Type> +Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator/=(Type other) +{ + for (size_t i = 0; i < Dimension; ++i) + { + mData[i] /= other; + } + return *static_cast<Vector<Dimension, Type> *>(this); +} + +// Implementation of comparison operators +template <size_t Dimension, typename Type> +bool VectorBase<Dimension, Type>::operator==(const Vector<Dimension, Type> &other) const +{ + for (size_t i = 0; i < Dimension; ++i) + { + if (mData[i] != other.mData[i]) + { + return false; + } + } + return true; +} + +template <size_t Dimension, typename Type> +bool VectorBase<Dimension, Type>::operator!=(const Vector<Dimension, Type> &other) const +{ + return !(*this == other); +} + +// Implementation of other arithmetic operations +template <size_t Dimension, typename Type> +Type VectorBase<Dimension, Type>::length() const +{ + static_assert(std::is_floating_point<Type>::value, + "VectorN::length is only defined for floating point vectors"); + return std::sqrt(lengthSquared()); +} + +template <size_t Dimension, typename Type> +Type VectorBase<Dimension, Type>::lengthSquared() const +{ + return dot(*this); +} + +template <size_t Dimension, typename Type> +Type VectorBase<Dimension, Type>::dot(const VectorBase<Dimension, Type> &other) const +{ + Type sum = Type(); + for (size_t i = 0; i < Dimension; ++i) + { + sum += mData[i] * other.mData[i]; + } + return sum; +} + +template <size_t Dimension, typename Type> +std::ostream &operator<<(std::ostream &ostream, const VectorBase<Dimension, Type> &vector) +{ + ostream << "[ "; + for (size_t elementIdx = 0; elementIdx < Dimension; elementIdx++) + { + if (elementIdx > 0) + { + ostream << ", "; + } + ostream << vector.data()[elementIdx]; + } + ostream << " ]"; + return ostream; +} + +template <size_t Dimension, typename Type> +Vector<Dimension, Type> VectorBase<Dimension, Type>::normalized() const +{ + static_assert(std::is_floating_point<Type>::value, + "VectorN::normalized is only defined for floating point vectors"); + return *this / length(); +} + +template <typename Type> +std::ostream &operator<<(std::ostream &ostream, const Vector<2, Type> &vector) +{ + return ostream << static_cast<const VectorBase<2, Type> &>(vector); +} + +template <typename Type> +Vector<3, Type> Vector<3, Type>::cross(const Vector<3, Type> &other) const +{ + return Vector<3, Type>(y() * other.z() - z() * other.y(), z() * other.x() - x() * other.z(), + x() * other.y() - y() * other.x()); +} + +template <typename Type> +std::ostream &operator<<(std::ostream &ostream, const Vector<3, Type> &vector) +{ + return ostream << static_cast<const VectorBase<3, Type> &>(vector); +} + +template <typename Type> +std::ostream &operator<<(std::ostream &ostream, const Vector<4, Type> &vector) +{ + return ostream << static_cast<const VectorBase<4, Type> &>(vector); +} + +} // namespace angle + +#endif // COMMON_VECTOR_UTILS_H_ |