Imported more code from the old engine.
[peakengine.git] / engine / include / support / quaternion.h
blob354d6a8ab97e1b0278635547a903bc0a060b5535
1 // Copyright (C) 2002-2007 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
5 #ifndef __IRR_QUATERNION_H_INCLUDED__
6 #define __IRR_QUATERNION_H_INCLUDED__
8 #include "irrTypes.h"
9 #include "irrMath.h"
10 #include "matrix4.h"
11 #include "vector3d.h"
13 namespace irr
15 namespace core
18 //! Quaternion class.
19 class quaternion
21 public:
23 //! Default Constructor
24 quaternion() : X(0.0f), Y(0.0f), Z(0.0f), W(1.0f) {}
26 //! Constructor
27 quaternion(f32 x, f32 y, f32 z, f32 w) : X(x), Y(y), Z(z), W(w) { }
29 //! Constructor which converts euler angles (radians) to a quaternion
30 quaternion(f32 x, f32 y, f32 z);
32 //! Constructor which converts euler angles (radians) to a quaternion
33 quaternion(const vector3df& vec);
35 //! Constructor which converts a matrix to a quaternion
36 quaternion(const matrix4& mat);
38 //! equal operator
39 bool operator==(const quaternion& other) const;
41 //! assignment operator
42 inline quaternion& operator=(const quaternion& other);
44 //! matrix assignment operator
45 inline quaternion& operator=(const matrix4& other);
47 //! add operator
48 quaternion operator+(const quaternion& other) const;
50 //! multiplication operator
51 quaternion operator*(const quaternion& other) const;
53 //! multiplication operator
54 quaternion operator*(f32 s) const;
56 //! multiplication operator
57 quaternion& operator*=(f32 s);
59 //! multiplication operator
60 vector3df operator* (const vector3df& v) const;
62 //! multiplication operator
63 quaternion& operator*=(const quaternion& other);
65 //! calculates the dot product
66 inline f32 getDotProduct(const quaternion& other) const;
68 //! sets new quaternion
69 inline void set(f32 x, f32 y, f32 z, f32 w);
71 //! sets new quaternion based on euler angles (radians)
72 inline void set(f32 x, f32 y, f32 z);
74 //! sets new quaternion based on euler angles (radians)
75 inline void set(const core::vector3df& vec);
77 //! normalizes the quaternion
78 inline quaternion& normalize();
80 //! Creates a matrix from this quaternion
81 matrix4 getMatrix() const;
83 //! Creates a matrix from this quaternion
84 void getMatrix( matrix4 &dest ) const;
86 //! Creates a matrix from this quaternion
87 void getMatrix_transposed( matrix4 &dest ) const;
89 //! Inverts this quaternion
90 void makeInverse();
92 //! set this quaternion to the result of the interpolation between two quaternions
93 void slerp( quaternion q1, quaternion q2, f32 interpolate );
95 //! axis must be unit length
96 //! The quaternion representing the rotation is
97 //! q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)
98 void fromAngleAxis (f32 angle, const vector3df& axis);
100 //! Fills an angle (radians) around an axis (unit vector)
101 void toAngleAxis (f32 &angle, vector3df& axis) const;
103 //! Output this quaternion to an euler angle (radians)
104 void toEuler(vector3df& euler) const;
106 //! set quaternion to identity
107 void makeIdentity();
109 //! sets quaternion to represent a rotation from one angle to another
110 void rotationFromTo(const vector3df& from, const vector3df& to);
112 f32 X, Y, Z, W;
116 //! Constructor which converts euler angles to a quaternion
117 inline quaternion::quaternion(f32 x, f32 y, f32 z)
119 set(x,y,z);
123 //! Constructor which converts euler angles to a quaternion
124 inline quaternion::quaternion(const vector3df& vec)
126 set(vec.X,vec.Y,vec.Z);
130 //! Constructor which converts a matrix to a quaternion
131 inline quaternion::quaternion(const matrix4& mat)
133 (*this) = mat;
137 //! equal operator
138 inline bool quaternion::operator==(const quaternion& other) const
140 if(X != other.X)
141 return false;
142 if(Y != other.Y)
143 return false;
144 if(Z != other.Z)
145 return false;
146 if(W != other.W)
147 return false;
149 return true;
153 //! assignment operator
154 inline quaternion& quaternion::operator=(const quaternion& other)
156 X = other.X;
157 Y = other.Y;
158 Z = other.Z;
159 W = other.W;
160 return *this;
164 //! matrix assignment operator
165 inline quaternion& quaternion::operator=(const matrix4& m)
167 f32 diag = m(0,0) + m(1,1) + m(2,2) + 1;
168 f32 scale = 0.0f;
170 if( diag > 0.0f )
172 scale = sqrtf(diag) * 2.0f; // get scale from diagonal
174 // TODO: speed this up
175 X = ( m(2,1) - m(1,2)) / scale;
176 Y = ( m(0,2) - m(2,0)) / scale;
177 Z = ( m(1,0) - m(0,1)) / scale;
178 W = 0.25f * scale;
180 else
182 if ( m(0,0) > m(1,1) && m(0,0) > m(2,2))
184 // 1st element of diag is greatest value
185 // find scale according to 1st element, and double it
186 scale = sqrtf( 1.0f + m(0,0) - m(1,1) - m(2,2)) * 2.0f;
188 // TODO: speed this up
189 X = 0.25f * scale;
190 Y = (m(0,1) + m(1,0)) / scale;
191 Z = (m(2,0) + m(0,2)) / scale;
192 W = (m(2,1) - m(1,2)) / scale;
194 else if ( m(1,1) > m(2,2))
196 // 2nd element of diag is greatest value
197 // find scale according to 2nd element, and double it
198 scale = sqrtf( 1.0f + m(1,1) - m(0,0) - m(2,2)) * 2.0f;
200 // TODO: speed this up
201 X = (m(0,1) + m(1,0) ) / scale;
202 Y = 0.25f * scale;
203 Z = (m(1,2) + m(2,1) ) / scale;
204 W = (m(0,2) - m(2,0) ) / scale;
206 else
208 // 3rd element of diag is greatest value
209 // find scale according to 3rd element, and double it
210 scale = sqrtf( 1.0f + m(2,2) - m(0,0) - m(1,1)) * 2.0f;
212 // TODO: speed this up
213 X = (m(0,2) + m(2,0)) / scale;
214 Y = (m(1,2) + m(2,1)) / scale;
215 Z = 0.25f * scale;
216 W = (m(1,0) - m(0,1)) / scale;
220 normalize();
221 return *this;
225 //! multiplication operator
226 inline quaternion quaternion::operator*(const quaternion& other) const
228 quaternion tmp;
230 tmp.W = (other.W * W) - (other.X * X) - (other.Y * Y) - (other.Z * Z);
231 tmp.X = (other.W * X) + (other.X * W) + (other.Y * Z) - (other.Z * Y);
232 tmp.Y = (other.W * Y) + (other.Y * W) + (other.Z * X) - (other.X * Z);
233 tmp.Z = (other.W * Z) + (other.Z * W) + (other.X * Y) - (other.Y * X);
235 return tmp;
239 //! multiplication operator
240 inline quaternion quaternion::operator*(f32 s) const
242 return quaternion(s*X, s*Y, s*Z, s*W);
245 //! multiplication operator
246 inline quaternion& quaternion::operator*=(f32 s)
248 X *= s; Y*=s; Z*=s; W*=s;
249 return *this;
252 //! multiplication operator
253 inline quaternion& quaternion::operator*=(const quaternion& other)
255 *this = other * (*this);
256 return *this;
259 //! add operator
260 inline quaternion quaternion::operator+(const quaternion& b) const
262 return quaternion(X+b.X, Y+b.Y, Z+b.Z, W+b.W);
266 //! Creates a matrix from this quaternion
267 inline matrix4 quaternion::getMatrix() const
269 core::matrix4 m;
271 m(0,0) = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z;
272 m(1,0) = 2.0f*X*Y + 2.0f*Z*W;
273 m(2,0) = 2.0f*X*Z - 2.0f*Y*W;
274 m(3,0) = 0.0f;
276 m(0,1) = 2.0f*X*Y - 2.0f*Z*W;
277 m(1,1) = 1.0f - 2.0f*X*X - 2.0f*Z*Z;
278 m(2,1) = 2.0f*Z*Y + 2.0f*X*W;
279 m(3,1) = 0.0f;
281 m(0,2) = 2.0f*X*Z + 2.0f*Y*W;
282 m(1,2) = 2.0f*Z*Y - 2.0f*X*W;
283 m(2,2) = 1.0f - 2.0f*X*X - 2.0f*Y*Y;
284 m(3,2) = 0.0f;
286 m(0,3) = 0.0f;
287 m(1,3) = 0.0f;
288 m(2,3) = 0.0f;
289 m(3,3) = 1.0f;
291 return m;
295 //! Creates a matrix from this quaternion
296 inline void quaternion::getMatrix( matrix4 &dest ) const
298 dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z;
299 dest[1] = 2.0f*X*Y + 2.0f*Z*W;
300 dest[2] = 2.0f*X*Z - 2.0f*Y*W;
301 dest[3] = 0.0f;
303 dest[4] = 2.0f*X*Y - 2.0f*Z*W;
304 dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z;
305 dest[6] = 2.0f*Z*Y + 2.0f*X*W;
306 dest[7] = 0.0f;
308 dest[8] = 2.0f*X*Z + 2.0f*Y*W;
309 dest[9] = 2.0f*Z*Y - 2.0f*X*W;
310 dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y;
311 dest[11] = 0.0f;
313 dest[12] = 0.f;
314 dest[13] = 0.f;
315 dest[14] = 0.f;
316 dest[15] = 1.f;
319 //! Creates a matrix from this quaternion
320 inline void quaternion::getMatrix_transposed( matrix4 &dest ) const
322 dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z;
323 dest[4] = 2.0f*X*Y + 2.0f*Z*W;
324 dest[8] = 2.0f*X*Z - 2.0f*Y*W;
325 dest[12] = 0.0f;
327 dest[1] = 2.0f*X*Y - 2.0f*Z*W;
328 dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z;
329 dest[9] = 2.0f*Z*Y + 2.0f*X*W;
330 dest[13] = 0.0f;
332 dest[2] = 2.0f*X*Z + 2.0f*Y*W;
333 dest[6] = 2.0f*Z*Y - 2.0f*X*W;
334 dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y;
335 dest[14] = 0.0f;
337 dest[3] = 0.f;
338 dest[7] = 0.f;
339 dest[11] = 0.f;
340 dest[15] = 1.f;
345 //! Inverts this quaternion
346 inline void quaternion::makeInverse()
348 X = -X; Y = -Y; Z = -Z;
351 //! sets new quaternion
352 inline void quaternion::set(f32 x, f32 y, f32 z, f32 w)
354 X = x;
355 Y = y;
356 Z = z;
357 W = w;
361 //! sets new quaternion based on euler angles
362 inline void quaternion::set(f32 x, f32 y, f32 z)
364 f64 angle;
366 angle = x * 0.5;
367 f64 sr = (f32)sin(angle);
368 f64 cr = (f32)cos(angle);
370 angle = y * 0.5;
371 f64 sp = (f32)sin(angle);
372 f64 cp = (f32)cos(angle);
374 angle = z * 0.5;
375 f64 sy = (f32)sin(angle);
376 f64 cy = (f32)cos(angle);
378 f64 cpcy = cp * cy;
379 f64 spcy = sp * cy;
380 f64 cpsy = cp * sy;
381 f64 spsy = sp * sy;
383 X = (f32)(sr * cpcy - cr * spsy);
384 Y = (f32)(cr * spcy + sr * cpsy);
385 Z = (f32)(cr * cpsy - sr * spcy);
386 W = (f32)(cr * cpcy + sr * spsy);
388 normalize();
391 //! sets new quaternion based on euler angles
392 inline void quaternion::set(const core::vector3df& vec)
394 set(vec.X, vec.Y, vec.Z);
397 //! normalizes the quaternion
398 inline quaternion& quaternion::normalize()
400 f32 n = X*X + Y*Y + Z*Z + W*W;
402 if (n == 1)
403 return *this;
405 //n = 1.0f / sqrtf(n);
406 n = reciprocal_squareroot ( n );
407 X *= n;
408 Y *= n;
409 Z *= n;
410 W *= n;
412 return *this;
416 // set this quaternion to the result of the interpolation between two quaternions
417 inline void quaternion::slerp( quaternion q1, quaternion q2, f32 time)
419 f32 angle = q1.getDotProduct(q2);
421 if (angle < 0.0f)
423 q1 *= -1.0f;
424 angle *= -1.0f;
427 f32 scale;
428 f32 invscale;
430 if ((angle + 1.0f) > 0.05f)
432 if ((1.0f - angle) >= 0.05f) // spherical interpolation
434 f32 theta = (f32)acos(angle);
435 f32 invsintheta = 1.0f / (f32)sin(theta);
436 scale = (f32)sin(theta * (1.0f-time)) * invsintheta;
437 invscale = (f32)sin(theta * time) * invsintheta;
439 else // linear interploation
441 scale = 1.0f - time;
442 invscale = time;
445 else
447 q2.set(-q1.Y, q1.X, -q1.W, q1.Z);
448 scale = (f32)sin(PI * (0.5f - time));
449 invscale = (f32)sin(PI * time);
452 *this = (q1*scale) + (q2*invscale);
456 //! calculates the dot product
457 inline f32 quaternion::getDotProduct(const quaternion& q2) const
459 return (X * q2.X) + (Y * q2.Y) + (Z * q2.Z) + (W * q2.W);
463 inline void quaternion::fromAngleAxis(f32 angle, const vector3df& axis)
465 f32 fHalfAngle = 0.5f*angle;
466 f32 fSin = (f32)sin(fHalfAngle);
467 W = (f32)cos(fHalfAngle);
468 X = fSin*axis.X;
469 Y = fSin*axis.Y;
470 Z = fSin*axis.Z;
473 inline void quaternion::toAngleAxis(f32 &angle, core::vector3df &axis) const
475 f32 scale = sqrtf(X*X + Y*Y + Z*Z);
477 if (core::iszero(scale) || W > 1.0f || W < -1.0f)
479 angle = 0.0f;
480 axis.X = 0.0f;
481 axis.Y = 1.0f;
482 axis.Z = 0.0f;
484 else
486 angle = 2.0f * acos(W);
487 axis.X = X / scale;
488 axis.Y = Y / scale;
489 axis.Z = Z / scale;
493 inline void quaternion::toEuler(vector3df& euler) const
495 double sqw = W*W;
496 double sqx = X*X;
497 double sqy = Y*Y;
498 double sqz = Z*Z;
500 // heading = rotation about z-axis
501 euler.Z = (f32) (atan2(2.0 * (X*Y +Z*W),(sqx - sqy - sqz + sqw)));
503 // bank = rotation about x-axis
504 euler.X = (f32) (atan2(2.0 * (Y*Z +X*W),(-sqx - sqy + sqz + sqw)));
506 // attitude = rotation about y-axis
507 euler.Y = (f32) (asin( clamp(-2.0 * (X*Z - Y*W), -1.0, 1.0) ));
510 inline vector3df quaternion::operator* (const vector3df& v) const
512 // nVidia SDK implementation
514 vector3df uv, uuv;
515 vector3df qvec(X, Y, Z);
516 uv = qvec.crossProduct(v);
517 uuv = qvec.crossProduct(uv);
518 uv *= (2.0f * W);
519 uuv *= 2.0f;
521 return v + uv + uuv;
524 //! set quaterion to identity
525 inline void quaternion::makeIdentity()
527 W = 1.f;
528 X = 0.f;
529 Y = 0.f;
530 Z = 0.f;
533 inline void quaternion::rotationFromTo(const vector3df& from, const vector3df& to)
535 // Based on Stan Melax's article in Game Programming Gems
536 // Copy, since cannot modify local
537 vector3df v0 = from;
538 vector3df v1 = to;
539 v0.normalize();
540 v1.normalize();
542 vector3df c = v0.crossProduct(v1);
544 f32 d = v0.dotProduct(v1);
545 if (d >= 1.0f) // If dot == 1, vectors are the same
547 *this=quaternion(0,0,0,1); //IDENTITY;
549 f32 s = sqrtf( (1+d)*2 ); // optimize inv_sqrt
550 f32 invs = 1 / s;
552 X = c.X * invs;
553 Y = c.Y * invs;
554 Z = c.Z * invs;
555 W = s * 0.5f;
559 } // end namespace core
560 } // end namespace irr
562 #endif