//===========================================================================//
// File:	AngleAxis.hpp                                                 
// Project: MechWarrior 4
// Contents: 
//			AngleAxis class for animation.  This is just an unlimited rotation
//	quaternion
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 07/01/98  JSE  Initial coding, 
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Fasa Interactive, Inc.
// All Rights reserved worldwide
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL
//===========================================================================//

#pragma once

#include "MW4AnimationSystem.hpp"

	namespace MW4Animation {class AngleAxis;}

	#if !defined(Spew)
		void
			Spew(
				const char* group,
				const MW4Animation::AngleAxis &angle
			);
	#endif

namespace MW4Animation {

	//===========================================================================//
	//  This is my angleaxis routines

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AngleAxis ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	//##########################################################################
	//#########################    AnglelAxis    ###############################
	//##########################################################################
	// This class is like a quaternion, except that it stores rotations over
	// PI

	class AngleAxis {
		public:
			Stuff::UnitVector3D axis;
			Stuff::Scalar angle;

			AngleAxis() {}
			AngleAxis(const Stuff::UnitVector3D& axis,Stuff::Scalar angle) 
				{this->axis=axis;this->angle=angle;}	
			
			AngleAxis&
				operator=(const AngleAxis &ang)
				{
					Check_Pointer(this); Check_Pointer(&ang);
					axis = ang.axis; angle = ang.angle; return *this;
				}
			
			AngleAxis&
				operator=(const Stuff::UnitQuaternion &quat)
				{
					Stuff::Scalar omega,s;
					Stuff::UnitQuaternion qn = quat;	
					qn.Normalize();
					omega = (Stuff::Scalar)acos(qn.w);
					angle = 2.0f*omega;
					s = (Stuff::Scalar)sin(omega);	
					if (!Stuff::Small_Enough(s)) 
					{
						axis.x = qn.x/s;
						axis.y = qn.x/s;
						axis.z = qn.x/s;
					}
					else
					{
						axis = Stuff::Point3D(0.0f,0.0f,0.0f);
					}
					
					return *this;
				}


			static 
				Stuff::UnitQuaternion
					AngleAxisToQuaternion(AngleAxis& angl)
				{
					Stuff::UnitQuaternion q;
					Stuff::Scalar omega,s;
					omega = angl.angle*0.5f;
					s = (Stuff::Scalar)sin(omega);
					q.x = s*angl.axis.x;
					q.y = s*angl.axis.y;
					q.z = s*angl.axis.z;
					q.w = (Stuff::Scalar)cos(omega);
					return q;
				}
			
			int GetNumRevs()
				{return int(angle/Stuff::Two_Pi);}

			void SetNumRevs(int num)
				{angle += Stuff::Scalar(num)*Stuff::Two_Pi;}

			void MakeLessThan180()
			{
				Stuff::Scalar temp_ang;
				MakeAngPos();
				temp_ang = angle;
				while (temp_ang > Stuff::Two_Pi)
				{
					temp_ang -= Stuff::Two_Pi;
				}

				if (fabs(temp_ang) > Stuff::Pi)
				{
					temp_ang -= Stuff::Two_Pi;
				}
				angle = temp_ang;
				MakeAngPos();

			}

			void MakeAngPos()
			{
				if (angle < 0.0f)
				{
					angle = -angle;
					axis.x = -axis.x;
					axis.y = -axis.y;
					axis.z = -axis.z;
				}
			}

			#if !defined(Spew)
				friend void
					::Spew(
						const char* group,
						const AngleAxis& angles
					)
					{
						SPEW((group, "<+"));
						Spew(group, angles.axis);
						SPEW((group, "><%f>+", angles.angle));
					}
			#endif
	};
}

