blob: a0af83062cde02e9abd4c4fafca313de503fc864 [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_3_SIMD_H_
#define MATHFU_VECTOR_3_SIMD_H_
#include "mathfu/internal/vector_3.h"
#include "mathfu/utilities.h"
#include <math.h>
#ifdef MATHFU_COMPILE_WITH_SIMD
#include "vectorial/simd4f.h"
#endif
/// @file mathfu/internal/vector_3_simd.h MathFu Vector<T, 3> Specialization
/// @brief 3-dimensional specialization of mathfu::Vector for SIMD optimized
/// builds.
/// @see mathfu::Vector
/// @cond MATHFU_INTERNAL
/// Add macros to account for both the case where the vector is stored as a
/// simd intrinsic using 4 elements or as 3 values of type T.
/// MATHFU_VECTOR3_STORE3/MATHFU_VECTOR3_LOAD3 are additional operations used
/// to load/store the non simd values from and to simd datatypes. If intrinsics
/// are used these amount to essentially noops. MATHFU_VECTOR3_INIT3 either
/// creates a simd datatype if the intrinsic is used or sets the T values if
/// not.
#ifdef MATHFU_COMPILE_WITH_PADDING
#define MATHFU_VECTOR3_STORE3(simd_to_store, data) \
{ (data).simd = simd_to_store; }
#define MATHFU_VECTOR3_LOAD3(data) (data).simd
#define MATHFU_VECTOR3_INIT3(data, v1, v2, v3) \
{ (data).simd = simd4f_create(v1, v2, v3, 0); }
#else
#define MATHFU_VECTOR3_STORE3(simd_to_store, data) \
{ simd4f_ustore3(simd_to_store, (data).data_); }
#define MATHFU_VECTOR3_LOAD3(data) simd4f_uload3((data).data_)
#define MATHFU_VECTOR3_INIT3(data, v1, v2, v3) \
{ \
(data).data_[0] = v1; \
(data).data_[1] = v2; \
(data).data_[2] = v3; \
}
#endif // MATHFU_COMPILE_WITH_PADDING
/// @endcond
namespace mathfu {
#ifdef MATHFU_COMPILE_WITH_SIMD
/// @cond MATHFU_INTERNAL
// This class should remain plain old data.
template <>
class Vector<float, 3> {
public:
typedef float Scalar;
inline Vector() {}
inline Vector(const Vector<float, 3>& v) {
#ifdef MATHFU_COMPILE_WITH_PADDING
simd = v.simd;
#else
MATHFU_VECTOR3_INIT3(*this, v[0], v[1], v[2]);
#endif // MATHFU_COMPILE_WITH_PADDING
}
explicit inline Vector(const Vector<int, 3>& v) {
MATHFU_VECTOR3_INIT3(*this, static_cast<float>(v[0]),
static_cast<float>(v[1]), static_cast<float>(v[2]));
}
inline Vector(const simd4f& v) { MATHFU_VECTOR3_STORE3(v, *this); }
explicit inline Vector(const float& s) {
MATHFU_VECTOR3_INIT3(*this, s, s, s);
}
inline Vector(const float& v1, const float& v2, const float& v3) {
MATHFU_VECTOR3_INIT3(*this, v1, v2, v3);
}
inline Vector(const Vector<float, 2>& v12, const float& v3) {
MATHFU_VECTOR3_INIT3(*this, v12[0], v12[1], v3);
}
explicit inline Vector(const float* v) {
#ifdef MATHFU_COMPILE_WITH_PADDING
simd = simd4f_uload3(v);
#else
MATHFU_VECTOR3_INIT3(*this, v[0], v[1], v[2]);
#endif // MATHFU_COMPILE_WITH_PADDING
}
explicit inline Vector(const VectorPacked<float, 3>& vector) {
#ifdef MATHFU_COMPILE_WITH_PADDING
simd = simd4f_uload3(vector.data);
#else
MATHFU_VECTOR3_INIT3(*this, vector.data[0], vector.data[1], vector.data[2]);
#endif // MATHFU_COMPILE_WITH_PADDING
}
inline float& operator()(const int i) { return data_[i]; }
inline const float& operator()(const int i) const { return data_[i]; }
inline float& operator[](const int i) { return data_[i]; }
inline const float& operator[](const int i) const { return data_[i]; }
/// GLSL style multi-component accessors.
inline Vector<float, 2> xy() { return Vector<float, 2>(x, y); }
inline const Vector<float, 2> xy() const { return Vector<float, 2>(x, y); }
inline void Pack(VectorPacked<float, 3>* const vector) const {
#ifdef MATHFU_COMPILE_WITH_PADDING
simd4f_ustore3(simd, vector->data);
#else
vector->data[0] = data_[0];
vector->data[1] = data_[1];
vector->data[2] = data_[2];
#endif // MATHFU_COMPILE_WITH_PADDING
}
inline Vector<float, 3> operator-() const {
return Vector<float, 3>(
simd4f_sub(simd4f_zero(), MATHFU_VECTOR3_LOAD3(*this)));
}
inline Vector<float, 3> operator*(const Vector<float, 3>& v) const {
return Vector<float, 3>(
simd4f_mul(MATHFU_VECTOR3_LOAD3(*this), MATHFU_VECTOR3_LOAD3(v)));
}
inline Vector<float, 3> operator/(const Vector<float, 3>& v) const {
return Vector<float, 3>(
simd4f_div(MATHFU_VECTOR3_LOAD3(*this), MATHFU_VECTOR3_LOAD3(v)));
}
inline Vector<float, 3> operator+(const Vector<float, 3>& v) const {
return Vector<float, 3>(
simd4f_add(MATHFU_VECTOR3_LOAD3(*this), MATHFU_VECTOR3_LOAD3(v)));
}
inline Vector<float, 3> operator-(const Vector<float, 3>& v) const {
return Vector<float, 3>(
simd4f_sub(MATHFU_VECTOR3_LOAD3(*this), MATHFU_VECTOR3_LOAD3(v)));
}
inline Vector<float, 3> operator*(const float& s) const {
return Vector<float, 3>(
simd4f_mul(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(s)));
}
inline Vector<float, 3> operator/(const float& s) const {
return Vector<float, 3>(
simd4f_div(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(s)));
}
inline Vector<float, 3> operator+(const float& s) const {
return Vector<float, 3>(
simd4f_add(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(s)));
}
inline Vector<float, 3> operator-(const float& s) const {
return Vector<float, 3>(
simd4f_sub(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(s)));
}
inline Vector<float, 3>& operator*=(const Vector<float, 3>& v) {
*this = simd4f_mul(MATHFU_VECTOR3_LOAD3(*this), MATHFU_VECTOR3_LOAD3(v));
return *this;
}
inline Vector<float, 3>& operator/=(const Vector<float, 3>& v) {
*this = simd4f_div(MATHFU_VECTOR3_LOAD3(*this), MATHFU_VECTOR3_LOAD3(v));
return *this;
}
inline Vector<float, 3>& operator+=(const Vector<float, 3>& v) {
*this = simd4f_add(MATHFU_VECTOR3_LOAD3(*this), MATHFU_VECTOR3_LOAD3(v));
return *this;
}
inline Vector<float, 3>& operator-=(const Vector<float, 3>& v) {
*this = simd4f_sub(MATHFU_VECTOR3_LOAD3(*this), MATHFU_VECTOR3_LOAD3(v));
return *this;
}
inline Vector<float, 3>& operator*=(const float& s) {
*this = simd4f_mul(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(s));
return *this;
}
inline Vector<float, 3>& operator/=(const float& s) {
*this = simd4f_div(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(s));
return *this;
}
inline Vector<float, 3>& operator+=(const float& s) {
*this = simd4f_add(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(s));
return *this;
}
inline Vector<float, 3>& operator-=(const float& s) {
*this = simd4f_sub(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(s));
return *this;
}
inline bool operator==(const Vector<float, 3>& v) const {
for (int i = 0; i < 3; ++i) {
if ((*this)[i] != v[i]) return false;
}
return true;
}
inline bool operator!=(const Vector<float, 3>& v) const {
return !operator==(v);
}
inline float LengthSquared() const {
return simd4f_dot3_scalar(MATHFU_VECTOR3_LOAD3(*this),
MATHFU_VECTOR3_LOAD3(*this));
}
inline float Length() const {
return simd4f_get_x(simd4f_length3(MATHFU_VECTOR3_LOAD3(*this)));
}
inline float Normalize() {
const float length = Length();
*this = simd4f_mul(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(1 / length));
return length;
}
inline Vector<float, 3> Normalized() const {
return Vector<float, 3>(simd4f_normalize3(MATHFU_VECTOR3_LOAD3(*this)));
}
template <typename CompatibleT>
static inline Vector<float, 3> FromType(const CompatibleT& compatible) {
return FromTypeHelper<float, 3, CompatibleT>(compatible);
}
template <typename CompatibleT>
static inline CompatibleT ToType(const Vector<float, 3>& v) {
return ToTypeHelper<float, 3, CompatibleT>(v);
}
static inline float DotProduct(const Vector<float, 3>& v1,
const Vector<float, 3>& v2) {
return simd4f_dot3_scalar(MATHFU_VECTOR3_LOAD3(v1),
MATHFU_VECTOR3_LOAD3(v2));
}
static inline Vector<float, 3> CrossProduct(const Vector<float, 3>& v1,
const Vector<float, 3>& v2) {
return Vector<float, 3>(
simd4f_cross3(MATHFU_VECTOR3_LOAD3(v1), MATHFU_VECTOR3_LOAD3(v2)));
}
static inline Vector<float, 3> HadamardProduct(const Vector<float, 3>& v1,
const Vector<float, 3>& v2) {
return Vector<float, 3>(
simd4f_mul(MATHFU_VECTOR3_LOAD3(v1), MATHFU_VECTOR3_LOAD3(v2)));
}
static inline Vector<float, 3> Lerp(const Vector<float, 3>& v1,
const Vector<float, 3>& v2,
float percent) {
const Vector<float, 3> percentv(percent);
const Vector<float, 3> one(1.0f);
const Vector<float, 3> one_minus_percent = one - percentv;
return Vector<float, 3>(simd4f_add(
simd4f_mul(MATHFU_VECTOR3_LOAD3(one_minus_percent),
MATHFU_VECTOR3_LOAD3(v1)),
simd4f_mul(MATHFU_VECTOR3_LOAD3(percentv), MATHFU_VECTOR3_LOAD3(v2))));
}
/// Generates a random vector, where the range for each component is
/// bounded by min and max.
static inline Vector<float, 3> RandomInRange(const Vector<float, 3>& min,
const Vector<float, 3>& max) {
return Vector<float, 3>(mathfu::RandomInRange<float>(min[0], max[0]),
mathfu::RandomInRange<float>(min[1], max[1]),
mathfu::RandomInRange<float>(min[2], max[2]));
}
static inline Vector<float, 3> Max(const Vector<float, 3>& v1,
const Vector<float, 3>& v2) {
#ifdef MATHFU_COMPILE_WITH_PADDING
return Vector<float, 3>(
simd4f_max(MATHFU_VECTOR3_LOAD3(v1), MATHFU_VECTOR3_LOAD3(v2)));
#else
return Vector<float, 3>(std::max(v1[0], v2[0]), std::max(v1[1], v2[1]),
std::max(v1[2], v2[2]));
#endif // MATHFU_COMPILE_WITH_PADDING
}
static inline Vector<float, 3> Min(const Vector<float, 3>& v1,
const Vector<float, 3>& v2) {
#ifdef MATHFU_COMPILE_WITH_PADDING
return Vector<float, 3>(
simd4f_min(MATHFU_VECTOR3_LOAD3(v1), MATHFU_VECTOR3_LOAD3(v2)));
#else
return Vector<float, 3>(std::min(v1[0], v2[0]), std::min(v1[1], v2[1]),
std::min(v1[2], v2[2]));
#endif // MATHFU_COMPILE_WITH_PADDING
}
template <class T, int rows, int cols>
friend class Matrix;
template <class T, int d>
friend class Vector;
MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE
#include "mathfu/internal/disable_warnings_begin.h"
union {
#ifdef MATHFU_COMPILE_WITH_PADDING
simd4f simd;
float data_[4];
#else
float data_[3];
#endif // MATHFU_COMPILE_WITH_PADDING
struct {
float x;
float y;
float z;
};
};
#include "mathfu/internal/disable_warnings_end.h"
};
/// @endcond
#endif // MATHFU_COMPILE_WITH_SIMD
} // namespace mathfu
#endif // MATHFU_VECTOR_3_SIMD_H_