/***************************************************************/
//
//
//		DirectX	[ matrix.cpp ]
//
//											Author	kazuki tanaka
//											Date	2017 5/15
/*---------------------------------------------------------------
■Update : 2017/5/15
			Create : matrix.cpp

/*---------------------------------------------------------------
	Include File
---------------------------------------------------------------*/

#include <math.h>

#include "rendererdx9.h"

#include "matrix.h"

#include "vector3.h"

/*---------------------------------------------------------------
	Macro Difinition
---------------------------------------------------------------*/


/*---------------------------------------------------------------
	Const Number Difinition
---------------------------------------------------------------*/


/*----------------------------------------------------------------
	static member variable Initialize 
----------------------------------------------------------------*/


// Matrix Constructor
Matrix::Matrix( )
{

	// Member Clear
	Identity( );

}

// Matrix Constructor
Matrix::Matrix( const float& ref )
{
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			mtx[i][j] = ref;
		}
	}
}

// Matrix Constructor
Matrix::Matrix( const Matrix& other )
{
	*this = other;
}

// Matrix Constructor
#ifdef __D3DX9_H__
Matrix::Matrix( const D3DXMATRIX& other )
{

	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			this->mtx[i][j] = other.m[i][j];
		}
	}

}
#endif //___D3DX9_H__

// Matrix Constructor
Matrix::Matrix( float _11, float _12, float _13, float _14,
            float _21, float _22, float _23, float _24,
            float _31, float _32, float _33, float _34,
            float _41, float _42, float _43, float _44 )
{
	this->_11 = _11;
	this->_12 = _12;
	this->_13 = _13;
	this->_14 = _14;
	this->_21 = _21;
	this->_22 = _22;
	this->_23 = _23;
	this->_24 = _24;
	this->_31 = _31;
	this->_32 = _32;
	this->_33 = _33;
	this->_34 = _34;
	this->_41 = _41;
	this->_42 = _42;
	this->_43 = _43;
	this->_44 = _44;
}

// Matrix Zerofill
Matrix& Matrix::ZeroFill( void )
{
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			mtx[i][j] = 0;
		}
	}
	return *this;
}

// Matrix Identity
Matrix& Matrix::Identity( void )
{
	
	for( int row = 0; row < 4; row++ ){
		for( int col = 0; col < 4; col++ ){
			if( row == col ){
				mtx[row][col] = 1.0f;
			}else{
				mtx[row][col] = 0.0f;
			}
		}
	}
	return *this;
}

// Matrix Identity
Matrix& Matrix::Transpose( void )
{
	
	for( int i = 0 ;i < 4;i++ ){
		for( int j = 0 ;j < 4 ; j++ ){
			mtx[i][j]=mtx[j][i];
		}
	}	
	return *this;
}

