/*
 * ExNihilo 3D Engine
 * 
 *  This program 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 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * Please read AUTHORS file !!!
 * 
 * $Id: ExCMatrix4x4.cpp,v 1.5 2002/07/07 00:35:10 data Exp $
 *
 */

#include "ExCMatrix4x4.h"

// Construction/Destruction
ExCMatrix4x4::ExCMatrix4x4()
{
Guard(ExCMatrix4x4::ExCMatrix4x4())
	LoadIdentity();	
UnGuard
}

ExCMatrix4x4::~ExCMatrix4x4()
{
Guard(ExCMatrix4x4::~ExCMatrix4x4())
UnGuard
}

// Methode
void ExCMatrix4x4::SetLine(short line,float c1,float c2,float c3,float c4)
{
Guard(void ExCMatrix4x4::SetLine(short line,float c1,float c2,float c3,float c4))
	switch(line)
	{
		case 1:
			m_Matrix[0] =c1;m_Matrix[4] =c2;m_Matrix[8] =c3;m_Matrix[12]=c4;
			break;
		case 2:
			m_Matrix[1] =c1;m_Matrix[5] =c2;m_Matrix[9] =c3;m_Matrix[13]=c4;
			break;
		case 3:
			m_Matrix[2] =c1;m_Matrix[6] =c2;m_Matrix[10]=c3;m_Matrix[14]=c4;
			break;
		case 4:
			m_Matrix[3] =c1;m_Matrix[7] =c2;m_Matrix[11]=c3;m_Matrix[15]=c4;
			break;
	}
UnGuard
}

void ExCMatrix4x4::SetColone(short colone,float l1,float l2,float l3,float l4)
{
Guard(void ExCMatrix4x4::SetColone(short colone,float l1,float l2,float l3,float l4))
	switch(colone)
	{
		case 1:
			m_Matrix[0] =l1;m_Matrix[1] =l2;m_Matrix[2] =l3;m_Matrix[3]=l4;
			break;
		case 2:
			m_Matrix[4] =l1;m_Matrix[5] =l2;m_Matrix[6] =l3;m_Matrix[7]=l4;
			break;
		case 3:
			m_Matrix[8] =l1;m_Matrix[9] =l2;m_Matrix[10]=l3;m_Matrix[11]=l4;
			break;
		case 4:
			m_Matrix[12] =l1;m_Matrix[13] =l2;m_Matrix[14]=l3;m_Matrix[15]=l4;
			break;
	}
UnGuard
}

void ExCMatrix4x4::SetMatrix(float Matrix[16])
{
	m_Matrix[0]= Matrix[0];
	m_Matrix[1]= Matrix[4];
	m_Matrix[2]= Matrix[8];
	m_Matrix[3]= Matrix[12];
	m_Matrix[4]= Matrix[1];
	m_Matrix[5]= Matrix[5];
	m_Matrix[6]= Matrix[9];
	m_Matrix[7]= Matrix[13];
	m_Matrix[8]= Matrix[2];
	m_Matrix[9]= Matrix[6];
	m_Matrix[10]=Matrix[10];
	m_Matrix[11]=Matrix[14];
	m_Matrix[12]=Matrix[3];
	m_Matrix[13]=Matrix[7];
	m_Matrix[14]=Matrix[11];
	m_Matrix[15]=Matrix[15];
}

void ExCMatrix4x4::SetMatrix(float l1c1,float l1c2,float l1c3,float l1c4,
					float l2c1,float l2c2,float l2c3,float l2c4,
					float l3c1,float l3c2,float l3c3,float l3c4,
					float l4c1,float l4c2,float l4c3,float l4c4)
{
Guard(ExCMatrix4x4::SetMatrix(float l1c1...))
	SetLine(1,l1c1,l1c2,l1c3,l1c4);
	SetLine(2,l2c1,l2c2,l2c3,l2c4);
	SetLine(3,l3c1,l3c2,l3c3,l3c4);
	SetLine(4,l4c1,l4c2,l4c3,l4c4);
UnGuard
}

