| // | |
| // 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 VectorBase<Dimension, Type> &other) const; | |
| bool operator!=(const VectorBase<Dimension, Type> &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 VectorBase<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 VectorBase<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_ |