//	Darkstar Engine  (c) UnderWorld Interactive Studio (all coding by Svarog    2007)
//
//      Данный файл является частью Darkstar Engine. Любое использование кода файла
//      без согласия компании, является нарушением закона об авторском праве (в слу-
//      чае если не оговорено обратное).
//
//      Имя файла: matr.hpp
//      Краткое описание: работа с матрицами
//

#ifndef DSE_MATH_MATR_HPP
#define DSE_MATH_MATR_HPP

#include <Darkstar/Math/common_math.hpp>
#include <Darkstar/Math/vect.hpp>

namespace math
{
	class Matr34;
	class Matr4;
	class Quat;

	class Matr3
	{
	public:
		union
		{
			struct
			{
				float _a00, _a01, _a02;
				float _a10, _a11, _a12;
				float _a20, _a21, _a22;
			};
			struct
			{
				Vect3 rows[3];
			};
			struct
			{
				float _a[9];
			};
			struct 
			{
				Vect3 row0, row1, row2;
			};
		};

		Matr3();
		Matr3(const Matr3& m);
		Matr3(const float a00, const float a01, const float a02, const float a10, const float a11, const float a12, const float a20, const float a21, const float a22);
		Matr3(const Vect3& row0, const Vect3& row1, const Vect3& row2);
		Matr3(const Vect3* rows);
		explicit Matr3(const Matr4& m);
		explicit Matr3(const Matr34& m);
		explicit Matr3(const Quat& q);
		~Matr3();

		Matr3& operator=(const Matr3& m);

		const Vect3& operator[](const unsigned int i) const;
		Vect3& operator[](const unsigned int i);

		Matr3 operator+(const Matr3& m) const;
		const Matr3& operator+=(const Matr3& m);
		Matr3 operator-(const Matr3& m) const;
		const Matr3& operator-=(const Matr3& m);
		Matr3 operator*(const Matr3& m) const;
		const Matr3& operator*=(const Matr3& m);

		Matr3 operator*(const float f) const;
		const Matr3& operator*=(const float f);
		Matr3 operator/(const float f) const;
		const Matr3& operator/=(const float f);

		Matr3 operator-() const;

		bool operator==(const Matr3& m) const;
		bool operator!=(const Matr3& m) const;

		const Matr3& transpose();
		Matr3 getTranspose() const;
		const Matr3& invert();
		const Matr3& fastInvert();
		Matr3 getInverse() const;
		Matr3 getFastInverse() const;
		float det() const;

		const Matr3& setIdentity();

		const Matr3& ApplyScaling(const float u_s);
		const Matr3& ApplyScaling(const Vect3& v);
		const Matr3& ApplyRotation(const Vect3& angles);
		const Matr3& ApplyRotation(const Vect3& v, const float ang);
		const Matr3& ApplyRotation(const Quat& q);

		const Matr3& setOnlyScaling(const float u_s);
		const Matr3& setOnlyScaling(const Vect3& v);
		const Matr3& setOnlyRotation(const Vect3& angles);
		const Matr3& setOnlyRotation(const Vect3& v, const float ang);
		const Matr3& setOnlyRotation(const Quat& q);

		bool getIsOrthogonalMatrix() const;
		Quat getQuaternion() const;

		friend Vect3 operator*(const Matr3& m, const Vect3& v);
	};

	class Matr4
	{
	public:
		union
		{
			struct
			{
				float _a00, _a01, _a02, _a03;
				float _a10, _a11, _a12, _a13;
				float _a20, _a21, _a22, _a23;
				float _a30, _a31, _a32, _a33;
			};
			struct
			{
				Vect4 rows[4];
			};
			struct
			{
				float _a[16];
			};
			struct
			{
				Vect4 row0, row1, row2, row3;
			};
		};

		Matr4();
		Matr4(const Matr4& m);
		Matr4(const float a00, const float a01, const float a02, const float a03, const float a10, const float a11, const float a12, const float a13, const float a20, const float a21, const float a22, const float a23, const float a30, const float a31, const float a32, const float a33);
		Matr4(const Vect4& row0, const Vect4& row1, const Vect4& row2, const Vect4& row3);
		Matr4(const Vect4* rows);
		Matr4(const Matr34& m);
		explicit Matr4(const Matr3& m);
		explicit Matr4(const Quat& q);
		Matr4(const Matr3& rot, const Vect3& tran, const Vect3& scale);
		Matr4(const Matr3& rot, const Vect3& tran, const float scale);
		Matr4(const Quat& rot, const Vect3& tran, const Vect3& scale);
		Matr4(const Quat& rot, const Vect3& tran, const float scale);
		~Matr4();

		Matr4& operator=(const Matr4& m);

		const Vect4& operator[](const unsigned int i) const;
		Vect4& operator[](const unsigned int i);

		Matr4 operator+(const Matr4& m) const;
		const Matr4& operator+=(const Matr4& m);
		Matr4 operator-(const Matr4& m) const;
		const Matr4& operator-=(const Matr4& m);
		Matr4 operator*(const Matr4& m) const;
		const Matr4& operator*=(const Matr4& m);

		Matr4 operator*(const float f) const;
		const Matr4& operator*=(const float f);
		Matr4 operator/(const float f) const;
		const Matr4& operator/=(const float f);

		Matr4 operator-() const;

		bool operator==(const Matr4& m) const;
		bool operator!=(const Matr4& m) const;

		const Matr4& transpose();
		Matr4 getTranspose() const;
		const Matr4& invert();
		const Matr4& fastInvert();
		Matr4 getInverse() const;
		Matr4 getFastInverse() const;
		float det() const;