// Matrix Inverse
Matrix& Matrix::Inverse( void )
{
	
	float d = Det( );

	if( d == 0 ){
		return Identity( );
	}

	Matrix other = (*this);
	Matrix out;

	// 余因子展開 < cramerの公式 >
	out.mtx[0][0]=(other.mtx[1][1]*other.mtx[2][2]*other.mtx[3][3]
				+other.mtx[1][2]*other.mtx[2][3]*other.mtx[3][1]
				+other.mtx[1][3]*other.mtx[2][1]*other.mtx[3][2]
				-other.mtx[1][1]*other.mtx[2][3]*other.mtx[3][2]
				-other.mtx[1][2]*other.mtx[2][1]*other.mtx[3][3]
				-other.mtx[1][3]*other.mtx[2][2]*other.mtx[3][1])/d;
	out.mtx[0][1]=(other.mtx[0][1]*other.mtx[2][3]*other.mtx[3][2]
				+other.mtx[0][2]*other.mtx[2][1]*other.mtx[3][3]
				+other.mtx[0][3]*other.mtx[2][2]*other.mtx[3][1]
				-other.mtx[0][1]*other.mtx[2][2]*other.mtx[3][3]
				-other.mtx[0][2]*other.mtx[2][3]*other.mtx[3][1]
				-other.mtx[0][3]*other.mtx[2][1]*other.mtx[3][2])/d;
	out.mtx[0][2]=(other.mtx[0][1]*other.mtx[1][2]*other.mtx[3][3]
				+other.mtx[0][2]*other.mtx[1][3]*other.mtx[3][1]
				+other.mtx[0][3]*other.mtx[1][1]*other.mtx[3][2]
				-other.mtx[0][1]*other.mtx[1][3]*other.mtx[3][2]
				-other.mtx[0][2]*other.mtx[1][1]*other.mtx[3][3]
				-other.mtx[0][3]*other.mtx[1][2]*other.mtx[3][1])/d;
	out.mtx[0][3]=(other.mtx[0][1]*other.mtx[1][3]*other.mtx[2][2]
				+other.mtx[0][2]*other.mtx[1][1]*other.mtx[2][3]
				+other.mtx[0][3]*other.mtx[1][2]*other.mtx[2][1]
				-other.mtx[0][1]*other.mtx[1][2]*other.mtx[2][3]
				-other.mtx[0][2]*other.mtx[1][3]*other.mtx[2][1]
				-other.mtx[0][3]*other.mtx[1][1]*other.mtx[2][2])/d;

	out.mtx[1][0]=(other.mtx[1][0]*other.mtx[2][3]*other.mtx[3][2]
				+other.mtx[1][2]*other.mtx[2][0]*other.mtx[3][3]
				+other.mtx[1][3]*other.mtx[2][2]*other.mtx[3][0]
				-other.mtx[1][0]*other.mtx[2][2]*other.mtx[3][3]
				-other.mtx[1][2]*other.mtx[2][3]*other.mtx[3][0]
				-other.mtx[1][3]*other.mtx[2][0]*other.mtx[3][2])/d;
	out.mtx[1][1]=(other.mtx[0][0]*other.mtx[2][2]*other.mtx[3][3]
				+other.mtx[0][2]*other.mtx[2][3]*other.mtx[3][0]
				+other.mtx[0][3]*other.mtx[2][0]*other.mtx[3][2]
				-other.mtx[0][0]*other.mtx[2][3]*other.mtx[3][2]
				-other.mtx[0][2]*other.mtx[2][0]*other.mtx[3][3]
				-other.mtx[0][3]*other.mtx[2][2]*other.mtx[3][0])/d;
	out.mtx[1][2]=(other.mtx[0][0]*other.mtx[1][3]*other.mtx[3][2]
				+other.mtx[0][2]*other.mtx[1][0]*other.mtx[3][3]
				+other.mtx[0][3]*other.mtx[1][2]*other.mtx[3][0]
				-other.mtx[0][0]*other.mtx[1][2]*other.mtx[3][3]
				-other.mtx[0][2]*other.mtx[1][3]*other.mtx[3][0]
				-other.mtx[0][3]*other.mtx[1][0]*other.mtx[3][2])/d;
	out.mtx[1][3]=(other.mtx[0][0]*other.mtx[1][2]*other.mtx[2][3]
				+other.mtx[0][2]*other.mtx[1][3]*other.mtx[2][0]
				+other.mtx[0][3]*other.mtx[1][0]*other.mtx[2][2]
				-other.mtx[0][0]*other.mtx[1][3]*other.mtx[2][2]
				-other.mtx[0][2]*other.mtx[1][0]*other.mtx[2][3]
				-other.mtx[0][3]*other.mtx[1][2]*other.mtx[2][0])/d;

	out.mtx[2][0]=(other.mtx[1][0]*other.mtx[2][1]*other.mtx[3][3]
				+other.mtx[1][1]*other.mtx[2][3]*other.mtx[3][0]
				+other.mtx[1][3]*other.mtx[2][0]*other.mtx[3][1]
				-other.mtx[1][0]*other.mtx[2][3]*other.mtx[3][1]
				-other.mtx[1][1]*other.mtx[2][0]*other.mtx[3][3]
				-other.mtx[1][3]*other.mtx[2][1]*other.mtx[3][0])/d;
	out.mtx[2][1]=(other.mtx[0][0]*other.mtx[2][3]*other.mtx[3][1]
				+other.mtx[0][1]*other.mtx[2][0]*other.mtx[3][3]
				+other.mtx[0][3]*other.mtx[2][1]*other.mtx[3][0]
				-other.mtx[0][0]*other.mtx[2][1]*other.mtx[3][3]
				-other.mtx[0][1]*other.mtx[2][3]*other.mtx[3][0]
				-other.mtx[0][3]*other.mtx[2][0]*other.mtx[3][1])/d;
	out.mtx[2][2]=(other.mtx[0][0]*other.mtx[1][1]*other.mtx[3][3]
				+other.mtx[0][1]*other.mtx[1][3]*other.mtx[3][0]
				+other.mtx[0][3]*other.mtx[1][0]*other.mtx[3][1]
				-other.mtx[0][0]*other.mtx[1][3]*other.mtx[3][1]
				-other.mtx[0][1]*other.mtx[1][0]*other.mtx[3][3]
				-other.mtx[0][3]*other.mtx[1][1]*other.mtx[3][0])/d;
	out.mtx[2][3]=(other.mtx[0][0]*other.mtx[1][3]*other.mtx[2][1]
				+other.mtx[0][1]*other.mtx[1][0]*other.mtx[2][3]
				+other.mtx[0][3]*other.mtx[1][1]*other.mtx[2][0]
				-other.mtx[0][0]*other.mtx[1][1]*other.mtx[2][3]
				-other.mtx[0][1]*other.mtx[1][3]*other.mtx[2][0]
				-other.mtx[0][3]*other.mtx[1][0]*other.mtx[2][1])/d;

	out.mtx[3][0]=(other.mtx[1][0]*other.mtx[2][2]*other.mtx[3][1]
				+other.mtx[1][1]*other.mtx[2][0]*other.mtx[3][2]
				+other.mtx[1][2]*other.mtx[2][1]*other.mtx[3][0]
				-other.mtx[1][0]*other.mtx[2][1]*other.mtx[3][2]
				-other.mtx[1][1]*other.mtx[2][2]*other.mtx[3][0]
				-other.mtx[1][2]*other.mtx[2][0]*other.mtx[3][1])/d;
	out.mtx[3][1]=(other.mtx[0][0]*other.mtx[2][1]*other.mtx[3][2]
				+other.mtx[0][1]*other.mtx[2][2]*other.mtx[3][0]
				+other.mtx[0][2]*other.mtx[2][0]*other.mtx[3][1]
				-other.mtx[0][0]*other.mtx[2][2]*other.mtx[3][1]
				-other.mtx[0][1]*other.mtx[2][0]*other.mtx[3][2]
				-other.mtx[0][2]*other.mtx[2][1]*other.mtx[3][0])/d;
	out.mtx[3][2]=(other.mtx[0][0]*other.mtx[1][2]*other.mtx[3][1]
				+other.mtx[0][1]*other.mtx[1][0]*other.mtx[3][2]
				+other.mtx[0][2]*other.mtx[1][1]*other.mtx[3][0]
				-other.mtx[0][0]*other.mtx[1][1]*other.mtx[3][2]
				-other.mtx[0][1]*other.mtx[1][2]*other.mtx[3][0]
				-other.mtx[0][2]*other.mtx[1][0]*other.mtx[3][1])/d;
	out.mtx[3][3]=(other.mtx[0][0]*other.mtx[1][1]*other.mtx[2][2]
				+other.mtx[0][1]*other.mtx[1][2]*other.mtx[2][0]
				+other.mtx[0][2]*other.mtx[1][0]*other.mtx[2][1]
				-other.mtx[0][0]*other.mtx[1][2]*other.mtx[2][1]
				-other.mtx[0][1]*other.mtx[1][0]*other.mtx[2][2]
				-other.mtx[0][2]*other.mtx[1][1]*other.mtx[2][0])/d;

	return out;
	
}

