/*
	Trampoline Sim.
	Copyright (c) 2009, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef GAME_QUATERNION_H
#define GAME_QUATERNION_H

//=====================================================================================================================
//=====================================================================================================================

#include "Base\Assertion.h"

//=====================================================================================================================
//=====================================================================================================================

namespace Game
{
	//=================================================================================================================
	/// @brief		Object representing a quaternion. Quaternions are representations of rotations using 3 complex 
	///				numbers and 1 real number.
	//=================================================================================================================

	template <class T> struct Quaternion
	{
		public:

			//=========================================================================================================
			// Functions
			//=========================================================================================================

				//=====================================================================================================
				/// @brief		Constructor. Creates the quaternion from the given components
				/// @param		x - x component of the quaternion (imaginary part)
				/// @param		y - y component of the quaternion (imaginary part)
				/// @param		z - z component of the quaternion (imaginary part)
				/// @param		s - s component of the quaternion (real part)
				//=====================================================================================================
				
				inline Quaternion( T x = (T) 0 , T y = (T) 0 , T z = (T) 0 , T s = (T) 1 )
				{
					this->x = x;
					this->y = y;
					this->z = z;
					this->s = s;
				}
				
				//=====================================================================================================
				/// @brief		Copy constructor. Creates this quaternion from another.
				/// @param		other - other quaternion to create from
				//=====================================================================================================
				
				template <class QT> inline Quaternion( const Quaternion<QT> & other )
				{
					this->x = (T) other.x;
					this->y = (T) other.y;
					this->z = (T) other.z;
					this->s = (T) other.s;
				}
			
				//=====================================================================================================
				/// @brief		Constructor. Creates this quaternion from a given vector, interpreting it as 
				///				a quaternion. XYZ components are the same, W component is the S component.
				/// @param		other - other vector to create from
				//=====================================================================================================
				
				template <class VT> inline Quaternion( const Vector4<VT> & other )
				{
					this->x = (T) other.x;
					this->y = (T) other.y;
					this->z = (T) other.z;
					this->s = (T) other.w;
				}
				
				//=====================================================================================================
				/// @brief		Constructor. Creates this quaternion from a given 3x3 rotation matrix
				/// @param		other - other matrix to create from
				//=====================================================================================================
				
				template <class MT> inline Quaternion( const Matrix3<MT> & other )
				{
					// Need to transpose the matrix: otherwise we get the inverse rotation

					Matrix3<T> t = other.Transpose();

					// Compute the s component
				
					s = (T)( t.m_components[0][0] + t.m_components[1][1] + t.m_components[2][2] ) + (T)(1);					
					s = (T)( Float::Sqrt( (float)(s) ) * 0.5f );
					
					// This divides by four times 's'
					
					T div = ((T)(1)) / ((T)(4) * s );
				
					x = ( t.m_components[2][1] - t.m_components[1][2] ) * div;
					y = ( t.m_components[0][2] - t.m_components[2][0] ) * div;
					z = ( t.m_components[1][0] - t.m_components[0][1] ) * div;
				}
				
				//=====================================================================================================
				/// @brief		Constructor. Creates this quaternion from a given 4x4 rotation matrix
				/// @param		other - other matrix to create from
				//=====================================================================================================
				
				template <class MT> inline Quaternion( const Matrix4<MT> & other )
				{
					// Need to transpose the matrix: otherwise we get the inverse rotation

					Matrix4<T> t = other.Transpose();

					// Compute the s component
				
					s = (T)( t.m_components[0][0] + t.m_components[1][1] + t.m_components[2][2] ) + (T)(1);					
					s = (T)( Float::Sqrt( (float)(s) ) * 0.5f );
					
					// This divides by four times 's'
					
					T div = ((T)(1)) / ((T)(4) * s );
				
					x = ( t.m_components[2][1] - t.m_components[1][2] ) * div;
					y = ( t.m_components[0][2] - t.m_components[2][0] ) * div;
					z = ( t.m_components[1][0] - t.m_components[0][1] ) * div;
				}			
				
				//=====================================================================================================
				/// @brief		Assignment operator. Assigns the other quaternion to this quaternion.
				/// @param		other - other quaternion to create from
				/// @returns	This quaternion
				//=====================================================================================================
				
				template <class QT> inline Quaternion<T> & operator = ( const Quaternion<QT> & other )
				{
					this->x = (T) other.x;
					this->y = (T) other.y;
					this->z = (T) other.z;
					this->s = (T) other.s;
					
					return * this;
				}
				
				//=====================================================================================================
				/// @brief		Assignment operator. Assigns the other vector to this quaternion, interpreting it as
				///				a quaterion. XYZ components are the same, W component is the S component.
				/// @param		other - other vector to create from
				/// @returns	This quaternion
				//=====================================================================================================
				
				template <class VT> inline Quaternion<T> & operator = ( const Vector4<VT> & other )
				{
					this->x = (T) other.x;
					this->y = (T) other.y;
					this->z = (T) other.z;
					this->s = (T) other.w;
					
					return * this;
				}
				
				//=====================================================================================================
				/// @brief		Assigment operator. Assigns the given 3x3 rotation matrix to this quaternion.
				/// @param		other - other matrix to assign from
				/// @returns	This quaternion
				//=====================================================================================================
				
				template <class MT> inline Quaternion & operator = ( const Matrix3<MT> & other )
				{
					// Need to transpose the matrix: otherwise quaternion ends up being the inverse of the other matrix

					Matrix3<T> t = other.Transpose();

					// Compute the s component
				
					s = (T)( t.m_components[0][0] + t.m_components[1][1] + t.m_components[2][2] ) + (T)(1);					
					s = (T)( Float::Sqrt( (float)(s) ) * 0.5f );
					
					// This divides by four times 's'
					
					T div = ((T)(1)) / ((T)(4) * s );
				
					x = ( t.m_components[2][1] - t.m_components[1][2] ) * div;
					y = ( t.m_components[0][2] - t.m_components[2][0] ) * div;
					z = ( t.m_components[1][0] - t.m_components[0][1] ) * div;
					
					return * this;
				}
				
				//=====================================================================================================
				/// @brief		Assigment operator. Assigns the given 4x4 rotation matrix to this quaternion.
				/// @param		other - other matrix to assign from
				/// @returns	This quaternion
				//=====================================================================================================
				
				template <class MT> inline Quaternion & operator = ( const Matrix4<MT> & other )
				{
					// Need to transpose the matrix: otherwise quaternion ends up being the inverse of the other matrix

					Matrix4<T> t = other.Transpose();

					// Compute the s component
				
					s = (T)( t.m_components[0][0] + t.m_components[1][1] + t.m_components[2][2] ) + (T)(1);					
					s = (T)( Float::Sqrt( (float)(s) ) * 0.5f );
					
					// This divides by four times 's'
					
					T div = ((T)(1)) / ((T)(4) * s );
				
					x = ( t.m_components[2][1] - t.m_components[1][2] ) * div;
					y = ( t.m_components[0][2] - t.m_components[2][0] ) * div;
					z = ( t.m_components[1][0] - t.m_components[0][1] ) * div;
					
					return * this;
				}				
				
				//=====================================================================================================
				/// @brief		Array index accessor. Returns a copy of the variable at the given index.
				/// @param		i - element to access
				/// @returns	chosen element
				/// @remarks	indexes access the elements in this order: x,y,z,s
				/// @pre		Given index must be in range				
				//=====================================================================================================
				
				inline T operator[]( unsigned i ) const
				{
					ENSURE( i < 3 , "Given index must be in range" );
				
					return *((&x)+i);
				}
				
				//=====================================================================================================
				/// @brief		Array index accessor. Returns a reference of the variable at the given index.
				/// @param		i - element to access
				/// @returns	chosen element, ready for writing
				/// @remarks	indexes access the elements in this order: x,y,z,s
				/// @pre		Given index must be in range
				//=====================================================================================================
				
				inline T & operator[]( unsigned i )
				{
					ENSURE( i < 3 , "Given index must be in range" );
				
					return *((&x)+i);
				}
				
				//=====================================================================================================
				/// @brief		Multiplies two quaternions together, thus combining rotations
				/// @param		other - other quaternion to multiply by
				/// @returns	A new quaternion that is the result of the two operations
				//=====================================================================================================
				
				template <class QT> inline Quaternion<T> operator * ( const Quaternion<QT> & other ) const
				{
					return Quaternion<T>
					(
						( s * (T) other.x ) + ( (T) other.s * x ) + ( y * (T) other.z ) - ( (T) other.y * z ) ,
						( s * (T) other.y ) + ( (T) other.s * y ) + ( z * (T) other.x ) - ( (T) other.z * x ) ,
						( s * (T) other.z ) + ( (T) other.s * z ) + ( x * (T) other.y ) - ( (T) other.x * y ) ,
						( s * (T) other.s ) - ( x * (T) other.x ) - ( y * (T) other.y ) - ( z * (T) other.z )
					);
				}
				
				//=====================================================================================================
				/// @brief		Adds two quaternions together
				/// @param		other - other quaternion to add to this one
				/// @returns	A new quaternion that is the result of the two operations
				//=====================================================================================================
				
				template <class QT> inline Quaternion<T> operator + ( const Quaternion<QT> & other ) const
				{
					return Quaternion<T>
					(
						x + (T)(other.x) ,
						y + (T)(other.y) ,
						z + (T)(other.z) ,
						s + (T)(other.s) 
					);
				}
				
				//=====================================================================================================
				/// @brief		Multiplies a quaternion by a vector, interpreting the other vector as a quaternion
				///				with the xyz coordinates as the xyz coordinates of the quaterion and the w coordinate
				///				as the s component of the quaternion.
				/// @param		other - other vector to multiply by
				/// @returns	A new quaternion that is the result of the operation
				//=====================================================================================================
				
				template <class VT> inline Quaternion<T> operator * ( const Vector4<VT> & other ) const
				{
					return Quaternion<T>
					(
						( s * (T) other.x ) + ( (T) other.w * x ) + ( y * (T) other.z ) - ( (T) other.y * z ) ,
						( s * (T) other.y ) + ( (T) other.w * y ) + ( z * (T) other.x ) - ( (T) other.z * x ) ,
						( s * (T) other.z ) + ( (T) other.w * z ) + ( x * (T) other.y ) - ( (T) other.x * y ) ,
						( s * (T) other.w ) - ( x * (T) other.x ) - ( y * (T) other.y ) - ( z * (T) other.z )
					);
				}
				
				//=====================================================================================================
				/// @brief		Adds a 4D vector to this quaternion, interpreting it as a quaternion. W component
				///				becomes the S component of the quaternion.
				/// @param		other - other vector to add to this one
				/// @returns	A new quaternion that is the result of the operation
				//=====================================================================================================
				
				template <class VT> inline Quaternion<T> operator + ( const Vector4<VT> & other ) const
				{
					return Quaternion<T>
					(
						x + (T)(other.x) ,
						y + (T)(other.y) ,
						z + (T)(other.z) ,
						s + (T)(other.w) 
					);
				}				
				
				//=====================================================================================================
				/// @brief		Multiplies this quaternion by a scalar
				/// @param		v - value to multiply by
				/// @returns	Returns the result of the multiplication
				//=====================================================================================================
				
				template <class ST> inline Quaternion<T> operator * ( ST v ) const
				{
					return Quaternion<T>
					(
						x * (T) v ,
						y * (T) v ,
						z * (T) v ,
						s * (T) v 
					);
				}
				
				//=====================================================================================================
				/// @brief		Divides this quaternion by a scalar
				/// @param		v - value to divide by
				/// @returns	Returns the result of the division
				//=====================================================================================================
				
				template <class ST> inline Quaternion<T> operator / ( ST v ) const
				{
					// This divides by the scalar
					
					T div = ((T)(1)) / ((T)(v));
				
					return Quaternion<T>
					(
						x * div ,
						y * div ,
						z * div ,
						s * div
					);
				}				
				
				//=====================================================================================================
				/// @brief		Multiplies a quaternion by a vector, interpreting the other vector as a quaternion
				///				with the xyz coordinates as the xyz coordinates of the quaterion and the w coordinate
				///				as the s component of the quaternion.
				/// @param		other - other quaternion to multiply by
				//=====================================================================================================
				
				template <class VT> inline void operator *= ( const Vector4<VT> & other )
				{
					// Do the multiply 
					
					* this = ( * this ) * other;
				}
				
				//=====================================================================================================
				/// @brief		Adds two quaternions together
				/// @param		other - other quaternion to add to this one
				//=====================================================================================================
				
				template <class QT> inline void operator += ( const Quaternion<QT> & other )
				{
					x += (T)(other.x);
					y += (T)(other.y);
					z += (T)(other.z);
					s += (T)(other.s);
				}				
				
				//=====================================================================================================
				/// @brief		Multiplies this quaternion by another vector
				/// @param		other - other quaternion to multiply by
				//=====================================================================================================
				
				template <class QT> inline void operator *= ( const Quaternion<QT> & other )
				{
					// Do the multiply 
					
					* this = ( * this ) * other;
				}
				
				//=====================================================================================================
				/// @brief		Adds two quaternions together. Interprets the given vector as a quaternion where the 
				///				W component corresponds to the s component of the quaternion.
				/// @param		other - other quaternion to add to this one
				//=====================================================================================================
				
				template <class VT> inline void operator += ( const Vector4<VT> & other )
				{
					x += (T)(other.x);
					y += (T)(other.y);
					z += (T)(other.z);
					s += (T)(other.w);
				}
				
				//=====================================================================================================
				/// @brief		Multiplies this quaternion by a scalar
				/// @param		v - value to multiply by
				//=====================================================================================================
				
				template <class ST> inline void operator *= ( ST v )
				{
					x *= (T) v;
					y *= (T) v;
					z *= (T) v;
					s *= (T) v;
				}
				
				//=====================================================================================================
				/// @brief		Divides this quaternion by a scalar
				/// @param		v - value to divide by
				//=====================================================================================================
				
				template <class ST> inline void operator /= ( ST v )
				{
					// This divides by the scalar
					
					T div = ((T)(1)) / ((T)(v));					
				
					x *= (T) div;
					y *= (T) div;
					z *= (T) div;
					s *= (T) div;
				}
				
				//=====================================================================================================
				/// @brief		Gives the square magnitude of this quaternion
				/// @returns	The square magnitude of the quaternion
				//=====================================================================================================
				
				inline T SqMagnitude() const 
				{
					return ( x * x ) + ( y * y ) + ( z * z ) + ( s * s );
				}
				
				//=====================================================================================================
				/// @brief		Gives the magnitude of this quaternion
				/// @returns	The magnitude of the quaternion
				//=====================================================================================================
				
				inline T Magnitude() const 
				{
					return (T) Float::Sqrt( float( ( x * x ) + ( y * y ) + ( z * z ) + ( s * s ) ) );
				}
				
				//=====================================================================================================
				/// @brief		Returns the conjugate of this quaternion
				/// @returns	The conjugate of the quaternion
				//=====================================================================================================
				
				inline Quaternion<T> Conjugate() const 
				{
					return Quaternion<T>
					(
						- x ,
						- y , 
						- z ,
						s
					);
				}
				
				//=====================================================================================================
				/// @brief		Returns the inverse of this quaternion
				/// @remarks	This function assumes there is an inverse to the quaternion	
				/// @pre		The magnitude of the quaternion should not be zero
				//=====================================================================================================
				
				inline Quaternion<T> Inverse() const 
				{ 
					// Make sure ok
					
					ENSURE( SqMagnitude() > 0 , "The magnitude of the quaternion should not be zero" )
					
					// Return
				
					return Conjugate() / SqMagnitude(); 
				}
				
				//=====================================================================================================
				/// @brief		Normalises this quaternion
				/// @returns	The previous magnitude of the quaternion
				/// @remarks	This function will check for divisions by zero and is safe
				//=====================================================================================================
				
				inline T Normalize()
				{
					// Get the magnitude:
					
					T magnitude = Magnitude();
					
					// Only if not zero:
					
					if ( magnitude != (T)(0) )
					{
						// Get the inverse magnitude:
						
						T inv_magnitude = ((T)(1)) / magnitude;
						
						// Scale all components by this
						
						x *= inv_magnitude;
						y *= inv_magnitude;
						z *= inv_magnitude;
						s *= inv_magnitude;
					}
					else
					{
						// Identity quaternion:

						x = 0;
						y = 0;
						z = 0;
						s = 1;
					}
					
					// Return
					
					return magnitude;
				}
				
				//=====================================================================================================
				/// @brief		Converts this quaternion to a 3D vector, discarding the s (real component)
				/// @returns	A 3D vector representing this quaternion's xyz components
				//=====================================================================================================
				
				inline Vector3<T> ToVec3() const { return Vector3<T>(x,y,z); }				
				
				//=====================================================================================================
				/// @brief		Converts this quaternion to a 4D vector.
				/// @returns	A 4D vector representing this quaternion. XYZ axes are the same, W component is the S
				///				component.
				//=====================================================================================================
				
				inline Vector4<T> ToVec4() const { return Vector4<T>(x,y,z,s); }
				
				//=====================================================================================================
				/// @brief		Converts this quaternion to a 3x3 matrix
				/// @returns	A 3x3 rotation matrix that represents the rotation that this quaternion represents.
				//=====================================================================================================
				
				inline Matrix3<T> ToMatrix3() const 
				{ 
					return Matrix3<T>
					(
						((T)(1)) - ( (T)(2) * y * y ) - ( (T)(2) * z * z )	,
						((T)(2) * x * y ) - ((T)(2) * s * z )				,
						((T)(2) * x * z ) + ((T)(2) * s * y )				,
						
						((T)(2) * x * y ) + ((T)(2) * s * z )				,
						((T)(1)) - ( (T)(2) * x * x ) - ( (T)(2) * z * z )	,
						((T)(2) * y * z ) - ((T)(2) * s * x )				,
						
						((T)(2) * x * z ) - ((T)(2) * s * y )				,
						((T)(2) * y * z ) + ((T)(2) * s * x )				,
						((T)(1)) - ( (T)(2) * x * x ) - ( (T)(2) * y * y )

					).Transpose();
				}
				
				//=====================================================================================================
				/// @brief		Converts this quaternion to a 4x4 matrix
				/// @returns	A 4x4 rotation matrix that represents the rotation that this quaternion represents.
				//=====================================================================================================
				
				inline Matrix4<T> ToMatrix4() const 
				{ 
					return Matrix4<T>
					(
						((T)(1)) - ( (T)(2) * y * y ) - ( (T)(2) * z * z )	,
						((T)(2) * x * y ) - ((T)(2) * s * z )				,
						((T)(2) * x * z ) + ((T)(2) * s * y )				,
						0													,
						
						((T)(2) * x * y ) + ((T)(2) * s * z )				,
						((T)(1)) - ( (T)(2) * x * x ) - ( (T)(2) * z * z )	,
						((T)(2) * y * z ) - ((T)(2) * s * x )				,
						0													,
						
						((T)(2) * x * z ) - ((T)(2) * s * y )				,
						((T)(2) * y * z ) + ((T)(2) * s * x )				,
						((T)(1)) - ( (T)(2) * x * x ) - ( (T)(2) * y * y )	,
						0													,
						
						0 ,
						0 ,
						0 ,
						1

					).Transpose();
				}
				
				//=====================================================================================================
				/// @brief		Transforms the given vector by this quaternion
				/// @param		v - vector to transform
				/// @returns	The transformed vector
				/// @remarks	The w component for the rotated vector will remain unchanged
				//=====================================================================================================
				
				template <class VT> inline Vector3<VT> Transform( const Vector3<VT> & other ) const
				{
					// Get the inverse of this quaternion
					
					Quaternion<T> inv = Inverse();
					
					// Calculate the rotated point:
					
					Quaternion<VT> rotated = (*this) * Quaternion<VT>(other.x,other.y,other.z,0) * inv;
					
					// Return the rotated point:
					
					return Vector3<VT>(rotated.x,rotated.y,rotated.z);
				}
				
				//=====================================================================================================
				/// @brief		Transforms the given vector by this quaternion
				/// @param		v - vector to transform
				/// @returns	The transformed vector
				/// @remarks	The w component for the rotated vector will remain unchanged
				//=====================================================================================================
				
				template <class VT> inline Vector4<VT> Transform( const Vector4<VT> & other ) const
				{
					// Get the inverse of this quaternion
					
					Quaternion<T> inv = Inverse();
					
					// Calculate the rotated point:
					
					Quaternion<VT> rotated = (*this) * other * inv;
					
					// Return the rotated point:
					
					return Vector4<VT>(rotated.x,rotated.y,rotated.z,other.w);
				}
				
				//=====================================================================================================
				/// @brief		Returns the identity quaternion
				/// @param		other - other quaternion to multiply by
				//=====================================================================================================
				
				static inline Quaternion<T> Identity(){ return Quaternion<T>(0,0,0,1); }				
				
				//=====================================================================================================
				/// @brief		Returns a quaternion to rotate 'a' radians through the given axis
				/// @param		ax - x component of the axis
				/// @param		ay - y component of the axis
				/// @param		az - z component of the axis
				/// @param		a - angle of the axis
				/// @pre		Axis of rotation must be normalized
				//=====================================================================================================
				
				static Quaternion<T> RotationAxis( T ax , T ay , T az , T a )
				{ 
					// Make sure ok:

					#ifdef DEBUG

						Vector3<T> axis(ax,ay,az);

						ENSURE
						(
							( axis.Length() > (T)( 0.99 ) ) && ( axis.Length() < (T)(1.01) ) , 
							"Axis of rotation must be normalized"
						)

					#endif				
					
					// Do the rotation
				
					return Quaternion<T>
					(
						(T)( Float::Sin( (float)(a) * 0.5f ) ) * ax ,
						(T)( Float::Sin( (float)(a) * 0.5f ) ) * ay ,
						(T)( Float::Sin( (float)(a) * 0.5f ) ) * az ,
						(T)( Float::Cos( (float)(a) * 0.5f ) )
					);
				}
				
				//=====================================================================================================
				/// @brief		Returns a quaternion to rotate 'a' radians through the given axis
				/// @param		axis - axis to rotate through
				/// @param		a - angle of the axis
				//=====================================================================================================
				
				static Quaternion<T> RotationAxis( const Vector3<T> & axis , T a )
				{ 					
					// Do the rotation
				
					return Quaternion<T>
					(
						(T)( Float::Sin( (float)(a) * 0.5f ) ) * axis.x ,
						(T)( Float::Sin( (float)(a) * 0.5f ) ) * axis.y ,
						(T)( Float::Sin( (float)(a) * 0.5f ) ) * axis.z ,
						(T)( Float::Cos( (float)(a) * 0.5f ) )
					);
				}
				
				//=====================================================================================================
				/// @brief		Returns a quaternion to rotate through the x axis by the given amount		
				/// @param		a - amount of rotation through the x axis
				/// @returns	The requested rotation
				//=====================================================================================================
				
				static Quaternion<T> RotationX( T a )
				{
					// Do the rotation:
					
					return RotationAxis( Vec3f(1,0,0) , a );
				}

				//=====================================================================================================
				/// @brief		Returns a quaternion to rotate through the y axis by the given amount		
				/// @param		a - amount of rotation through the y axis
				/// @returns	The requested rotation
				//=====================================================================================================
				
				static Quaternion<T> RotationY( T a )
				{
					// Do the rotation:
					
					return RotationAxis( Vec3f(0,1,0) , a );
				}

				//=====================================================================================================
				/// @brief		Returns a quaternion to rotate through the z axis by the given amount		
				/// @param		a - amount of rotation through the z axis
				/// @returns	The requested rotation
				//=====================================================================================================
				
				static Quaternion<T> RotationZ( T a )
				{
					// Do the rotation:
					
					return RotationAxis( Vec3f(0,0,1) , a );
				}
		
			//=========================================================================================================
			// Variables
			//=========================================================================================================
			
				/// X component for the quaternion : this is the multiplier of the i imaginary part
				
				T x;
				
				/// Y component for the quaternion : this is the multiplier of the j imaginary part
				
				T y;
				
				/// Z component for the quaternion : this is the multiplier of the k imaginary part
				
				T z;
				
				/// S component for the quaternion : this is the real part of the quaternion
				
				T s;
	};
};

#endif 
