/*************************************************************************/
/*	File : VxMatrix.h													 */
/*	Author :  Romain SIDIDRIS											 */	
/*																		 */	
/*	Virtools SDK 														 */	 
/*	Copyright (c) Virtools 2000, All Rights Reserved.					 */	
/*************************************************************************/
#ifndef VXMATRIX_H

#define VXMATRIX_H

#ifdef DOCJET_DUMMY // Prevent doc processing
#else

#ifdef PSP
	#define ALIGNED16 __attribute__((aligned(16)))
#else
	#define ALIGNED16 
#endif
#endif

#include "VxQuaternion.h"

class VxMatrix;

VX_EXPORT	void			Vx3DMatrixIdentity		(VxMatrix& Mat);

VX_EXPORT	void			Vx3DMultiplyMatrixVector(VxVector *ResultVector,const VxMatrix& Mat,const VxVector *Vector);
VX_EXPORT	void			Vx3DMultiplyMatrixVectorMany(VxVector *ResultVectors,const VxMatrix& Mat,const  VxVector *Vectors,int count,int stride);
VX_EXPORT	void			Vx3DMultiplyMatrixVector4(VxVector4 *ResultVector,const VxMatrix& Mat,const  VxVector4 *Vector);
VX_EXPORT	void			Vx3DMultiplyMatrixVector4(VxVector4 *ResultVector,const VxMatrix& Mat,const  VxVector *Vector); // w=1
VX_EXPORT	void			Vx3DRotateVector		(VxVector *ResultVector,const VxMatrix& Mat,const VxVector *Vector);
VX_EXPORT	void			Vx3DRotateVectorMany	(VxVector *ResultVector,const VxMatrix& Mat,const VxVector *Vector,int count,int stride);
VX_EXPORT	void			Vx3DMultiplyMatrix		(VxMatrix& ResultMat,const VxMatrix& MatA,const VxMatrix& MatB);
VX_EXPORT	void			Vx3DMultiplyMatrix4		(VxMatrix& ResultMat,const VxMatrix& MatA,const VxMatrix& MatB);
VX_EXPORT	void			Vx3DInverseMatrix		(VxMatrix& InverseMat,const VxMatrix& Mat);
VX_EXPORT	void			Vx3DInverseMatrix44		(VxMatrix& InverseMat,const VxMatrix& Mat);
VX_EXPORT	float			Vx3DMatrixDeterminant	(const  VxMatrix& Mat);
VX_EXPORT	void			Vx3DMatrixFromRotation	(VxMatrix& ResultMat,const VxVector& Vector, float Angle);
VX_EXPORT	void			Vx3DMatrixFromRotationAndOrigin(VxMatrix& ResultMat,const VxVector& Vector,const VxVector& Origin, float Angle);
VX_EXPORT	void			Vx3DMatrixFromEulerAngles(VxMatrix& Mat,float eax,float eay,float eaz);
VX_EXPORT	void			Vx3DMatrixToEulerAngles	(const VxMatrix& Mat,float *eax,float* eay,float* eaz);
VX_EXPORT	void			Vx3DInterpolateMatrix(float step,VxMatrix& Res,const VxMatrix& A, const VxMatrix& B);
VX_EXPORT	void			Vx3DInterpolateMatrixNoScale(float step,VxMatrix& Res,const VxMatrix& A, const VxMatrix& B);

VX_EXPORT	void			Vx3DMultiplyMatrixVectorStrided(VxStridedData* Dest,VxStridedData* Src,const VxMatrix& Mat,int count);
VX_EXPORT	void			Vx3DMultiplyMatrixVector4Strided(VxStridedData* Dest,VxStridedData* Src,const VxMatrix& Mat,int count);
VX_EXPORT	void			Vx3DRotateVectorStrided		  (VxStridedData* Dest,VxStridedData* Src,const VxMatrix& Mat,int count);

