/***************************************************************************
 * matrix and vector operations                                            *
 * Note that the provided functions are provided for 4x4 matrices and 4x1  *
 * vectors (as OpenGL uses them). The 4x4 matrix is saved in an array of   *
 * 16 values. The first row is saved in the first 4 positions (0 to 3), at *
 * position 4 the first column of the second row is written, at position 5 *
 * the second column of the second row, etc.                               *
 *                                                                         *
 * authors: Ines Stuppacher, Peter Supan                                   *
 * last update: 2005/06/01                                                 *
 **************************************************************************/

#ifndef ARSMATH_H
#define ARSMATH_H

//--- inludes ----------------------------------------------------------
//#include <gl/glut.h>

//--- typedefs ---------------------------------------------------------
typedef float ARSVector4[4];
typedef float ARSMatrix4x4[16];


//--- functions for 4x4 matrices ---------------------------------------
/* Set the values of a matrix. */
void arsMat4x4SetValues(ARSMatrix4x4 matrix,
				 float a, float b, float c, float d,
				 float e, float f, float g, float h,
				 float i, float j, float k, float l,
				 float m, float n, float o, float p );

/* Set identity matrix. */
void arsMat4x4MatrixSetIdentity(ARSMatrix4x4 matrix);

/* Set values of source matrix to destinatin matrix. */
void arsMat4x4SetValuesOfMatrix(ARSMatrix4x4 source, ARSMatrix4x4 destination);

/* Write the transpose matrix into the one given to the function. */
void arsMat4x4GetTranspose(ARSMatrix4x4 matrix);

/* Calculate the inverse matrix of source and save it into
 * destination. */
void arsMat4x4GetInverse(ARSMatrix4x4 source, ARSMatrix4x4 destination);

/* Multiply two 4x4 matrices and save the result into a new 
 * matrix. */
void arsMat4x4Mat4x4Mult(ARSMatrix4x4 mat1, ARSMatrix4x4 mat2, ARSMatrix4x4 matOut);


/* Multiply a vector (with 4 rows) with a 4x4 matrix and save
 * the result in a new vector. */
void arsVec4Mat4x4Mult(ARSVector4 vecIn, ARSMatrix4x4 matIn, ARSVector4 vecOut);

/* Calculate length of a vector (ignoring the w-Coordinate). */
float arsVec4Length(const ARSVector4 vector);

/* Calculate the squared length of a vector (ignoring the w-Coordinate). */
float arsVec4LengthSq(const ARSVector4 vector);

/* Calculate 4D dot product of two vectors. */
float arsVec4Dot(ARSVector4 vecA, ARSVector4 vecB);

/* Calculate cross product of two vectors and save the result
 * in a new vector. */
void arsVec4Cross(ARSVector4 vecA, ARSVector4 vecB, ARSVector4 vecOut);

/* Add two vectors and save result in a new vector. */
void arsVec4Add(ARSVector4 vecA, ARSVector4 vecB, ARSVector4 vecOut);

/* Subtract two vectors and save result in a new vector. 
 * (vecOut = vecA - vecB) */
void arsVec4Subtract(ARSVector4 vecA, ARSVector4 vecB, ARSVector4 vecOut);

/* Normalize a vector. */
void arsVec4Normalize(ARSVector4 vector);


//--- functions for transforming 4x4 matrices ----------------------------
// all matrices taken from http://pyopengl.sourceforge.net/documentation/manual/
void arsTranslatef(ARSMatrix4x4 matrix, float x, float y, float z);
void arsRotatef(ARSMatrix4x4 matrix, float angle, float x, float y, float z);
void arsScalef(ARSMatrix4x4 matrix, float x, float y, float z);

void arsPerspective(ARSMatrix4x4 matrix, float fovy, float aspect, float zNear, float zFar);
void arsFrustum(ARSMatrix4x4 matrix, float left, float right, float bottom, float top, float zNear, float zFar);


//--- functions for debugging --------------------------------------------
void arsMat4x4Print(ARSMatrix4x4 matrix);
void arsVec4Print(ARSVector4 vector);


//--- vector3 (used to reconstruct D3DXVECTOR3 used in NVMeshMender) -----
typedef struct ARSVector3{
public:
	//--- variables ------------------------------------------------------
	float x;
	float y;
	float z;

	//--- methods --------------------------------------------------------
	ARSVector3();
	ARSVector3(const float* values);
	ARSVector3(const ARSVector3 &vector);
	ARSVector3(float x, float y, float z);

	virtual ~ARSVector3() {};

	// casting
	operator float* ();
	operator const float* () const;

	// assignment operators
	ARSVector3& operator  = (const ARSVector3 &vector);
	ARSVector3& operator += (const ARSVector3 &vector);
	ARSVector3& operator -= (const ARSVector3 &vector);
	ARSVector3& operator *= (float value);
	ARSVector3& operator /= (float value);

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

	// binary operators
	ARSVector3 operator + (const ARSVector3 &vector) const;
	ARSVector3 operator - (const ARSVector3 &vector) const;
	ARSVector3 operator * (const float value) const;
	ARSVector3 operator / (const float value) const;

	friend ARSVector3 operator * (float value, const struct ARSVector3 &vector);

	bool operator == (const ARSVector3 &vector) const;
	bool operator != (const ARSVector3 &vector) const;

	// set-methods
	void arsSetX(float x);
	void arsSetY(float y);
	void arsSetZ(float z);

	// get-methods
	float arsGetX(void) const;
	float arsGetY(void) const;
	float arsGetZ(void) const;
} ARSVector3;

//--- functions for ARSVector3 -----------------------------------------
float arsVector3Length(const ARSVector3* vector);
float arsVector3LengthSq(const ARSVector3* vector);
float arsVector3Dot(const ARSVector3* vectorA, const ARSVector3* vectorB);
ARSVector3* arsVector3Cross(ARSVector3* out, const ARSVector3* vectorA, const ARSVector3* vectorB);
ARSVector3* arsVector3Add(ARSVector3* out, const ARSVector3* vectorA, const ARSVector3* vectorB);
ARSVector3* arsVector3Subtract(ARSVector3* out, const ARSVector3* vectorA, const ARSVector3* vectorB);
ARSVector3* arsVector3Normalize(ARSVector3* out, const ARSVector3* in);


#endif