2019-07-27 17:36:24 +03:00
|
|
|
//
|
2020-06-12 18:52:38 +03:00
|
|
|
// CRLib - Simple library for STL replacement in private projects.
|
|
|
|
|
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
|
2019-07-27 17:36:24 +03:00
|
|
|
//
|
2020-06-12 18:52:38 +03:00
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU General Public License for more details.
|
2019-07-27 17:36:24 +03:00
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <crlib/cr-math.h>
|
|
|
|
|
|
|
|
|
|
CR_NAMESPACE_BEGIN
|
|
|
|
|
|
2020-06-12 18:52:38 +03:00
|
|
|
// small simd operations for 3d vector
|
|
|
|
|
#if defined (CR_HAS_SSE)
|
|
|
|
|
|
|
|
|
|
template <typename T> class CR_ALIGN16 SimdWrap {
|
|
|
|
|
private:
|
|
|
|
|
__m128 wrap_dp_sse2 (__m128 v1, __m128 v2) {
|
|
|
|
|
auto mul = _mm_mul_ps (v1, v2);
|
|
|
|
|
auto res = _mm_add_ps (_mm_shuffle_ps (v2, mul, _MM_SHUFFLE (1, 0, 0, 0)), mul);
|
|
|
|
|
|
|
|
|
|
mul = _mm_add_ps (_mm_shuffle_ps (mul, res, _MM_SHUFFLE (0, 3, 0, 0)), res);
|
|
|
|
|
|
|
|
|
|
return _mm_shuffle_ps (mul, mul, _MM_SHUFFLE (2, 2, 2, 2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
union {
|
|
|
|
|
__m128 m;
|
|
|
|
|
|
|
|
|
|
struct {
|
|
|
|
|
T x, y, z;
|
|
|
|
|
} vec;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
SimdWrap (const T &x, const T &y, const T &z) {
|
|
|
|
|
m = _mm_set_ps (0.0f, z, y, x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SimdWrap (const T &x, const T &y) {
|
|
|
|
|
m = _mm_set_ps (0.0f, 0.0f, y, x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SimdWrap (__m128 m) : m (m)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
SimdWrap normalize () {
|
|
|
|
|
return { _mm_div_ps (m, _mm_sqrt_ps (wrap_dp_sse2 (m, m))) };
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-07-27 17:36:24 +03:00
|
|
|
// 3dmath vector
|
2019-08-18 21:00:00 +03:00
|
|
|
template <typename T> class Vec3D {
|
2019-07-27 17:36:24 +03:00
|
|
|
public:
|
2020-06-12 18:52:38 +03:00
|
|
|
T x {};
|
|
|
|
|
T y {};
|
|
|
|
|
T z {};
|
2019-07-27 17:36:24 +03:00
|
|
|
|
|
|
|
|
public:
|
2019-08-18 21:00:00 +03:00
|
|
|
Vec3D (const T &scaler = 0.0f) : x (scaler), y (scaler), z (scaler)
|
2019-07-27 17:36:24 +03:00
|
|
|
{ }
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
Vec3D (const T &x, const T &y, const T &z) : x (x), y (y), z (z)
|
2019-07-27 17:36:24 +03:00
|
|
|
{ }
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
Vec3D (T *rhs) : x (rhs[0]), y (rhs[1]), z (rhs[2])
|
2019-07-27 17:36:24 +03:00
|
|
|
{ }
|
|
|
|
|
|
2020-06-12 18:52:38 +03:00
|
|
|
#if defined (CR_HAS_SSE)
|
|
|
|
|
Vec3D (const SimdWrap <T> &rhs) : x (rhs.vec.x), y (rhs.vec.y), z (rhs.vec.z)
|
|
|
|
|
{ }
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
Vec3D (const Vec3D &) = default;
|
|
|
|
|
|
|
|
|
|
Vec3D (decltype (nullptr)) {
|
|
|
|
|
clear ();
|
|
|
|
|
}
|
2019-07-27 17:36:24 +03:00
|
|
|
|
|
|
|
|
public:
|
2019-08-18 21:00:00 +03:00
|
|
|
operator T * () {
|
2019-07-27 17:36:24 +03:00
|
|
|
return &x;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
operator const T * () const {
|
2019-07-27 17:36:24 +03:00
|
|
|
return &x;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
Vec3D operator + (const Vec3D &rhs) const {
|
|
|
|
|
return { x + rhs.x, y + rhs.y, z + rhs.z };
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
Vec3D operator - (const Vec3D &rhs) const {
|
|
|
|
|
return { x - rhs.x, y - rhs.y, z - rhs.z };
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
Vec3D operator - () const {
|
|
|
|
|
return { -x, -y, -z };
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
friend Vec3D operator * (const T &scale, const Vec3D &rhs) {
|
|
|
|
|
return { rhs.x * scale, rhs.y * scale, rhs.z * scale };
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
Vec3D operator * (const T &scale) const {
|
|
|
|
|
return { scale * x, scale * y, scale * z };
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
Vec3D operator / (const T &rhs) const {
|
|
|
|
|
const auto inv = 1 / (rhs + kFloatEqualEpsilon);
|
|
|
|
|
return { inv * x, inv * y, inv * z };
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// cross product
|
2019-08-18 21:00:00 +03:00
|
|
|
Vec3D operator ^ (const Vec3D &rhs) const {
|
|
|
|
|
return { y * rhs.z - z * rhs.y, z * rhs.x - x * rhs.z, x * rhs.y - y * rhs.x };
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// dot product
|
2019-08-18 21:00:00 +03:00
|
|
|
T operator | (const Vec3D &rhs) const {
|
2019-07-27 17:36:24 +03:00
|
|
|
return x * rhs.x + y * rhs.y + z * rhs.z;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
const Vec3D &operator += (const Vec3D &rhs) {
|
2019-07-27 17:36:24 +03:00
|
|
|
x += rhs.x;
|
|
|
|
|
y += rhs.y;
|
|
|
|
|
z += rhs.z;
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
const Vec3D &operator -= (const Vec3D &rhs) {
|
|
|
|
|
x -= rhs.x;
|
|
|
|
|
y -= rhs.y;
|
|
|
|
|
z -= rhs.z;
|
2019-07-27 17:36:24 +03:00
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
const Vec3D &operator *= (const T &rhs) {
|
|
|
|
|
x *= rhs;
|
|
|
|
|
y *= rhs;
|
|
|
|
|
z *= rhs;
|
2019-07-27 17:36:24 +03:00
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
const Vec3D &operator /= (const T &rhs) {
|
|
|
|
|
const auto inv = 1 / (rhs + kFloatEqualEpsilon);
|
2019-07-27 17:36:24 +03:00
|
|
|
|
|
|
|
|
x *= inv;
|
|
|
|
|
y *= inv;
|
|
|
|
|
z *= inv;
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
bool operator == (const Vec3D &rhs) const {
|
2019-07-27 17:36:24 +03:00
|
|
|
return cr::fequal (x, rhs.x) && cr::fequal (y, rhs.y) && cr::fequal (z, rhs.z);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
bool operator != (const Vec3D &rhs) const {
|
|
|
|
|
return !operator == (rhs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void operator = (decltype (nullptr)) {
|
|
|
|
|
clear ();
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
2020-06-12 18:52:38 +03:00
|
|
|
const float &operator [] (const int i) const {
|
|
|
|
|
return &(x)[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float &operator [] (const int i) {
|
|
|
|
|
return &(x)[i];
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
Vec3D &operator = (const Vec3D &) = default;
|
2019-07-27 17:36:24 +03:00
|
|
|
|
|
|
|
|
public:
|
2019-08-18 21:00:00 +03:00
|
|
|
T length () const {
|
2019-07-27 17:36:24 +03:00
|
|
|
return cr::sqrtf (lengthSq ());
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
T length2d () const {
|
2020-06-12 18:52:38 +03:00
|
|
|
return cr::sqrtf (cr::square (x) + cr::square (y));
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
T lengthSq () const {
|
2020-06-12 18:52:38 +03:00
|
|
|
return cr::square (x) + cr::square (y) + cr::square (z);
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
Vec3D get2d () const {
|
|
|
|
|
return { x, y, 0.0f };
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
Vec3D normalize () const {
|
2020-06-12 18:52:38 +03:00
|
|
|
#if defined (CR_HAS_SSE)
|
|
|
|
|
return SimdWrap <T> { x, y, z }.normalize ();
|
|
|
|
|
#else
|
2019-08-18 21:00:00 +03:00
|
|
|
auto len = length () + cr::kFloatCmpEpsilon;
|
2019-07-27 17:36:24 +03:00
|
|
|
|
|
|
|
|
if (cr::fzero (len)) {
|
2019-08-18 21:00:00 +03:00
|
|
|
return { 0.0f, 0.0f, 1.0f };
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
len = 1.0f / len;
|
2019-08-18 21:00:00 +03:00
|
|
|
return { x * len, y * len, z * len };
|
2020-06-12 18:52:38 +03:00
|
|
|
#endif
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
Vec3D normalize2d () const {
|
2020-06-12 18:52:38 +03:00
|
|
|
#if defined (CR_HAS_SSE)
|
|
|
|
|
return SimdWrap <T> { x, y }.normalize ();
|
|
|
|
|
#else
|
2019-08-18 21:00:00 +03:00
|
|
|
auto len = length2d () + cr::kFloatCmpEpsilon;
|
2019-07-27 17:36:24 +03:00
|
|
|
|
|
|
|
|
if (cr::fzero (len)) {
|
2019-08-18 21:00:00 +03:00
|
|
|
return { 0.0f, 1.0f, 0.0f };
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
len = 1.0f / len;
|
2019-08-18 21:00:00 +03:00
|
|
|
return { x * len, y * len, 0.0f };
|
2020-06-12 18:52:38 +03:00
|
|
|
#endif
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool empty () const {
|
|
|
|
|
return cr::fzero (x) && cr::fzero (y) && cr::fzero (z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void clear () {
|
|
|
|
|
x = y = z = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
Vec3D clampAngles () {
|
2019-07-27 17:36:24 +03:00
|
|
|
x = cr::normalizeAngles (x);
|
|
|
|
|
y = cr::normalizeAngles (y);
|
|
|
|
|
z = 0.0f;
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
T pitch () const {
|
2020-06-12 18:52:38 +03:00
|
|
|
if (cr::fzero (z)) {
|
2019-07-27 17:36:24 +03:00
|
|
|
return 0.0f;
|
|
|
|
|
}
|
2020-06-12 18:52:38 +03:00
|
|
|
return cr::deg2rad (cr::atan2f (z, length2d ()));
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
T yaw () const {
|
2019-07-27 17:36:24 +03:00
|
|
|
if (cr::fzero (x) && cr::fzero (y)) {
|
|
|
|
|
return 0.0f;
|
|
|
|
|
}
|
2020-06-12 18:52:38 +03:00
|
|
|
return cr::rad2deg (cr:: atan2f (y, x));
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
Vec3D angles () const {
|
2019-07-27 17:36:24 +03:00
|
|
|
if (cr::fzero (x) && cr::fzero (y)) {
|
2019-08-18 21:00:00 +03:00
|
|
|
return { z > 0.0f ? 90.0f : 270.0f, 0.0, 0.0f };
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
2020-06-12 18:52:38 +03:00
|
|
|
return { cr::rad2deg (cr::atan2f (z, length2d ())), cr::rad2deg (cr::atan2f (y, x)), 0.0f };
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
void angleVectors (Vec3D *forward, Vec3D *right, Vec3D *upward) const {
|
2019-07-27 17:36:24 +03:00
|
|
|
enum { pitch, yaw, roll, unused, max };
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
T sines[max] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
|
|
|
|
T cosines[max] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
2019-07-27 17:36:24 +03:00
|
|
|
|
|
|
|
|
// compute the sine and cosine compontents
|
2020-06-12 18:52:38 +03:00
|
|
|
cr::sincosf (cr::deg2rad (x), cr::deg2rad (y), cr::deg2rad (z), sines, cosines);
|
2019-07-27 17:36:24 +03:00
|
|
|
|
|
|
|
|
if (forward) {
|
2019-08-18 21:00:00 +03:00
|
|
|
*forward = {
|
|
|
|
|
cosines[pitch] * cosines[yaw],
|
|
|
|
|
cosines[pitch] * sines[yaw],
|
|
|
|
|
-sines[pitch]
|
|
|
|
|
};
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (right) {
|
2019-08-18 21:00:00 +03:00
|
|
|
*right = {
|
|
|
|
|
-sines[roll] * sines[pitch] * cosines[yaw] + cosines[roll] * sines[yaw],
|
|
|
|
|
-sines[roll] * sines[pitch] * sines[yaw] - cosines[roll] * cosines[yaw],
|
|
|
|
|
-sines[roll] * cosines[pitch]
|
|
|
|
|
};
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (upward) {
|
2019-08-18 21:00:00 +03:00
|
|
|
*upward = {
|
|
|
|
|
cosines[roll] * sines[pitch] * cosines[yaw] + sines[roll] * sines[yaw],
|
|
|
|
|
upward->y = cosines[roll] * sines[pitch] * sines[yaw] - sines[roll] * cosines[yaw],
|
|
|
|
|
upward->z = cosines[roll] * cosines[pitch]
|
|
|
|
|
};
|
2019-07-27 17:36:24 +03:00
|
|
|
}
|
|
|
|
|
}
|
2019-08-12 14:16:28 +03:00
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
const Vec3D &forward () {
|
|
|
|
|
static Vec3D s_fwd {};
|
|
|
|
|
angleVectors (&s_fwd, nullptr, nullptr);
|
2019-08-12 14:16:28 +03:00
|
|
|
|
|
|
|
|
return s_fwd;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
const Vec3D &upward () {
|
|
|
|
|
static Vec3D s_up {};
|
|
|
|
|
angleVectors (nullptr, nullptr, &s_up);
|
2019-08-12 14:16:28 +03:00
|
|
|
|
|
|
|
|
return s_up;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
const Vec3D &right () {
|
|
|
|
|
static Vec3D s_right {};
|
|
|
|
|
angleVectors (nullptr, &s_right, nullptr);
|
2019-08-12 14:16:28 +03:00
|
|
|
|
|
|
|
|
return s_right;
|
|
|
|
|
}
|
2019-07-27 17:36:24 +03:00
|
|
|
};
|
|
|
|
|
|
2019-08-18 21:00:00 +03:00
|
|
|
// default is float
|
|
|
|
|
using Vector = Vec3D <float>;
|
2019-07-27 17:36:24 +03:00
|
|
|
|
2020-06-12 18:52:38 +03:00
|
|
|
CR_NAMESPACE_END
|