VX_EXPORT	void			Vx3DTransposeMatrix(VxMatrix& Result,const VxMatrix& A);

VX_EXPORT	void			Vx3DDecomposeMatrix(const VxMatrix& A, VxQuaternion &Quat,VxVector &Pos,VxVector &Scale);
VX_EXPORT	float			Vx3DDecomposeMatrixTotal(const VxMatrix& A, VxQuaternion &Quat,VxVector &Pos,VxVector &Scale,VxQuaternion &URot);
VX_EXPORT	float			Vx3DDecomposeMatrixTotalPtr(const VxMatrix& A, VxQuaternion* Quat,VxVector* Pos,VxVector* Scale,VxQuaternion* URot);

VX_EXPORT	void			VxInverseProject(const VxMatrix& iProjection, const Vx2DVector& i2D, const float iZ, VxVector* o3D);

/*****************************************

{filename:VxMatrix}
******************************************/
class VxMatrix
{
public:
	VxMatrix() {}
#ifdef PSP
	VxMatrix(const float m[4][4]);
	VxMatrix(const VxMatrix& src);

	VxMatrix& operator= (const VxMatrix& src);

#else
	VxMatrix(float m[4][4]) {
		m_Data[0][0] = m[0][0];
		m_Data[0][1] = m[0][1];
		m_Data[0][2] = m[0][2];
		m_Data[0][3] = m[0][3];

		m_Data[1][0] = m[1][0];
		m_Data[1][1] = m[1][1];
		m_Data[1][2] = m[1][2];
		m_Data[1][3] = m[1][3];

		m_Data[2][0] = m[2][0];
		m_Data[2][1] = m[2][1];
		m_Data[2][2] = m[2][2];
		m_Data[2][3] = m[2][3];

		m_Data[3][0] = m[3][0];
		m_Data[3][1] = m[3][1];
		m_Data[3][2] = m[3][2];
		m_Data[3][3] = m[3][3];	
	}
#endif
#ifdef PSP
	const static VxMatrix& Identity(){
		extern VxMatrix g_IdentityMatrix;
		return g_IdentityMatrix;
	}
#else
	VX_EXPORT	const static VxMatrix& Identity();
#endif
VX_EXPORT	XBOOL Compare(const VxMatrix &mat) const;

// Matrix construction
	void Clear() {memset(m_Data,0,sizeof(VxMatrix));}
	void SetIdentity();
	void Orthographic(float Zoom,float Aspect,float Near_plane,float Far_plane);
	void Perspective(float Fov,float Aspect,float Near_plane,float Far_plane);
	void OrthographicRect(float Left,float Right,float Top,float Bottom,float Near_plane,float Far_plane);
	void PerspectiveRect(float Left,float Right,float Top,float Bottom,float Near_plane,float Far_plane);
VX_EXPORT	void RecomposeMatrixEx(const VxVector *Pos,const VxVector *Scale,const VxQuaternion *Quat, const VxQuaternion *Shear, float Sign);
VX_EXPORT	void RecomposeMatrix(const VxVector *Pos, const VxVector *Scale, const VxQuaternion *Quat);
	
// operators
	const VxVector4& operator[] (int i) const {return (const VxVector4&)(*(VxVector4*)(m_Data+i));}
	VxVector4& operator[] (int i){return (VxVector4&)(*(VxVector4*)(m_Data+i));}

	operator const void* () const {return &m_Data[0];}
	operator void* () {return &m_Data[0];}

	BOOL operator == (const VxMatrix& mat) const {return Compare(mat);}
	BOOL operator != (const VxMatrix& mat) const {return !Compare(mat);}

	VxMatrix& operator *= (const VxMatrix& mat) {
		VxMatrix tmp = *this;
		Vx3DMultiplyMatrix(*this,tmp,mat);
		return *this;
	}

	VxMatrix operator * (const VxMatrix& iMat) const
	{
		VxMatrix temp;
		Vx3DMultiplyMatrix(temp,*this,iMat);
		return temp;
	}
	
