//===========================================================================//
// File:	matrix.hh                                                           //
// Project: MUNGA           Brick: Math Library                              //
// Contents: Interface specification for the matrix class                    //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 11/21/94  JMA  Initial coding.                                            //
// 12/01/94  JMA  Changed Matrix to Matrix4x4, based both matrix classes on  //
//                  Matrix44Base                                             //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#if !defined(MATRIX_HPP)
#	define MATRIX_HPP

#	if !defined(SCALAR_HPP)
#		include <scalar.hpp>
#	endif

	class AffineMatrix;
	class TransposedMatrix;
	class Origin;
	class Hinge;
	class EulerAngles;
	class YawPitchRoll;
	class Point3D;
	class Quaternion;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~ AbstractMatrix4x4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	class AbstractMatrix4x4
	{
	public:
		Scalar
			entries[16];

		#if defined(USE_SIGNATURE)
			friend int
				Is_Signature_Bad(const volatile AbstractMatrix4x4 *);
		#endif

		AbstractMatrix4x4&
			operator=(const AbstractMatrix4x4& m);

		Logical
			TestInstance() const;

	protected:
		AbstractMatrix4x4()
			{}
		AbstractMatrix4x4&
			Transpose(const AbstractMatrix4x4 &m);
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Matrix4x4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	class Matrix4x4:
		public AbstractMatrix4x4
	{
	public:
		static const Matrix4x4
			Identity;

		//
		// Constructors
		//
		Matrix4x4()
			{}
		Matrix4x4&
			BuildIdentity();
		Matrix4x4(int)
			{BuildIdentity();}

		//
		// Assignment operators
		//
		Matrix4x4&
			operator=(const Matrix4x4 &m)
				{
					Check_Pointer(this); Check(&m);
					AbstractMatrix4x4::operator=(m); return *this;
				}
		Matrix4x4&
			operator=(const TransposedMatrix &m);
		Matrix4x4&
			operator=(const AffineMatrix &m);
		Matrix4x4&
			operator=(const Origin &p);
		Matrix4x4&
			operator=(const Hinge &hinge);
		Matrix4x4&
			operator=(const EulerAngles &angles);
		Matrix4x4&
			operator=(const YawPitchRoll &angles);
		Matrix4x4&
			BuildRotation(const Quaternion &q);
		Matrix4x4&
			operator=(const Quaternion &q);
		Matrix4x4&
			BuildTranslation(const Point3D &p);
		Matrix4x4&
			operator=(const Point3D &p);

		//
		// Index operators
		// Note that Matrix4x4 is stored in row major format, not column major,
		//   although they are indexed the same
		//
		Scalar&
			operator ()(size_t Row,size_t Column)
				{
					Check_Pointer(this); Warn(Row>3); Warn(Column>3);
					return entries[(Row<<2)+Column];
				}
		const Scalar&
			operator ()(size_t Row,size_t Column) const
				{
					Check_Pointer(this); Warn(Row>3); Warn(Column>3);
					return entries[(Row<<2)+Column];
				}

		//
		// Matrix4x4 Multiplication
		//
		Matrix4x4&
			Multiply(
				const Matrix4x4& Source1,
				const Matrix4x4& Source2
			);
		Matrix4x4&
			operator *=(const Matrix4x4& m)
				{Matrix4x4 temp(*this); return Multiply(temp,m);}
		Matrix4x4&
			Multiply(
				const Matrix4x4& Source1,
				const AffineMatrix &Source2
			);
		Matrix4x4&
			operator *=(const AffineMatrix& m)
				{Matrix4x4 temp(*this); return Multiply(temp,m);}
		Matrix4x4&
			Multiply(
				const AffineMatrix &Source1,
				const Matrix4x4& Source2
			);
		Matrix4x4&
			Multiply(
				const AffineMatrix &Source1,
				const AffineMatrix &Source2
			);

		//
		// Matrix4x4 Inversion
		//
#if 0
		Matrix4x4&
			Invert(const Matrix4x4& Source);
		Matrix4x4&
			Invert()
				{Matrix4x4 src(*this); return Invert(src);}
#endif

		//
		// Viewpoint Calculation
		//
		Matrix4x4&
			SetToProjection(
				Scalar Z_Plane,
				Scalar Inv_Q,
				Scalar Dx,
				Scalar Dy,
				Scalar Dz
			);
		Matrix4x4&
			SetToPerspectiveProjection(Scalar Distance)
				{
					Verify(Distance != 0.0);
					return SetToProjection(0.0,1.0/Distance,0.0,0.0,-1.0);
				}
		Matrix4x4&
			SetToOrthogonalProjection()
				{return SetToProjection(0.0,0.0,0.0,0.0,-1.0);}

		friend ostream&
			operator <<(
				ostream& stream,
				const Matrix4x4& Matrix4x4
			);
		static Logical
			TestClass();
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Matrix4x4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	class TransposedMatrix:
		public AbstractMatrix4x4
	{
	public:
		//
		// Constructors
		//
		TransposedMatrix()
			{}

		//
		// Assignment operators
		//
		TransposedMatrix&
			operator=(const Matrix4x4 &m)
				{
					Check_Pointer(this); Check(&m);
					AbstractMatrix4x4::Transpose(m); return *this;
				}
		TransposedMatrix&
			operator=(const TransposedMatrix &m)
				{
					Check_Pointer(this); Check(&m);
					AbstractMatrix4x4::operator=(m); return *this;
				}
		TransposedMatrix&
			operator=(const AffineMatrix &m);

		//
		// Index operators
		//
		Scalar&
			operator ()(size_t Row,size_t Column)
				{
					Check_Pointer(this); Warn(Row>3); Warn(Column>3);
					return entries[(Column<<2)+Row];
				}
		const Scalar&
			operator ()(size_t Row,size_t Column) const
				{
					Check_Pointer(this); Warn(Row>3); Warn(Column>3);
					return entries[(Column<<2)+Row];
				}

		//
		// Support Functions
		//
		friend ostream&
			operator <<(
				ostream& stream,
				const TransposedMatrix& Matrix4x4
			);
	};

	inline Matrix4x4&
		Matrix4x4::operator=(const TransposedMatrix &m)
			{
				Check_Pointer(this); Check(&m);
				AbstractMatrix4x4::Transpose(m); return *this;
			}

#endif