		const Matr4& setIdentity();
		const Matr4& setTranslation(const Vect3& v);
		const Matr4& setScaling(const Vect3& v);
		const Matr4& setScaling(const float f);
		const Matr4& setRotation(const Vect3& v, const float ang);
		const Matr4& setRotation(const Vect3& v);
		const Matr4& setRotation(const Matr3& m);
		const Matr4& setRotation(const Quat& q);

		const Matr4& ApplyTranslation(const Vect3& v);
		const Matr4& ApplyScaling(const Vect3& v);
		const Matr4& ApplyScaling(const float f);
		const Matr4& ApplyRotation(const Vect3& v, const float ang);
		const Matr4& ApplyRotation(const Vect3& v);
		const Matr4& ApplyRotation(const Matr3& m);
		const Matr4& ApplyRotation(const Quat& q);

		const Matr4& setOnlyTranslation(const Vect3& v);
		const Matr4& setOnlyScaling(const Vect3& v);
		const Matr4& setOnlyScaling(const float f);
		const Matr4& setOnlyRotation(const Vect3& v, const float ang);
		const Matr4& setOnlyRotation(const Vect3& v);
		const Matr4& setOnlyRotation(const Matr3& m);
		const Matr4& setOnlyRotation(const Quat& q);

		bool getIsOrthogonalMatrix() const;
		Quat getQuaternion() const;

		friend Vect4 operator*(const Matr4& m, const Vect4& v);

		friend Vect4 operator*(const Matr4& m, const Vect3& v);
	};

	class Matr34
	{
	public:
		union
		{
			struct
			{
				float _a00, _a01, _a02, _a03;
				float _a10, _a11, _a12, _a13;
				float _a20, _a21, _a22, _a23;
			};
			struct
			{
				Vect4 rows[3];
			};
			struct
			{
				float _a[12];
			};
			struct
			{
				Vect4 row0, row1, row2;
			};
		};

		Matr34();
		Matr34(const Matr34& m);
		Matr34(const float a00, const float a01, const float a02, const float a03, const float a10, const float a11, const float a12, const float a13, const float a20, const float a21, const float a22, const float a23);
		Matr34(const Vect4& row0, const Vect4& row1, const Vect4& row2);
		Matr34(const Vect4* rows);
		Matr34(const Matr3& m);
		explicit Matr34(const Matr4& m);
		explicit Matr34(const Quat& q);
		Matr34(const Matr3& rot, const Vect3& tran, const Vect3& scale);
		Matr34(const Matr3& rot, const Vect3& tran, const float scale);
		Matr34(const Quat& rot, const Vect3& tran, const Vect3& scale);
		Matr34(const Quat& rot, const Vect3& tran, const float scale);
		~Matr34();

		Matr34& operator=(const Matr34& m);

		const Vect4& operator[](const unsigned int i) const;
		Vect4& operator[](const unsigned int i);

		Matr34 operator+(const Matr34& m) const;
		const Matr34& operator+=(const Matr34& m);
		Matr34 operator-(const Matr34& m) const;
		const Matr34& operator-=(const Matr34& m);
		Matr34 operator*(const Matr34& m) const;
		const Matr34& operator*=(const Matr34& m);

		Matr34 operator*(const float f) const;
		const Matr34& operator*=(const float f);
		Matr34 operator/(const float f) const;
		const Matr34& operator/=(const float f);

		Matr34 operator-() const;

		bool operator==(const Matr34& m) const;
		bool operator!=(const Matr34& m) const;

		const Matr34& invert();
		const Matr34& fastInvert();
		Matr34 getInverse() const;
		Matr34 getFastInverse() const;

		const Matr34& setIdentity();
		const Matr34& setTranslation(const Vect3& v);
		const Matr34& setScaling(const Vect3& v);
		const Matr34& setScaling(const float f);
		const Matr34& setRotation(const Vect3& v, const float ang);
		const Matr34& setRotation(const Vect3& v);
		const Matr34& setRotation(const Matr3& m);
		const Matr34& setRotation(const Quat& q);

		const Matr34& ApplyTranslation(const Vect3& v);
		const Matr34& ApplyScaling(const Vect3& v);
		const Matr34& ApplyScaling(const float f);
		const Matr34& ApplyRotation(const Vect3& v, const float ang);
		const Matr34& ApplyRotation(const Vect3& v);
		const Matr34& ApplyRotation(const Matr3& m);
		const Matr34& ApplyRotation(const Quat& q);

		const Matr34& setOnlyTranslation(const Vect3& v);
		const Matr34& setOnlyScaling(const Vect3& v);
		const Matr34& setOnlyScaling(const float f);
		const Matr34& setOnlyRotation(const Vect3& v, const float ang);
		const Matr34& setOnlyRotation(const Vect3& v);
		const Matr34& setOnlyRotation(const Matr3& m);
		const Matr34& setOnlyRotation(const Quat& q);

		Quat getQuaternion() const;

		friend Vect3 operator*(const Matr34& m, const Vect4& v);
		
		friend Vect3 operator*(const Matr34& m, const Vect3& v);
	};

	const Matr3 matr3_zero = Matr3(vect3_zero, vect3_zero, vect3_zero);
	const Matr3 matr3_sing = Matr3(vect3_sing_x, vect3_sing_y, vect3_sing_z);

	const Matr4 matr4_zero = Matr4(vect4_zero, vect4_zero, vect4_zero, vect4_zero);
	const Matr4 matr4_sing = Matr4(vect4_sing_x, vect4_sing_y, vect4_sing_z, vect4_sing_w);
		
	const Matr34 matr34_zero = Matr34(vect4_zero, vect4_zero, vect4_zero);
	const Matr34 matr34_sing = Matr34(vect4_sing_x, vect4_sing_y, vect4_sing_z);
};

using math::Matr3;
using math::Matr4;
using math::Matr34;

#include <Darkstar/Math/matr.inl>

#endif