// Liquid3D - Moteur 3D C++ NDS par Morukutsu
// Surcouche de l'ulibrary de Brunni
// Version alpha 1

#include <nds.h>

#ifndef _H_L3DTYPES
#define _H_L3DTYPES

//Defines
//Gestion des nombres fixedpoint
#define itofx(x) ((x) << 12)				// Integer to fixed point
#define ftofx(x) ((x) * 4096)				// Float to fixed point
#define fxtoi(x) ((x) >> 12)				// Fixed point to integer
#define fxtof(x) (divf32((float)(x), 4096))	// Fixed point to float
#define Mulfx(x,y) (((y) * (x)) >> 8)		// Multiply a fixed by a fixed
#define Divfx(x,y) ((y << 8) / (x))    		// Divide a fixed by a fixed

namespace L3D
{
	//- - - - - - - - - - 
	// Fonctions maths de base
	//- - - - - - - - - -
	inline int32 sign(int32 x) { return (x < 0)? -1 : 1; }
	inline void  swapf32(int32& a, int32& b) { int32 c = a; a = b; b = c; }
	inline int32 clampf32(int32 x, int32 min, int32 max) { return (x < min)? min : (x > max)? max : x; }
	inline int32 wrapf32(int32 x, int32 min, int32 max) { return (x < min)? (x - min) + max : (x > max)? (x - max) + min : x; }
	void v_fnormalizef32(int32* a);
	void v2_fnormalizef32(int32* a);

	//- - - - - - - - - -
	// Classe vecteur 2D
	//- - - - - - - - - -
	class v2d
	{
	public:
		int32 x, y;
	public:
		v2d() { x = y = 0; }
		v2d(int32 px, int32 py) { x = px, y = py; }
		inline v2d &operator /=(const int32 Scalar) { x = divf32(x, Scalar); y = divf32(y, Scalar); return *this; }
		inline v2d &operator *=(const int32 Scalar) { x = mulf32(x, Scalar); y = mulf32(y, Scalar); return *this; }
		inline v2d &operator +=(const v2d &Other) { x += Other.x;	y += Other.y; return *this; }
		inline v2d &operator -=(const v2d &Other) { x -= Other.x;	y -= Other.y; return *this;	}
		inline int32 operator ^ (const v2d &V) const{	return (mulf32(x, V.y) ) - (mulf32(y, V.x) ); } //Produit vectoriel
		inline int32 operator * (const v2d &V) const{	return (mulf32(x, V.x) ) + (mulf32(y, V.y) ); } //Produit scalaire
		inline v2d operator * (int32 s)    const { return v2d(mulf32(x, s), mulf32(y, s) ); }
		inline v2d operator / (int32 s)	 const { return v2d(divf32(x, s), divf32(y, s) ); }
		inline v2d operator + (const v2d &V) const	{ return v2d(x+V.x, y+V.y); }	
		inline v2d operator - (const v2d &V) const	{ return v2d(x-V.x, y-V.y); }
		friend v2d operator * (int32 k, const v2d& V) { return v2d(mulf32(V.x, k), mulf32(V.y, k) ); }
		inline v2d operator -(void) const { return v2d(-x, -y); }
		inline int32 Length() const { return sqrtf32(mulf32(x, x) + mulf32(y, y) ); }
		void Normalise() 
		{	
			/*int32 fLength = Length();		
			if(fLength == 0) 
				return; 
			(*this) *= divf32(4096, fLength); */
			int32 v[2] = {x, y};
			v2_fnormalizef32(v);
			x = v[0], y = v[1];
		}
		v2d Direction() const
		{
			v2d Temp(*this);
			Temp.Normalise();
			return Temp;
		}
		v2d& Rotate(int32 angle) //A tester
		{
			int32 tx = x;
			x = mulf32(x, cosLerp(angle)) - mulf32(y, sinLerp(angle));
			y = mulf32(tx, sinLerp(angle)) + mulf32(y, cosLerp(angle));
			return *this;
		}
		v2d& Rotate(const v2d& xCentre, float fAngle)
		{
			v2d D = *this - xCentre;
			D.Rotate(fAngle);
			*this = xCentre + D;
			return *this;
		}
		void Clamp(const v2d& min, const v2d& max)
		{
			x = (x < min.x)? min.x : (x > max.x)? max.x : x;
			y = (y < min.y)? min.y : (y > max.y)? max.y : y;
		}
	};

	//- - - - - - - - - -
	// Classe vecteur 3D
	//- - - - - - - - - -
	class v3d
	{
	public:
		int32 x, y, z;
	public:
		v3d() { x = y = z = 0; }
		v3d(int32 px, int32 py, int32 pz) { x = px, y = py, z = pz; }
		inline v3d &operator /=(const int32 Scalar) { x = divf32(x, Scalar); y = divf32(y, Scalar); z = divf32(z, Scalar); return *this; }
		inline v3d &operator *=(const int32 Scalar) { x = mulf32(x, Scalar); y = mulf32(y, Scalar); z = mulf32(z, Scalar); return *this; }
		inline v3d &operator +=(const v3d &Other) { x += Other.x;	y += Other.y;   z += Other.z; return *this; }
		inline v3d &operator -=(const v3d &Other) { x -= Other.x;	y -= Other.y;   z += Other.z; return *this;	}
		inline v3d operator ^ (const v3d &V) const //Produit vectoriel
		{
			return v3d(mulf32(y,V.z) - mulf32(z,V.y), mulf32(z,V.x) - mulf32(x,V.z), mulf32(x,V.y) - mulf32(y,V.x));
		} 
		inline int32 operator * (const v3d &V) const{	return mulf32(x, V.x) + mulf32(y, V.y) + mulf32(z, V.z) ; } //Produit scalaire (dot)
		inline v3d operator * (int32 s)    const { return v3d(mulf32(x, s), mulf32(y, s), mulf32(z, s)); }
		inline v3d operator / (int32 s)	 const { return v3d(divf32(x, s), divf32(y, s), divf32(z, s) ); }
		inline v3d operator + (const v3d &V) const	{ return v3d(x+V.x, y+V.y, z+V.z); }	
		inline v3d operator - (const v3d &V) const	{ return v3d(x-V.x, y-V.y, z-V.z); }
		friend v3d operator * (int32 k, const v3d& V) { return v3d(mulf32(V.x, k), mulf32(V.y, k), mulf32(V.z, k) ); }
		inline v3d operator -(void) const { return v3d(-x, -y, -z); }
		inline int32 Length() const { return sqrtf32(mulf32(x, x) + mulf32(y, y) + mulf32(z, z) ); }
		void Normalise() 
		{	
			/*int32 fLength = Length();		
			if(fLength == 0) 
				return; 
			(*this) *= divf32(4096, fLength);*/
			int32 v[3] = {x, y, z};
			v_fnormalizef32(v);
			x = v[0], y = v[1], z = v[2];
		}
		v3d Direction() const
		{
			v3d Temp(*this);
			Temp.Normalise();
			return Temp;
		}
		void Clamp(const v3d& min, const v3d& max)
		{
			x = (x < min.x)? min.x : (x > max.x)? max.x : x;
			y = (y < min.y)? min.y : (y > max.y)? max.y : y;
			z = (z < min.z)? min.z : (z > max.z)? max.z : z;
		}
	};
};

#endif
