#ifndef __VECTORS
#define __VECTORS

typedef struct{
	float x,y;
} tVector2;

typedef struct{
	float x,y,z;
} tVector3;

typedef float tMatrix3[3][3];
typedef float tMatrix4[4][4];

#ifndef PI
#define PI 3.14159265359
#endif

#define kDegreeRadians (2*PI/360.0)

#define kMatrixTolerance 0.001

#define MatrixGetXVector(m) ((tVector3*)(m)[0])
#define MatrixGetYVector(m) ((tVector3*)(m)[1])
#define MatrixGetZVector(m) ((tVector3*)(m)[2])
#define MatrixGetPosVector(m) ((tVector3*)(m)[3])

void MatrixAdd(tMatrix3 x, tMatrix3 y, tMatrix3 m);
void MatrixAdd(tMatrix4 x, tMatrix4 y, tMatrix4 m);
void MatrixSub(tMatrix3 x, tMatrix3 y, tMatrix3 m);
void MatrixSub(tMatrix4 x, tMatrix4 y, tMatrix4 m);
void MatrixCopy(tMatrix3 src,tMatrix3 dst);
void MatrixCopy(tMatrix4 src,tMatrix4 dst);
void MatrixCopy(tMatrix3 src,tMatrix4 dst);
void MatrixMult(tMatrix3 x, tMatrix3 y, tMatrix3 m);
void MatrixMult(tMatrix3 x, tMatrix4 y, tMatrix4 m);
void MatrixMult(tMatrix4 x, tMatrix3 y, tMatrix4 m);
void MatrixMult(tMatrix4 x, tMatrix4 y, tMatrix4 m);
void MatrixIdentity(tMatrix3 m);
void MatrixIdentity(tMatrix4 m);
void MatrixTranslate(tMatrix4 target, float x, float y, float z);
void MatrixTranslateVector(tMatrix4 target,tVector3 v);
void MatrixScale(tMatrix3 target, float x, float y, float z);
void MatrixScale(tMatrix4 target, float x, float y, float z);
void MatrixScaleVector(tMatrix3 target,tVector3 v);
void MatrixScaleVector(tMatrix4 target,tVector3 v);
void MatrixRotX(tMatrix3 target, float r);
void MatrixRotX(tMatrix4 target, float r);
void MatrixRotY(tMatrix3 target, float r);
void MatrixRotY(tMatrix4 target, float r);
void MatrixRotZ(tMatrix3 target, float r);
void MatrixRotZ(tMatrix4 target, float r);
void MatrixTranspose(tMatrix3 x,tMatrix3 dst);
void MatrixTranspose(tMatrix4 x,tMatrix4 dst);
int MatrixVerify(tMatrix3 m);
int MatrixVerify(tMatrix4 m);
void MatrixReAdjust(tMatrix3 m);
void MatrixReAdjust(tMatrix4 m);
void RotationVectorToMatrix(tVector3 axis,tMatrix3 mat); 
void RotationVectorToMatrix(tVector3 axis,tMatrix4 mat); 
void EulerAnglesToMatrix(tVector3 euler,tMatrix3 dst);
void EulerAnglesToMatrix(tVector3 euler,tMatrix4 dst);
tVector3 MatrixToEulerAngles(tMatrix3 m);
tVector3 MatrixToEulerAngles(tMatrix4 m);

//returns the vector (x,y)
inline tVector2 Vector(float x,float y)
{
	tVector2 v;
	v.x=x;
	v.y=y;
	return v;
}

//returns the vector (x,y,z)
inline tVector3 Vector(float x,float y,float z)
{
	tVector3 v;
	v.x=x;
	v.y=y;
	v.z=z;
	return v;
}

int VectorZero(tVector2 v);
int VectorZero(tVector3 v);
int VectorEqual(tVector3 a,tVector3 b);
int VectorEqual(tVector2 a,tVector2 b);

//add two vectors
inline tVector2 operator +(tVector2 a,tVector2 b)
{
	tVector2 v;
	v.x=a.x+b.x;
	v.y=a.y+b.y;
	return v;
}

inline tVector3 operator +(tVector3 a,tVector3 b)
{
	tVector3 v;
	v.x=a.x+b.x;
	v.y=a.y+b.y;
	v.z=a.z+b.z;
	return v;
}

//subtracts two vectors
inline tVector2 operator -(tVector2 a,tVector2 b)
{
	tVector2 v;
	v.x=a.x-b.x;
	v.y=a.y-b.y;
	return v;
}

inline tVector3 operator -(tVector3 a,tVector3 b)
{
	tVector3 v;
	v.x=a.x-b.x;
	v.y=a.y-b.y;
	v.z=a.z-b.z;
	return v;
}

//returns the additive inverse of a vector
inline tVector2 operator -(tVector2 v)
{
	tVector2 w;
	w.x=-v.x;
	w.y=-v.y;
	return w;
}

