32#ifndef DVD_QUATERNION_INL_
33#define DVD_QUATERNION_INL_
39 static __m128
multiplynew(
const __m128 xyzw,
const __m128 abcd)
noexcept {
42 const __m128 wzyx = _mm_shuffle_ps(xyzw, xyzw, _MM_SHUFFLE(0, 1, 2, 3));
43 const __m128 baba = _mm_shuffle_ps(abcd, abcd, _MM_SHUFFLE(0, 1, 0, 1));
44 const __m128 dcdc = _mm_shuffle_ps(abcd, abcd, _MM_SHUFFLE(2, 3, 2, 3));
50 const __m128 ZnXWY = _mm_hsub_ps(_mm_mul_ps(xyzw, baba), _mm_mul_ps(wzyx, dcdc));
53 const __m128 XZYnW = _mm_hadd_ps(_mm_mul_ps(xyzw, dcdc), _mm_mul_ps(wzyx, baba));
63 const __m128 XZWY = _mm_addsub_ps(_mm_shuffle_ps(XZYnW, ZnXWY, _MM_SHUFFLE(3, 2, 1, 0)),
64 _mm_shuffle_ps(ZnXWY, XZYnW, _MM_SHUFFLE(2, 3, 0, 1)));
67 return _mm_shuffle_ps(XZWY, XZWY, _MM_SHUFFLE(2, 1, 3, 0));
79 : _elements(x, y, z, w)
92 fromMatrix(rotationMatrix);
98 fromAxisAngle(axis, angle);
104 lookRotation(forward, up);
110 fromEuler(pitch, yaw, roll);
115 : _elements(q._elements)
127 return _elements.dot(rq._elements);
132 return _elements.length();
137 return _elements.lengthSquared();
150 _elements.set(values);
155 _elements.set(x, y, z, w);
165 _elements.normalize();
170 return getConjugate() * (1.0f / magnitude());
181 W() * rq.
Y() + Y() * rq.
W() + Z() * rq.
X() -
X() * rq.
Z(),
182 W() * rq.
Z() + Z() * rq.
W() +
X() * rq.
Y() - Y() * rq.
X(),
183 W() * rq.
W() -
X() * rq.
X() - Y() * rq.
Y() - Z() * rq.
Z());
215 return vec + uv + uuv * 2;
287 F32 k0 = 0.f, k1 = 0.f;
288 T cosomega = q0.dot(q1);
290 if (cosomega < 0.f) {
291 cosomega = -cosomega;
297 if (1. - cosomega > 1e-6) {
298 const F32 omega =
to_F32(std::acos(cosomega));
299 const F32 sinomega =
to_F32(std::sin(omega));
300 k0 =
to_F32(std::sin((1.f - t) * omega) / sinomega);
301 k1 =
to_F32(std::sin(t * omega) / sinomega);
306 _elements.set(q0._elements * k0 + q.
_elements * k1);
312 _elements.set(
Normalized(v) * std::sin(angleHalfRad), std::cos(angleHalfRad));
317 fromEuler(v.pitch, v.yaw, v.roll);
326 std::cos(eulerAngles.
y),
327 std::cos(eulerAngles.
z));
329 std::sin(eulerAngles.
y),
330 std::sin(eulerAngles.
z));
332 W(c.
x * c.
y * c.
z + s.
x * s.
y * s.
z);
333 X(s.
x * c.
y * c.
z - c.
x * s.
y * s.
z);
334 Y(c.
x * s.
y * c.
z + s.
x * c.
y * s.
z);
335 Z(c.
x * c.
y * s.
z - s.
x * s.
y * c.
z);
344 up =
Cross(forward, right);
345 const T m00 = right.
x;
346 const T m01 = right.
y;
347 const T m02 = right.
z;
351 const T m20 = forward.
x;
352 const T m21 = forward.
y;
353 const T m22 = forward.
z;
355 const T num8 = (m00 + m11) + m22;
359 W(num * 0.5); num = T{ 0.5f / num };
360 X((m12 - m21) * num);
361 Y((m20 - m02) * num);
362 Z((m01 - m10) * num);
366 if ((m00 >= m11) && (m00 >= m22)) {
368 const T num4 = T{ 0.5f / num7 };
370 Y((m01 + m10) * num4);
371 Z((m02 + m20) * num4);
372 W((m12 - m21) * num4);
378 const T num3 = T{ 0.5f / num6 };
379 X((m10 + m01) * num3);
381 Z((m21 + m12) * num3);
382 W((m20 - m02) * num3);
387 const T num2 = T{ 0.5f / num5 };
388 X((m20 + m02) * num2);
389 Y((m21 + m12) * num2);
391 W((m01 - m10) * num2);
397 viewMatrix.extractMat3(rotMatrix);
398 fromMatrix(rotMatrix);
406 T fTrace = rotationMatrix.m[0][0] + rotationMatrix.m[1][1] +
407 rotationMatrix.m[2][2];
412 fRoot = Divide::Sqrt<T, F32>(fTrace + 1.0f);
414 fRoot = T(0.5f / fRoot);
415 X((rotationMatrix.m[2][1] - rotationMatrix.m[1][2]) * fRoot);
416 Y((rotationMatrix.m[0][2] - rotationMatrix.m[2][0]) * fRoot);
417 Z((rotationMatrix.m[1][0] - rotationMatrix.m[0][1]) * fRoot);
420 static size_t s_iNext[3] = {1, 2, 0};
422 if (rotationMatrix.m[1][1] > rotationMatrix.m[0][0]) {
425 if (rotationMatrix.m[2][2] > rotationMatrix.m[i][i]) {
428 size_t j = s_iNext[i];
429 size_t k = s_iNext[j];
431 fRoot = Divide::Sqrt<T, F32>(rotationMatrix.m[i][i] - rotationMatrix.m[j][j] - rotationMatrix.m[k][k] + 1.0f);
432 T* apkQuat[3] = {&_elements.x, &_elements.y, &_elements.z};
433 *apkQuat[i] = T(0.5f * fRoot);
434 fRoot = T(0.5f / fRoot);
435 W((rotationMatrix.m[k][j] - rotationMatrix.m[j][k]) * fRoot);
436 *apkQuat[j] = (rotationMatrix.m[j][i] + rotationMatrix.m[i][j]) * fRoot;
437 *apkQuat[k] = (rotationMatrix.m[k][i] + rotationMatrix.m[i][k]) * fRoot;
460 outMatrix.m[0][0] =
static_cast<T
>(1.0f - (fTyy + fTzz));
461 outMatrix.m[0][1] = fTxy - fTwz;
462 outMatrix.m[0][2] = fTxz + fTwy;
463 outMatrix.m[1][0] = fTxy + fTwz;
464 outMatrix.m[1][1] =
static_cast<T
>(1.0f - (fTxx + fTzz));
465 outMatrix.m[1][2] = fTyz - fTwx;
466 outMatrix.m[2][0] = fTxz - fTwy;
467 outMatrix.m[2][1] = fTyz + fTwx;
468 outMatrix.m[2][2] =
static_cast<T
>(1.0f - (fTxx + fTyy));
473 axis.
set(_elements / _elements.xyz().length());
489 const T test = x * y + z * w;
491 const T unit = sqx + sqy + sqz + sqw;
495 euler.
pitch = 2 * std::atan2(x, w);
499 euler.
pitch = -2 * std::atan2(x, w);
502 euler.
roll = std::atan2(2 * x * y + 2 * w * z, sqw + sqx - sqy - sqz);
503 euler.
pitch = std::atan2(2 * y * z + 2 * w * x, sqw - sqx - sqy + sqz);
504 euler.
yaw = std::asin(-2 * (x * z - w * y));
514 for (
U8 col = 0u; col < 3u; col++) {
515 rot.
setCol(col, axis[col]);
535 toAxes(axis[0], axis[1], axis[2]);
555 const T fTy = 2.0f*y;
556 const T fTz = 2.0f*z;
557 const T fTwy = fTy*w;
558 const T fTwz = fTz*w;
559 const T fTxy = fTy*x;
560 const T fTxz = fTz*x;
561 const T fTyy = fTy*y;
562 const T fTzz = fTz*z;
564 return vec3<T>(1.0f - (fTyy + fTzz), fTxy + fTwz, fTxz - fTwy);
574 const T fTx = 2.0f*x;
575 const T fTy = 2.0f*y;
576 const T fTz = 2.0f*z;
577 const T fTwx = fTx*w;
578 const T fTwz = fTz*w;
579 const T fTxx = fTx*x;
580 const T fTxy = fTy*x;
581 const T fTyz = fTz*y;
582 const T fTzz = fTz*z;
584 return vec3<T>(fTxy - fTwz, 1.0f - (fTxx + fTzz), fTyz + fTwx);
594 const T fTx = 2.0f*x;
595 const T fTy = 2.0f*y;
596 const T fTz = 2.0f*z;
597 const T fTwx = fTx*w;
598 const T fTwy = fTy*w;
599 const T fTxx = fTx*x;
600 const T fTxz = fTz*x;
601 const T fTyy = fTy*y;
602 const T fTyz = fTz*y;
604 return vec3<T>(fTxz + fTwy, fTyz - fTwx, 1.0f - (fTxx + fTyy));
629 return _elements.xyz;
635 _elements.x =
static_cast<T
>(x);
641 _elements.y =
static_cast<T
>(y);
647 _elements.z =
static_cast<T
>(z);
653 _elements.w =
static_cast<T
>(w);
658 _elements.set(0, 0, 0, 1);
684 if (d < 1e-6f - 1.0f) {
701 const F32 invs = 1.f / s;
704 q.
set(c.
x, c.
y, c.
z, s * 0.5f);
714 temp.
slerp(q0, q1, t);
739 return v + q.W() * t +
Cross(xyz, t);
bool compare(const Quaternion &rq, Angle::DEGREES< T > tolerance=1e-3f) const
Quaternion operator/(const Quaternion &rq) const
Dividing q1 by q2.
bool operator==(const Quaternion &rq) const
void fromMatrix(const mat3< T > &rotationMatrix) noexcept
Quaternion & operator-=(const Quaternion &rq)
T dot(const Quaternion &rq) const noexcept
Quaternion getConjugate() const
We need to get the inverse of a quaternion to properly apply a.
vec3< T > xAxis() const noexcept
void fromAxisAngle(const vec3< T > &v, Angle::DEGREES< T > angle) noexcept
Convert from Axis Angle.
Quaternion & operator*=(const Quaternion &rq) noexcept
Multiply so that rotations are applied in a left to right order.
void set(const vec4< T > &values) noexcept
void fromAxes(const vec3< T > *axis)
X/Y/Z Axis get/set a la Ogre: OgreQuaternion.cpp.
void getAxisAngle(vec3< T > &axis, Angle::DEGREES< T > &angle) const
Convert to Axis/Angles.
Quaternion & operator/=(const Quaternion &rq)
void getMatrix(mat3< T > &outMatrix) const noexcept
Convert to Matrix.
Quaternion operator-(const Quaternion &rq) const
Quaternion & operator+=(const Quaternion &rq)
void toAxes(vec3< T > *axis) const
const vec4< T > & asVec4() const noexcept
void lookRotation(vec3< T > forward, vec3< T > up)
Quaternion operator+(const Quaternion &rq) const
void normalize() noexcept
normalizing a quaternion works similar to a vector. This method will not
Quaternion operator*(const Quaternion &rq) const noexcept
void slerp(const Quaternion &q, F32 t) noexcept
vec3< T > XYZ() const noexcept
vec3< T > yAxis() const noexcept
vec3< T > zAxis() const noexcept
Quaternion inverse() const
vec3< Angle::RADIANS< T > > getEuler() const noexcept
bool operator!=(const Quaternion &rq) const
void fromEuler(const vec3< Angle::DEGREES< T > > &v) noexcept
Quaternion & operator=(const Quaternion &q) noexcept
void setCol(I32 index, const vec3< U > &value) noexcept
vec3< T > getCol(I32 index) const noexcept
T dot(const vec3 &v) const noexcept
calculate the dot product between this vector and the specified one
vec3 & normalize() noexcept
transform the vector to unit length
bool isZeroLength() const noexcept
return true if length is zero
void cross(const vec3 &v1, const vec3 &v2) noexcept
set this vector to be equal to the cross of the 2 specified vectors
void set(const T *v) noexcept
set the 3 components of the vector manually using a source pointer to a (large enough) array
static __m128 multiplynew(const __m128 xyzw, const __m128 abcd) noexcept
constexpr DEGREES< T > to_DEGREES(RADIANS< T > angle) noexcept
constexpr RADIANS< T > to_RADIANS(DEGREES< T > angle) noexcept
Handle console commands that start with a forward slash.
vec2< T > Normalized(vec2< T > vector) noexcept
Quaternion< T > Slerp(const Quaternion< T > &q0, const Quaternion< T > &q1, F32 t) noexcept
vec2< T > operator*(T fl, vec2< T > v) noexcept
multiply a vector by a value
static const vec3< F32 > WORLD_X_AXIS
Quaternion< T > RotationFromVToU(const vec3< T > &v, const vec3< T > &u, const vec3< T > &fallbackAxis=VECTOR3_ZERO) noexcept
get the shortest arc quaternion to rotate vector 'v' to the target vector 'u'(from Ogre3D!...
constexpr F32 to_F32(const T value)
bool IS_TOLERANCE(const T X, const T TOLERANCE) noexcept
constexpr F32 EPSILON_F32
vec3< Angle::RADIANS< T > > GetEuler(const Quaternion< T > &q)
vec3< T > DirectionFromAxis(const Quaternion< T > &q, const vec3< T > &AXIS) noexcept
vec2< T > Normalize(vec2< T > &vector) noexcept
vec3< T > DirectionFromEuler(vec3< Angle::DEGREES< T > > const &euler, const vec3< T > &FORWARD_DIRECTION)
bool COMPARE_TOLERANCE(const T X, const U Y, const T TOLERANCE) noexcept
vec2< T > Cross(vec2< T > v1, vec2< T > v2) noexcept
general vec2 cross function
mat3< T > GetMatrix(const Quaternion< T > &q) noexcept
static const vec3< F32 > VECTOR3_ZERO
static const vec3< F32 > WORLD_Y_AXIS
vec3< T > Rotate(vec3< T > const &v, Quaternion< T > const &q) noexcept
float acosf(const float in)