void ExCMatrix4x4::LoadIdentity(void)
{
Guard(void ExCMatrix4x4::LoadIdentity(void))
	m_Matrix[0] =1.0f;m_Matrix[4] =0.0f;m_Matrix[8] =0.0f;m_Matrix[12]=0.0f;
	m_Matrix[1] =0.0f;m_Matrix[5] =1.0f;m_Matrix[9] =0.0f;m_Matrix[13]=0.0f;  
	m_Matrix[2] =0.0f;m_Matrix[6] =0.0f;m_Matrix[10]=1.0f;m_Matrix[14]=0.0f; 
	m_Matrix[3] =0.0f;m_Matrix[7] =0.0f;m_Matrix[11]=0.0f;m_Matrix[15]=1.0f;
UnGuard
}

float ExCMatrix4x4::GetDeterminant(void)
{
Guard(float ExCMatrix4x4::GetDeterminant(void))
//Using Kramer rule to calculate determinant
//si deter !=0 inverse posible		
	return 
		((m_Matrix[5]*((m_Matrix[10]*m_Matrix[15])-(m_Matrix[11]*m_Matrix[14])))
		-(m_Matrix[9]*((m_Matrix[14]*m_Matrix[7])-(m_Matrix[6]*m_Matrix[15])))
		+(m_Matrix[13]*((m_Matrix[6]*m_Matrix[11])-(m_Matrix[7]*m_Matrix[10]))))
		-((m_Matrix[1]*((m_Matrix[10]*m_Matrix[15])-(m_Matrix[11]*m_Matrix[14])))
		-(m_Matrix[9]*((m_Matrix[14]*m_Matrix[3])-(m_Matrix[2]*m_Matrix[15])))
		+(m_Matrix[13]*((m_Matrix[6]*m_Matrix[11])-(m_Matrix[7]*m_Matrix[10]))))
		+((m_Matrix[1]*((m_Matrix[6]*m_Matrix[15])-(m_Matrix[7]*m_Matrix[14])))
		-(m_Matrix[5]*((m_Matrix[14]*m_Matrix[3])-(m_Matrix[2]*m_Matrix[15])))
		+(m_Matrix[13]*((m_Matrix[2]*m_Matrix[7])-(m_Matrix[3]*m_Matrix[6]))))
		-((m_Matrix[1]*((m_Matrix[2]*m_Matrix[7])-(m_Matrix[3]*m_Matrix[6])))
		-(m_Matrix[5]*((m_Matrix[10]*m_Matrix[3])-(m_Matrix[2]*m_Matrix[11])))
		+(m_Matrix[9]*((m_Matrix[2]*m_Matrix[7])-(m_Matrix[3]*m_Matrix[6]))));
UnGuard
}
//---------------------------------
//Transposeé Ligne=colone
//---------------------------------
ExCMatrix4x4 ExCMatrix4x4::GetTransposee(void)
{
Guard(ExCMatrix4x4 ExCMatrix4x4::GetTransposee(void))
	ExCMatrix4x4 result;
	result.m_Matrix[0]= m_Matrix[0];
	result.m_Matrix[1]= m_Matrix[4];
	result.m_Matrix[2]= m_Matrix[8];
	result.m_Matrix[3]= m_Matrix[12];
	result.m_Matrix[4]= m_Matrix[1];
	result.m_Matrix[5]= m_Matrix[5];
	result.m_Matrix[6]= m_Matrix[9];
	result.m_Matrix[7]= m_Matrix[13];
	result.m_Matrix[8]= m_Matrix[2];
	result.m_Matrix[9]= m_Matrix[6];
	result.m_Matrix[10]=m_Matrix[10];
	result.m_Matrix[11]=m_Matrix[14];
	result.m_Matrix[12]=m_Matrix[3];
	result.m_Matrix[13]=m_Matrix[7];
	result.m_Matrix[14]=m_Matrix[11];
	result.m_Matrix[15]=m_Matrix[15];
	return result;
UnGuard
}
//////////////////////////////////////////////////////////////////////
// Operator
//////////////////////////////////////////////////////////////////////
ExCMatrix4x4 ExCMatrix4x4::operator- (const ExCMatrix4x4 &m2)
{
	ExCMatrix4x4 result;
	ExCMatrix4x4 m1=*this;
	result.m_Matrix[0]= m1.m_Matrix[0]-m2.m_Matrix[0];
	result.m_Matrix[1]= m1.m_Matrix[1]-m2.m_Matrix[1];
	result.m_Matrix[2]= m1.m_Matrix[2]-m2.m_Matrix[2];
	result.m_Matrix[3]= m1.m_Matrix[3]-m2.m_Matrix[3];
	result.m_Matrix[4]= m1.m_Matrix[4]-m2.m_Matrix[4];
	result.m_Matrix[5]= m1.m_Matrix[5]-m2.m_Matrix[5];
	result.m_Matrix[6]= m1.m_Matrix[6]-m2.m_Matrix[6];
	result.m_Matrix[7]= m1.m_Matrix[7]-m2.m_Matrix[7];
	result.m_Matrix[8]= m1.m_Matrix[8]-m2.m_Matrix[8];
	result.m_Matrix[9]= m1.m_Matrix[9]-m2.m_Matrix[9];
	result.m_Matrix[10]=m1.m_Matrix[10]-m2.m_Matrix[10];
	result.m_Matrix[11]=m1.m_Matrix[11]-m2.m_Matrix[11];
	result.m_Matrix[12]=m1.m_Matrix[12]-m2.m_Matrix[12];
	result.m_Matrix[13]=m1.m_Matrix[13]-m2.m_Matrix[13];
	result.m_Matrix[14]=m1.m_Matrix[14]-m2.m_Matrix[14];
	result.m_Matrix[15]=m1.m_Matrix[15]-m2.m_Matrix[15];
	return result;
}

