/*************************************************************************************************************************************************
						    This file defines the use of mathematical functions for 3D (matrix,vctor,quaternion...........)
*************************************************************************************************************************************************/

#ifndef __ZOOMATRIX_H__
#define __ZOOMATRIX_H__

#ifdef MATH_EXPORTS
#define MATH_API		__declspec(dllexport)
#else
#define MATH_API		__declspec(dllimport)
#endif



class ZMatrix;
class ZQuat;
class ZVector3;
class ZVector4;


extern bool			infoP3;
extern bool			infoP4;


#define				__OPTI_P3__				// flag pour la compilation sans P3, ou avec le test de détection P3
#define				__OPTI_P4__			// flag pour la compilation sans P4, ou avec le test de détection P4

#include	<assert.h>
#include	<math.h>

#include	<memory.h>

// Matrix Creation

class MATH_API ZMatrix
{
public:

	union
	{
		__declspec(align(16))	float	matxArray[16];
		struct 
		{
			float	_11, _21, _31, _41;
			float	_12, _22, _32, _42;
			float	_13, _23, _33, _43;
			float	_14, _24, _34, _44;
		};
	};



// Constructor

	ZMatrix()		
	{	_14 =  _13 =  _12 =  _24 =  _23 =  _21 =  _34 =  _32 =  _31 =  _43 =  _42 =  _41 = 0.0f;
		_11 =  _22 =  _33 =  _44 = 1.0f;
	}
	
	ZMatrix(float _11, float _21, float _31, float _41,
			float _12, float _22, float _32, float _42,
			float _13, float _23, float _33, float _43,
			float _14, float _24, float _34, float _44);




// Access of datas													

	float& operator() (int i, int j) 
	{
		assert( (0<=i) && (i<=3) && (0<=j) && (j<=3) );
		return *(((float *)&_11) + (j<<2)+i);
	}
	
	


// Operators							

	ZMatrix& operator= (const ZMatrix &a) 
	{
		_11=a._11;	_12=a._12;	_13=a._13;	_14=a._14;
		_21=a._21;	_22=a._22;	_23=a._23;	_24=a._24;
		_31=a._31;	_32=a._32;	_33=a._33;	_34=a._34;
		_41=a._41;	_42=a._42;	_43=a._43;	_44=a._44;
		return *this;
	}


// Basic Operations for matrix calculate

	friend ZMatrix operator * (const ZMatrix&, const ZMatrix&);
	friend ZMatrix operator + (const ZMatrix&, const ZMatrix&);
	friend ZMatrix operator - (const ZMatrix&, const ZMatrix&);
	friend ZMatrix operator + (const ZMatrix&);
	friend ZMatrix operator - (const ZMatrix&);
	friend ZMatrix operator * (const ZMatrix&, const float);
	friend ZMatrix operator * (const float, const ZMatrix&);

	ZMatrix & operator *= (const ZMatrix &);
	ZMatrix & operator *= (const float);
	ZMatrix & operator += (const ZMatrix &);
	ZMatrix & operator -= (const ZMatrix &);




// Advanced math computing	on matrices		

	void	Transpose();	// Transposes the matrix
	float	Inverse();		// Inverses the matrix and returns the determinant
	float	Determinant();	// Returns the determinant
	
	ZQuat		GetQuat();
	ZVector3	GetAnglesYXZ();
	ZVector3	GetAnglesZXY();

// Other Functions		

	void ZeroMatrix();
	void IdentityMatrix();
	void TranslateMatrix(const float dx, const float dy, const float dz);
	void SetTrans(const float dx, const float dy, const float dz);
	void ScaleMatrix(const float a, const float b, const float c);
	void ScaleMatrix(const float a);
	void RotateYXZMatrix(const float rotX, const float rotY, const float rotZ);
	void RotateYXZMatrix(const ZVector3 angle);
//	void RotateZXYMatrix(const float rotX, const float rotY, const float rotZ);
	void RotateXMatrix(const float rads);
	void RotateYMatrix(const float rads);
	void RotateZMatrix(const float rads);
	void PerpectiveMatrix(float fovy, float aspect, float znear, float zfar);
	void OrthoMatrix(float left, float right, float bottom, float top, float znear, float zfar);
};













