1007 lines
33 KiB
C++
1007 lines
33 KiB
C++
/*
|
|
* Copyright 2014 Google Inc. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#ifndef MATHFU_VECTOR_H_
|
|
#define MATHFU_VECTOR_H_
|
|
|
|
#include "mathfu/utilities.h"
|
|
|
|
#include <math.h>
|
|
|
|
/// @file mathfu/vector.h Vector
|
|
/// @brief Vector class and functions.
|
|
/// @addtogroup mathfu_vector
|
|
|
|
// Disable spurious warnings generated by MATHFU_VECTOR_OPERATION().
|
|
#if defined(_MSC_VER)
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 4127) // conditional expression is constant
|
|
#if _MSC_VER >= 1900 // MSVC 2015
|
|
#pragma warning(disable : 4456) // allow shadowing in unrolled loops
|
|
#endif // _MSC_VER >= 1900
|
|
#elif defined(__clang__)
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Warray-bounds"
|
|
#endif
|
|
|
|
/// @cond MATHFU_INTERNAL
|
|
#define MATHFU_VECTOR_OPERATION(OP) MATHFU_UNROLLED_LOOP(i, d, OP)
|
|
/// @endcond
|
|
|
|
/// @cond MATHFU_INTERNAL
|
|
#define MATHFU_VECTOR_OPERATOR(OP) \
|
|
{ \
|
|
Vector<T, d> result; \
|
|
MATHFU_VECTOR_OPERATION(result[i] = OP); \
|
|
return result; \
|
|
}
|
|
/// @endcond
|
|
|
|
/// @cond MATHFU_INTERNAL
|
|
#define MATHFU_VECTOR_SELF_OPERATOR(OP) \
|
|
{ \
|
|
MATHFU_VECTOR_OPERATION(OP); \
|
|
return *this; \
|
|
}
|
|
/// @endcond
|
|
|
|
namespace mathfu {
|
|
|
|
template <class T, int d>
|
|
class Vector;
|
|
|
|
/// @cond MATHFU_INTERNAL
|
|
template <class T, int d>
|
|
static inline T DotProductHelper(const Vector<T, d>& v1,
|
|
const Vector<T, d>& v2);
|
|
template <class T>
|
|
static inline T DotProductHelper(const Vector<T, 2>& v1,
|
|
const Vector<T, 2>& v2);
|
|
template <class T>
|
|
static inline T DotProductHelper(const Vector<T, 3>& v1,
|
|
const Vector<T, 3>& v2);
|
|
template <class T>
|
|
static inline T DotProductHelper(const Vector<T, 4>& v1,
|
|
const Vector<T, 4>& v2);
|
|
|
|
template <typename T, int d, typename CompatibleT>
|
|
static inline Vector<T, d> FromTypeHelper(const CompatibleT& compatible);
|
|
|
|
template <typename T, int d, typename CompatibleT>
|
|
static inline CompatibleT ToTypeHelper(const Vector<T, d>& v);
|
|
/// @endcond
|
|
|
|
/// @addtogroup mathfu_vector
|
|
/// @{
|
|
|
|
/// @class VectorPacked "mathfu/vector.h"
|
|
/// @brief Packed N-dimensional vector.
|
|
///
|
|
/// Some Vector classes are padded so that it's possible to use the data
|
|
/// structures with SIMD instructions. This structure can be used in
|
|
/// conjunction with unpacked Vector classes to pack data
|
|
/// into flat arrays suitable for sending to a GPU (e.g vertex buffers).
|
|
///
|
|
/// <p>
|
|
/// For example, to pack (store) an unpacked to packed vector:<br>
|
|
/// <blockquote><code><pre>
|
|
/// VectorPacked<float, 3> packed;
|
|
/// Vector<float, 3> vector(3, 2, 1);
|
|
/// vector.Pack(&packed);
|
|
/// </pre></code></blockquote>
|
|
/// or<br>
|
|
/// <blockquote><code><pre>
|
|
/// Vector<float, 3> vector(3, 2, 1);
|
|
/// VectorPacked<float, 3> packed = vector;
|
|
/// </pre></code></blockquote>
|
|
/// </p>
|
|
///
|
|
/// <p>
|
|
/// To initialize a vector from a packed vector:<br>
|
|
/// <blockquote><code><pre>
|
|
/// VectorPacked<float, 3> packed = { 3, 2, 1 };
|
|
/// Vector<float, 3> vector(packed);
|
|
/// </pre></code></blockquote>
|
|
///
|
|
/// @tparam T type of VectorPacked elements.
|
|
/// @tparam d dimensions (number of elements) in the VectorPacked structure.
|
|
template <class T, int d>
|
|
struct VectorPacked {
|
|
/// Create an uninitialized VectorPacked.
|
|
VectorPacked() {}
|
|
|
|
/// Create a VectorPacked from a Vector.
|
|
///
|
|
/// Both VectorPacked and Vector must have the same number of dimensions.
|
|
/// @param vector Vector to create the VectorPacked from.
|
|
explicit VectorPacked(const Vector<T, d>& vector) { vector.Pack(this); }
|
|
|
|
/// Copy a Vector to a VectorPacked.
|
|
///
|
|
/// Both VectorPacked and Vector must have the same number of dimensions.
|
|
/// @param vector Vector to copy to the VectorPacked.
|
|
/// @returns A reference to this VectorPacked.
|
|
VectorPacked& operator=(const Vector<T, d>& vector) {
|
|
vector.Pack(this);
|
|
return *this;
|
|
}
|
|
|
|
/// Elements of the packed vector one per dimension.
|
|
T data[d];
|
|
};
|
|
/// @}
|
|
|
|
/// @addtogroup mathfu_vector
|
|
/// @{
|
|
/// @class Vector "mathfu/vector.h"
|
|
/// @brief Vector of d elements with type T
|
|
///
|
|
/// Vector stores <b>d</b> elements of type <b>T</b> and provides a set
|
|
/// functions to perform operations on the set of elements.
|
|
///
|
|
/// @tparam T type of Vector elements.
|
|
/// @tparam d dimensions (number of elements) in the Vector structure.
|
|
template <class T, int d>
|
|
class Vector {
|
|
public:
|
|
/// @brief Element type to enable reference by other classes.
|
|
typedef T Scalar;
|
|
|
|
/// @brief Create an uninitialized Vector.
|
|
inline Vector() {}
|
|
|
|
/// @brief Create a vector from another vector copying each element.
|
|
///
|
|
/// @param v Vector that the data will be copied from.
|
|
inline Vector(const Vector<T, d>& v) {
|
|
MATHFU_VECTOR_OPERATION(data_[i] = v.data_[i]);
|
|
}
|
|
|
|
/// @brief Create a vector from another vector of a different type.
|
|
///
|
|
/// This copies each element of a Vector which makes it possible to between
|
|
/// vectors of different types, for example
|
|
/// <code>float/double/int</code> vectors.
|
|
/// @param v Vector that the data will be copied from.
|
|
/// @tparam U type of Vector elements to copy.
|
|
template <typename U>
|
|
explicit inline Vector(const Vector<U, d>& v) {
|
|
MATHFU_VECTOR_OPERATION(data_[i] = static_cast<T>(v[i]));
|
|
}
|
|
|
|
/// @brief Create a vector from a single float.
|
|
///
|
|
/// Each elements is set to be equal to the value given.
|
|
/// @param s Scalar value that the vector will be initialized to.
|
|
explicit inline Vector(const T& s) { MATHFU_VECTOR_OPERATION(data_[i] = s); }
|
|
|
|
/// @brief Create a vector form the first d elements of an array.
|
|
///
|
|
/// @param a Array of values that the vector will be iniitlized to.
|
|
explicit inline Vector(const T* a) {
|
|
MATHFU_VECTOR_OPERATION(data_[i] = a[i]);
|
|
}
|
|
|
|
/// @brief Create a vector from two values.
|
|
///
|
|
/// @note This method only works when the vector is of size two.
|
|
///
|
|
/// @param s1 Scalar value for the first element of the vector.
|
|
/// @param s2 Scalar value for the second element of the vector.
|
|
inline Vector(const T& s1, const T& s2) {
|
|
MATHFU_STATIC_ASSERT(d == 2);
|
|
data_[0] = s1;
|
|
data_[1] = s2;
|
|
}
|
|
|
|
/// @brief Create a vector from three values.
|
|
///
|
|
/// @note This method only works when the vector is of size three.
|
|
///
|
|
/// @param s1 Scalar value for the first element of the vector.
|
|
/// @param s2 Scalar value for the second element of the vector.
|
|
/// @param s3 Scalar value for the third element of the vector.
|
|
inline Vector(const T& s1, const T& s2, const T& s3) {
|
|
MATHFU_STATIC_ASSERT(d == 3);
|
|
data_[0] = s1;
|
|
data_[1] = s2;
|
|
data_[2] = s3;
|
|
}
|
|
|
|
/// @brief Create a vector from a 2 component vector and a third value.
|
|
///
|
|
/// @note This method only works when the vector is of size three.
|
|
///
|
|
/// @param v12 Vector containing the first 2 values.
|
|
/// @param s3 Scalar value for the third element of the vector.
|
|
inline Vector(const Vector<T, 2>& v12, const T& s3) {
|
|
MATHFU_STATIC_ASSERT(d == 3);
|
|
data_[0] = v12[0];
|
|
data_[1] = v12[1];
|
|
data_[2] = s3;
|
|
}
|
|
|
|
/// @brief Create a vector from four values.
|
|
///
|
|
/// @note This method only works when the vector is of size four.
|
|
///
|
|
/// @param s1 Scalar value for the first element of the vector.
|
|
/// @param s2 Scalar value for the second element of the vector.
|
|
/// @param s3 Scalar value for the third element of the vector.
|
|
/// @param s4 Scalar value for the forth element of the vector.
|
|
inline Vector(const T& s1, const T& s2, const T& s3, const T& s4) {
|
|
MATHFU_STATIC_ASSERT(d == 4);
|
|
data_[0] = s1;
|
|
data_[1] = s2;
|
|
data_[2] = s3;
|
|
data_[3] = s4;
|
|
}
|
|
|
|
/// @brief Create a 4-dimensional vector from a Vector<T, 3>.
|
|
///
|
|
/// The last element is initialized to the specified value.
|
|
/// @note This method only works with 4 element vectors.
|
|
///
|
|
/// @param vector3 Vector used to initialize the first 3 elements.
|
|
/// @param value Value used to set the last element of the vector.
|
|
inline Vector(const Vector<T, 3>& vector3, const T& value) {
|
|
MATHFU_STATIC_ASSERT(d == 4);
|
|
data_[0] = vector3[0];
|
|
data_[1] = vector3[1];
|
|
data_[2] = vector3[2];
|
|
data_[3] = value;
|
|
}
|
|
|
|
/// @brief Create a vector from two 2 component vectors.
|
|
///
|
|
/// @note This method only works when the vector is of size four.
|
|
///
|
|
/// @param v12 Vector containing the first 2 values.
|
|
/// @param v34 Vector containing the last 2 values.
|
|
inline Vector(const Vector<T, 2>& v12, const Vector<T, 2>& v34) {
|
|
MATHFU_STATIC_ASSERT(d == 4);
|
|
data_[0] = v12[0];
|
|
data_[1] = v12[1];
|
|
data_[2] = v34[0];
|
|
data_[3] = v34[1];
|
|
}
|
|
|
|
/// @brief Create a vector from packed vector (VectorPacked).
|
|
///
|
|
/// @param vector Packed vector used to initialize an unpacked.
|
|
explicit inline Vector(const VectorPacked<T, d>& vector) {
|
|
MATHFU_VECTOR_OPERATION(data_[i] = vector.data[i]);
|
|
}
|
|
|
|
/// @brief Access an element of the vector.
|
|
///
|
|
/// @param i Index of the element to access.
|
|
/// @return A reference to the accessed data that can be modified by the
|
|
/// caller.
|
|
inline T& operator()(const int i) { return data_[i]; }
|
|
|
|
/// @brief Access an element of the vector.
|
|
///
|
|
/// @param i Index of the element to access.
|
|
/// @return A reference to the accessed data.
|
|
inline const T& operator()(const int i) const { return data_[i]; }
|
|
|
|
/// @brief Access an element of the vector.
|
|
///
|
|
/// @param i Index of the element to access.
|
|
/// @return A reference to the accessed data that can be modified by the
|
|
/// caller.
|
|
inline T& operator[](const int i) { return data_[i]; }
|
|
|
|
/// @brief Access an element of the vector.
|
|
///
|
|
/// @param i Index of the element to access.
|
|
/// @return A const reference to the accessed.
|
|
inline const T& operator[](const int i) const { return data_[i]; }
|
|
|
|
/// @brief GLSL style 3 element accessor.
|
|
///
|
|
/// This only works with vectors that contain more than 3 elements.
|
|
/// @returns A 3-dimensional Vector containing the first 3 elements of
|
|
// this Vector.
|
|
inline Vector<T, 3> xyz() {
|
|
MATHFU_STATIC_ASSERT(d > 3);
|
|
return Vector<T, 3>(data_[0], data_[1], data_[2]);
|
|
}
|
|
|
|
/// @brief GLSL style 3 element accessor.
|
|
///
|
|
/// This only works with vectors that contain more than 3 elements.
|
|
/// @returns A 3-dimensional Vector containing the first 3 elements of
|
|
// this Vector.
|
|
inline const Vector<T, 3> xyz() const {
|
|
MATHFU_STATIC_ASSERT(d > 3);
|
|
return Vector<T, 3>(data_[0], data_[1], data_[2]);
|
|
}
|
|
|
|
/// @brief GLSL style 2 element accessor.
|
|
///
|
|
/// This only works with vectors that contain more than 2 elements.
|
|
/// @returns A 2-dimensional Vector with the first 2 elements of this Vector.
|
|
inline Vector<T, 2> xy() {
|
|
MATHFU_STATIC_ASSERT(d > 2);
|
|
return Vector<T, 2>(data_[0], data_[1]);
|
|
}
|
|
|
|
/// @brief GLSL style 2 element accessor.
|
|
///
|
|
/// This only works with vectors that contain more than 2 elements.
|
|
/// @returns A 2-dimensional Vector with the first 2 elements of this Vector.
|
|
inline const Vector<T, 2> xy() const {
|
|
MATHFU_STATIC_ASSERT(d > 2);
|
|
return Vector<T, 2>(data_[0], data_[1]);
|
|
}
|
|
|
|
/// @brief GLSL style 2 element accessor.
|
|
///
|
|
/// This only works with vectors that contain 4 elements.
|
|
/// @returns A 2-dimensional Vector with the last 2 elements of this Vector.
|
|
inline Vector<T, 2> zw() {
|
|
MATHFU_STATIC_ASSERT(d == 4);
|
|
return Vector<T, 2>(data_[2], data_[3]);
|
|
}
|
|
|
|
/// @brief GLSL style 2 element accessor.
|
|
///
|
|
/// This only works with vectors that contain 4 elements.
|
|
/// @returns A 2-dimensional Vector with the last 2 elements of this Vector.
|
|
inline const Vector<T, 2> zw() const {
|
|
MATHFU_STATIC_ASSERT(d == 4);
|
|
return Vector<T, 2>(data_[2], data_[3]);
|
|
}
|
|
|
|
/// @brief Pack a Vector to a packed "d" element vector structure.
|
|
///
|
|
/// @param vector Packed "d" element vector to write to.
|
|
inline void Pack(VectorPacked<T, d>* const vector) const {
|
|
MATHFU_VECTOR_OPERATION(vector->data[i] = data_[i]);
|
|
}
|
|
|
|
/// @brief Calculate the squared length of this vector.
|
|
///
|
|
/// @return The length of this vector squared.
|
|
inline T LengthSquared() const { return LengthSquaredHelper(*this); }
|
|
|
|
/// @brief Calculate the length of this vector.
|
|
///
|
|
/// @return The length of this vector.
|
|
inline T Length() const { return LengthHelper(*this); }
|
|
|
|
/// @brief Normalize this vector in-place.
|
|
///
|
|
/// @return The length of this vector.
|
|
inline T Normalize() { return NormalizeHelper(*this); }
|
|
|
|
/// @brief Calculate the normalized version of this vector.
|
|
///
|
|
/// @return The normalized vector.
|
|
inline Vector<T, d> Normalized() const { return NormalizedHelper(*this); }
|
|
|
|
/// @brief Load from any type that is some formulation of a length d array of
|
|
/// type T.
|
|
///
|
|
/// Essentially this is just a type cast and a load, but it happens safely
|
|
/// so that we avoid aliasing bugs.
|
|
///
|
|
/// @return `compatible` cast to `Vector<T,d>` and dereferenced.
|
|
template <typename CompatibleT>
|
|
static inline Vector<T, d> FromType(const CompatibleT& compatible) {
|
|
return FromTypeHelper<T, d, CompatibleT>(compatible);
|
|
}
|
|
|
|
/// @brief Load into any type that is some formulation of a length d array of
|
|
/// type T.
|
|
///
|
|
/// Essentially this is just a type cast and a load, but it happens safely
|
|
/// so that we avoid aliasing bugs.
|
|
///
|
|
/// @return `v` cast to `CompatibleT` and dereferenced.
|
|
template <typename CompatibleT>
|
|
static inline CompatibleT ToType(const Vector<T, d>& v) {
|
|
return ToTypeHelper<T, d, CompatibleT>(v);
|
|
}
|
|
|
|
/// @brief Calculate the dot product of two vectors.
|
|
///
|
|
/// @param v1 First vector.
|
|
/// @param v2 Second vector.
|
|
/// @return The dot product of v1 and v2.
|
|
static inline T DotProduct(const Vector<T, d>& v1, const Vector<T, d>& v2) {
|
|
return DotProductHelper(v1, v2);
|
|
}
|
|
|
|
/// @brief Calculate the hadamard or componentwise product of two vectors.
|
|
///
|
|
/// @param v1 First vector.
|
|
/// @param v2 Second vector.
|
|
/// @return The hadamard product of v1 and v2.
|
|
static inline Vector<T, d> HadamardProduct(const Vector<T, d>& v1,
|
|
const Vector<T, d>& v2) {
|
|
return HadamardProductHelper(v1, v2);
|
|
}
|
|
|
|
/// @brief Calculate the cross product of two vectors.
|
|
///
|
|
/// Note that this function is only defined for 3-dimensional Vectors.
|
|
/// @param v1 First vector.
|
|
/// @param v2 Second vector.
|
|
/// @return The cross product of v1 and v2.
|
|
static inline Vector<T, 3> CrossProduct(const Vector<T, 3>& v1,
|
|
const Vector<T, 3>& v2) {
|
|
return CrossProductHelper(v1, v2);
|
|
}
|
|
|
|
/// @brief Linearly interpolate two vectors.
|
|
///
|
|
/// @param v1 First vector.
|
|
/// @param v2 Second vector.
|
|
/// @param percent Percentage from v1 to v2 in range 0.0...1.0.
|
|
/// @return The hadamard product of v1 and v2.
|
|
static inline Vector<T, d> Lerp(const Vector<T, d>& v1,
|
|
const Vector<T, d>& v2, const T percent) {
|
|
return LerpHelper(v1, v2, percent);
|
|
}
|
|
|
|
/// @brief Generates a random vector.
|
|
///
|
|
/// The range of each component is bounded by min and max.
|
|
/// @param min Minimum value of the vector.
|
|
/// @param max Maximum value of the vector.
|
|
static inline Vector<T, d> RandomInRange(const Vector<T, d>& min,
|
|
const Vector<T, d>& max) {
|
|
return RandomInRangeHelper(min, max);
|
|
}
|
|
|
|
/// @brief Compare each component and returns max values.
|
|
///
|
|
/// @param v1 First vector.
|
|
/// @param v2 Second vector.
|
|
/// @return Max value of v1 and v2.
|
|
static inline Vector<T, d> Max(const Vector<T, d>& v1,
|
|
const Vector<T, d>& v2) {
|
|
return MaxHelper(v1, v2);
|
|
}
|
|
|
|
/// @brief Compare each component and returns min values.
|
|
///
|
|
/// @param v1 First vector.
|
|
/// @param v2 Second vector.
|
|
/// @return Min value of v1 and v2.
|
|
static inline Vector<T, d> Min(const Vector<T, d>& v1,
|
|
const Vector<T, d>& v2) {
|
|
return MinHelper(v1, v2);
|
|
}
|
|
|
|
MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE
|
|
|
|
/// Elements of the vector.
|
|
T data_[d];
|
|
};
|
|
/// @}
|
|
|
|
/// @addtogroup mathfu_vector
|
|
/// @{
|
|
|
|
/// @brief Compare 2 Vectors of the same size for equality.
|
|
///
|
|
/// @note: The likelyhood of two float values being the same is very small.
|
|
/// Instead consider comparing the difference between two float vectors using
|
|
/// LengthSquared() with an epsilon value.
|
|
/// For example, v1.LengthSquared(v2) < epsilon.
|
|
///
|
|
/// @return true if the 2 vectors contains the same value, false otherwise.
|
|
template <class T, int d>
|
|
inline bool operator==(const Vector<T, d>& lhs, const Vector<T, d>& rhs) {
|
|
for (int i = 0; i < d; ++i) {
|
|
if (lhs[i] != rhs[i]) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/// @brief Compare 2 Vectors of the same size for inequality.
|
|
///
|
|
/// @return true if the elements of two vectors differ, false otherwise.
|
|
template <class T, int d>
|
|
inline bool operator!=(const Vector<T, d>& lhs, const Vector<T, d>& rhs) {
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
/// @brief Negate all elements of the Vector.
|
|
///
|
|
/// @return A new Vector containing the result.
|
|
template <class T, int d>
|
|
inline Vector<T, d> operator-(const Vector<T, d>& v) {
|
|
MATHFU_VECTOR_OPERATOR(-v.data_[i]);
|
|
}
|
|
|
|
/// @brief Multiply a Vector by a scalar.
|
|
///
|
|
/// Multiplies each component of the specified Vector with a scalar.
|
|
///
|
|
/// @param s scalar to multiply.
|
|
/// @param v Vector to multiply.
|
|
/// @return Vector containing the result.
|
|
/// @related Vector
|
|
template <class T, int d>
|
|
inline Vector<T, d> operator*(const T& s, const Vector<T, d>& v) {
|
|
MATHFU_VECTOR_OPERATOR(v.data_[i] * s);
|
|
}
|
|
|
|
/// @brief Divide a Vector by a scalar.
|
|
///
|
|
/// Divides each component of the specified Vector by a scalar.
|
|
///
|
|
/// @param v Vector to be divided.
|
|
/// @param s scalar to divide the vector by.
|
|
/// @return Vector containing the result.
|
|
/// @related Vector
|
|
template <class T, int d>
|
|
inline Vector<T, d> operator/(const Vector<T, d>& v, const T& s) {
|
|
MATHFU_VECTOR_OPERATOR(v.data_[i] / s);
|
|
}
|
|
|
|
/// @brief Add a scalar to each element of a Vector.
|
|
///
|
|
/// @param s scalar to add to each element of a Vector.
|
|
/// @param v Vector to add the scalar to.
|
|
/// @return Vector containing the result.
|
|
/// @related Vector
|
|
template <class T, int d>
|
|
inline Vector<T, d> operator+(const T& s, const Vector<T, d>& v) {
|
|
MATHFU_VECTOR_OPERATOR(v.data_[i] + s);
|
|
}
|
|
|
|
/// @brief Subtract a scalar from each element of a Vector.
|
|
///
|
|
/// @param s scalar to subtract from each element of a Vector.
|
|
/// @param v Vector to subtract the scalar from.
|
|
/// @return Vector containing the result.
|
|
/// @related Vector
|
|
template <class T, int d>
|
|
inline Vector<T, d> operator-(const T& s, const Vector<T, d>& v) {
|
|
MATHFU_VECTOR_OPERATOR(v.data_[i] - s);
|
|
}
|
|
|
|
/// @brief Multiply a vector by another Vector.
|
|
///
|
|
/// In line with GLSL, this performs component-wise multiplication.
|
|
/// @param lhs First vector to use as a starting point.
|
|
/// @param rhs Second vector to multiply by.
|
|
/// @return A new Vector containing the result.
|
|
template <class T, int d>
|
|
inline Vector<T, d> operator*(const Vector<T, d>& lhs,
|
|
const Vector<T, d>& rhs) {
|
|
return HadamardProductHelper(lhs, rhs);
|
|
}
|
|
|
|
/// @brief Divide a vector by another Vector.
|
|
///
|
|
/// In line with GLSL, this performs component-wise division.
|
|
/// @param lhs First vector to use as a starting point.
|
|
/// @param rhs Second vector to divide by.
|
|
/// @return A new Vector containing the result.
|
|
template <class T, int d>
|
|
inline Vector<T, d> operator/(const Vector<T, d>& lhs,
|
|
const Vector<T, d>& rhs) {
|
|
MATHFU_VECTOR_OPERATOR(lhs.data_[i] / rhs[i]);
|
|
}
|
|
|
|
/// @brief Add a vector with another Vector.
|
|
///
|
|
/// @param lhs First vector to use as a starting point.
|
|
/// @param rhs Second vector to add by.
|
|
/// @return A new vector containing the result.
|
|
template <class T, int d>
|
|
inline Vector<T, d> operator+(const Vector<T, d>& lhs,
|
|
const Vector<T, d>& rhs) {
|
|
MATHFU_VECTOR_OPERATOR(lhs.data_[i] + rhs[i]);
|
|
}
|
|
|
|
/// @brief subtract a vector with another Vector.
|
|
///
|
|
/// @param lhs First vector to use as a starting point.
|
|
/// @param rhs Second vector to subtract by.
|
|
/// @return A new vector containing the result.
|
|
template <class T, int d>
|
|
inline Vector<T, d> operator-(const Vector<T, d>& lhs,
|
|
const Vector<T, d>& rhs) {
|
|
MATHFU_VECTOR_OPERATOR(lhs.data_[i] - rhs[i]);
|
|
}
|
|
|
|
/// @brief Multiply a vector with a scalar.
|
|
///
|
|
/// @param v Vector for the operation.
|
|
/// @param s A scalar to multiply the vector with.
|
|
/// @return A new vector containing the result.
|
|
template <class T, int d>
|
|
inline Vector<T, d> operator*(const Vector<T, d>& v, const T& s) {
|
|
MATHFU_VECTOR_OPERATOR(v.data_[i] * s);
|
|
}
|
|
|
|
/// @brief Add a scalar to all elements of a vector.
|
|
///
|
|
/// @param v Vector for the operation.
|
|
/// @param s A scalar to add to the vector.
|
|
/// @return A new vector containing the result.
|
|
template <class T, int d>
|
|
inline Vector<T, d> operator+(const Vector<T, d>& v, const T& s) {
|
|
MATHFU_VECTOR_OPERATOR(v.data_[i] + s);
|
|
}
|
|
|
|
/// @brief Subtract a scalar from all elements of a vector.
|
|
///
|
|
/// @param v Vector for the operation.
|
|
/// @param s A scalar to subtract from a vector.
|
|
/// @return A new vector that stores the result.
|
|
template <class T, int d>
|
|
inline Vector<T, d> operator-(const Vector<T, d>& v, const T& s) {
|
|
MATHFU_VECTOR_OPERATOR(v.data_[i] - s);
|
|
}
|
|
|
|
/// @brief Multiply (in-place) a vector with another Vector.
|
|
///
|
|
/// In line with GLSL, this performs component-wise multiplication.
|
|
/// @param lhs First vector to use as a starting point.
|
|
/// @param rhs Second vector to multiply by.
|
|
/// @return A reference to the input <b>v</b> vector.
|
|
template <class T, int d>
|
|
inline Vector<T, d>& operator*=(Vector<T, d>& lhs, const Vector<T, d>& rhs) {
|
|
MATHFU_VECTOR_OPERATION(lhs.data_[i] *= rhs[i]);
|
|
return lhs;
|
|
}
|
|
|
|
/// @brief Divide (in-place) a vector by another Vector.
|
|
///
|
|
/// In line with GLSL, this performs component-wise division.
|
|
/// @param lhs First vector to use as a starting point.
|
|
/// @param rhs Second vector to divide by.
|
|
/// @return A reference to the input <b>v</b> vector.
|
|
template <class T, int d>
|
|
inline Vector<T, d>& operator/=(Vector<T, d>& lhs, const Vector<T, d>& rhs) {
|
|
MATHFU_VECTOR_OPERATION(lhs.data_[i] /= rhs[i]);
|
|
return lhs;
|
|
}
|
|
|
|
/// @brief Add (in-place) a vector with another Vector.
|
|
///
|
|
/// @param lhs First vector to use as a starting point.
|
|
/// @param rhs Second vector to add.
|
|
/// @return A reference to the input <b>v</b> vector.
|
|
template <class T, int d>
|
|
inline Vector<T, d>& operator+=(Vector<T, d>& lhs, const Vector<T, d>& rhs) {
|
|
MATHFU_VECTOR_OPERATION(lhs.data_[i] += rhs[i]);
|
|
return lhs;
|
|
}
|
|
|
|
/// @brief Subtract (in-place) another Vector from a vector.
|
|
///
|
|
/// @param lhs First vector to use as a starting point.
|
|
/// @param rhs Second vector to subtract by.
|
|
/// @return A reference to the input <b>v</b> vector.
|
|
template <class T, int d>
|
|
inline Vector<T, d>& operator-=(Vector<T, d>& lhs, const Vector<T, d>& rhs) {
|
|
MATHFU_VECTOR_OPERATION(lhs.data_[i] -= rhs[i]);
|
|
return lhs;
|
|
}
|
|
|
|
/// @brief Multiply (in-place) each element of a vector with a scalar.
|
|
///
|
|
/// @param v Vector for the operation.
|
|
/// @param s A scalar to multiply the vector with.
|
|
/// @return A reference to the input <b>v</b> vector.
|
|
template <class T, int d>
|
|
inline Vector<T, d>& operator*=(Vector<T, d>& v, const T& s) {
|
|
MATHFU_VECTOR_OPERATION(v.data_[i] *= s);
|
|
return v;
|
|
}
|
|
|
|
/// @brief Divide (in-place) each element of a vector by a scalar.
|
|
///
|
|
/// @param v Vector for the operation.
|
|
/// @param s A scalar to divide the vector by.
|
|
/// @return A reference to the input <b>v</b> vector.
|
|
template <class T, int d>
|
|
inline Vector<T, d>& operator/=(Vector<T, d>& v, const T& s) {
|
|
MATHFU_VECTOR_OPERATION(v.data_[i] /= s);
|
|
return v;
|
|
}
|
|
|
|
/// @brief Add (in-place) a scalar to each element of a vector.
|
|
///
|
|
/// @param v Vector for the operation.
|
|
/// @param s A scalar to add the vector to.
|
|
/// @return A reference to the input <b>v</b> vector.
|
|
template <class T, int d>
|
|
inline Vector<T, d>& operator+=(Vector<T, d>& v, const T& s) {
|
|
MATHFU_VECTOR_OPERATION(v.data_[i] += s);
|
|
return v;
|
|
}
|
|
|
|
/// @brief Subtract (in-place) a scalar from each element of a vector.
|
|
///
|
|
/// @param v Vector for the operation.
|
|
/// @param s A scalar to subtract from the vector.
|
|
/// @return A reference to the input <b>v</b> vector.
|
|
template <class T, int d>
|
|
inline Vector<T, d>& operator-=(Vector<T, d>& v, const T& s) {
|
|
MATHFU_VECTOR_OPERATION(v.data_[i] -= s);
|
|
return v;
|
|
}
|
|
|
|
/// @brief Calculate the hadamard or componentwise product of two vectors.
|
|
///
|
|
/// @param v1 First vector.
|
|
/// @param v2 Second vector.
|
|
/// @return The hadamard product of v1 and v2.
|
|
template <class T, int d>
|
|
inline Vector<T, d> HadamardProductHelper(const Vector<T, d>& v1,
|
|
const Vector<T, d>& v2) {
|
|
MATHFU_VECTOR_OPERATOR(v1[i] * v2[i]);
|
|
}
|
|
|
|
/// @brief Calculate the cross product of two vectors.
|
|
///
|
|
/// Note that this function is only defined for 3-dimensional Vectors.
|
|
/// @param v1 First vector.
|
|
/// @param v2 Second vector.
|
|
/// @return The cross product of v1 and v2.
|
|
template <class T>
|
|
inline Vector<T, 3> CrossProductHelper(const Vector<T, 3>& v1,
|
|
const Vector<T, 3>& v2) {
|
|
return Vector<T, 3>(v1[1] * v2[2] - v1[2] * v2[1],
|
|
v1[2] * v2[0] - v1[0] * v2[2],
|
|
v1[0] * v2[1] - v1[1] * v2[0]);
|
|
}
|
|
|
|
/// @brief Calculate the squared length of a vector.
|
|
///
|
|
/// @param v Vector to get the squared length of.
|
|
/// @return The length of the vector squared.
|
|
template <class T, int d>
|
|
inline T LengthSquaredHelper(const Vector<T, d>& v) {
|
|
return DotProductHelper(v, v);
|
|
}
|
|
|
|
/// @brief Calculate the length of a vector.
|
|
///
|
|
/// @param v Vector to get the squared length of.
|
|
/// @return The length of the vector.
|
|
template <class T, int d>
|
|
inline T LengthHelper(const Vector<T, d>& v) {
|
|
return sqrt(LengthSquaredHelper(v));
|
|
}
|
|
|
|
/// @brief Normalize a vector in-place.
|
|
///
|
|
/// @param v Vector to get the squared length of.
|
|
/// @return The length of the vector.
|
|
template <class T, int d>
|
|
inline T NormalizeHelper(Vector<T, d>& v) {
|
|
const T length = LengthHelper(v);
|
|
v *= (T(1) / length);
|
|
return length;
|
|
}
|
|
|
|
/// @brief Calculate the normalized version of a vector.
|
|
///
|
|
/// @param v Vector to get the squared length of.
|
|
/// @return The normalized vector.
|
|
template <class T, int d>
|
|
inline Vector<T, d> NormalizedHelper(const Vector<T, d>& v) {
|
|
return v * (T(1) / LengthHelper(v));
|
|
}
|
|
|
|
/// @brief Linearly interpolate two vectors.
|
|
///
|
|
/// @param v1 First vector.
|
|
/// @param v2 Second vector.
|
|
/// @param percent Percentage from v1 to v2 in range 0.0...1.0.
|
|
/// @return The hadamard product of v1 and v2.
|
|
template <class T, int d>
|
|
inline Vector<T, d> LerpHelper(const Vector<T, d>& v1, const Vector<T, d>& v2,
|
|
const T percent) {
|
|
const T one_minus_percent = static_cast<T>(1.0) - percent;
|
|
MATHFU_VECTOR_OPERATOR(one_minus_percent * v1[i] + percent * v2[i]);
|
|
}
|
|
|
|
/// @brief Generates a random vector.
|
|
///
|
|
/// The range of each component is bounded by min and max.
|
|
/// @param min Minimum value of the vector.
|
|
/// @param max Maximum value of the vector.
|
|
template <class T, int d>
|
|
inline Vector<T, d> RandomInRangeHelper(const Vector<T, d>& min,
|
|
const Vector<T, d>& max) {
|
|
Vector<T, d> result;
|
|
MATHFU_VECTOR_OPERATION(result[i] = mathfu::RandomInRange<T>(min[i], max[i]));
|
|
return result;
|
|
}
|
|
|
|
/// @brief Compare each component and returns max values.
|
|
///
|
|
/// @param v1 First vector.
|
|
/// @param v2 Second vector.
|
|
/// @return Max value of v1 and v2.
|
|
template <class T, int d>
|
|
inline Vector<T, d> MaxHelper(const Vector<T, d>& v1, const Vector<T, d>& v2) {
|
|
Vector<T, d> result;
|
|
MATHFU_VECTOR_OPERATION(result[i] = std::max(v1[i], v2[i]));
|
|
return result;
|
|
}
|
|
|
|
/// @brief Compare each component and returns min values.
|
|
///
|
|
/// @param v1 First vector.
|
|
/// @param v2 Second vector.
|
|
/// @return Min value of v1 and v2.
|
|
template <class T, int d>
|
|
inline Vector<T, d> MinHelper(const Vector<T, d>& v1, const Vector<T, d>& v2) {
|
|
Vector<T, d> result;
|
|
MATHFU_VECTOR_OPERATION(result[i] = std::min(v1[i], v2[i]));
|
|
return result;
|
|
}
|
|
|
|
/// @brief Check if val is within [range_start..range_end), denoting a
|
|
/// rectangular area.
|
|
///
|
|
/// @param val 2D vector to be tested.
|
|
/// @param range_start Starting point of the range (inclusive).
|
|
/// @param range_end Ending point of the range (non-inclusive).
|
|
/// @return Bool indicating success.
|
|
///
|
|
/// @tparam T Type of vector components to test.
|
|
template <class T>
|
|
bool InRange2D(const mathfu::Vector<T, 2>& val,
|
|
const mathfu::Vector<T, 2>& range_start,
|
|
const mathfu::Vector<T, 2>& range_end) {
|
|
return InRange(val[0], range_start[0], range_end[0]) &&
|
|
InRange(val[1], range_start[1], range_end[1]);
|
|
}
|
|
|
|
/// @cond MATHFU_INTERNAL
|
|
/// @brief Calculate the dot product of two vectors.
|
|
///
|
|
/// @param v1 First vector.
|
|
/// @param v2 Second vector.
|
|
/// @return The dot product of v1 and v2.
|
|
/// @related Vector
|
|
template <class T, int d>
|
|
static inline T DotProductHelper(const Vector<T, d>& v1,
|
|
const Vector<T, d>& v2) {
|
|
T result = 0;
|
|
MATHFU_VECTOR_OPERATION(result += v1[i] * v2[i]);
|
|
return result;
|
|
}
|
|
/// @endcond
|
|
|
|
/// @cond MATHFU_INTERNAL
|
|
template <class T>
|
|
static inline T DotProductHelper(const Vector<T, 2>& v1,
|
|
const Vector<T, 2>& v2) {
|
|
return v1[0] * v2[0] + v1[1] * v2[1];
|
|
}
|
|
/// @endcond
|
|
|
|
/// @cond MATHFU_INTERNAL
|
|
template <class T>
|
|
static inline T DotProductHelper(const Vector<T, 3>& v1,
|
|
const Vector<T, 3>& v2) {
|
|
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
|
|
}
|
|
/// @endcond
|
|
|
|
/// @cond MATHFU_INTERNAL
|
|
template <class T>
|
|
static inline T DotProductHelper(const Vector<T, 4>& v1,
|
|
const Vector<T, 4>& v2) {
|
|
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] + v1[3] * v2[3];
|
|
}
|
|
/// @endcond
|
|
|
|
/// @cond MATHFU_INTERNAL
|
|
template <typename T, int d, typename CompatibleT>
|
|
static inline Vector<T, d> FromTypeHelper(const CompatibleT& compatible) {
|
|
// C++11 is required for constructed unions.
|
|
#if __cplusplus >= 201103L
|
|
// Use a union instead of reinterpret_cast to avoid aliasing bugs.
|
|
union ConversionUnion {
|
|
ConversionUnion() {} // C++11.
|
|
CompatibleT compatible;
|
|
VectorPacked<T, d> packed;
|
|
} u;
|
|
static_assert(sizeof(u.compatible) == d * sizeof(T),
|
|
"Conversion size mismatch.");
|
|
|
|
// The read of `compatible` and write to `u.compatible` gets optimized away,
|
|
// and this becomes essentially a safe reinterpret_cast.
|
|
u.compatible = compatible;
|
|
|
|
// Call the packed vector constructor with the `compatible` data.
|
|
return Vector<T, d>(u.packed);
|
|
#else
|
|
// Use the less-desirable memcpy technique if C++11 is not available.
|
|
// Most compilers understand memcpy deep enough to avoid replace the function
|
|
// call with a series of load/stores, which should then get optimized away,
|
|
// however in the worst case the optimize away may not happen.
|
|
// Note: Memcpy avoids aliasing bugs because it operates via unsigned char*,
|
|
// which is allowed to alias any type.
|
|
// See:
|
|
// http://stackoverflow.com/questions/15745030/type-punning-with-void-without-breaking-the-strict-aliasing-rule-in-c99
|
|
Vector<T, d> v;
|
|
assert(sizeof(compatible) == d * sizeof(T));
|
|
memcpy(&v, &compatible, sizeof(compatible));
|
|
return v;
|
|
#endif // __cplusplus >= 201103L
|
|
}
|
|
/// @endcond
|
|
|
|
/// @cond MATHFU_INTERNAL
|
|
template <typename T, int d, typename CompatibleT>
|
|
static inline CompatibleT ToTypeHelper(const Vector<T, d>& v) {
|
|
// See FromTypeHelper() for comments.
|
|
#if __cplusplus >= 201103L
|
|
union ConversionUnion {
|
|
ConversionUnion() {}
|
|
CompatibleT compatible;
|
|
VectorPacked<T, d> packed;
|
|
} u;
|
|
static_assert(sizeof(u.compatible) == d * sizeof(T), "Conversion size mismatch.");
|
|
v.Pack(&u.packed);
|
|
return u.compatible;
|
|
#else
|
|
CompatibleT compatible;
|
|
assert(sizeof(compatible) == d * sizeof(T));
|
|
memcpy(&compatible, &v, sizeof(compatible));
|
|
return compatible;
|
|
#endif // __cplusplus >= 201103L
|
|
}
|
|
/// @endcond
|
|
|
|
/// @}
|
|
|
|
/// @addtogroup mathfu_utilities
|
|
/// @{
|
|
|
|
/// @brief Specialized version of RoundUpToPowerOf2 for vector.
|
|
template <typename T, int d>
|
|
inline Vector<T, d> RoundUpToPowerOf2(const Vector<T, d>& v) {
|
|
Vector<T, d> ret;
|
|
MATHFU_VECTOR_OPERATION(ret(i) = RoundUpToPowerOf2(v(i)));
|
|
return ret;
|
|
}
|
|
/// @}
|
|
|
|
} // namespace mathfu
|
|
|
|
// Include the specializations to avoid template errors.
|
|
// For example, if you include vector.h, use Vector<float, 3>, and then
|
|
// include vector_3.h, you the compiler will generate an error since you're
|
|
// specializing something that has already been instantiated.
|
|
#include "mathfu/internal/vector_2_simd.h"
|
|
#include "mathfu/internal/vector_3_simd.h"
|
|
#include "mathfu/internal/vector_4_simd.h"
|
|
|
|
#if defined(_MSC_VER)
|
|
#pragma warning(pop)
|
|
#elif defined(__clang__)
|
|
#pragma clang diagnostic pop
|
|
#endif
|
|
|
|
#endif // MATHFU_VECTOR_H_
|