// Matrix Transform
Matrix& Matrix::Transform( const Vector3& trans )
{
	
	_41 += trans.x;
	_42 += trans.y;
	_43 += trans.z;
	
	return *this;

}

// Matrix Rotate
Matrix& Matrix::Rotate( const Vector3& rot )
{
	
	Matrix x,y,z;

	// Axis Y
	y._11 = cosf( rot.y );
	y._13 = (-sinf( rot.y ));

	y._31 = sinf( rot.y );
	y._33 = cosf( rot.y );
	
	
	// Axis X
	x._22 = cosf( rot.x );
	x._23 = sinf( rot.x );

	x._32 = (-sinf( rot.x ));
	x._33 = cosf( rot.x );
	
	
	// Axis Z
	z._11 = cosf( rot.z );
	z._12 = sinf( rot.z );

	z._21 = (-sinf( rot.z ));
	z._22 = cosf( rot.z );
	
	
	(*this) = (*this)*z*x*y; 

	return *this;


}

// Matrix Scaling
Matrix& Matrix::Scaling( const Vector3& scale )
{
	
	_11 *= scale.x;
	_22 *= scale.y;
	_33 *= scale.z;

	return *this;

}

// Matrix trace
float Matrix::Trace( void )
{

	float trace = 0;
	for(int i = 0; i < 4 ;i++ )
	{
		trace += mtx[i][i];
	}
	return trace;
}