///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ZVector4 Class
///
///		- Classe des vecteurs de dim 4
///		- Méthodes de calculs classiques sur les vecteurs
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class MATH_API ZVector4 
{
public:

	union 
	{
		__declspec(align(16))	float	vals[4];
		struct 
		{
			float	x,y,z,w;
		};
	};


	///////////////////////////////////////////////////////////////////////////
	/// Constructors														///
	///////////////////////////////////////////////////////////////////////////
	ZVector4()		{	x = y = z = w = 0.0f;	}
	ZVector4(const float nx, const float ny, const float nz, const float nw=0.0f)		{	x=nx;	y=ny;	z=nz;	w=nw;	}


	///////////////////////////////////////////////////////////////////////////
	/// Setting des 4 coords du vecteur										///
	///////////////////////////////////////////////////////////////////////////
	void SetCoord(float nx, float ny, float nz, float nw);


	///////////////////////////////////////////////////////////////////////////
	/// Setting des 4 coords ŕ zéro											///
	///////////////////////////////////////////////////////////////////////////
	void SetNull();


	///////////////////////////////////////////////////////////////////////////
	/// Data access															///
	///////////////////////////////////////////////////////////////////////////
	float& operator() (int i)
	{
		assert((0<=i) && (i<=3));
		return *(((float *)&x) + i);
	}
	
	float& operator[] (int i) 
	{
		assert((0<=i) && (i<=3));
		return *(((float *)&x) + i);
	}
	
	float& operator[] (int i) const 
	{
		assert((0<=i) && (i<=3));
		return *(((float *)&x) + i);
	}


	///////////////////////////////////////////////////////////////////////////
	/// Operators															///
	///////////////////////////////////////////////////////////////////////////
	ZVector4& operator = (const ZVector4 &a)	{	x=a.x;	y=a.y;	z=a.z;	w=a.w;	return *this; }
	ZVector4& operator = (const ZVector3 &);	
	
	friend ZVector4 operator ^ (const ZVector4 &, const ZVector4 &);		// Cross Product
	friend ZVector4 operator * (const ZMatrix&, const ZVector4&);
	friend float	operator * (const ZVector4 &, const ZVector4 &);		// Dot Product
	friend ZVector4 operator * (const ZVector4 &, const float);
	friend ZVector4 operator * (const float, const ZVector4 &);
	friend ZVector4 operator + (const ZVector4&);
	friend ZVector4 operator + (const ZVector4&, const ZVector4&);
	friend ZVector4 operator - (const ZVector4&);
	friend ZVector4 operator - (const ZVector4&, const ZVector4&);
	friend ZVector4 operator ~ (const ZVector4&);							// Normalize

	ZVector4 & operator *= (const ZMatrix &);
	ZVector4 & operator *= (const float);
	ZVector4 & operator += (const ZVector4 &);
	ZVector4 & operator -= (const ZVector4 &);

	float		Length();
	float		SqLength();

	ZVector4&	Normalize();


	

};











///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ZQuat Class
///
///		- Classe des quaternions
///		- Méthodes de passage de quaternion a matrice, et vice-versa
///		- Interpolation circulaire de quaternions
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class MATH_API ZQuat
{
public:

	__declspec(align(16))	float x, y, z, w;
	

	///////////////////////////////////////////////////////////////////////////
	/// Constructors														///
	///////////////////////////////////////////////////////////////////////////
	ZQuat()		{	x = y = z = w = 0.0f;	}

	
	///////////////////////////////////////////////////////////////////////////
	/// Setting des 4 coords du quaternion									///
	///////////////////////////////////////////////////////////////////////////
	void SetCoord(float nx, float ny, float nz, float nw);

	
	///////////////////////////////////////////////////////////////////////////
	/// Transforme un quaternion en matrice									///
	///////////////////////////////////////////////////////////////////////////
	ZMatrix	GetMatrix();


	///////////////////////////////////////////////////////////////////////////
	/// retourne les angles XYZ de rotation equivalents au quaternion		///
	///////////////////////////////////////////////////////////////////////////
	ZVector3 GetAnglesZXY();
	ZVector3 GetAnglesYXZ();


	ZQuat& operator = (const ZQuat &a)	{	x=a.x;	y=a.y;	z=a.z;	w=a.w;	return *this; }
	
//	friend float operator * (const ZQuat &, const ZQuat &);		// Dot Product
	friend ZQuat operator * (const ZQuat &, const float);
	friend ZQuat operator * (const float, const ZQuat &);
	friend ZQuat operator + (const ZQuat&);
	friend ZQuat operator + (const ZQuat&, const ZQuat&);
	friend ZQuat operator - (const ZQuat&);
	friend ZQuat operator - (const ZQuat&, const ZQuat&);
//	friend ZQuat operator ~ (const ZQuat&);							// Normalize

	ZQuat & operator *= (const float);
	ZQuat & operator += (const ZQuat &);
	ZQuat & operator -= (const ZQuat &);


};