	friend VxVector operator * (const VxMatrix& m,const VxVector& v);
	friend VxVector4 operator * (const VxMatrix& m,const VxVector4& v);
	friend VxVector operator * (const VxVector& v,const VxMatrix& m);
	friend VxVector4 operator * (const VxVector4& v,const VxMatrix& m);

protected:
	float	m_Data[4][4];
} ALIGNED16;

#ifdef PSP
	// Use of VFPU on the PSP.
	#include "VxMatrixPSP.h"
#else

//////////////////////////////////////////////////////////////////////
////////////////////////// Matrix operations /////////////////////////
//////////////////////////////////////////////////////////////////////


inline void VxMatrix::SetIdentity()
{
	m_Data[0][1] = m_Data[0][2] = m_Data[0][3] =
	m_Data[1][0] = m_Data[1][2] = m_Data[1][3] =
	m_Data[2][0] = m_Data[2][1] = m_Data[2][3] = 
	m_Data[3][0] = m_Data[3][1] = m_Data[3][2] = 0;
	m_Data[0][0] = m_Data[1][1] = m_Data[2][2] = m_Data[3][3] = 1.0f;
}


inline  VxVector operator * (const VxVector& v,const VxMatrix& m)
{
	return VxVector(m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z+m[3][0],
					m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z+m[3][1],
					m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z+m[3][2]);
}

inline VxVector operator * (const VxMatrix& m,const VxVector& v) 
{
	return VxVector(m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z+m[3][0],
					m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z+m[3][1],
					m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z+m[3][2]);
}

inline VxVector4 operator * (const VxMatrix& m,const VxVector4& v) 
{
	return VxVector4(m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z+ m[3][0],
					m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z+ m[3][1],
					m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z+ m[3][2],
					m[0][3]*v.x + m[1][3]*v.y + m[2][3]*v.z+ m[3][3]);
}

inline VxVector4 operator * (const VxVector4& v,const VxMatrix& m) 
{
	return VxVector4(m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z+ m[3][0],
					m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z+ m[3][1],
					m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z+ m[3][2],
					m[0][3]*v.x + m[1][3]*v.y + m[2][3]*v.z+ m[3][3]);
}


/************************************************
Summary: Constructs a perspective projection matrix.

Input Arguments:
	Fov: Field of View.
	Aspect: Aspect ratio (Width/height)
	Near_plane: Distance of the near clipping plane.
	Far_plane: Distance of the far clipping plane.
Output Arguments:
	Mat: Matrix to set to the perspective projection.

Remarks:
Sets Mat to 
		
		A	=Cos(Fov/2)/Sin(Fov/2)
        F	=	Far_plane
        N	=	Near_plane
  
	            [ A			0			0			0]
                [ 0			A*Aspect	0			0]
           MAT=	[ 0			0			F/F-N		1]
                [ 0			0			-F.N/F-N	0]



See also: PerspectiveRect,Orthographic,Identity,OrthographicRect
************************************************/
inline void	VxMatrix::Perspective(float Fov,float Aspect,float Near_plane,float Far_plane)
{
	Clear();
	m_Data[0][0] = cosf(Fov*0.5f)/sinf(Fov*0.5f);
	m_Data[1][1] = m_Data[0][0]*Aspect;
	m_Data[2][2] = Far_plane / (Far_plane - Near_plane);
	m_Data[3][2] = -m_Data[2][2]*Near_plane;
	m_Data[2][3] = 1;
}