ExCMatrix4x4 ExCMatrix4x4::operator+(const ExCMatrix4x4 &m2)
{
	ExCMatrix4x4 result;
	ExCMatrix4x4 m1=*this;
	result.m_Matrix[0]= m1.m_Matrix[0]+m2.m_Matrix[0];
	result.m_Matrix[1]= m1.m_Matrix[1]+m2.m_Matrix[1];
	result.m_Matrix[2]= m1.m_Matrix[2]+m2.m_Matrix[2];
	result.m_Matrix[3]= m1.m_Matrix[3]+m2.m_Matrix[3];
	result.m_Matrix[4]= m1.m_Matrix[4]+m2.m_Matrix[4];
	result.m_Matrix[5]= m1.m_Matrix[5]+m2.m_Matrix[5];
	result.m_Matrix[6]= m1.m_Matrix[6]+m2.m_Matrix[6];
	result.m_Matrix[7]= m1.m_Matrix[7]+m2.m_Matrix[7];
	result.m_Matrix[8]= m1.m_Matrix[8]+m2.m_Matrix[8];
	result.m_Matrix[9]= m1.m_Matrix[9]+m2.m_Matrix[9];
	result.m_Matrix[10]=m1.m_Matrix[10]+m2.m_Matrix[10];
	result.m_Matrix[11]=m1.m_Matrix[11]+m2.m_Matrix[11];
	result.m_Matrix[12]=m1.m_Matrix[12]+m2.m_Matrix[12];
	result.m_Matrix[13]=m1.m_Matrix[13]+m2.m_Matrix[13];
	result.m_Matrix[14]=m1.m_Matrix[14]+m2.m_Matrix[14];
	result.m_Matrix[15]=m1.m_Matrix[15]+m2.m_Matrix[15];
	return result;
}