// Matrix dat
float Matrix::Det( void )
{

	// Sarrusの方法
	float d = 0;

	d += mtx[0][0] * ( mtx[1][1]*mtx[2][2]*mtx[3][3]
						+mtx[1][2]*mtx[2][3]*mtx[3][1]
						+mtx[1][3]*mtx[2][1]*mtx[3][2]
						-mtx[1][3]*mtx[2][2]*mtx[3][1]
						-mtx[1][2]*mtx[2][1]*mtx[3][3]
						-mtx[1][1]*mtx[2][3]*mtx[3][2]);
	d -= mtx[1][0] * ( mtx[0][1]*mtx[2][2]*mtx[3][3]
						+mtx[0][2]*mtx[2][3]*mtx[3][1]
						+mtx[0][3]*mtx[2][1]*mtx[3][2]
						-mtx[0][3]*mtx[2][2]*mtx[3][1]
						-mtx[0][2]*mtx[2][1]*mtx[3][3]
						-mtx[0][1]*mtx[2][3]*mtx[3][2]);
	d += mtx[2][0] * ( mtx[0][1]*mtx[1][2]*mtx[3][3]
						+mtx[0][2]*mtx[1][3]*mtx[3][1]
						+mtx[0][3]*mtx[1][1]*mtx[3][2]
						-mtx[0][3]*mtx[1][2]*mtx[3][1]
						-mtx[0][2]*mtx[1][1]*mtx[3][3]
						-mtx[0][1]*mtx[1][3]*mtx[3][2]);
	d -= mtx[3][0] * ( mtx[0][1]*mtx[1][2]*mtx[2][3]
						+mtx[0][2]*mtx[1][3]*mtx[2][1]
						+mtx[0][3]*mtx[1][1]*mtx[2][2]
						-mtx[0][3]*mtx[1][2]*mtx[2][1]
						-mtx[0][2]*mtx[1][1]*mtx[2][3]
						-mtx[0][1]*mtx[1][3]*mtx[2][2]);	
	return d;
	
}

// Matrix Operator menber Access
Matrix::operator float* ()
{
	return &mtx[0][0];
}

// Matrix Operator menber Access
Matrix::operator const float* () const
{
	return &mtx[0][0];
}

#ifdef __D3DX9_H__
// Matrix Operator menber Access
Matrix::operator D3DXMATRIX ()
{
	D3DXMATRIX matrix;
	
	memcpy( &matrix, &mtx, sizeof(mtx));

	return matrix;
}
#endif //___D3DX9_H__

// Matrix Operator menber Access
float& Matrix::operator () ( unsigned int row, unsigned int col )
{
	return mtx[row][col];
}

// Matrix Operator menber Access
float  Matrix::operator () ( unsigned int row, unsigned int col ) const
{
	return mtx[row][col];
}

// *= Matrix
Matrix& Matrix::operator *= ( const Matrix& other )
{

	Matrix copy( *this );
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			for(int k=0;k<4;k++)mtx[i][j]+=copy.mtx[i][k]*other.mtx[k][j];
		}
	}
	return *this;
}

// += Matrix
Matrix& Matrix::operator += ( const Matrix& other )
{
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			mtx[i][j] += other.mtx[i][j];
		}
	}
	return *this;
}

// -= Matrix
Matrix& Matrix::operator -= ( const Matrix& other )
{
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			mtx[i][j] -= other.mtx[i][j];
		}
	}
	return *this;
}

// *= float
Matrix& Matrix::operator *= ( float ref )
{
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			mtx[i][j] *= ref;
		}
	}
	return *this;
}

// /= float
Matrix& Matrix::operator /= ( float ref )
{
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			mtx[i][j] /= ref;
		}
	}
	return *this;
}

// + Matrix
Matrix Matrix::operator + () const
{
	return *this;
}

// - Matrix
Matrix Matrix::operator - () const
{
	Matrix other;
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			other.mtx[i][j]=-mtx[i][j];
		}
	}
	return other;
}

// Matrix * Matrix
Matrix Matrix::operator * ( const Matrix& other ) const
{
	Matrix m(0);
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			for(int k=0;k<4;k++)m.mtx[i][j]+=mtx[i][k]*other.mtx[k][j];
		}
	}
	return m;
}

// Matrix * Matrix(D3D)
#ifdef __D3DX9_H__
Matrix Matrix::operator * ( const D3DXMATRIX& other ) const
{
	Matrix m(0);
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			for(int k=0;k<4;k++)m.mtx[i][j]+=mtx[i][k]*other.m[k][j];
		}
	}
	return m;
}
#endif //___D3DX9_H__

// Matrix * Matrix
Matrix Matrix::operator + ( const Matrix& other ) const
{
	Matrix m;
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			m.mtx[i][j] = mtx[i][j]+other.mtx[i][j];
		}
	}
	return m;
}

// Matrix * Matrix
Matrix Matrix::operator - ( const Matrix& other ) const
{
	Matrix m;
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			m.mtx[i][j] = mtx[i][j]-other.mtx[i][j];
		}
	}
	return m;
}

// Matrix *
Matrix Matrix::operator * ( float ref ) const
{
	Matrix m;
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			m.mtx[i][j] = mtx[i][j] * ref;
		}
	}
	return m;
}

// Matrix /
Matrix Matrix::operator / ( float ref ) const
{
	Matrix m;
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			m.mtx[i][j] = mtx[i][j] * ref;
		}
	}
	return m;
}

// Matrix Compare Operator
bool Matrix::operator == ( const Matrix& other ) const
{
	bool result=true;
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			result &= (mtx[i][j] == other.mtx[i][j]);
		}
	}
	return result;
}

// Matrix Compare Operator
bool Matrix::operator != ( const Matrix& other ) const
{

	return !((*this) == other);

}




