///////////////////////////////////////////////////////////////////////////////
//  SMatrix.h

#ifndef __SMATRIX_H__
#define __SMATRIX_H__

#include "S3D.h"
#include "S4D.h"

struct SQuaternion;

struct SMatrix {
	union {
		float	m[4][4];
		float	mm[16];
	};

private:
	float	det2x2(const float a1, const float a2, const float b1, const float b2) const;
	float	det3x3(const float a1, const float a2, const float a3,
		const float b1, const float b2, const float b3,
		const float c1, const float c2, const float c3) const;

public:
	bool	operator==(const SMatrix& Right) const;
	bool	operator!=(const SMatrix& Right) const;

	// Creation Method
	static SMatrix CreateMove(float fX, float fY, float fZ) {
		return SMatrix(
			 1,  0,  0, 0,
			 0,  1,  0, 0,
			 0,  0,  1, 0,
			fX, fY, fZ, 1);
	}

	static SMatrix CreateMove(const S3D& Pos);

	static SMatrix CreateScale(float fX, float fY, float fZ) {
		return SMatrix(
			fX,  0,  0, 0,
			 0, fY,  0, 0,
			 0,  0, fZ, 0,
			 0,  0,  0, 1);
	}

	static SMatrix CreateScale(const S3D& Scale);

	static SMatrix CreateScale(float fSize) {
		return SMatrix(
			fSize,     0,     0, 0,
			    0, fSize,     0, 0,
			    0,     0, fSize, 0,
			    0,     0,     0, 1);
	}

	static SMatrix CreateRotHRad(float fAngle) {
		SMatrix mat;
		mat.SetRotHRad(fAngle);
		return mat;
	}

	static SMatrix CreateRotPRad(float fAngle) {
		SMatrix mat;
		mat.SetRotPRad(fAngle);
		return mat;
	}

	static SMatrix CreateRotBRad(float fAngle) {
		SMatrix mat;
		mat.SetRotBRad(fAngle);
		return mat;
	}

	static SMatrix CreateRotH(float fAngle) {
		SMatrix mat;
		mat.SetRotH(fAngle);
		return mat;
	}

	static SMatrix CreateRotP(float fAngle) {
		SMatrix mat;
		mat.SetRotP(fAngle);
		return mat;
	}

	static SMatrix CreateRotB(float fAngle) {
		SMatrix mat;
		mat.SetRotB(fAngle);
		return mat;
	}

	static SMatrix CreateRotAxis(const S3D& Vec, float Radian);

	static SMatrix CreateLookAt(const S3D& EyePos, const S3D& AtPos, const S3D& UpVec);

	static SMatrix	CreateXYZVector(const S3D& XVector, const S3D& YVector, const S3D& ZVector);

	static SMatrix CreateIdentity(void) {
		return SMatrix(
			1, 0, 0, 0,
			0, 1, 0, 0,
			0, 0, 1, 0,
			0, 0, 0, 1);
	}

	SMatrix(void)
	{
		m[0][0] = 1.0f; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = 0.0f;
		m[1][0] = 0.0f; m[1][1] = 1.0f; m[1][2] = 0.0f; m[1][3] = 0.0f;
		m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = 1.0f; m[2][3] = 0.0f;
		m[3][0] = 0.0f; m[3][1] = 0.0f; m[3][2] = 0.0f; m[3][3] = 1.0f;
	}

	// 未初期化用コンストラクタ
	explicit SMatrix(int);

	//
	SMatrix(float a11, float a12, float a13, float a14,
				float a21, float a22, float a23, float a24,
				float a31, float a32, float a33, float a34,
				float a41, float a42, float a43, float a44)
	{
		m[0][0] = a11; m[0][1] = a12; m[0][2] = a13; m[0][3] = a14;
		m[1][0] = a21; m[1][1] = a22; m[1][2] = a23; m[1][3] = a24;
		m[2][0] = a31; m[2][1] = a32; m[2][2] = a33; m[2][3] = a34;
		m[3][0] = a41; m[3][1] = a42; m[3][2] = a43; m[3][3] = a44;
	}

	explicit SMatrix(const float* pData);

	void	Set(float a11, float a12, float a13, float a14,
				float a21, float a22, float a23, float a24,
				float a31, float a32, float a33, float a34,
				float a41, float a42, float a43, float a44) {
		m[0][0] = a11; m[0][1] = a12; m[0][2] = a13; m[0][3] = a14;
		m[1][0] = a21; m[1][1] = a22; m[1][2] = a23; m[1][3] = a24;
		m[2][0] = a31; m[2][1] = a32; m[2][2] = a33; m[2][3] = a34;
		m[3][0] = a41; m[3][1] = a42; m[3][2] = a43; m[3][3] = a44;
	}

	void	Identity(void);

	void	Trans(void);

	void	MulMatrix(const SMatrix& a);

	SMatrix&	operator*=(const SMatrix& a);

	friend SMatrix	operator*(const SMatrix& b, const SMatrix& a);

	void	SetMove(float fX, float fY, float fZ) {
		Set( 1,  0,  0, 0,
			 0,  1,  0, 0,
			 0,  0,  1, 0,
			fX, fY, fZ, 1);
	}

	void	SetScale(float fX, float fY, float fZ) {
		Set(fX,  0,  0, 0,
			 0, fY,  0, 0,
			 0,  0, fZ, 0,
			 0,  0,  0, 1);
	}

	float	GetScaleX() const;

	void	SetRotHRad(float fAngle);
	void	SetRotPRad(float fAngle);
	void	SetRotBRad(float fAngle);

	void	SetRotH(float fAngle);
	void	SetRotP(float fAngle);
	void	SetRotB(float fAngle);

	void	Inverse(void);
	SMatrix	GetInverse(void) const;

	// 取得
	SQuaternion		GetQuaternion(void) const;
	S3D				GetMove(void) const;

	SMatrix			GetTranspose(void) const {
		return SMatrix(
			m[0][0], m[1][0], m[2][0], m[3][0],
			m[0][1], m[1][1], m[2][1], m[3][1],
			m[0][2], m[1][2], m[2][2], m[3][2],
			m[0][3], m[1][3], m[2][3], m[3][3]);
	}

	SMatrix			GetOpenGLMatrix() const;

	S3D		GetXVector() const;
	S3D		GetYVector() const;
	S3D		GetZVector() const;

	S4D		GetXVector4() const;
	S4D		GetYVector4() const;
	S4D		GetZVector4() const;

	// オイラー角
	S3D		GetEulerRadXYZ() const;
	S3D		GetEulerRadYXZ() const;
	S3D		GetEulerRadZXY() const;
	S3D		GetEulerRadZYX() const;

};

#endif // __SMATRIX_H__