ExCMatrix4x4 ExCMatrix4x4::operator * (const float scalar)
{
	ExCMatrix4x4 result;
	ExCMatrix4x4 m1=*this;
	result.m_Matrix[0]= m1.m_Matrix[0]*scalar;
	result.m_Matrix[1]= m1.m_Matrix[1]*scalar;
	result.m_Matrix[2]= m1.m_Matrix[2]*scalar;
	result.m_Matrix[3]= m1.m_Matrix[3]*scalar;
	result.m_Matrix[4]= m1.m_Matrix[4]*scalar;
	result.m_Matrix[5]= m1.m_Matrix[5]*scalar;
	result.m_Matrix[6]= m1.m_Matrix[6]*scalar;
	result.m_Matrix[7]= m1.m_Matrix[7]*scalar;
	result.m_Matrix[8]= m1.m_Matrix[8]*scalar;
	result.m_Matrix[9]= m1.m_Matrix[9]*scalar;
	result.m_Matrix[10]=m1.m_Matrix[10]*scalar;
	result.m_Matrix[11]=m1.m_Matrix[11]*scalar;
	result.m_Matrix[12]=m1.m_Matrix[12]*scalar;
	result.m_Matrix[13]=m1.m_Matrix[13]*scalar;
	result.m_Matrix[14]=m1.m_Matrix[14]*scalar;
	result.m_Matrix[15]=m1.m_Matrix[15]*scalar;
	return result;
}