///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ZVector3 Class
///
///		- Classe des vecteurs de dim 3
///		- Méthodes de calculs classiques sur les vecteurs
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class MATH_API ZVector3 
{
public:

	union 
	{
		__declspec(align(16))	float	vals[3];
		struct 
		{
			float	x,y,z;
		};
	};



	///////////////////////////////////////////////////////////////////////////
	/// Setting des 3 coords du vecteur										///
	///////////////////////////////////////////////////////////////////////////
	void SetCoord(float nx, float ny, float nz);


	///////////////////////////////////////////////////////////////////////////
	/// Setting des 3 coords ŕ zéro											///
	///////////////////////////////////////////////////////////////////////////
	void SetNull();


	///////////////////////////////////////////////////////////////////////////
	/// Constructors														///
	///////////////////////////////////////////////////////////////////////////
	ZVector3()		{	x = y = z = 0.0f;	}
	ZVector3(const float nx, const float ny, const float nz)	{	x=nx;	y=ny;	z=nz;	}
	

	///////////////////////////////////////////////////////////////////////////
	/// Operators															///
	///////////////////////////////////////////////////////////////////////////
	ZVector3& operator = (const ZVector3 &a)					{	x=a.x;	y=a.y;	z=a.z;	return *this;	}
	ZVector3& operator = (const ZVector4 &a)					{	x=a.x;	y=a.y;	z=a.z;	return *this;	}

	friend ZVector3 operator * (const ZMatrix&, const ZVector3&);
	friend float	operator * (const ZVector3 &, const ZVector3 &);		// Dot Product
	friend ZVector3 operator ^ (const ZVector3 &, const ZVector3 &);		// Cross Product
	friend ZVector3 operator * (const ZVector3 &, const float);
	friend ZVector3 operator * (const float, const ZVector3 &);
	friend ZVector3 operator + (const ZVector3&);
	friend ZVector3 operator + (const ZVector3&, const ZVector3&);
	friend ZVector3 operator - (const ZVector3&);
	friend ZVector3 operator - (const ZVector3&, const ZVector3&);
	friend ZVector3 operator ~ (const ZVector3&);							// Normalize

	ZVector3 & operator *= (const ZMatrix &);
	ZVector3 & operator *= (const float);
	ZVector3 & operator += (const ZVector3 &);
	ZVector3 & operator -= (const ZVector3 &);

	float Length();
	float SqLength();
	ZVector3& Normalize();


};








///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ZUV Class
///
///		- Classe des vecteurs de dim 3
///		- Méthodes de calculs classiques sur les vecteurs
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class MATH_API ZUV
{
public:

	union
	{
		float	vals[2];
		struct 
		{
			float	u,v;
		};
	};



	///////////////////////////////////////////////////////////////////////////
	/// Setting des 2 coords du vecteur										///
	///////////////////////////////////////////////////////////////////////////
	void SetCoord(float nu, float nv);


	///////////////////////////////////////////////////////////////////////////
	/// Setting des 2 coords ŕ zéro											///
	///////////////////////////////////////////////////////////////////////////
	void SetNull();


	///////////////////////////////////////////////////////////////////////////
	/// Constructors														///
	///////////////////////////////////////////////////////////////////////////
	ZUV()		{	u = v = 0.0f;	}
	ZUV(const float nu, const float nv)	{	u=nu;	v=nv;	}
	

	///////////////////////////////////////////////////////////////////////////
	/// Operators															///
	///////////////////////////////////////////////////////////////////////////
	ZUV& operator = (const ZVector3 &a)					{	u=a.x;	v=a.y;	return *this;	}
	ZUV& operator = (const ZVector4 &a)					{	u=a.x;	v=a.y;	return *this;	}

	ZUV& operator *= (const float);
	ZUV& operator += (const ZUV &);
	ZUV& operator -= (const ZUV &);

};










///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
///		Functions and not methods !!
///
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



ZMatrix ZeroMatrix();
ZMatrix IdentityMatrix();
ZMatrix TranslateMatrix(const float dx, const float dy, const float dz);
ZMatrix ScaleMatrix(const float a, const float b, const float c);
ZMatrix ScaleMatrix(const float a);
ZMatrix RotateXMatrix(const float rads);
ZMatrix RotateYMatrix(const float rads);
ZMatrix RotateZMatrix(const float rads);
ZMatrix RotateYXZMatrix(const float rotX, const float rotY, const float rotZ);
ZMatrix RotateYXZMatrix(const ZVector3 angle);
ZMatrix PerpectiveMatrix(float fovy, float aspect, float znear, float zfar);



void	MatrixMult(const ZMatrix &A, const ZMatrix &B, ZMatrix &Res);
void	VectorMult(const ZMatrix &Mat, const ZVector4 &Vec, ZVector4 &Res);
ZMatrix MatrixMult(const ZMatrix &A, const ZMatrix &B);



inline	ZMatrix MatrixInverse(ZMatrix &m) 		{ ZMatrix l=m; l.Inverse(); return l; }
inline	float	Determinant(ZMatrix &m)			{ return m.Determinant(); }
inline	ZMatrix MatrixTranspose(ZMatrix &m)		{ ZMatrix l=m; l.Transpose(); return l; }



///////////////////////////////////////////////////////////////////////////
/// Interpolation de deux quads											///
///////////////////////////////////////////////////////////////////////////
ZQuat quatSlerp(ZQuat start, ZQuat end, float t);


///////////////////////////////////////////////////////////////////////////
/// Interpolation de deux vecteurs d'angles								///
///////////////////////////////////////////////////////////////////////////
ZVector3 interpAng(ZVector3 a, ZVector3 b, float tx);









#include "ZooMatrix.inl"


#endif
