//=he3d=file============================================================================================
//	Helium3d system	(c) 2000/2001 acid.z51 
//------------------------------------------------------------------------------------------------------
//
//	name:	he3d_math.h
//  desc:	header for helium3d math util lib including matrix, vector and quaternion classes
//			methods are described in implementation files
//
//	history		
//		+ 11.12.2000				initial version by acid
//		+ 22.12.2000				all classes final version
//		+ 20.01.2001				added mtxstack class
//
//	todo
//		+ 11.12.2000				a lot :)
//		+ 22.12.2000				nothing :)
//======================================================================================================

#ifndef __HE3D_MATH_H_
#define __HE3D_MATH_H_

#include <d3dx8.h>

#define	H_2PI			6.283185307f
#define H_PI			3.141592654f
#define H_PI2			1.570796327f

#define RAD2DEG(x)		( (x)*180.0f )/H_PI
#define DEG2RAD(x)		( (x)*H_PI )/180.0f

#define H_EPSILON		0.001f

#define	ISZERO(x)		( fabs(x) <= H_EPSILON )


class he3d_CVector;
class he3d_CQuaternion;


//=he3d=class===========================================================================================
//	Helium3d lib	(c) 2000 acid.z51 
//------------------------------------------------------------------------------------------------------
//
//	name:	CMatrix
//	desc:	representation of commonly use 4x4 matrices
//
//======================================================================================================
class he3d_CMatrix
{
public:

	union
	{
		struct
		{
			FLOAT	_11, _12, _13, _14;
			FLOAT	_21, _22, _23, _24;
			FLOAT	_31, _32, _33, _34;
			FLOAT	_41, _42, _43, _44;
		};

		FLOAT	m[4][4];
	};

public:

	he3d_CMatrix( FLOAT val = 0.0f );
	he3d_CMatrix( const D3DMATRIX& d3dmat );
	he3d_CMatrix( const D3DXMATRIX& d3dxmat );
	he3d_CMatrix( const he3d_CMatrix& mtx );
	he3d_CMatrix( const FLOAT* pfmtx );

	// assigment operator
	he3d_CMatrix& operator=( const he3d_CMatrix& mtx );
	he3d_CMatrix& operator+=( const he3d_CMatrix& mtx );
	he3d_CMatrix& operator*=( const he3d_CMatrix& mtx );	
	he3d_CMatrix& operator*=( FLOAT a );
	he3d_CMatrix& operator/=( FLOAT a );	
	he3d_CMatrix& operator-=( const he3d_CMatrix& mtx );

	// arithmetic operators
	he3d_CMatrix operator*( const he3d_CMatrix& mtx ) const;
	he3d_CMatrix operator*( FLOAT a ) const;	
	he3d_CMatrix operator/( FLOAT a ) const;
	he3d_CMatrix operator+( const he3d_CMatrix& mtx ) const;
	he3d_CMatrix operator-( const he3d_CMatrix& mtx ) const;

	// unary operators
	he3d_CMatrix operator+() const;
	he3d_CMatrix operator-() const;

	// selector	
	FLOAT& operator()( INT i, INT j );

	// typecast operators
	operator D3DMATRIX() const;
	operator D3DXMATRIX() const;

	operator D3DMATRIX*();
	operator const D3DMATRIX*() const;	

	operator D3DXMATRIX*();
	operator const D3DXMATRIX*() const;		

	// friend function represent common matrix and other operation

