/* Transformation matrix code V1.50 23/1/04
   See tmat.h for details
   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/>.
*/

void fix_op(NAME,_mult,const NAME *a,const NAME *b,NAME *out)
{
	int i,j;
	for (j=0;j<4;j++) /* Columns */
		for (i=0;i<4;i++) /* Rows */
			out->t[i][j] = fix_op(TYPE,_mul,a->t[i][0],b->t[0][j]) +
				    fix_op(TYPE,_mul,a->t[i][1],b->t[1][j]) +
				    fix_op(TYPE,_mul,a->t[i][2],b->t[2][j]) +
				    fix_op(TYPE,_mul,a->t[i][3],b->t[3][j]);
}

void fix_op(NAME,_dotprod,const NAME *matrix,const VEC *in,VEC *out)
{
	out->x = fix_op(TYPE,_mul,in->x,matrix->t[0][0]) + fix_op(TYPE,_mul,in->y,matrix->t[1][0]) + fix_op(TYPE,_mul,in->z,matrix->t[2][0]) + matrix->t[3][0];
	out->y = fix_op(TYPE,_mul,in->x,matrix->t[0][1]) + fix_op(TYPE,_mul,in->y,matrix->t[1][1]) + fix_op(TYPE,_mul,in->z,matrix->t[2][1]) + matrix->t[3][1];
	out->z = fix_op(TYPE,_mul,in->x,matrix->t[0][2]) + fix_op(TYPE,_mul,in->y,matrix->t[1][2]) + fix_op(TYPE,_mul,in->z,matrix->t[2][2]) + matrix->t[3][2];
}

void fix_op(NAME,_copy,const NAME *in,NAME *out)
{
	out->t[0][0] = in->t[0][0]; out->t[0][1] = in->t[0][1]; out->t[0][2] = in->t[0][2]; out->t[0][3] = in->t[0][3];
	out->t[1][0] = in->t[1][0]; out->t[1][1] = in->t[1][1]; out->t[1][2] = in->t[1][2]; out->t[1][3] = in->t[1][3];
	out->t[2][0] = in->t[2][0]; out->t[2][1] = in->t[2][1]; out->t[2][2] = in->t[2][2]; out->t[2][3] = in->t[2][3];
	out->t[3][0] = in->t[3][0]; out->t[3][1] = in->t[3][1]; out->t[3][2] = in->t[3][2]; out->t[3][3] = in->t[3][3];
}

void fix_op(NAME,_translate,const NAME *in,NAME *out,const VEC *by)
{
	TYPE one;
	one = conv_op(int,TYPE,1); /* Get value of '1' */
#define _30 by->x
#define _31 by->y
#define _32 by->z
#define _00 one
#define _11 one
#define _22 one
#define _33 one
#include "tmattran.c"
}

void fix_op(NAME,_scale,const NAME *in,NAME *out,const VEC *by)
{
#define _00 by->x
#define _11 by->y
#define _22 by->z
#define _33 conv_op(int,TYPE,1)
#include "tmattran.c"
}

void fix_op(NAME,_rotx,const NAME *in,NAME *out,TYPE ang)
{
	TYPE s,c,one;
	one = conv_op(int,TYPE,1);
	s = fix_op(TYPE,_sin,ang);
	c = fix_op(TYPE,_cos,ang);
#define _00 one
#define _11 c
#define _12 s
#define _21 -s
#define _22 c
#define _33 one
#include "tmattran.c"
}

void fix_op(NAME,_roty,const NAME *in,NAME *out,TYPE ang)
{
	TYPE s,c,one;
	one = conv_op(int,TYPE,1);
	s = fix_op(TYPE,_sin,ang);
	c = fix_op(TYPE,_cos,ang);
#define _00 c
#define _02 -s
#define _11 one
#define _20 s
#define _22 c
#define _33 one
#include "tmattran.c"
}

void fix_op(NAME,_rotz,const NAME *in,NAME *out,TYPE ang)
{
	TYPE s,c,one;
	one = conv_op(int,TYPE,1);
	s = fix_op(TYPE,_sin,ang);
	c = fix_op(TYPE,_cos,ang);
	/* Used to be s -s */
#define _00 c
#define _01 -s
#define _10 s
#define _11 c
#define _22 one
#define _33 one
#include "tmattran.c"
}

