#ifndef	__GEMMATH_H_
#define __GEMMATH_H_

#include <d3d.h>

class gem_Quat
{
public:

	FLOAT	w, x, y, z;	

	gem_Quat(FLOAT a = 0) : w(a), x(a), y(a), z(a)
	{
	}

	gem_Quat(FLOAT _w, FLOAT _x, FLOAT _y, FLOAT _z) : w(_w), x(_x), y(_y), z(_z)
	{
	}

	gem_Quat(gem_Quat& q) : w(q.w), x(q.x), y(q.y), z(q.z)
	{
	}
};


class gem_Vector
{
public:
	FLOAT	x, y, z;

	gem_Vector(FLOAT a = 0) : x(a), y(a), z(a)
	{
	}

	gem_Vector(FLOAT a, FLOAT b, FLOAT c) : x(a), y(b), z(c)
	{
	}

	gem_Vector(gem_Vector& v) : x(v.x), y(v.y), z(v.z)
	{
	}

	gem_Vector(D3DVECTOR& v) : x(v.dvX), y(v.dvY), z(v.dvZ)
	{
	}

};


class gem_Matrix
{
public:

	FLOAT	MATRIX[4][4];

	gem_Matrix()
	{
	}

	gem_Matrix(gem_Matrix& mat)
	{
		for( int i = 0 ; i<4 ; i++ )
			for( int j=0 ; j<4; j++ )
				MATRIX[i][j] = mat.MATRIX[i][j];
	}

	gem_Matrix(D3DMATRIX& mat)
	{
		MATRIX[0][0]=mat._11; MATRIX[0][1]=mat._12; MATRIX[0][2]=mat._13; MATRIX[0][3]=mat._14;
		MATRIX[1][0]=mat._21; MATRIX[1][1]=mat._22; MATRIX[1][2]=mat._23; MATRIX[1][3]=mat._24;
		MATRIX[2][0]=mat._31; MATRIX[2][1]=mat._32; MATRIX[2][2]=mat._33; MATRIX[2][3]=mat._34;
		MATRIX[3][0]=mat._41; MATRIX[3][1]=mat._42; MATRIX[3][2]=mat._43; MATRIX[3][3]=mat._44;
	}

	FLOAT& operator() (int row, int col)
	{
		return MATRIX[row-1][col-1];
	}

	gem_Matrix& operator= (gem_Matrix& mat)
	{
		if( this==&mat )
			return *this;

		for( int i=0 ; i<4 ; i++ )
			for( int j=0 ; j<4 ;  j++)
				MATRIX[i][j]=mat( i+1, j+1 );

		return *this;
	}

	operator D3DMATRIX ();

};


FLOAT	   Length(gem_Vector& v);
gem_Vector Normalize(gem_Vector& v);
FLOAT	   Dot(gem_Vector& v, gem_Vector& u);
gem_Vector Cross(gem_Vector& v, gem_Vector& u);
gem_Vector LERP(gem_Vector v, gem_Vector u, FLOAT a);
D3DVERTEX  vLERP( D3DVERTEX a, D3DVERTEX b, FLOAT t );
gem_Vector operator+ (gem_Vector& v, gem_Vector& u);
gem_Vector operator- (gem_Vector& v, gem_Vector& u);
gem_Vector operator- (gem_Vector& v);
gem_Vector operator* (gem_Vector& v, FLOAT a);
gem_Vector operator* (FLOAT a, gem_Vector& v);
D3DVECTOR  GetD3DVECTOR(gem_Vector& v);


gem_Matrix ZeroMtx();
gem_Matrix IdentMtx();
gem_Matrix operator* (gem_Matrix& A, gem_Matrix& B);
gem_Vector operator* (gem_Vector& a, gem_Matrix& A);
gem_Matrix operator* (FLOAT a, gem_Matrix& A);
gem_Matrix operator* (gem_Matrix& A, FLOAT a);
D3DVERTEX operator* ( D3DVERTEX& a, gem_Matrix& A );
gem_Matrix operator- (gem_Matrix& A);
gem_Matrix operator+ (gem_Matrix& A, gem_Matrix& B);
gem_Matrix operator- (gem_Matrix& A, gem_Matrix& B);
gem_Matrix Transpose(gem_Matrix& A);
gem_Matrix Invert(gem_Matrix& a);
D3DMATRIX  GetD3DMATRIX(gem_Matrix& mat);
gem_Matrix TranslationMtx(gem_Vector& vTrans);
gem_Matrix TranslationMtx( FLOAT x, FLOAT y, FLOAT z );
gem_Matrix ScaleMtx( gem_Vector& vScale );
gem_Matrix ScaleMtx( FLOAT delta );
gem_Matrix ScaleMtx( FLOAT dx, FLOAT dy, FLOAT dz );
gem_Matrix RotationMtx(gem_Vector& vAxis, FLOAT theta);
gem_Matrix RotationMtx( FLOAT alpha, FLOAT beta, FLOAT gamma );
gem_Matrix ViewMtx(gem_Vector& CamPos, gem_Vector& CamTrg);
gem_Matrix CameraMtx(gem_Vector& CamPos, gem_Vector& CamTrg, FLOAT roll);
gem_Matrix InvCameraMtx(gem_Vector& CamPos, gem_Vector& CamTrg, FLOAT roll);
gem_Matrix ProjectionMtx(FLOAT fov, FLOAT nearZ, FLOAT farZ, FLOAT aspect);
VOID SwapMatrix(gem_Matrix& A);


gem_Quat Normalize(gem_Quat& q);
FLOAT Norm(gem_Quat& q);
gem_Quat Inverse(gem_Quat& q);
gem_Quat UnityInverse(gem_Quat& q);	
gem_Quat exp(gem_Quat& q);
gem_Quat ln(gem_Quat& q);
gem_Quat operator^(gem_Quat& q, FLOAT t);
FLOAT Dot(gem_Quat& p, gem_Quat& q);
gem_Quat Cross(gem_Quat& p, gem_Quat& q);
gem_Quat SLERP(gem_Quat& p, gem_Quat& q, FLOAT t); 
//gem_Quat ExtraSpinSlerp(gem_Quat& p, gem_Quat& q, FLOAT t, FLOAT spin);
gem_Quat SQUAD(gem_Quat& p, gem_Quat& a, gem_Quat& b, gem_Quat& q, FLOAT t);
gem_Quat operator*(gem_Quat& p, gem_Quat& q);
gem_Quat operator*(gem_Quat& p, FLOAT a);
gem_Quat operator*(FLOAT a, gem_Quat& p);
gem_Quat operator+(gem_Quat& p, gem_Quat& q);
gem_Quat operator-(gem_Quat& p, gem_Quat& q);
gem_Quat operator-(gem_Quat& q);
gem_Quat FromAxisAngle(gem_Vector& vAxis, FLOAT angle);
gem_Quat FromAxisAngle(FLOAT x, FLOAT y, FLOAT z, FLOAT angle);
gem_Matrix MtxFromQuat(gem_Quat& q);	


FLOAT RemapEase(FLOAT t, FLOAT a, FLOAT b);
FLOAT LensToFOV( FLOAT lens );

#endif /*__GEMMATH_H_*/