inline tVector3 operator -(tVector3 v)
{
	tVector3 w;
	w.x=-v.x;
	w.y=-v.y;
	w.z=-v.z;
	return w;
}

inline tVector2 operator *(float s, tVector2 v)
{
	tVector2 w;
	w.x=v.x*s;
	w.y=v.y*s;
	return w;
}

inline tVector3 operator *(float s, tVector3 v)
{
	tVector3 w;
	w.x=v.x*s;
	w.y=v.y*s;
	w.z=v.z*s;
	return w;
}

inline tVector2 operator *(tVector2 v,float s)
{
	tVector2 w;
	w.x=v.x*s;
	w.y=v.y*s;
	return w;
}

inline tVector3 operator *(tVector3 v,float s)
{
	tVector3 w;
	w.x=v.x*s;
	w.y=v.y*s;
	w.z=v.z*s;
	return w;
}

/*
tVector3 operator *(tVector3 v,tMatrix4 m);
tVector3 operator *(tVector3 v,tMatrix3 m);
tVector3 operator *(tMatrix4 m,tVector3 v);
tVector3 operator *(tMatrix3 m,tVector3 v);
tVector2 operator /(tVector2 v,float s);
tVector3 operator /(tVector3 v,float s);
*/
//the dot product of two vectors
inline float operator *(tVector2 a,tVector2 b)
{
	return a.x*b.x+a.y*b.y;
}

inline float operator *(tVector3 a,tVector3 b)
{
	return a.x*b.x+a.y*b.y+a.z*b.z;
}

//i know the overloading operators with operations that do not relate
//to the operator's original meaning is considered bad programming.
//however, imho, once one has adopted these conventions, complex vector
//code becomes much more readable.

//the cross product of two vectors
inline tVector3 operator %(tVector3 a,tVector3 b) 
{
	return Vector(
				a.y*b.z-b.y*a.z,
				a.z*b.x-b.z*a.x,
				a.x*b.y-b.x*a.y
				);	
}

//the absolute value of a vector

inline float operator ~(tVector2 v)
{
	return sqrt(v.x*v.x+v.y*v.y);	
}

inline float operator ~(tVector3 v) 
{
	return sqrt(v.x*v.x+v.y*v.y+v.z*v.z);	
}

//the normalized form of a vector
inline tVector2 operator !(tVector2 v) 
{
	float val=~v;
	return val>0.0?((1/val)*v):Vector(0,0);	
}

inline tVector3 operator !(tVector3 v) 
{
	float val=~v;
	return val>0.0?((1/val)*v):Vector(0,0,0);	
}

//x*x
inline float sqr(float x)
{
	return x*x;
}

inline float sqr(tVector2 x)
{
	return x*x;
}

inline float sqr(tVector3 x)
{
	return x*x;
}

//multiplies a vector by a matrix
inline tVector3 operator *(tVector3 v,tMatrix4 m)
{
    return Vector(
	   	v.x*m[0][0]+v.y*m[1][0]+v.z*m[2][0]+m[3][0],
	    v.x*m[0][1]+v.y*m[1][1]+v.z*m[2][1]+m[3][1],
	    v.x*m[0][2]+v.y*m[1][2]+v.z*m[2][2]+m[3][2]
    );
}

inline tVector3 operator *(tVector3 v,tMatrix3 m)
{
    return Vector(
	   	v.x*m[0][0]+v.y*m[1][0]+v.z*m[2][0],
	    v.x*m[0][1]+v.y*m[1][1]+v.z*m[2][1],
	    v.x*m[0][2]+v.y*m[1][2]+v.z*m[2][2]
    );
}

inline tVector3 operator *(tMatrix4 m,tVector3 v)
{
    return Vector(
	   	v.x*m[0][0]+v.y*m[1][0]+v.z*m[2][0]+m[3][0],
	    v.x*m[0][1]+v.y*m[1][1]+v.z*m[2][1]+m[3][1],
	    v.x*m[0][2]+v.y*m[1][2]+v.z*m[2][2]+m[3][2]
    );
}

inline tVector3 operator *(tMatrix3 m,tVector3 v)
{
    return Vector(
	   	v.x*m[0][0]+v.y*m[1][0]+v.z*m[2][0],
	    v.x*m[0][1]+v.y*m[1][1]+v.z*m[2][1],
	    v.x*m[0][2]+v.y*m[1][2]+v.z*m[2][2]
    );
}

//multiplies a vector by 1/scalar
inline tVector2 operator /(tVector2 v,float s)
{
	return Vector(v.x/s,v.y/s);
}

inline tVector3 operator /(tVector3 v,float s)
{
	return Vector(v.x/s,v.y/s,v.z/s);
}



#define sign(x) ((x)<0?-1:1)

#endif