Files
starruler-linux/source/util/include/vec3.h
T
2018-07-17 14:15:37 +02:00

293 lines
6.9 KiB
C++

#pragma once
#include <math.h>
#if defined(_MSC_VER) && defined(_M_AMD64)
#include <emmintrin.h>
#endif
//3 Dimensional Vector structure
template<class T = double>
struct vec3 {
T x,y,z;
vec3() : x(0), y(0), z(0) {}
explicit vec3(T def) : x(def), y(def), z(def) {}
explicit vec3(T X, T Y, T Z) : x(X), y(Y), z(Z) {}
template<class O>
explicit vec3(const vec3<O>& other) : x((T)other.x), y((T)other.y), z((T)other.z) {}
static vec3 up(T len = (T)1.0) { return vec3(0,len,0); }
static vec3 front(T len = (T)1.0) { return vec3(len,0,0); }
static vec3 right(T len = (T)1.0) { return vec3(0,0,-len); }
#if defined(_MSC_VER) && defined(_M_AMD64)
double distanceTo(const vec3& other) const {
__m128d reg0 = _mm_set_sd(x), reg1 = _mm_set_sd(other.x);
reg0 = _mm_sub_sd(reg0, reg1);
__m128d reg2 = _mm_set_sd(y);
reg0 = _mm_mul_sd(reg0, reg0);
reg1 = _mm_set_sd(other.y);
reg1 = _mm_sub_sd(reg2, reg1);
__m128d reg3 = _mm_set_sd(z);
reg1 = _mm_mul_sd(reg1, reg1);
reg2 = _mm_set_sd(other.z);
reg0 = _mm_add_sd(reg0, reg1);
reg2 = _mm_sub_sd(reg3, reg2);
reg2 = _mm_mul_sd(reg2, reg2);
reg0 = _mm_add_sd(reg0, reg2);
reg0 = _mm_sqrt_sd(reg0, reg0);
return reg0.m128d_f64[0];
}
double distanceToSQ(const vec3& other) const {
__m128d reg0 = _mm_set_sd(x), reg1 = _mm_set_sd(other.x);
reg0 = _mm_sub_sd(reg0, reg1);
__m128d reg2 = _mm_set_sd(y);
reg0 = _mm_mul_sd(reg0, reg0);
reg1 = _mm_set_sd(other.y);
reg1 = _mm_sub_sd(reg2, reg1);
__m128d reg3 = _mm_set_sd(z);
reg1 = _mm_mul_sd(reg1, reg1);
reg2 = _mm_set_sd(other.z);
reg0 = _mm_add_sd(reg0, reg1);
reg2 = _mm_sub_sd(reg3, reg2);
reg2 = _mm_mul_sd(reg2, reg2);
reg0 = _mm_add_sd(reg0, reg2);
return reg0.m128d_f64[0];
}
T getLength() const {
__m128d reg0 = _mm_set_sd(x);
reg0 = _mm_mul_sd(reg0, reg0);
__m128d reg1 = _mm_set_sd(y);
reg1 = _mm_mul_sd(reg1, reg1);
__m128d reg2 = _mm_set_sd(z);
reg2 = _mm_mul_sd(reg2, reg2);
reg0 = _mm_add_sd(reg0, reg1);
reg0 = _mm_add_sd(reg0, reg2);
reg0 = _mm_sqrt_sd(reg0, reg0);
return reg0.m128d_f64[0];
}
T getLengthSQ() const {
__m128d reg0 = _mm_set_sd(x);
reg0 = _mm_mul_sd(reg0, reg0);
__m128d reg1 = _mm_set_sd(y);
reg1 = _mm_mul_sd(reg1, reg1);
__m128d reg2 = _mm_set_sd(z);
reg2 = _mm_mul_sd(reg2, reg2);
reg0 = _mm_add_sd(reg0, reg1);
reg0 = _mm_add_sd(reg0, reg2);
return reg0.m128d_f64[0];
}
double dot(const vec3& other) const {
__m128d reg0 = _mm_set_sd(x), reg1 = _mm_set_sd(other.x);
reg0 = _mm_mul_sd(reg0, reg1);
__m128d reg2 = _mm_set_sd(y);
reg1 = _mm_set_sd(other.y);
reg1 = _mm_mul_sd(reg2, reg1);
__m128d reg3 = _mm_set_sd(z);
reg0 = _mm_add_sd(reg0, reg1);
reg2 = _mm_set_sd(other.z);
reg2 = _mm_mul_sd(reg3, reg2);
reg0 = _mm_add_sd(reg0, reg2);
return reg0.m128d_f64[0];
}
#else
double distanceTo(const vec3& other) const {
double tx = x-other.x,
ty = y-other.y,
tz = z-other.z;
return sqrt((tx*tx)+(ty*ty)+(tz*tz));
}
double distanceToSQ(const vec3& other) const {
double tx = x-other.x,
ty = y-other.y,
tz = z-other.z;
return ((tx*tx)+(ty*ty)+(tz*tz));
}
T getLength() const {
return (T)sqrt((double)(x*x)+(double)(y*y)+(double)(z*z));
}
T getLengthSQ() const {
return (x*x)+(y*y)+(z*z);
}
double dot(const vec3& other) const {
return (double(x)*double(other.x)) + (double(y)*double(other.y)) + (double(z)*double(other.z));
}
#endif
double angleDistance(const vec3& other) const {
double _dot = dot(other);
if(_dot < -1.0)
_dot = -1.0;
else if(_dot > 1.0)
_dot = 1.0;
return acos(_dot);
}
vec3 cross(const vec3& other) const {
return vec3(
(y*other.z)-(z*other.y),
(z*other.x)-(x*other.z),
(x*other.y)-(y*other.x) );
}
vec3 operator+(const vec3& other) const {
return vec3(x+other.x, y+other.y, z+other.z);
}
vec3& operator+=(const vec3& other) {
x += other.x;
y += other.y;
z += other.z;
return *this;
}
vec3 operator-() const {
return vec3(-x, -y, -z);
}
vec3 operator-(const vec3& other) const {
return vec3(x-other.x, y-other.y, z-other.z);
}
vec3& operator-=(const vec3& other) {
x -= other.x;
y -= other.y;
z -= other.z;
return *this;
}
vec3 operator*(const vec3& other) const {
return vec3(x*other.x, y*other.y, z*other.z);
}
vec3 operator*(double scalar) const {
return vec3(T((double)x*scalar), T((double)y*scalar), T((double)z*scalar));
}
vec3& operator*=(double scalar) {
x = T((double)x * scalar);
y = T((double)y * scalar);
z = T((double)z * scalar);
return *this;
}
vec3 operator/(double scalar) const {
return vec3(T((double)x/scalar), T((double)y/scalar), T((double)z/scalar));
}
vec3& operator/=(double scalar) {
x = T((double)x / scalar);
y = T((double)y / scalar);
z = T((double)z / scalar);
return *this;
}
vec3& operator=(const vec3& other) {
x = other.x;
y = other.y;
z = other.z;
return *this;
}
bool operator==(const vec3& other) const {
return x == other.x && y == other.y && z == other.z;
}
bool operator!=(const vec3& other) const {
return x != other.x || y != other.y || z != other.z;
}
vec3 interpolate(const vec3& other, double pct) const {
return *this + (other - *this) * pct;
}
//Spherically interpolate between normalized vectors
vec3 slerp(const vec3& other, double pct) const {
if(pct >= 1.0)
return other;
if(pct <= 0.0)
return *this;
double _dot = dot(other);
if(_dot > 0.999)
return interpolate(other, pct);
if(_dot <= -1.0) {
//Normally this would reduce to lerp, but we know we want to rotate in some direction instead
// We find a vector perpendicular to our endpoints and interpolate based on our progress
vec3 temp = cross(vec3::up());
if(temp.zero())
return other;
else if(pct < 0.5)
return slerp(temp, pct * 2.0);
else
return temp.slerp(other, (pct - 0.5) * 2.0);
}
double omega = acos(_dot);
if(omega < 0.001)
return interpolate(other, pct);
double sinOmg = sin(omega);
return ((*this * sin((1.0 - pct)*omega)/sinOmg) + (other * sin(pct * omega)/sinOmg)).normalized();
}
vec3& normalize(T length = (T)1.0) {
double X = x, Y = y, Z = z,
L = (X*X)+(Y*Y)+(Z*Z);
if(L == 0.0)
return *this;
L = (double)length / sqrt(L);
x = (T)(X*L);
y = (T)(Y*L);
z = (T)(Z*L);
return *this;
}
vec3 normalized(T length = (T)1.0) const {
vec3 temp(*this);
temp.normalize(length);
return temp;
}
void set(T X, T Y, T Z) {
x = X;
y = Y;
z = Z;
}
vec3<T> elementMax(const vec3<T>& other) const {
return vec3<T>(
x > other.x ? x : other.x,
y > other.y ? y : other.y,
z > other.z ? z : other.z);
}
vec3<T> elementMin(const vec3<T>& other) const {
return vec3<T>(
x < other.x ? x : other.x,
y < other.y ? y : other.y,
z < other.z ? z : other.z);
}
bool zero() {
return x == 0.0 && y == 0.0 && z == 0.0;
}
};
typedef vec3<float> vec3f;
typedef vec3<double> vec3d;
typedef vec3<int> vec3i;