/* Transformation matrix code V1.50 23/1/04
   Copyright 2008 Jeffrey Lee
   This file is part of WOUM.
   WOUM is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
   WOUM is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   You should have received a copy of the GNU General Public License
   along with WOUM.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _TMAT_H
#define _TMAT_H

#include "vec.h"

/* Matricies are in [row][column] format */
typedef struct {
	float t[4][4];
} tmat; /* Using structs to make returning pointers easier */
typedef struct {
	f1616 t[4][4];
} tmat16;
typedef struct {
	f248 t[4][4];
} tmat24;
typedef struct {
	f2012 t[4][4];
} tmat20;
typedef struct {
	f4816 t[4][4];
} tmat48;

/* Multiply two matricies */
extern void tmat_mult(const tmat *a,const tmat *b,tmat *out);
extern void tmat16_mult(const tmat16 *a,const tmat16 *b,tmat16 *out);
extern void tmat24_mult(const tmat24 *a,const tmat24 *b,tmat24 *out);
extern void tmat20_mult(const tmat20 *a,const tmat20 *b,tmat20 *out);
extern void tmat48_mult(const tmat48 *a,const tmat48 *b,tmat48 *out);

/* Calculate the dot product of a matrix and a vector */
extern void tmat_dotprod(const tmat *a,const vec *in,vec *out);
extern void tmat16_dotprod(const tmat16 *a,const vec16 *in,vec16 *out);
extern void tmat24_dotprod(const tmat24 *a,const vec24 *in,vec24 *out);
extern void tmat20_dotprod(const tmat20 *a,const vec20 *in,vec20 *out);
extern void tmat48_dotprod(const tmat48 *a,const vec48 *in,vec48 *out);

/* Copy a matrix */
extern void tmat_copy(const tmat *in,tmat *out);
extern void tmat16_copy(const tmat16 *in,tmat16 *out);
extern void tmat24_copy(const tmat24 *in,tmat24 *out);
extern void tmat20_copy(const tmat20 *in,tmat20 *out);
extern void tmat48_copy(const tmat48 *in,tmat48 *out);

/* Apply a linear translation to a matrix */
extern void tmat_translate(const tmat *in,tmat *out,const vec *by);
extern void tmat16_translate(const tmat16 *in,tmat16 *out,const vec16 *by);
extern void tmat24_translate(const tmat24 *in,tmat24 *out,const vec24 *by);
extern void tmat20_translate(const tmat20 *in,tmat20 *out,const vec20 *by);
extern void tmat48_translate(const tmat48 *in,tmat48 *out,const vec48 *by);

/* Apply a scale translation to a matrix */
extern void tmat_scale(const tmat *in,tmat *out,const vec *by);
extern void tmat16_scale(const tmat16 *in,tmat16 *out,const vec16 *by);
extern void tmat24_scale(const tmat24 *in,tmat24 *out,const vec24 *by);
extern void tmat20_scale(const tmat20 *in,tmat20 *out,const vec20 *by);
extern void tmat48_scale(const tmat48 *in,tmat48 *out,const vec48 *by);

/* Apply a rotation around the X axis
   Angles are in degrees
*/
extern void tmat_rotx(const tmat *in,tmat *out,float ang);
extern void tmat16_rotx(const tmat16 *in,tmat16 *out,f1616 ang);
extern void tmat24_rotx(const tmat24 *in,tmat24 *out,f248 ang);
extern void tmat20_rotx(const tmat20 *in,tmat20 *out,f2012 ang);
extern void tmat48_rotx(const tmat48 *in,tmat48 *out,f4816 ang);

/* Apply a rotation around the Y axis
   Angles are in degrees
*/
extern void tmat_roty(const tmat *in,tmat *out,float ang);
extern void tmat16_roty(const tmat16 *in,tmat16 *out,f1616 ang);
extern void tmat24_roty(const tmat24 *in,tmat24 *out,f248 ang);
extern void tmat20_roty(const tmat20 *in,tmat20 *out,f2012 ang);
extern void tmat48_roty(const tmat48 *in,tmat48 *out,f4816 ang);

/* Apply a rotation around the Z axis
   Angles are in degrees
*/
extern void tmat_rotz(const tmat *in,tmat *out,float ang);
extern void tmat16_rotz(const tmat16 *in,tmat16 *out,f1616 ang);
extern void tmat24_rotz(const tmat24 *in,tmat24 *out,f248 ang);
extern void tmat20_rotz(const tmat20 *in,tmat20 *out,f2012 ang);
extern void tmat48_rotz(const tmat48 *in,tmat48 *out,f4816 ang);

/* Apply the inverse of a matrix to a vector
   Only works with matricies with a determinant (i.e. [3][3]) of 1
   Probably doesn't work correctly anyway
*/
extern void tmat_inv(const tmat *a,const vec *in,vec *out);
extern void tmat16_inv(const tmat16 *a,const vec16 *in,vec16 *out);
extern void tmat24_inv(const tmat24 *a,const vec24 *in,vec24 *out);
extern void tmat20_inv(const tmat20 *a,const vec20 *in,vec20 *out);
extern void tmat48_inv(const tmat48 *a,const vec48 *in,vec48 *out);