	friend he3d_CMatrix ProjectionMtx( FLOAT fov, FLOAT aspect, FLOAT zMin, FLOAT zMax );
	friend he3d_CMatrix CameraMtx( const he3d_CVector& pos, const he3d_CVector& trg, FLOAT roll );
	//friend he3d_CMatrix EulerCameraMtx( FLOAT yaw, FLOAT pitch, FLOAT roll );
	friend he3d_CMatrix XRotationMtx( FLOAT ang );
	friend he3d_CMatrix YRotationMtx( FLOAT ang );
	friend he3d_CMatrix ZRotationMtx( FLOAT ang );
	friend he3d_CMatrix RotationMtx( FLOAT alpha, FLOAT beta, FLOAT gamma );
	friend he3d_CMatrix RotationMtx( const he3d_CVector& ang );
	friend he3d_CMatrix RotationMtx( const he3d_CVector& axis, FLOAT ang );
	friend he3d_CMatrix RotationMtx( const he3d_CQuaternion& quat );
	friend he3d_CMatrix TranslationMtx( const he3d_CVector& vec );
	friend he3d_CMatrix TranslationMtx( FLOAT x, FLOAT y, FLOAT z );
	friend he3d_CMatrix ScaleMtx( const he3d_CVector& vec );
	friend he3d_CMatrix ScaleMtx( FLOAT sx, FLOAT sy, FLOAT sz );
	friend he3d_CMatrix ScaleMtx( FLOAT scale );
	friend he3d_CMatrix IdentMtx();
	friend he3d_CMatrix ZeroMtx();
	friend he3d_CMatrix InverseMtx( const he3d_CMatrix& mtx );
	friend he3d_CMatrix InverseCameraMtx( const he3d_CMatrix& mtx );
	friend he3d_CMatrix GaussInverseMtx( const he3d_CMatrix& mtx );
	friend he3d_CMatrix TransposeMtx( const he3d_CMatrix& mtx );
	friend he3d_CMatrix operator*( FLOAT a, const he3d_CMatrix& mtx );
};


//=he3d=class===========================================================================================
//	Helium3d lib	(c) 2000 acid.z51 
//------------------------------------------------------------------------------------------------------
//
//	name:	CVector
//	desc:	3 elements vector representation
//
//======================================================================================================
class he3d_CVector
{
public:

	FLOAT		x, y, z;

public:

	he3d_CVector( FLOAT _x = 0.0f, FLOAT _y = 0.0f, FLOAT _z = 0.0f );
	he3d_CVector( const D3DVECTOR& vec );
	he3d_CVector( const D3DXVECTOR3& vec );
	he3d_CVector( const he3d_CVector& vec );

	// assigment operators
	he3d_CVector& operator=( const he3d_CVector& vec );
	he3d_CVector& operator+=( const he3d_CVector& vec );
	he3d_CVector& operator-=( const he3d_CVector& vec );
	he3d_CVector& operator*=( FLOAT a );
	he3d_CVector& operator/=( FLOAT a );
	he3d_CVector& operator*=( const he3d_CMatrix& mtx );

	// arithmetic operator
	he3d_CVector operator+( const he3d_CVector& vec ) const;
	he3d_CVector operator-( const he3d_CVector& vec ) const;
	he3d_CVector operator*( FLOAT a ) const;
	he3d_CVector operator*( const he3d_CVector& v ) const;
	he3d_CVector operator*( const he3d_CMatrix& mtx ) const;
	he3d_CVector operator/( FLOAT a ) const;

	// unary operator
	he3d_CVector operator+() const;
	he3d_CVector operator-() const;

	//typecast operator
	operator D3DVECTOR() const;
	operator D3DXVECTOR3() const;

	operator D3DVECTOR*();
	operator const D3DVECTOR*() const;

	operator D3DXVECTOR3*();
	operator const D3DXVECTOR3*() const;

	//friend function
	friend FLOAT Length( const he3d_CVector& vec );
	friend he3d_CVector Normalize( const he3d_CVector& vec );
	friend he3d_CVector CrossProd( const he3d_CVector& u, const he3d_CVector& v );
	friend FLOAT DotProd( const he3d_CVector& u, const he3d_CVector& v );
	friend he3d_CVector LERP( FLOAT t, const he3d_CVector& u, const he3d_CVector& v );
	friend he3d_CVector operator*( FLOAT a, const he3d_CVector& vec );
	friend VOID FaceNormal( const he3d_CVector& v1, const he3d_CVector& v2, const he3d_CVector& v3, he3d_CVector& n );
};

