#ifndef MATRIX_MATH
#define MATRIX_MATH

#include <GL/glew.h>

typedef struct {
	GLfloat x;
	GLfloat y;
	GLfloat z;
} vec3;

typedef struct {
	GLfloat x;
	GLfloat y;
	GLfloat z;
	GLfloat w;
} vec4;

typedef struct {
	GLfloat m00;
	GLfloat m10;
	GLfloat m20;
	GLfloat m30;

	GLfloat m01;
	GLfloat m11;
	GLfloat m21;
	GLfloat m31;

	GLfloat m02;
	GLfloat m12;
	GLfloat m22;
	GLfloat m32;

	GLfloat m03;
	GLfloat m13;
	GLfloat m23;
	GLfloat m33;
} mat4;

extern void vec3Zero(vec3* out);
extern void vec3Add(vec3* out, vec3* a, vec3* b);
extern void vec3Multiply(vec3* out, vec3* a, GLfloat x);
extern void vec3Subtract(vec3* out, vec3* a, vec3* b);
extern void vec3Cross(vec3* out, vec3* a, vec3* b);
extern void vec3Normalise(vec3* out, vec3* a);
extern GLfloat vec3Length(vec3* a);
extern GLfloat vec3Dot(vec3* a, vec3* b);

extern void identity(mat4* out);
extern void translation(mat4* out, vec3* v);
extern void scaling(mat4* out, vec3* v);
extern void rotationZ(mat4* out, GLfloat angle);
extern void rotationY(mat4* out, GLfloat angle);
extern void rotationX(mat4* out, GLfloat angle);

extern void multiplyAny(GLfloat* out, GLfloat* A, GLfloat* B, int wA, int hA, int wB);
extern void multiply(mat4* out, mat4* A, mat4* B);

extern void translate(mat4* out, mat4* in, vec3* v);
extern void scale(mat4* out, mat4* in, vec3* v);
extern void rotateZ(mat4* out, mat4* in, GLfloat angle);
extern void rotateY(mat4* out, mat4* in, GLfloat angle);
extern void rotateX(mat4* out, mat4* in, GLfloat angle);

extern void transposeAny(GLfloat* out, GLfloat* in, int w, int h);
extern void transpose(mat4* out, mat4* in);

extern void printAny(GLfloat* M, int w, int h);
extern void vec3Print(vec3* a);
extern void mat4Print(mat4* m);

#endif