/* Initialise the matrix to the identity matrix */
extern void tmat_ident(tmat *m);
extern void tmat16_ident(tmat16 *m);
extern void tmat24_ident(tmat24 *m);
extern void tmat20_ident(tmat20 *m);
extern void tmat48_ident(tmat48 *m);

/* Reverse transformations - these perform the same operations as the normal
   versions, but the multiplication is performed with the matricies swapped
   Thus the operation will appear to have been performed 'before' all the
   previous ones:
   tmat_translate(a,b,...), tmat_rotx(b,c,...)
   is the same as
   tmat_rotxr(a,b,...), tmat_translater(b,c,...)
*/
extern void tmat_translater(const tmat *in,tmat *out,const vec *by);
extern void tmat16_translater(const tmat16 *in,tmat16 *out,const vec16 *by);
extern void tmat24_translater(const tmat24 *in,tmat24 *out,const vec24 *by);
extern void tmat20_translater(const tmat20 *in,tmat20 *out,const vec20 *by);
extern void tmat48_translater(const tmat48 *in,tmat48 *out,const vec48 *by);

extern void tmat_scaler(const tmat *in,tmat *out,const vec *by);
extern void tmat16_scaler(const tmat16 *in,tmat16 *out,const vec16 *by);
extern void tmat24_scaler(const tmat24 *in,tmat24 *out,const vec24 *by);
extern void tmat20_scaler(const tmat20 *in,tmat20 *out,const vec20 *by);
extern void tmat48_scaler(const tmat48 *in,tmat48 *out,const vec48 *by);

extern void tmat_rotxr(const tmat *in,tmat *out,float ang);
extern void tmat16_rotxr(const tmat16 *in,tmat16 *out,f1616 ang);
extern void tmat24_rotxr(const tmat24 *in,tmat24 *out,f248 ang);
extern void tmat20_rotxr(const tmat20 *in,tmat20 *out,f2012 ang);
extern void tmat48_rotxr(const tmat48 *in,tmat48 *out,f4816 ang);

extern void tmat_rotyr(const tmat *in,tmat *out,float ang);
extern void tmat16_rotyr(const tmat16 *in,tmat16 *out,f1616 ang);
extern void tmat24_rotyr(const tmat24 *in,tmat24 *out,f248 ang);
extern void tmat20_rotyr(const tmat20 *in,tmat20 *out,f2012 ang);
extern void tmat48_rotyr(const tmat48 *in,tmat48 *out,f4816 ang);

extern void tmat_rotzr(const tmat *in,tmat *out,float ang);
extern void tmat16_rotzr(const tmat16 *in,tmat16 *out,f1616 ang);
extern void tmat24_rotzr(const tmat24 *in,tmat24 *out,f248 ang);
extern void tmat20_rotzr(const tmat20 *in,tmat20 *out,f2012 ang);
extern void tmat48_rotzr(const tmat48 *in,tmat48 *out,f4816 ang);

/* Type conversion */
extern void tmat_to_tmat(const tmat *in,tmat *out);
extern void tmat_to_tmat16(const tmat *in,tmat16 *out);
extern void tmat_to_tmat24(const tmat *in,tmat24 *out);
extern void tmat_to_tmat20(const tmat *in,tmat20 *out);
extern void tmat_to_tmat48(const tmat *in,tmat48 *out);
extern void tmat16_to_tmat(const tmat16 *in,tmat *out);
extern void tmat16_to_tmat16(const tmat16 *in,tmat16 *out);
extern void tmat16_to_tmat24(const tmat16 *in,tmat24 *out);
extern void tmat16_to_tmat20(const tmat16 *in,tmat20 *out);
extern void tmat16_to_tmat48(const tmat16 *in,tmat48 *out);
extern void tmat24_to_tmat(const tmat24 *in,tmat *out);
extern void tmat24_to_tmat16(const tmat24 *in,tmat16 *out);
extern void tmat24_to_tmat24(const tmat24 *in,tmat24 *out);
extern void tmat24_to_tmat20(const tmat24 *in,tmat20 *out);
extern void tmat24_to_tmat48(const tmat24 *in,tmat48 *out);
extern void tmat20_to_tmat(const tmat20 *in,tmat *out);
extern void tmat20_to_tmat16(const tmat20 *in,tmat16 *out);
extern void tmat20_to_tmat24(const tmat20 *in,tmat24 *out);
extern void tmat20_to_tmat20(const tmat20 *in,tmat20 *out);
extern void tmat20_to_tmat48(const tmat20 *in,tmat48 *out);
extern void tmat48_to_tmat(const tmat48 *in,tmat *out);
extern void tmat48_to_tmat16(const tmat48 *in,tmat16 *out);
extern void tmat48_to_tmat24(const tmat48 *in,tmat24 *out);
extern void tmat48_to_tmat20(const tmat48 *in,tmat20 *out);
extern void tmat48_to_tmat48(const tmat48 *in,tmat48 *out);

#endif