//=he3d=class===========================================================================================
//	Helium3d lib	(c) 2000 acid.z51 
//------------------------------------------------------------------------------------------------------
//
//	name:	CQuaternion
//	desc:	quaternion representation
//
//======================================================================================================
class he3d_CQuaternion
{
public:

	FLOAT		w, x, y, z;

public:

	he3d_CQuaternion( FLOAT _w = 0.0f, FLOAT _x = 0.0f, FLOAT _y = 0.0f, FLOAT _z = 0.0f );
	he3d_CQuaternion( FLOAT _w, const he3d_CVector& vec );
	he3d_CQuaternion( const D3DXQUATERNION& quat );
	he3d_CQuaternion( const he3d_CQuaternion& quat );

	// assigment operators
	he3d_CQuaternion& operator=( const he3d_CQuaternion& quat );
	he3d_CQuaternion& operator*=( FLOAT a );
	he3d_CQuaternion& operator/=( FLOAT a );
	he3d_CQuaternion& operator^=( FLOAT a );
	he3d_CQuaternion& operator+=( const he3d_CQuaternion& quat );
	he3d_CQuaternion& operator-=( const he3d_CQuaternion& quat );

	// arithmetic operators
	he3d_CQuaternion operator+( const he3d_CQuaternion& quat ) const;
	he3d_CQuaternion operator-( const he3d_CQuaternion& quat ) const;
	he3d_CQuaternion operator*( FLOAT a ) const;
	he3d_CQuaternion operator*( const he3d_CQuaternion& q ) const;
	he3d_CQuaternion operator/( FLOAT a ) const;
	he3d_CQuaternion operator^( FLOAT a ) const;

	// unary operators
	he3d_CQuaternion operator-() const;
	he3d_CQuaternion operator+() const;

	// friend functions
	friend he3d_CQuaternion operator*( FLOAT a, const he3d_CQuaternion& quat );
	friend FLOAT Length( const he3d_CQuaternion& quat );
	friend he3d_CQuaternion Normalize( const he3d_CQuaternion& quat );
	friend he3d_CQuaternion Inverse( const he3d_CQuaternion& quat );
	friend he3d_CQuaternion UnaryInverse( const he3d_CQuaternion& quat );
	friend he3d_CQuaternion Conjunction( const he3d_CQuaternion& quat );
	friend he3d_CQuaternion ln( const he3d_CQuaternion& quat );
	friend he3d_CQuaternion exp( const he3d_CQuaternion& quat );
	friend he3d_CQuaternion CrossProd( const he3d_CQuaternion& p, const he3d_CQuaternion& q );
	friend FLOAT DotProd( const he3d_CQuaternion& p, const he3d_CQuaternion& q );
	friend he3d_CQuaternion FromAxisAngle( FLOAT x, FLOAT y, FLOAT z, FLOAT angle );
	friend he3d_CQuaternion FromAxisAngle( const he3d_CVector& axis, FLOAT angle );
	friend he3d_CQuaternion SLERP( FLOAT t, const he3d_CQuaternion& p, const he3d_CQuaternion& q );
	friend he3d_CQuaternion SQUAD( FLOAT t, const he3d_CQuaternion& p, const he3d_CQuaternion& a, 
							                const he3d_CQuaternion& b, const he3d_CQuaternion& q );	
};

class he3d_CMtxStack
{
private:

	class Node
	{
	public:

		he3d_CMatrix	mtx;
		Node*			prev;
	};

	Node*			top;

public:

	he3d_CMtxStack();
	~he3d_CMtxStack();

	void Clear();
	void Push( he3d_CMatrix& mtx );
	he3d_CMatrix Pop();
	void MulAndPush( he3d_CMatrix& mtx );
	he3d_CMatrix GetTop();
};

#endif