/************************************************
Summary: Constructs a perspective projection matrix given a view rectangle .

Arguments:
	Left - [In][Out]Left clipping plane value.
	Right - Right clipping plane value.
	Top - [Out]top clipping plane value.
	Bottom - [In]bottom clipping plane value.
	Near_plane - [In][Out]Distance of the near clipping plane.
	Far_plane - [In/Out]Distance of the far clipping plane.

Remarks:
Sets Mat to 
		
		F	=	Far_plane
		N	=	Near_plane
		R	=	Right
		L	=	Left
		T	=	Top
		B	=	Bottom

				[ 2/(R-L)		0			0			0]
				[ 0				2/(T-B)		0			0]
		  MAT =	[ -(L+R)/(R-L)	(T+B)/(T-B)	F/F-N		0]
				[ 0				0	 	  -F.N/F-N		1]





See also: Perspective,Orthographic,Identity,OrthographicRect
************************************************/
inline void	VxMatrix::PerspectiveRect(float Left,float Right,float Top,float Bottom,float Near_plane,float Far_plane)
{
	Clear();
	float RL = 1.0f / (Right - Left);
	float TB = 1.0f / (Top - Bottom);
	m_Data[0][0] = 2.0f*Near_plane * RL;
	m_Data[1][1] = 2.0f*Near_plane * TB;
	m_Data[2][0] = -(Right+Left) * RL;
	m_Data[2][1] = -(Top + Bottom)* TB;
	m_Data[2][2] = Far_plane / (Far_plane - Near_plane);
	m_Data[3][2] = -m_Data[2][2]*Near_plane;
	m_Data[2][3] = 1;
}


/************************************************
Summary: Constructs a orthographic projection matrix.

Input Arguments:
	Zoom: Zoom factor.
	Aspect: Aspect ratio (Width/height)
Output Arguments:
	Near_plane: Distance of the near clipping plane.
	Far_plane: Distance of the far clipping plane.

Remarks:
Sets Mat to
		
		F	=	Far_plane
		N	=	Near_plane
						[ Zoom		0			0			0]
						[ 0			Zoom*Aspect	0			0]
				MAT =	[ 0			0			1/F-N		0]
						[ 0			0			-N/F-N		1]
See also: Vx3DMatrixIdentity,Perspective,OrthographicRect
************************************************/
inline void	VxMatrix::Orthographic(float Zoom,float Aspect,float Near_plane,float Far_plane)
{
	Clear();
	float iz=1.0f/(Far_plane-Near_plane);
	m_Data[0][0]=Zoom;
	m_Data[1][1]=Zoom*Aspect;
	m_Data[2][2]=iz;
	m_Data[3][2]=-Near_plane*iz;
	m_Data[3][3]=1.0f;
}




/************************************************
Summary: Constructs a orthographic projection matrix.

Input Arguments:
	Left: Left clipping plane value.
	Right: Right clipping plane value.
	Top: top clipping plane value.
	Bottom: bottom clipping plane value.
	Near_plane: Distance of the near clipping plane.
	Far_plane: Distance of the far clipping plane.
Remarks:
Sets Mat to 
		
		F	=	Far_plane
		N	=	Near_plane
		R	=	Right
		L	=	Left
		T	=	Top
		B	=	Bottom

				[ 2/(R-L)		0			0			0]
				[ 0				-2/(T-B)	0			0]
		  MAT =	[ 0				0			1/F-N		0]
				[ -(L+R)/(R-L)	(T+B)/(T-B)	-N/F-N		1]




See also: Vx3DMatrixIdentity,Perspective,Orthographic
************************************************/
inline void VxMatrix::OrthographicRect(float Left,float Right,float Top,float Bottom,float Near_plane,float Far_plane)
{
	Clear();
	float ix=1.0f/(Right-Left);
	float iy=1.0f/(Top-Bottom);
	float iz=1.0f/(Far_plane-Near_plane);
	m_Data[0][0]=2.0f*ix;
	m_Data[1][1]=2.0f*iy;
	m_Data[2][2]=iz;
	m_Data[3][0]=-(Left+Right)*ix;
	m_Data[3][1]=-(Top+Bottom)*iy;
	m_Data[3][2]=-Near_plane*iz;
	m_Data[3][3]=1.0f;
}

#endif // #ifdef PSP



#endif