void fix_op(NAME,_inv,const NAME *matrix,const VEC *in,VEC *out)
{
	out->x = fix_op(TYPE,_mul,in->x,matrix->t[0][0])
	       + fix_op(TYPE,_mul,in->y,matrix->t[0][1])
	       + fix_op(TYPE,_mul,in->z,matrix->t[0][2])
	       + matrix->t[0][3];
	out->y = fix_op(TYPE,_mul,in->x,matrix->t[1][0])
	       + fix_op(TYPE,_mul,in->y,matrix->t[1][1])
	       + fix_op(TYPE,_mul,in->z,matrix->t[1][2])
	       + matrix->t[1][3];
	out->z = fix_op(TYPE,_mul,in->x,matrix->t[2][0])
	       + fix_op(TYPE,_mul,in->y,matrix->t[2][1])
	       + fix_op(TYPE,_mul,in->z,matrix->t[2][2])
	       + matrix->t[2][3];
}

void fix_op(NAME,_ident,NAME *m)
{
	m->t[0][0] = m->t[1][1] = m->t[2][2] = m->t[3][3] = conv_op(int,TYPE,1);
	m->t[0][1] = m->t[0][2] = m->t[0][3] = 0;
	m->t[1][0] = m->t[1][2] = m->t[1][3] = 0;
	m->t[2][0] = m->t[2][1] = m->t[2][3] = 0;
	m->t[3][0] = m->t[3][1] = m->t[3][2] = 0;
}

void fix_op(NAME,_translater,const NAME *in,NAME *out,const VEC *by)
{
	TYPE one;
	one = conv_op(int,TYPE,1); /* Get value of '1' */
#define _30 by->x
#define _31 by->y
#define _32 by->z
#define _00 one
#define _11 one
#define _22 one
#define _33 one
#include "rtmattran.c"
}

void fix_op(NAME,_scaler,const NAME *in,NAME *out,const VEC *by)
{
#define _00 by->x
#define _11 by->y
#define _22 by->z
#define _33 conv_op(int,TYPE,1)
#include "rtmattran.c"
}

void fix_op(NAME,_rotxr,const NAME *in,NAME *out,TYPE ang)
{
	TYPE s,c,one;
	one = conv_op(int,TYPE,1);
	s = fix_op(TYPE,_sin,ang);
	c = fix_op(TYPE,_cos,ang);
#define _00 one
#define _11 c
#define _12 s
#define _21 -s
#define _22 c
#define _33 one
#include "rtmattran.c"
}

void fix_op(NAME,_rotyr,const NAME *in,NAME *out,TYPE ang)
{
	TYPE s,c,one;
	one = conv_op(int,TYPE,1);
	s = fix_op(TYPE,_sin,ang);
	c = fix_op(TYPE,_cos,ang);
#define _00 c
#define _02 -s
#define _11 one
#define _20 s
#define _22 c
#define _33 one
#include "rtmattran.c"
}

void fix_op(NAME,_rotzr,const NAME *in,NAME *out,TYPE ang)
{
	TYPE s,c,one;
	one = conv_op(int,TYPE,1);
	s = fix_op(TYPE,_sin,ang);
	c = fix_op(TYPE,_cos,ang);
#define _00 c
#define _01 -s
#define _10 s
#define _11 c
#define _22 one
#define _33 one
#include "rtmattran.c"
}

#define convmcr(TONAME,TOTYPE)\
void fix_op(NAME,_to_ ## TONAME,const NAME *in,TONAME *out)\
{\
	int i,j;\
	for (i=0;i<4;i++)\
		for (j=0;j<4;j++)\
			out->t[i][j] = conv_op(TYPE,TOTYPE,in->t[i][j]);\
}

convmcr(tmat,float)
convmcr(tmat16,f1616)
convmcr(tmat24,f248)
convmcr(tmat20,f2012)
convmcr(tmat48,f4816)

#undef convmcr