ExCMatrix4x4 ExCMatrix4x4::operator* (const ExCMatrix4x4 &m2)
{
	ExCMatrix4x4 result;
	ExCMatrix4x4 m1=*this;
	
	result.m_Matrix[0]= (m1.m_Matrix[0]*m2.m_Matrix[0])+(m1.m_Matrix[4]*m2.m_Matrix[1])+(m1.m_Matrix[8]*m2.m_Matrix[2])+(m1.m_Matrix[12]*m2.m_Matrix[3]);
	result.m_Matrix[4]= (m1.m_Matrix[0]*m2.m_Matrix[4])+(m1.m_Matrix[4]*m2.m_Matrix[5])+(m1.m_Matrix[8]*m2.m_Matrix[6])+(m1.m_Matrix[12]*m2.m_Matrix[7]);
	result.m_Matrix[8]= (m1.m_Matrix[0]*m2.m_Matrix[8])+(m1.m_Matrix[4]*m2.m_Matrix[9])+(m1.m_Matrix[8]*m2.m_Matrix[10])+(m1.m_Matrix[12]*m2.m_Matrix[11]);
	result.m_Matrix[12]= (m1.m_Matrix[0]*m2.m_Matrix[12])+(m1.m_Matrix[4]*m2.m_Matrix[13])+(m1.m_Matrix[8]*m2.m_Matrix[14])+(m1.m_Matrix[12]*m2.m_Matrix[15]);
	
	result.m_Matrix[1]= (m1.m_Matrix[1]*m2.m_Matrix[0])+(m1.m_Matrix[5]*m2.m_Matrix[1])+(m1.m_Matrix[9]*m2.m_Matrix[2])+(m1.m_Matrix[13]*m2.m_Matrix[3]);
	result.m_Matrix[5]= (m1.m_Matrix[1]*m2.m_Matrix[4])+(m1.m_Matrix[5]*m2.m_Matrix[5])+(m1.m_Matrix[9]*m2.m_Matrix[6])+(m1.m_Matrix[13]*m2.m_Matrix[7]);
	result.m_Matrix[9]= (m1.m_Matrix[1]*m2.m_Matrix[8])+(m1.m_Matrix[5]*m2.m_Matrix[9])+(m1.m_Matrix[9]*m2.m_Matrix[10])+(m1.m_Matrix[13]*m2.m_Matrix[11]);
	result.m_Matrix[13]= (m1.m_Matrix[1]*m2.m_Matrix[12])+(m1.m_Matrix[5]*m2.m_Matrix[13])+(m1.m_Matrix[9]*m2.m_Matrix[14])+(m1.m_Matrix[13]*m2.m_Matrix[15]);

	result.m_Matrix[2]= (m1.m_Matrix[2]*m2.m_Matrix[0])+(m1.m_Matrix[6]*m2.m_Matrix[1])+(m1.m_Matrix[10]*m2.m_Matrix[2])+(m1.m_Matrix[14]*m2.m_Matrix[3]);
	result.m_Matrix[6]= (m1.m_Matrix[2]*m2.m_Matrix[4])+(m1.m_Matrix[6]*m2.m_Matrix[5])+(m1.m_Matrix[10]*m2.m_Matrix[6])+(m1.m_Matrix[14]*m2.m_Matrix[7]);
	result.m_Matrix[10]= (m1.m_Matrix[2]*m2.m_Matrix[8])+(m1.m_Matrix[6]*m2.m_Matrix[9])+(m1.m_Matrix[10]*m2.m_Matrix[10])+(m1.m_Matrix[14]*m2.m_Matrix[11]);
	result.m_Matrix[14]= (m1.m_Matrix[2]*m2.m_Matrix[12])+(m1.m_Matrix[6]*m2.m_Matrix[13])+(m1.m_Matrix[10]*m2.m_Matrix[14])+(m1.m_Matrix[14]*m2.m_Matrix[15]);

	result.m_Matrix[3]= (m1.m_Matrix[3]*m2.m_Matrix[0])+(m1.m_Matrix[7]*m2.m_Matrix[1])+(m1.m_Matrix[11]*m2.m_Matrix[2])+(m1.m_Matrix[15]*m2.m_Matrix[3]);
	result.m_Matrix[7]= (m1.m_Matrix[3]*m2.m_Matrix[4])+(m1.m_Matrix[7]*m2.m_Matrix[5])+(m1.m_Matrix[11]*m2.m_Matrix[6])+(m1.m_Matrix[15]*m2.m_Matrix[7]);
	result.m_Matrix[11]= (m1.m_Matrix[3]*m2.m_Matrix[8])+(m1.m_Matrix[7]*m2.m_Matrix[9])+(m1.m_Matrix[11]*m2.m_Matrix[10])+(m1.m_Matrix[15]*m2.m_Matrix[11]);
	result.m_Matrix[15]= (m1.m_Matrix[3]*m2.m_Matrix[12])+(m1.m_Matrix[7]*m2.m_Matrix[13])+(m1.m_Matrix[11]*m2.m_Matrix[14])+(m1.m_Matrix[15]*m2.m_Matrix[15]);

	return result;
}

//////////////////////////////////////////////////////////////////////
// friends methode
//////////////////////////////////////////////////////////////////////

std::ostream& operator<<(std::ostream& s,const ExCMatrix4x4 &m)
{
Guard(friend std::ostream& operator<<(std::ostream& s,const ExCMatrix4x4 &m))
	s<<std::endl<<"|["<<m.m_Matrix[0]<<"]"<<"["<<m.m_Matrix[4]<<"]"<<"["<<m.m_Matrix[8]<<"]"<<"["<<m.m_Matrix[12]<<"]|"<<std::endl;
	s<<"|["<<m.m_Matrix[1]<<"]"<<"["<<m.m_Matrix[5]<<"]"<<"["<<m.m_Matrix[9]<<"]"<<"["<<m.m_Matrix[13]<<"]|"<<std::endl;
	s<<"|["<<m.m_Matrix[2]<<"]"<<"["<<m.m_Matrix[6]<<"]"<<"["<<m.m_Matrix[10]<<"]"<<"["<<m.m_Matrix[14]<<"]|"<<std::endl;
	s<<"|["<<m.m_Matrix[3]<<"]"<<"["<<m.m_Matrix[7]<<"]"<<"["<<m.m_Matrix[11]<<"]"<<"["<<m.m_Matrix[15]<<"]|";
	return s;
UnGuard
}
