blob: 4d1625e13fecaa79a2fcec55e9e77ae1aa23e8ab [file] [log] [blame]
/*
* 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_