#include "Mix/Matrix4x4.h"

namespace Mix{

Matrix4x4::Matrix4x4( void )
{
	m00 = 1.0f;
	m01 = 0.0f;
	m02 = 0.0f;
	m03 = 0.0f;
	m10 = 0.0f;
	m11 = 1.0f;
	m12 = 0.0f;
	m13 = 0.0f;
	m20 = 0.0f;
	m21 = 0.0f;
	m22 = 1.0f;
	m23 = 0.0f;
	m30 = 0.0f;
	m31 = 0.0f;
	m32 = 0.0f;
	m33 = 1.0f;
}

Matrix4x4::Matrix4x4( const Mix::Quaternion& r )
{
	SetRotation( r );
}

Matrix4x4::Matrix4x4( const Mix::Quaternion& r, const Mix::Vector3& t )
{
	SetRotation( r );

	m30 = t.x;
	m31 = t.y;
	m32 = t.z;
	m33 = 1.0f;
}

Matrix4x4::Matrix4x4( const Mix::Vector3& s, const Mix::Quaternion& r, const Mix::Vector3& t )
{
	Compose( s, r, t );

}

Matrix4x4::Matrix4x4(	Float32 _m00, Float32 _m01, Float32 _m02, Float32 _m03,
						Float32 _m10, Float32 _m11, Float32 _m12, Float32 _m13,
						Float32 _m20, Float32 _m21, Float32 _m22, Float32 _m23,
						Float32 _m30, Float32 _m31, Float32 _m32, Float32 _m33 )
{
	m00 = _m00;
	m01 = _m01;
	m02 = _m02;
	m03 = _m03;
	m10 = _m10;
	m11 = _m11;
	m12 = _m12;
	m13 = _m13;
	m20 = _m20;
	m21 = _m21;
	m22 = _m22;
	m23 = _m23;
	m30 = _m30;
	m31 = _m31;
	m32 = _m32;
	m33 = _m33;
}

Matrix4x4::Matrix4x4( const Matrix4x4& mm )
{
	Mix::Memory::Copy( m, mm.m, sizeof( m ) );
}

Boolean Matrix4x4::operator == ( const Matrix4x4& mat ) const
{
	for( UInt32 i = 0; i < 4; i++ )
	{
		for( UInt32 j = 0; j < 4; j++ )
		{
			if( MIX_FLOAT_EQUAL( m[i][j], mat.m[i][j] ) == False )
			{
				return False;
			}
		}
	}

	return True;
}

Boolean Matrix4x4::operator != ( const Matrix4x4& mat ) const
{
	for( UInt32 i = 0; i < 4; i++ )
	{
		for( UInt32 j = 0; j < 4; j++ )
		{
			if( MIX_FLOAT_EQUAL( m[i][j], mat.m[i][j] ) == False )
			{
				return True;
			}
		}
	}

	return False;
}

Matrix4x4& Matrix4x4::operator = ( const Matrix4x4& mm )
{
	Mix::Memory::Copy( m, mm.m, sizeof( m ) );
	return *this;
}

Matrix4x4& Matrix4x4::operator *= ( const Matrix4x4& mm )
{
	Matrix4x4 temp( Matrix4x4::Zero() );

#ifdef _MIX_USE_SSE2

	MIX_ALIGN_16 Float32 data[4];

	UInt32 i;

	__m128 t0;
	__m128 t1;
	__m128 c0;
	__m128 c1;
	__m128 c2;
	__m128 c3;

	for( i = 0; i < 4; i++ )
	{
		t0 = _mm_set1_ps( m[i][0] );
		t1 = _mm_set_ps( mm.m[0][2], mm.m[0][1], mm.m[0][0], mm.m[0][3] );
		c0 = _mm_mul_ps( t0, t1 );

		t0 = _mm_set1_ps( m[i][1] );
		t1 = _mm_set_ps( mm.m[1][2], mm.m[1][1], mm.m[1][0], mm.m[1][3] );
		c1 = _mm_mul_ps( t0, t1 );

		t0 = _mm_set1_ps( m[i][2] );
		t1 = _mm_set_ps( mm.m[2][2], mm.m[2][1], mm.m[2][0], mm.m[2][3] );
		c2 = _mm_mul_ps( t0, t1 );

		t0 = _mm_set1_ps( m[i][3] );
		t1 = _mm_set_ps( mm.m[3][2], mm.m[3][1], mm.m[3][0], mm.m[3][3] );
		c3 = _mm_mul_ps( t0, t1 );

		c0 = _mm_add_ps( c0, c1 );
		c0 = _mm_add_ps( c0, c2 );
		c0 = _mm_add_ps( c0, c3 );

		_mm_store_ps( data, c0 );

		temp.m[i][0] = data[1];
		temp.m[i][1] = data[2];
		temp.m[i][2] = data[3];
		temp.m[i][3] = data[0];
	}

#else //_MIX_USE_SSE2

	UInt32 i;

	for( i = 0; i < 4; i++ )
	{
		temp.m[i][0] += m[i][0] * mm.m[0][0] + m[i][1] * mm.m[1][0] + m[i][2] * mm.m[2][0] + m[i][3] * mm.m[3][0];
		temp.m[i][1] += m[i][0] * mm.m[0][1] + m[i][1] * mm.m[1][1] + m[i][2] * mm.m[2][1] + m[i][3] * mm.m[3][1];
		temp.m[i][2] += m[i][0] * mm.m[0][2] + m[i][1] * mm.m[1][2] + m[i][2] * mm.m[2][2] + m[i][3] * mm.m[3][2];
		temp.m[i][3] += m[i][0] * mm.m[0][3] + m[i][1] * mm.m[1][3] + m[i][2] * mm.m[2][3] + m[i][3] * mm.m[3][3];
	}

#endif //_MIX_USE_SSE2

	*this = temp;

	return *this;
}

Matrix4x4 Matrix4x4::operator * ( const Matrix4x4& mm ) const
{
	Matrix4x4 temp = *this;

	temp *= mm;

	return temp;
}

Vector3 Matrix4x4::operator * ( const Vector3& v ) const
{
	Float32 invW = v.x * m03 + v.y * m13 + v.z * m23 + 1.0f * m33;

	if( MIX_FLOAT_IS_ZERO( invW ) == True )
	{
		return Mix::Vector3::Zero();
	}

	invW = 1.0f / invW;

#ifdef _MIX_USE_SSE2

	MIX_ALIGN_16 Float32 data[4];

	__m128 mt;
	__m128 mr;
	__m128 mv;

	mr = _mm_setzero_ps();

	mt = _mm_set_ps( m02, m01, m00, m03 );
	mv = _mm_set_ps( v.x, v.x, v.x, 1.0f );
	mr = _mm_mul_ps( mt, mv );

	mt = _mm_set_ps( m12, m11, m10, m13 );
	mv = _mm_set_ps( v.y, v.y, v.y, 1.0f );
	mt = _mm_mul_ps( mt, mv );
	mr = _mm_add_ps( mr, mt );

	mt = _mm_set_ps( m22, m21, m20, m23 );
	mv = _mm_set_ps( v.z, v.z, v.z, 1.0f );
	mt = _mm_mul_ps( mt, mv );
	mr = _mm_add_ps( mr, mt );

	mt = _mm_set_ps( m32, m31, m30, m33 );
	mr = _mm_add_ps( mr, mt );

	mt = _mm_set1_ps( invW );
	mr = _mm_mul_ps( mr, mt );

	_mm_store_ps( data, mr );

	return Mix::Vector3( data[1], data[2], data[3] );

#else //_MIX_USE_SSE2

	return Mix::Vector3(	( v.x * m00 + v.y * m10 + v.z * m20 + m30 ) * invW,
							( v.x * m01 + v.y * m11 + v.z * m21 + m31 ) * invW,
							( v.x * m02 + v.y * m12 + v.z * m22 + m32 ) * invW );

#endif //_MIX_USE_SSE2
}

Vector4 Matrix4x4::operator * ( const Vector4& v ) const
{
#ifdef _MIX_USE_SSE2

	MIX_ALIGN_16 Float32 data[4];

	__m128 mt;
	__m128 mr;
	__m128 mv;

	mr = _mm_setzero_ps();

	mt = _mm_set_ps( m02, m01, m00, m03 );
	mv = _mm_set1_ps( v.x );
	mr = _mm_mul_ps( mt, mv );

	mt = _mm_set_ps( m12, m11, m10, m13 );
	mv = _mm_set1_ps( v.y );
	mt = _mm_mul_ps( mt, mv );
	mr = _mm_add_ps( mr, mt );

	mt = _mm_set_ps( m22, m21, m20, m23 );
	mv = _mm_set1_ps( v.z );
	mt = _mm_mul_ps( mt, mv );
	mr = _mm_add_ps( mr, mt );

	mt = _mm_set_ps( m32, m31, m30, m33 );
	mv = _mm_set1_ps( v.w );
	mt = _mm_mul_ps( mt, mv );
	mr = _mm_add_ps( mr, mt );

	_mm_store_ps( data, mr );

	return Mix::Vector4( data[1], data[2], data[3], data[0] );

#else //_MIX_USE_SSE2

	return Mix::Vector4(	v.x * m00 + v.y * m10 + v.z * m20 + v.w * m30,
							v.x * m01 + v.y * m11 + v.z * m21 + v.w * m31,
							v.x * m02 + v.y * m12 + v.z * m22 + v.w * m32,
							v.x * m03 + v.y * m13 + v.z * m23 + v.w * m33 );

#endif //_MIX_USE_SSE2
}

Mix::Vector3 Matrix4x4::GetScaling( void ) const
{
	Mix::Vector3 scaling;

	scaling.x = ::sqrtf( ( m00 * m00 ) + ( m01 * m01 ) + ( m02 * m02 ) );
	scaling.y = ::sqrtf( ( m10 * m10 ) + ( m11 * m11 ) + ( m12 * m12 ) );
	scaling.z = ::sqrtf( ( m20 * m20 ) + ( m21 * m21 ) + ( m22 * m22 ) );

	return scaling;
}

void Matrix4x4::SetScaling( Float32 s )
{
	m00 = s;    m01 = 0.0f; m02 = 0.0f; m03 = 0.0f;
	m10 = 0.0f; m11 = s;    m12 = 0.0f; m13 = 0.0f;
	m20 = 0.0f; m21 = 0.0f; m22 = s;    m23 = 0.0f;
	m30 = 0.0f; m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
}

void Matrix4x4::SetScaling( Float32 sx, Float32 sy, Float32 sz )
{
	m00 = sx;   m01 = 0.0f; m02 = 0.0f; m03 = 0.0f;
	m10 = 0.0f; m11 = sy;   m12 = 0.0f; m13 = 0.0f;
	m20 = 0.0f; m21 = 0.0f; m22 = sz;   m23 = 0.0f;
	m30 = 0.0f; m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
}

void Matrix4x4::SetScaling( const Vector3& s )
{
	m00 = s.x;  m01 = 0.0f; m02 = 0.0f; m03 = 0.0f;
	m10 = 0.0f; m11 = s.y;  m12 = 0.0f; m13 = 0.0f;
	m20 = 0.0f; m21 = 0.0f; m22 = s.z;  m23 = 0.0f;
	m30 = 0.0f; m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
}

Float32 Sign( Float32 s )
{
	return ( s >= 0.0f )? +1.0f : -1.0f;
}

Mix::Quaternion Matrix4x4::GetRotation( void ) const
{
	Mix::Quaternion ret;

#if 0

	ret.x = (  m00 + m11 + m22 + 1.0f ) / 4.0f;
	ret.y = (  m00 - m11 - m22 + 1.0f ) / 4.0f;
	ret.z = ( -m00 + m11 - m22 + 1.0f ) / 4.0f;
	ret.w = ( -m00 - m11 + m22 + 1.0f ) / 4.0f;

	if( ret.x < 0.0f ) { ret.x = 0.0f; }
	if( ret.y < 0.0f ) { ret.y = 0.0f; }
	if( ret.z < 0.0f ) { ret.z = 0.0f; }
	if( ret.w < 0.0f ) { ret.w = 0.0f; }

	ret.x = sqrtf( ret.x );
	ret.y = sqrtf( ret.y );
	ret.z = sqrtf( ret.z );
	ret.w = sqrtf( ret.w );

	if( ret.w >= ret.x && ret.w >= ret.y && ret.w >= ret.z )
	{
		ret.x *= +1.0f;
		ret.y *= Mix::SignF( m21 - m12 );
		ret.z *= Mix::SignF( m02 - m20 );
		ret.w *= Mix::SignF( m10 - m01 );
	}
	else if( ret.x >= ret.w && ret.x >= ret.y && ret.x >= ret.z )
	{
		ret.x *= Mix::SignF( m21 - m12 );
		ret.y *= +1.0f;
		ret.z *= Mix::SignF( m10 + m01 );
		ret.w *= Mix::SignF( m02 + m20 );
	}
	else if( ret.y >= ret.w && ret.y >= ret.x && ret.y >= ret.z )
	{
		ret.x *= Mix::SignF( m02 - m20 );
		ret.y *= Mix::SignF( m10 + m01 );
		ret.z *= +1.0f;
		ret.w *= Mix::SignF( m21 + m12 );
	}
	else if( ret.z >= ret.w && ret.z >= ret.x && ret.z >= ret.y )
	{
		ret.x *= Mix::SignF( m10 - m01 );
		ret.y *= Mix::SignF( m20 + m02 );
		ret.z *= Mix::SignF( m21 + m12 );
		ret.w *= +1.0f;
	}
	else
	{
		MIX_ERROR( L"Mix::Quaternion : GetRotation でエラーが発生しました" );
	}

	ret.Normalize();

#else

	UInt32 index = 0;
	Float32 value = m00 - m11 - m22 + 1.0f; //要素の1/4
	Float32 temp;

	//要素の2/4
	temp = -m00 + m11 - m22 + 1.0f;
	if( value < temp ) { index = 1; value = temp; }

	//要素の3/4
	temp = -m00 - m11 + m22 + 1.0f;
	if( value < temp ) { index = 2; value = temp; }

	//要素の3/4
	temp = m00 + m11 + m22 + 1.0f;
	if( value < temp ) { index = 3; value = temp; }

	if( value < 0.0f )
	{
		//無理！
		ret.x = 0.0f;
		ret.y = 0.0f;
		ret.z = 0.0f;
		ret.w = 1.0f;
	}
	else
	{
		Float32 mul;

		value = ::sqrtf( value ) * 0.5f;
		mul = MIX_FLOAT_DIV( 0.25f, value );

		switch( index )
		{
		case 0:
			ret.x = value;
			ret.y = ( m01 + m10 ) * mul;
			ret.z = ( m20 + m02 ) * mul;
			ret.w = ( m12 - m21 ) * mul;
			break;

		case 1:
			ret.x = ( m01 + m10 ) * mul;
			ret.y = value;
			ret.z = ( m12 + m21 ) * mul;
			ret.w = ( m20 - m02 ) * mul;
			break;

		case 2:
			ret.x = ( m20 + m02 ) * mul;
			ret.y = ( m12 + m21 ) * mul;
			ret.z = value;
			ret.w = ( m01 - m10 ) * mul;
			break;

		case 3:
			ret.x = ( m12 - m21 ) * mul;
			ret.y = ( m20 - m02 ) * mul;
			ret.z = ( m01 - m10 ) * mul;
			ret.w = value;
			break;
		}
	}

#endif

	return ret;
}

void Matrix4x4::SetRotation( const Mix::Quaternion& rot )
{
	Float32 x = rot.x;
	Float32 y = rot.y;
	Float32 z = rot.z;
	Float32 w = rot.w;

	Float32 xx = 2.0f * x * x;
	Float32 xy = 2.0f * x * y;
	Float32 xz = 2.0f * x * z;
	Float32 yy = 2.0f * y * y;
	Float32 yz = 2.0f * y * z;
	Float32 zz = 2.0f * z * z;
	Float32 wx = 2.0f * w * x;
	Float32 wy = 2.0f * w * y;
	Float32 wz = 2.0f * w * z;
	Float32 ww = 2.0f * w * w;

	m00 = 1.0f - yy - zz;
    m01 = xy + wz;
    m02 = xz - wy;
	m03 = 0.0f;

    m10 = xy - wz;
    m11 = 1.0f - xx - zz;
    m12 = yz + wx;
	m13 = 0.0f;

    m20 = xz + wy;
    m21 = yz - wx;
    m22 = 1.0f - xx - yy;
	m23 = 0.0f;

	m30 = 0.0f;
	m31 = 0.0f;
	m32 = 0.0f;
	m33 = 1.0f;
}

void Matrix4x4::SetRotationX( Float32 r )
{
	Float32 c = cosf( r );
	Float32 s = sinf( r );

	m00 = 1.0f; m01 = 0.0f; m02 = 0.0f; m03 = 0.0f;
	m10 = 0.0f; m11 = c;    m12 = s;    m13 = 0.0f;
	m20 = 0.0f; m21 = -s;   m22 = c;    m23 = 0.0f;
	m30 = 0.0f; m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
}

void Matrix4x4::SetRotationY( Float32 r )
{
	Float32 c = cosf( r );
	Float32 s = sinf( r );

	m00 = c;    m01 = 0.0f; m02 = -s;   m03 = 0.0f;
	m10 = 0.0f; m11 = 1.0f; m12 = 0.0f; m13 = 0.0f;
	m20 = s;    m21 = 0.0f; m22 = c;    m23 = 0.0f;
	m30 = 0.0f; m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
}

void Matrix4x4::SetRotationZ( Float32 r )
{
	Float32 c = cosf( r );
	Float32 s = sinf( r );

	m00 = c;    m01 = s;    m02 = 0.0f; m03 = 0.0f;
	m10 = -s;   m11 = c;    m12 = 0.0f; m13 = 0.0f;
	m20 = 0.0f; m21 = 0.0f; m22 = 1.0f; m23 = 0.0f;
	m30 = 0.0f; m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
}

Mix::Vector3 Matrix4x4::GetTranslation( void ) const
{
	return Mix::Vector3( m30, m31, m32 );
}

void Matrix4x4::SetTranslation( Float32 tx, Float32 ty, Float32 tz )
{
	m00 = 1.0f; m01 = 0.0f; m02 = 0.0f; m03 = 0.0f;
	m10 = 0.0f; m11 = 1.0f; m12 = 0.0f; m13 = 0.0f;
	m20 = 0.0f; m21 = 0.0f; m22 = 1.0f; m23 = 0.0f;
	m30 = tx;   m31 = ty;   m32 = tz;   m33 = 1.0f;
}

void Matrix4x4::SetTranslation( const Vector3& t )
{
	m00 = 1.0f; m01 = 0.0f; m02 = 0.0f; m03 = 0.0f;
	m10 = 0.0f; m11 = 1.0f; m12 = 0.0f; m13 = 0.0f;
	m20 = 0.0f; m21 = 0.0f; m22 = 1.0f; m23 = 0.0f;
	m30 = t.x;  m31 = t.y;  m32 = t.z;  m33 = 1.0f;
}

Mix::Vector4 Matrix4x4::GetColumn( UInt32 index ) const
{
	MIX_ASSERT( index <= 3 );

	return Mix::Vector4( m[0][index], m[1][index], m[2][index], m[3][index] );
}

void Matrix4x4::SetColumn( UInt32 index, const Mix::Vector4& v )
{
	MIX_ASSERT( index <= 3 );

	m[0][index] = v.x;
	m[1][index] = v.y;
	m[2][index] = v.z;
	m[3][index] = v.w;
}

Mix::Vector4 Matrix4x4::GetRow( UInt32 index ) const
{
	MIX_ASSERT( index <= 3 );

	return Mix::Vector4( m[index][0], m[index][1], m[index][2], m[index][3] );
}

void Matrix4x4::SetRow( UInt32 index, const Mix::Vector4& v )
{
	MIX_ASSERT( index <= 3 );

	m[index][0] = v.x;
	m[index][1] = v.y;
	m[index][2] = v.z;
	m[index][3] = v.w;
}

void Matrix4x4::Inverse( void )
{
	Float32 a11 = m00;
	Float32 a12 = m01;
	Float32 a13 = m02;
	Float32 a14 = m03;
	Float32 a21 = m10;
	Float32 a22 = m11;
	Float32 a23 = m12;
	Float32 a24 = m13;
	Float32 a31 = m20;
	Float32 a32 = m21;
	Float32 a33 = m22;
	Float32 a34 = m23;
	Float32 a41 = m30;
	Float32 a42 = m31;
	Float32 a43 = m32;
	Float32 a44 = m33;

	Float32 b11 = + a22 * (a33 * a44 - a43 * a34) - a23 * (a32 * a44 - a42 * a34) + a24 * (a32 * a43 - a42 * a33);
	Float32 b12 = - a12 * (a33 * a44 - a43 * a34) + a13 * (a32 * a44 - a42 * a34) - a14 * (a32 * a43 - a42 * a33);
	Float32 b13 = + a12 * (a23 * a44 - a43 * a24) - a13 * (a22 * a44 - a42 * a24) + a14 * (a22 * a43 - a42 * a23);
	Float32 b14 = - a12 * (a23 * a34 - a33 * a24) + a13 * (a22 * a34 - a32 * a24) - a14 * (a22 * a33 - a32 * a23);

	Float32 b21 = - a21 * (a33 * a44 - a43 * a34) + a23 * (a31 * a44 - a41 * a34) - a24 * (a31 * a43 - a41 * a33);
	Float32 b22 = + a11 * (a33 * a44 - a43 * a34) - a13 * (a31 * a44 - a41 * a34) + a14 * (a31 * a43 - a41 * a33);
	Float32 b23 = - a11 * (a23 * a44 - a43 * a24) + a13 * (a21 * a44 - a41 * a24) - a14 * (a21 * a43 - a41 * a23);
	Float32 b24 = + a11 * (a23 * a34 - a33 * a24) - a13 * (a21 * a34 - a31 * a24) + a14 * (a21 * a33 - a31 * a23);

	Float32 b31 = + a21 * (a32 * a44 - a42 * a34) - a22 * (a31 * a44 - a41 * a34) + a24 * (a31 * a42 - a41 * a32);
	Float32 b32 = - a11 * (a32 * a44 - a42 * a34) + a12 * (a31 * a44 - a41 * a34) - a14 * (a31 * a42 - a41 * a32);
	Float32 b33 = + a11 * (a22 * a44 - a42 * a24) - a12 * (a21 * a44 - a41 * a24) + a14 * (a21 * a42 - a41 * a22);
	Float32 b34 = - a11 * (a22 * a34 - a32 * a24) + a12 * (a21 * a34 - a31 * a24) - a14 * (a21 * a32 - a31 * a22);

	Float32 b41 = - a21 * (a32 * a43 - a42 * a33) + a22 * (a31 * a43 - a41 * a33) - a23 * (a31 * a42 - a41 * a32);
	Float32 b42 = + a11 * (a32 * a43 - a42 * a33) - a12 * (a31 * a43 - a41 * a33) + a13 * (a31 * a42 - a41 * a32);
	Float32 b43 = - a11 * (a22 * a43 - a42 * a23) + a12 * (a21 * a43 - a41 * a23) - a13 * (a21 * a42 - a41 * a22);
	Float32 b44 = + a11 * (a22 * a33 - a32 * a23) - a12 * (a21 * a33 - a31 * a23) + a13 * (a21 * a32 - a31 * a22);

	Float32 det = ( a11 * b11 ) + ( a12 * b21 ) + ( a13 * b31 ) + ( a14 * b41 );
	if ( MIX_FLOAT_IS_ZERO( det ) == True )
	{
		return;
	}

	Float32 detInv = ( 1.0f / det );

	m00 = ( b11 * detInv );
	m01 = ( b12 * detInv );
	m02 = ( b13 * detInv );
	m03 = ( b14 * detInv );

	m10 = ( b21 * detInv );
	m11 = ( b22 * detInv );
	m12 = ( b23 * detInv );
	m13 = ( b24 * detInv );

	m20 = ( b31 * detInv );
	m21 = ( b32 * detInv );
	m22 = ( b33 * detInv );
	m23 = ( b34 * detInv );

	m30 = ( b41 * detInv );
	m31 = ( b42 * detInv );
	m32 = ( b43 * detInv );
	m33 = ( b44 * detInv );
}

Mix::Matrix4x4 Matrix4x4::ToInverse( void ) const
{
	Matrix4x4 temp = *this;
	temp.Inverse();
	return temp;
}

void Matrix4x4::Transpose( void )
{
	UInt32 i;
	UInt32 j;
	Mix::Matrix4x4 temp;

	temp = *this;

	for( i = 0; i < 4; i++ )
	{
		for( j= 0; j < 4; j++ )
		{
			m[i][j] = temp.m[j][i];
		}
	}
}

Mix::Matrix4x4 Matrix4x4::ToTranspose( void ) const
{
	return Mix::Matrix4x4(	m00, m10, m20, m30,
							m01, m11, m21, m31,
							m02, m12, m22, m32,
							m03, m13, m23, m33 );
}

Mix::Vector3 Matrix4x4::ToEulerXYZ( void ) const
{
	Mix::Vector3 rot;
	float cosY;

	rot.y = asin( MIX_CLAMP( -m02, -1.0f, +1.0f ) );
	cosY = cosf( rot.y );

	if( MIX_FLOAT_IS_ZERO( cosY ) == false )
	{
		rot.z = atan2( m01, m00 );

		rot.x = asin( MIX_CLAMP( m12 / cosY, -1.0f, +1.0f ) );
		if( m22 < MIX_FLOAT_EPSILON )
		{
			rot.x = MIX_PI - rot.x;
		}
	}
	else
	{
		rot.z = atan2( -m10, m11 );

		rot.x = 0.0f;
	}

	return rot;
}

Mix::Vector3 Matrix4x4::ToEulerXZY( void ) const
{
	Mix::Vector3 rot;
	float cosZ;

	rot.z = asin( MIX_CLAMP( m01, -1.0f, +1.0f ) );
	cosZ = cosf( rot.z );

	if( MIX_FLOAT_IS_ZERO( cosZ ) == false )
	{
		rot.y = atan2( -m02, m00 );

		rot.x = asin( MIX_CLAMP( -m21 / cosZ, -1.0f, +1.0f ) );
		if( m11 < MIX_FLOAT_EPSILON )
		{
			rot.x = MIX_PI - rot.x;
		}
	}
	else
	{
		rot.y = atan2( m20, m22 );

		rot.x = 0.0f;
	}

	return rot;
}

Mix::Vector3 Matrix4x4::ToEulerYXZ( void ) const
{
	Mix::Vector3 rot;
	float cosX;

	rot.x = asin( MIX_CLAMP( m12, -1.0f, +1.0f ) );
	cosX = cosf( rot.x );

	if( MIX_FLOAT_IS_ZERO( cosX ) == false )
	{
		rot.z = atan2( -m10, m11 );

		rot.y = asin( MIX_CLAMP( -m02 / cosX, -1.0f, +1.0f ) );
		if( m22 < MIX_FLOAT_EPSILON )
		{
			rot.y = MIX_PI - rot.y;
		}
	}
	else
	{
		rot.z = atan2( m01, m00 );

		rot.y = 0.0f;
	}

	return rot;
}

Mix::Vector3 Matrix4x4::ToEulerYZX( void ) const
{
	Mix::Vector3 rot;
	float cosZ;

	rot.z = asin( MIX_CLAMP( -m10, -1.0f, +1.0f ) );
	cosZ = cosf( rot.z );

	if( MIX_FLOAT_IS_ZERO( cosZ ) == false )
	{
		rot.x = atan2( m12, m11 );

		rot.y = asin( MIX_CLAMP( m20 / cosZ, -1.0f, +1.0f ) );
		if( m00 < MIX_FLOAT_EPSILON )
		{
			rot.y = MIX_PI - rot.y;
		}
	}
	else
	{
		rot.x = atan2( -m21, m22 );

		rot.y = 0.0f;
	}

	return rot;
}

Mix::Vector3 Matrix4x4::ToEulerZXY( void ) const
{
	Mix::Vector3 rot;
	float cosX;

	rot.x = asin( MIX_CLAMP( -m21, -1.0f, +1.0f ) );
	cosX = cosf( rot.x );

	if( MIX_FLOAT_IS_ZERO( cosX ) == false )
	{
		rot.y = atan2( m20, m22 );

		rot.z = asin( MIX_CLAMP( m01 / cosX, -1.0f, +1.0f ) );
		if( m11 < MIX_FLOAT_EPSILON )
		{
			rot.z = MIX_PI - rot.z;
		}
	}
	else
	{
		rot.y = atan2( -m02, m00 );

		rot.z = 0.0f;
	}

	return rot;
}

Mix::Vector3 Matrix4x4::ToEulerZYX( void ) const
{
	Mix::Vector3 rot;
	float cosY;

	rot.y = asin( MIX_CLAMP( m20, -1.0f, +1.0f ) );
	cosY = cosf( rot.y );

	if( MIX_FLOAT_IS_ZERO( cosY ) == false )
	{
		rot.x = atan2( -m21, m22 );

		rot.z = asin( MIX_CLAMP( -m10 / cosY, -1.0f, +1.0f ) );
		if( m00 < MIX_FLOAT_EPSILON )
		{
			rot.z = MIX_PI - rot.z;
		}
	}
	else
	{
		rot.x = atan2( m12, m11 );

		rot.z = 0.0f;
	}

	return rot;
}

void Matrix4x4::Transform( Mix::Vector3* vectors, UInt32 numVector ) const
{
	Mix::Vector3* pVec = &( vectors[0] );
	Mix::Vector3* pVecEnd = pVec + numVector;

	Float32 invW;

	Float32 sx;
	Float32 sy;
	Float32 sz;

#ifdef _MIX_USE_SSE2

	MIX_ALIGN_16 Float32 data[4];

	__m128 mt;
	__m128 mr;
	__m128 mv;

	while( pVec != pVecEnd )
	{
		invW = pVec->x * m03 + pVec->y * m13 + pVec->z * m23 + 1.0f * m33;

		if( MIX_FLOAT_IS_ZERO( invW ) == False )
		{
			invW = 1.0f / invW;

			sx = pVec->x;
			sy = pVec->y;
			sz = pVec->z;

			mr = _mm_setzero_ps();

			mt = _mm_set_ps( m02, m01, m00, m03 );
			mv = _mm_set_ps( sx, sx, sx, 1.0f );
			mr = _mm_mul_ps( mt, mv );

			mt = _mm_set_ps( m12, m11, m10, m13 );
			mv = _mm_set_ps( sy, sy, sy, 1.0f );
			mt = _mm_mul_ps( mt, mv );
			mr = _mm_add_ps( mr, mt );

			mt = _mm_set_ps( m22, m21, m20, m23 );
			mv = _mm_set_ps( sz, sz, sz, 1.0f );
			mt = _mm_mul_ps( mt, mv );
			mr = _mm_add_ps( mr, mt );

			mt = _mm_set_ps( m32, m31, m30, m33 );
			mr = _mm_add_ps( mr, mt );

			mt = _mm_set1_ps( invW );
			mr = _mm_mul_ps( mr, mt );

			_mm_store_ps( data, mr );

			pVec->x = data[1];
			pVec->y = data[2];
			pVec->z = data[3];
		}
		else
		{
			pVec->x = 0.0f;
			pVec->y = 0.0f;
			pVec->z = 0.0f;
		}

		pVec++;
	}

#else //_MIX_USE_SSE2

	while( pVec != pVecEnd )
	{
		invW = pVec->x * m03 + pVec->y * m13 + pVec->z * m23 + 1.0f * m33;

		if( MIX_FLOAT_IS_ZERO( invW ) == False )
		{
			invW = 1.0f / invW;

			sx = pVec->x;
			sy = pVec->y;
			sz = pVec->z;

			pDst->x = ( sx * m00 + sy * m10 + sz * m20 + m30 ) * invW;
			pDst->y = ( sx * m01 + sy * m11 + sz * m21 + m31 ) * invW;
			pDst->z = ( sx * m02 + sy * m12 + sz * m22 + m32 ) * invW;
		}
		else
		{
			pDst->x = 0.0f;
			pDst->y = 0.0f;
			pDst->z = 0.0f;
		}

		pVec++;
	}

#endif //_MIX_USE_SSE2
}

void Matrix4x4::Transform( Mix::Vector4* vectors, UInt32 numVector ) const
{
	Mix::Vector4* pVec = &( vectors[0] );
	Mix::Vector4* pVecEnd = pVec + numVector;

#ifdef _MIX_USE_SSE2

	MIX_ALIGN_16 Float32 data[4];

	__m128 mt;
	__m128 mr;
	__m128 mv;

	while( pVec != pVecEnd )
	{
		mr = _mm_setzero_ps();

		mt = _mm_set_ps( m02, m01, m00, m03 );
		mv = _mm_set_ps1( pVec->x );
		mr = _mm_mul_ps( mt, mv );

		mt = _mm_set_ps( m12, m11, m10, m13 );
		mv = _mm_set_ps1( pVec->y );
		mt = _mm_mul_ps( mt, mv );
		mr = _mm_add_ps( mr, mt );

		mt = _mm_set_ps( m22, m21, m20, m23 );
		mv = _mm_set_ps1( pVec->z );
		mt = _mm_mul_ps( mt, mv );
		mr = _mm_add_ps( mr, mt );

		mt = _mm_set_ps( m32, m31, m30, m33 );
		mv = _mm_set_ps1( pVec->w );
		mt = _mm_mul_ps( mt, mv );
		mr = _mm_add_ps( mr, mt );

		_mm_store_ps( data, mr );

		pVec->x = data[1];
		pVec->y = data[2];
		pVec->z = data[3];
		pVec->w = data[0];

		pVec++;
	}

#else //_MIX_USE_SSE2

	Float32 sx;
	Float32 sy;
	Float32 sz;
	Float32 sw;

	while( pVec != pVecEnd )
	{
		sx = pVec->x;
		sy = pVec->y;
		sz = pVec->z;
		sw = pVec->w;

		pVec->x = sx * m00 + sy * m10 + sz * m20 + sw * m30;
		pVec->y = sx * m01 + sy * m11 + sz * m21 + sw * m31;
		pVec->z = sx * m02 + sy * m12 + sz * m22 + sw * m32;
		pVec->w = sx * m03 + sy * m13 + sz * m23 + sw * m33;

		pVec++;
	}

#endif //_MIX_USE_SSE2
}

void Matrix4x4::Transform( const Mix::Vector3* srcVectors, Mix::Vector3* dstVectors, UInt32 numVector ) const
{
	const Mix::Vector3* pSrc = &( srcVectors[0] );
	const Mix::Vector3* pSrcEnd = pSrc + numVector;

	Mix::Vector3* pDst = &( dstVectors[0] );

	Float32 invW;

	Float32 sx;
	Float32 sy;
	Float32 sz;

#ifdef _MIX_USE_SSE2

	MIX_ALIGN_16 Float32 data[4];

	__m128 mt;
	__m128 mr;
	__m128 mv;

	while( pSrc != pSrcEnd )
	{
		invW = pSrc->x * m03 + pSrc->y * m13 + pSrc->z * m23 + 1.0f * m33;

		if( MIX_FLOAT_IS_ZERO( invW ) == False )
		{
			invW = 1.0f / invW;

			sx = pSrc->x;
			sy = pSrc->y;
			sz = pSrc->z;

			mr = _mm_setzero_ps();

			mt = _mm_set_ps( m02, m01, m00, m03 );
			mv = _mm_set_ps( sx, sx, sx, 1.0f );
			mr = _mm_mul_ps( mt, mv );

			mt = _mm_set_ps( m12, m11, m10, m13 );
			mv = _mm_set_ps( sy, sy, sy, 1.0f );
			mt = _mm_mul_ps( mt, mv );
			mr = _mm_add_ps( mr, mt );

			mt = _mm_set_ps( m22, m21, m20, m23 );
			mv = _mm_set_ps( sz, sz, sz, 1.0f );
			mt = _mm_mul_ps( mt, mv );
			mr = _mm_add_ps( mr, mt );

			mt = _mm_set_ps( m32, m31, m30, m33 );
			mr = _mm_add_ps( mr, mt );

			mt = _mm_set1_ps( invW );
			mr = _mm_mul_ps( mr, mt );

			_mm_store_ps( data, mr );

			pDst->x = data[1];
			pDst->y = data[2];
			pDst->z = data[3];
		}
		else
		{
			pDst->x = 0.0f;
			pDst->y = 0.0f;
			pDst->z = 0.0f;
		}

		pSrc++;
		pDst++;
	}

#else //_MIX_USE_SSE2

	while( pSrc != pSrcEnd )
	{
		invW = pSrc->x * m03 + pSrc->y * m13 + pSrc->z * m23 + 1.0f * m33;

		if( MIX_FLOAT_IS_ZERO( invW ) == False )
		{
			invW = 1.0f / invW;

			sx = pSrc->x;
			sy = pSrc->y;
			sz = pSrc->z;

			pDst->x = ( sx * m00 + sy * m10 + sz * m20 + m30 ) * invW;
			pDst->y = ( sx * m01 + sy * m11 + sz * m21 + m31 ) * invW;
			pDst->z = ( sx * m02 + sy * m12 + sz * m22 + m32 ) * invW;
		}
		else
		{
			pDst->x = 0.0f;
			pDst->y = 0.0f;
			pDst->z = 0.0f;
		}

		pSrc++;
		pDst++;
	}

#endif //_MIX_USE_SSE2
}

void Matrix4x4::Transform( const Mix::Vector4* srcVectors, Mix::Vector4* dstVectors, UInt32 numVector ) const
{
	const Mix::Vector4* pSrc = &( srcVectors[0] );
	const Mix::Vector4* pSrcEnd = pSrc + numVector;

	Mix::Vector4* pDst = &( dstVectors[0] );

#ifdef _MIX_USE_SSE2

	MIX_ALIGN_16 Float32 data[4];

	__m128 mt;
	__m128 mr;
	__m128 mv;

	while( pSrc != pSrcEnd )
	{
		mr = _mm_setzero_ps();

		mt = _mm_set_ps( m02, m01, m00, m03 );
		mv = _mm_set_ps1( pSrc->x );
		mr = _mm_mul_ps( mt, mv );

		mt = _mm_set_ps( m12, m11, m10, m13 );
		mv = _mm_set_ps1( pSrc->y );
		mt = _mm_mul_ps( mt, mv );
		mr = _mm_add_ps( mr, mt );

		mt = _mm_set_ps( m22, m21, m20, m23 );
		mv = _mm_set_ps1( pSrc->z );
		mt = _mm_mul_ps( mt, mv );
		mr = _mm_add_ps( mr, mt );

		mt = _mm_set_ps( m32, m31, m30, m33 );
		mv = _mm_set_ps1( pSrc->w );
		mt = _mm_mul_ps( mt, mv );
		mr = _mm_add_ps( mr, mt );

		_mm_store_ps( data, mr );

		pDst->x = data[1];
		pDst->y = data[2];
		pDst->z = data[3];
		pDst->w = data[0];

		pSrc++;
		pDst++;
	}

#else //_MIX_USE_SSE2

	while( pSrc != pSrcEnd )
	{
		sx = pSrc->x;
		sy = pSrc->y;
		sz = pSrc->z;
		sw = pSrc->w;

		pDst->x = sx * m00 + sy * m10 + sz * m20 + sw * m30;
		pDst->y = sx * m01 + sy * m11 + sz * m21 + sw * m31;
		pDst->z = sx * m02 + sy * m12 + sz * m22 + sw * m32;
		pDst->w = sx * m03 + sy * m13 + sz * m23 + sw * m33;

		pSrc++;
		pDst++;
	}

#endif //_MIX_USE_SSE2
}

Mix::Vector3 Matrix4x4::TransformSR( const Mix::Vector3& v ) const
{
	return Mix::Vector3(	( v.x * m00 + v.y * m10 + v.z * m20 ),
							( v.x * m01 + v.y * m11 + v.z * m21 ),
							( v.x * m02 + v.y * m12 + v.z * m22 ) );
}

void Matrix4x4::TransformSR( Mix::Vector3* vectors, UInt32 numVector ) const
{
	MIX_ASSERT( numVector > 0 );

	Mix::Vector3* pVec = &( vectors[0] );
	Mix::Vector3* pVecEnd = pVec + numVector;

	Float32 sx;
	Float32 sy;
	Float32 sz;

	while( pVec != pVecEnd )
	{
		sx = pVec->x;
		sy = pVec->y;
		sz = pVec->z;

		pVec->x = sx * m00 + sy * m10 + sz * m20;
		pVec->y = sx * m01 + sy * m11 + sz * m21;
		pVec->z = sx * m02 + sy * m12 + sz * m22;

		pVec++;
	}
}

void Matrix4x4::TransformSR( const Mix::Vector3* srcVectors, Mix::Vector3* dstVectors, UInt32 numVector ) const
{
	MIX_ASSERT( numVector > 0 );

	const Mix::Vector3* pSrc = &( srcVectors[0] );
	const Mix::Vector3* pSrcEnd = pSrc + numVector;

	Mix::Vector3* pDst = &( dstVectors[0] );

	Float32 sx;
	Float32 sy;
	Float32 sz;

	while( pSrc != pSrcEnd )
	{
		sx = pSrc->x;
		sy = pSrc->y;
		sz = pSrc->z;

		pDst->x = sx * m00 + sy * m10 + sz * m20;
		pDst->y = sx * m01 + sy * m11 + sz * m21;
		pDst->z = sx * m02 + sy * m12 + sz * m22;

		pDst++;
		pSrc++;
	}
}

Mix::Vector4 Matrix4x4::TransformSR( const Mix::Vector4& v ) const
{
	Float32 invW = v.x * m03 + v.y * m13 + v.z * m23;

	if( MIX_FLOAT_IS_ZERO( invW ) == True )
	{
		return Mix::Vector4::Zero();
	}

	invW = ( 1.0f / invW );

	return Mix::Vector4(	( v.x * m00 + v.y * m10 + v.z * m20 ) * invW,
							( v.x * m01 + v.y * m11 + v.z * m21 ) * invW,
							( v.x * m02 + v.y * m12 + v.z * m22 ) * invW,
							( v.x * m03 + v.y * m13 + v.z * m23 ) * invW );
}

void Matrix4x4::TransformSR( Mix::Vector4* vectors, UInt32 numVector ) const
{
	MIX_ASSERT( numVector > 0 );

	Mix::Vector4* pVec = &( vectors[0] );
	Mix::Vector4* pVecEnd = pVec + numVector;

	Float32 sx;
	Float32 sy;
	Float32 sz;

	Float32 invW;

	while( pVec != pVecEnd )
	{
		sx = pVec->x;
		sy = pVec->y;
		sz = pVec->z;

		invW = sx * m03 + sy * m13 + sz * m23;

		if( MIX_FLOAT_IS_ZERO( invW ) == False )
		{
			pVec->x = ( sx * m00 + sy * m10 + sz * m20 ) * invW;
			pVec->y = ( sx * m01 + sy * m11 + sz * m21 ) * invW;
			pVec->z = ( sx * m02 + sy * m12 + sz * m22 ) * invW;
			pVec->w = ( sx * m03 + sy * m13 + sz * m23 ) * invW;
		}
		else
		{
			pVec->x = 0.0f;
			pVec->y = 0.0f;
			pVec->z = 0.0f;
			pVec->w = 1.0f;
		}

		pVec++;
	}
}

void Matrix4x4::TransformSR( const Mix::Vector4* srcVectors, Mix::Vector4* dstVectors, UInt32 numVector ) const
{
	MIX_ASSERT( numVector > 0 );

	const Mix::Vector4* pSrc = &( srcVectors[0] );
	const Mix::Vector4* pSrcEnd = pSrc + numVector;

	Mix::Vector4* pDst = &( dstVectors[0] );

	Float32 sx;
	Float32 sy;
	Float32 sz;

	Float32 invW;

	while( pSrc != pSrcEnd )
	{
		sx = pSrc->x;
		sy = pSrc->y;
		sz = pSrc->z;

		invW = sx * m03 + sy * m13 + sz * m23;

		if( MIX_FLOAT_IS_ZERO( invW ) == False )
		{
			pDst->x = ( sx * m00 + sy * m10 + sz * m20 ) * invW;
			pDst->y = ( sx * m01 + sy * m11 + sz * m21 ) * invW;
			pDst->z = ( sx * m02 + sy * m12 + sz * m22 ) * invW;
			pDst->w = ( sx * m03 + sy * m13 + sz * m23 ) * invW;
		}
		else
		{
			pDst->x = 0.0f;
			pDst->y = 0.0f;
			pDst->z = 0.0f;
			pDst->w = 1.0f;
		}

		pDst++;
		pSrc++;
	}
}

void Matrix4x4::Compose( const Mix::Vector3& s, const Mix::Quaternion& r, const Mix::Vector3& t )
{
	SetScaling( s );

	*this *= Mix::Matrix4x4( r );

	m30 = t.x;
	m31 = t.y;
	m32 = t.z;
	m33 = 1.0f;
}

Boolean Matrix4x4::Decompose( Mix::Vector3& scaling, Mix::Quaternion& rotation, Mix::Vector3& translation ) const
{
	Boolean ret = True;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// スケーリング
	////////////////////////////////////////////////////////////////////////////////////////////////////

	scaling.x = ::sqrtf( ( m00 * m00 ) + ( m01 * m01 ) + ( m02 * m02 ) );
	scaling.y = ::sqrtf( ( m10 * m10 ) + ( m11 * m11 ) + ( m12 * m12 ) );
	scaling.z = ::sqrtf( ( m20 * m20 ) + ( m21 * m21 ) + ( m22 * m22 ) );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ローテーション
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( ( MIX_FLOAT_IS_ZERO( scaling.x ) == True ) ||
		( MIX_FLOAT_IS_ZERO( scaling.y ) == True ) ||
		( MIX_FLOAT_IS_ZERO( scaling.z ) == True ) )
	{
		rotation = Mix::Quaternion::Identity();
		ret = False;
	}
	else
	{
		Float32 sx = 1.0f / scaling.x;
		Float32 sy = 1.0f / scaling.y;
		Float32 sz = 1.0f / scaling.z;

		Mix::Matrix4x4 normRot(	m00 * sx, m01 * sx, m02 * sx, 0.0f,
								m10 * sy, m11 * sy, m12 * sy, 0.0f,
								m20 * sz, m21 * sz, m22 * sz, 0.0f,
								0.0f,     0.0f,     0.0f,     1.0f );

		rotation = normRot.GetRotation();
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// トランスレーション
	////////////////////////////////////////////////////////////////////////////////////////////////////

	translation.x = m30;
	translation.y = m31;
	translation.z = m32;

	////////////////////////////////////////////////////////////////////////////////////////////////////

	return ret;
}


Mix::Matrix4x4 Matrix4x4::Remake( Boolean bScaling, Boolean bRotation, Boolean bTranslation ) const
{
	Float32 sx = 1.0f;
	Float32 sy = 1.0f;
	Float32 sz = 1.0f;

	Mix::Matrix4x4 mat;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// スケーリング
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( ( bScaling == True ) ||
		( bRotation == True ) )
	{
		sx = ::sqrtf( ( m00 * m00 ) + ( m01 * m01 ) + ( m02 * m02 ) );
		sy = ::sqrtf( ( m10 * m10 ) + ( m11 * m11 ) + ( m12 * m12 ) );
		sz = ::sqrtf( ( m20 * m20 ) + ( m21 * m21 ) + ( m22 * m22 ) );
	}

	if( bScaling == True )
	{
		mat.m00 = sx;
		mat.m11 = sy;
		mat.m22 = sz;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ローテーション
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( bRotation == True )
	{
		sx = 1.0f / sx;
		sy = 1.0f / sy;
		sz = 1.0f / sz;

		if( bScaling == False )
		{
			mat.m00 = m00 * sx; mat.m01 = m01 * sx; mat.m02 = m02 * sx; mat.m03 = 0.0f;
			mat.m10 = m10 * sy; mat.m11 = m11 * sy; mat.m12 = m12 * sy; mat.m13 = 0.0f;
			mat.m20 = m20 * sz; mat.m21 = m21 * sz; mat.m22 = m22 * sz; mat.m23 = 0.0f;
		}
		else
		{
			mat *= Mix::Matrix4x4(	m00 * sx, m01 * sx, m02 * sx, 0.0f,
									m10 * sy, m11 * sy, m12 * sy, 0.0f,
									m20 * sz, m21 * sz, m22 * sz, 0.0f,
									0.0f,     0.0f,     0.0f,     1.0f );
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// トランスレーション
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( bTranslation == True )
	{
		mat.m30 = m30; mat.m31 = m31; mat.m32 = m32; mat.m33 = 1.0f;
	}

	return mat;
}

void Matrix4x4::LookAtLH( const Mix::Vector3& eye, const Mix::Vector3& at, const Mix::Vector3& up, Mix::Matrix4x4& mat )
{
	Mix::Vector3 xAxis;
	Mix::Vector3 yAxis;
	Mix::Vector3 zAxis;
	
	zAxis = at - eye;
	zAxis.Normalize();

	xAxis = Mix::Vector3::Cross( up, zAxis );
	xAxis.Normalize();

	yAxis = Mix::Vector3::Cross( zAxis, xAxis );
	yAxis.Normalize();

	mat.m00 = xAxis.x; 
	mat.m01 = yAxis.x;
	mat.m02 = zAxis.x;
	mat.m03 = 0.0f;

	mat.m10 = xAxis.y;
	mat.m11 = yAxis.y;
	mat.m12 = zAxis.y;
	mat.m13 = 0.0f;

	mat.m20 = xAxis.z;
	mat.m21 = yAxis.z;
	mat.m22 = zAxis.z;
	mat.m23 = 0.0f;

	mat.m30 = -Mix::Vector3::Dot( xAxis, eye );
	mat.m31 = -Mix::Vector3::Dot( yAxis, eye );
	mat.m32 = -Mix::Vector3::Dot( zAxis, eye );
	mat.m33 = 1.0f;
}

void Matrix4x4::LookAtLH( const Mix::Quaternion& rot, const Mix::Vector3& at, Float32 dist, Mix::Matrix4x4& mat )
{
	Mix::Matrix4x4 rotMat( rot );
	Mix::Vector3 localEye = rotMat * Mix::Vector3( 0.0f, 0.0f, dist );
	Mix::Vector3 eye = at + localEye;

	Mix::Vector3 xAxis;
	Mix::Vector3 yAxis;
	Mix::Vector3 zAxis;

	//Z軸
	zAxis = -localEye;
	zAxis.Normalize();

	//X軸
	xAxis = Mix::Vector3::Cross( Mix::Vector3( rotMat.m10, rotMat.m11, rotMat.m12 ), zAxis );
	xAxis.Normalize();

	//Y軸
	yAxis = Mix::Vector3::Cross( zAxis, xAxis );
	yAxis.Normalize();

	mat.m00 = xAxis.x;
	mat.m01 = xAxis.y;
	mat.m02 = xAxis.z;
	mat.m03 = 0.0f;

	mat.m10 = yAxis.x;
	mat.m11 = yAxis.y;
	mat.m12 = yAxis.z;
	mat.m13 = 0.0f;

	mat.m20 = zAxis.x;
	mat.m21 = zAxis.y;
	mat.m22 = zAxis.z;
	mat.m23 = 0.0f;

	mat.m30 = eye.x;
	mat.m31 = eye.y;
	mat.m32 = eye.z;
	mat.m33 = 1.0f;

	mat.Inverse();
}

void Matrix4x4::PerspectiveFovLH( Float32 fovY, Float32 aspect, Float32 nearZ, Float32 farZ, Mix::Matrix4x4& mat )
{
	//h = 1 / tan( fovY / 2 )
	//w = h * aspect
	//
	//w       0       0               0
	//0       h       0               0
	//0       0       zf/(zf-zn)      1
	//0       0       -zn*zf/(zf-zn)  1

	Float32 t;
	Float32 w;
	Float32 h;
	Float32 invLenZ;

	t = ::tanf( fovY * 0.5f );
	h = ( MIX_FLOAT_IS_ZERO( t ) == False )? ( 1.0f / t ) : 0.0f;
	w = ( h / aspect );
	invLenZ = ( MIX_FLOAT_IS_ZERO( farZ - nearZ ) == False )? ( 1.0f / ( farZ - nearZ ) ) : 0.0f;

	mat.m00 = w;
	mat.m01 = 0.0f;
	mat.m02 = 0.0f;
	mat.m03 = 0.0f;

	mat.m10 = 0.0f;
	mat.m11 = h;
	mat.m12 = 0.0f;
	mat.m13 = 0.0f;

	mat.m20 = 0.0f;
	mat.m21 = 0.0f;
	mat.m22 = ( farZ * invLenZ );
//	mat.m22 = ( farZ / ( farZ - nearZ ) );
	mat.m23 = 1.0f;

	mat.m30 = 0.0f;
	mat.m31 = 0.0f;
	mat.m32 = ( -nearZ * farZ * invLenZ );
//	mat.m32 = ( -nearZ * farZ / ( farZ - nearZ ) );
	mat.m33 = 0.0f;
}

void Matrix4x4::OrthoLH( Float32 width, Float32 height, Float32 nearZ, Float32 farZ, Mix::Matrix4x4& mat )
{
	//2/width  0         0                   0
	//0        2/height  0                   0
	//0        0         1/(farZ-nearZ)      0
	//0        0         nearZ/(nearZ-farZ)  1

	mat.m00 = ( MIX_FLOAT_IS_ZERO( width ) == False )? ( 2.0f / width ) : 0.0f;
	mat.m10 = 0.0f;
	mat.m20 = 0.0f;
	mat.m30 = 0.0f;

	mat.m01 = 0.0f;
	mat.m11 = ( MIX_FLOAT_IS_ZERO( height ) == False )? ( 2.0f / height ) : 0.0f;
	mat.m21 = 0.0f;
	mat.m31 = 0.0f;

	mat.m02 = 0.0f;
	mat.m12 = 0.0f;
	mat.m22 = ( 1.0f / ( farZ - nearZ ) );
	mat.m32 = ( nearZ / ( nearZ - farZ ) );

	mat.m03 = 0.0f;
	mat.m13 = 0.0f;
	mat.m23 = 0.0f;
	mat.m33 = 1.0f;
}

void Matrix4x4::OrthoOffCenterLH( const Mix::Vector3& min, const Mix::Vector3& max, Mix::Matrix4x4& mat )
{
	//2/(max.x-min.x)              0                            0                    0
	//0                            2/(min.y-max.y)              0                    0
	//0                            0                            1/(max.z-min.z)      0
	//(min.x+max.x)/(min.x-max.x)  (min.y+max.y)/(max.y-min.y)  min.z/(min.z-max.z)  1

	mat.m00 = ( 2.0f / ( max.x - min.x ) );
	mat.m10 = 0.0f;
	mat.m20 = 0.0f;
	mat.m30 = ( ( min.x + max.x ) / ( min.x - max.x ) );

	mat.m01 = 0.0f;
	mat.m11 = ( 2.0f / ( min.y - max.y ) );
	mat.m21 = 0.0f;
	mat.m31 = ( ( min.y + max.y ) / ( max.y - min.y ) );

	mat.m02 = 0.0f;
	mat.m12 = 0.0f;
	mat.m22 = ( 1.0f / ( max.z - min.z ) );
	mat.m32 = ( min.z / ( min.z - max.z ) );

	mat.m03 = 0.0f;
	mat.m13 = 0.0f;
	mat.m23 = 0.0f;
	mat.m33 = 1.0f;
}

}
