#ifndef BLUECORE_QUATERNION_H #define BLUECORE_QUATERNION_H #include "Vector.h" namespace BlueCore { template class QuaternionTemplate { public: T w, x, y, z; inline QuaternionTemplate() { w = static_cast(1.0); x = static_cast(0.0); y = static_cast(0.0); z = static_cast(0.0); } template inline QuaternionTemplate(S w, S x, S y, S z) { this->w = static_cast(w); this->x = static_cast(x); this->y = static_cast(y); this->z = static_cast(z); } template inline QuaternionTemplate(Vector3Template axis, S angle) { T half_angle = static_cast(angle)/static_cast(2.0); T sin_half_angle = static_cast(sin(half_angle) ); w = static_cast(cos(half_angle) ); x = sin_half_angle * static_cast(axis.x); y = sin_half_angle * static_cast(axis.y); z = sin_half_angle * static_cast(axis.z); } template inline QuaternionTemplate(S h, S a, S b) { T c1 = static_cast(cos(h / 2.0) ); T c2 = static_cast(cos(a / 2.0) ); T c3 = static_cast(cos(b / 2.0) ); T s1 = static_cast(sin(h / 2.0) ); T s2 = static_cast(sin(a / 2.0) ); T s3 = static_cast(sin(b / 2.0) ); w = c1 * c2 * c3 - s1 * s2 * s3; x = s1 * s2 * c3 + c1 * c2 * s3; y = s1 * c2 * c3 + c1 * s2 * s3; z = c1 * s2 * c3 - s1 * c2 * s3; } inline void identity() { w = static_cast(1.0); x = static_cast(0.0); y = static_cast(0.0); z = static_cast(0.0); } template inline QuaternionTemplate operator +( const QuaternionTemplate &a) const { return QuaternionTemplate(w + static_cast(a.w), x + static_cast(a.x), y + static_cast(a.y), z + static_cast(a.z) ); } template inline QuaternionTemplate &operator +=( const QuaternionTemplate &a) { w += static_cast(a.w); x += static_cast(a.x); y += static_cast(a.y); z += static_cast(a.z); return *this; } template inline QuaternionTemplate operator -( const QuaternionTemplate &a) const { return QuaternionTemplate(w - static_cast(a.w), x - static_cast(a.x), y - static_cast(a.y), z - static_cast(a.z) ); } template inline QuaternionTemplate operator *( const QuaternionTemplate &a) const { return QuaternionTemplate(w * static_cast(a.w) - x * static_cast(a.x) - y * static_cast(a.y) - z * static_cast(a.z), w * static_cast(a.x) + x * static_cast(a.w) + y * static_cast(a.z) - z * static_cast(a.y), w * static_cast(a.y) - x * static_cast(a.z) + y * static_cast(a.w) + z * static_cast(a.x), w * static_cast(a.z) + x * static_cast(a.y) - y * static_cast(a.x) + z * static_cast(a.w) ); } template inline QuaternionTemplate &operator *=( const QuaternionTemplate &a) { w = w * static_cast(a.w) - x * static_cast(a.x) - y * static_cast(a.y) - z * static_cast(a.z); x = w * static_cast(a.x) + x * static_cast(a.w) + y * static_cast(a.z) - z * static_cast(a.y); y = w * static_cast(a.y) - x * static_cast(a.z) + y * static_cast(a.w) + z * static_cast(a.x); z = w * static_cast(a.z) + x * static_cast(a.y) - y * static_cast(a.x) + z * static_cast(a.w); return *this; } template inline QuaternionTemplate &operator -=( const QuaternionTemplate &a) { w -= static_cast(a.w); x -= static_cast(a.x); y -= static_cast(a.y); z -= static_cast(a.z); return *this; } template inline QuaternionTemplate &operator =( const QuaternionTemplate &a) { w = static_cast(a.w); x = static_cast(a.x); y = static_cast(a.y); z = static_cast(a.z); return *this; } inline QuaternionTemplate unit() const { T d = 1/sqrt(w*w + x*x + y*y + z*z); return QuaternionTemplate(w * d, x * d, y * d, z * d); } inline QuaternionTemplate inversed() const { return QuaternionTemplate(w, -x, -y, -z); } inline void inverse() { x = -x; y = -y; z = -z; } inline QuaternionTemplate &normalize() { T d = 1/sqrt(w*w + x*x + y*y + z*z); w *= d; x *= d; y *= d; z *= d; return *this; } template inline const Vector3Template apply( const Vector3Template &a) const { T xx = x*x, xy = x*y, xz = x*z, xw = x*w, yy = y*y, yz = y*z, yw = y*w, zz = z*z, zw = z*w; return Vector3Template( 2.0 * ( static_cast(a.x) * ( 0.5 - yy - zz ) + static_cast(a.y) * (xy - zw ) + static_cast(a.z) * (xz + yw ) ), 2.0 * ( static_cast(a.x) * (xy + zw ) + static_cast(a.y) * ( 0.5 - xx - zz ) + static_cast(a.z) * (yz - xw ) ), 2.0 * ( static_cast(a.x) * (xz - yw ) + static_cast(a.y) * (yz + xw ) + static_cast(a.z) * ( 0.5 - xx - yy ) )); } template inline const Vector3Template operator *( const Vector3Template &a) const { T xx = x*x, xy = x*y, xz = x*z, xw = x*w, yy = y*y, yz = y*z, yw = y*w, zz = z*z, zw = z*w; return Vector3Template( 2.0 * ( static_cast(a.x) * ( 0.5 - yy - zz ) + static_cast(a.y) * (xy - zw ) + static_cast(a.z) * (xz + yw ) ), 2.0 * ( static_cast(a.x) * (xy + zw ) + static_cast(a.y) * ( 0.5 - xx - zz ) + static_cast(a.z) * (yz - xw ) ), 2.0 * ( static_cast(a.x) * (xz - yw ) + static_cast(a.y) * (yz + xw ) + static_cast(a.z) * ( 0.5 - xx - yy ) )); } template inline Vector3Template applyInversed( const Vector3Template &a) const { T xx = x*x, xy = x*y, xz = x*z, xw = -x*w, yy = y*y, yz = y*z, yw = -y *w, zz = z*z, zw = -z*w; return Vector3Template( 2.0 * ( static_cast(a.x) * ( 0.5 - yy - zz ) + static_cast(a.y) * (xy - zw ) + static_cast(a.z) * (xz + yw ) ), 2.0 * ( static_cast(a.x) * (xy + zw ) + static_cast(a.y) * ( 0.5 - xx - zz ) + static_cast(a.z) * (yz - xw ) ), 2.0 * ( static_cast(a.x) * (xz - yw ) + static_cast(a.y) * (yz + xw ) + static_cast(a.z) * ( 0.5 - xx - yy ) )); } inline QuaternionTemplate slerp(const QuaternionTemplate &q, const Scalar &t) { T phi = acos(w*q.w + x*q.x + y*q.y + z*q.z); T s = 1 / sin(phi); T a = sin(phi*(1-t)) * s; T b = sin(phi*t) * s; return QuaternionTemplate(a*w+b*q.w, a*x+b*q.x, a*y+b*q.y, a*z+b*q.z); } }; typedef QuaternionTemplate QuaternionFloat; typedef QuaternionTemplate QuaternionDouble; typedef QuaternionTemplate Quaternion; } #endif