//===========================================================================//
// File:	affnmtrx.hh                                                         //
// Project: MUNGA           Brick: Math Library                              //
// Contents: Interface specifications for Affine matrices                    //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 11/20/94  JMA  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#if !defined(AFFNMTRX_HPP)
#	define AFFNMTRX_HPP

#	if !defined(POINT3D_HPP)
#		include <point3d.hpp>
#	endif

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~ AffineMatrix ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	class AffineMatrix
	{
	 public:
		static const AffineMatrix
			Identity;

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

		Scalar
			entries[12];

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

		//
		// Assignment Operators
		//
		AffineMatrix&
			operator=(const AffineMatrix &m);
		AffineMatrix&
			operator=(const Origin &p);
		AffineMatrix&
			operator=(const Hinge &hinge);
		AffineMatrix&
			operator=(const EulerAngles &angles);
		AffineMatrix&
			operator=(const YawPitchRoll &angles);
		AffineMatrix&
			operator=(const Quaternion &q);
		AffineMatrix&
			operator=(const Point3D &p)
				{return SetFromAxis(W_Axis,p);}
		AffineMatrix&
			operator=(const Matrix4x4 &m);
		AffineMatrix&
			operator=(const TransposedMatrix &m);

		//
		// Comparison operators
		//
		Logical
			operator==(const AffineMatrix& m) const;
		Logical
			operator!=(const AffineMatrix& m) const;

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

		//
		// Axis Manipulation functions
		//
		void
			GetFromAxis(size_t index, Vector3D *v) const;
		void
			GetToAxis(size_t index, Vector3D *v) const;

		AffineMatrix&
			SetFromAxis(size_t index, const Vector3D &v);
		AffineMatrix&
			SetToAxis(size_t index, const Vector3D &v);

		//
		// Matrix Multiplication
		//
		AffineMatrix&
			Multiply(
				const AffineMatrix& m1,
				const AffineMatrix& m2
			);
		AffineMatrix&
			operator*=(const AffineMatrix& m)
				{AffineMatrix temp(*this); return Multiply(temp,m);}

		//
		// Matrix Inversion
		//
		AffineMatrix&
			Invert(const AffineMatrix& Source);
		AffineMatrix&
			Invert()
				{AffineMatrix src(*this); return Invert(src);}

		//
		// Scaling, Rotation and Translation
		//
		AffineMatrix&
			Multiply(const AffineMatrix &m,const Vector3D &v);
		AffineMatrix&
			operator*=(const Vector3D &v)
				{AffineMatrix m(*this); return Multiply(m,v);}
		AffineMatrix&
			Multiply(const AffineMatrix &m,const Quaternion &q);
		AffineMatrix&
			operator*=(const Quaternion &q)
				{AffineMatrix m(*this); return Multiply(m,q);}
		AffineMatrix&
			Multiply(const AffineMatrix &m,const Point3D &p);
		AffineMatrix&
			operator*=(const Point3D& p)
				{AffineMatrix m(*this); return Multiply(m,p);}

		//
		// Miscellaneous Functions
		//
		Scalar
			Determinant() const;
		AffineMatrix&
			Solve();

		//
		// Support functions
		//
		friend ostream&
			operator <<(
				ostream& stream,
				const AffineMatrix& m
			);
		Logical
			TestInstance() const;
		static Logical
			TestClass();
	};

	inline Point3D&
		Point3D::operator=(const AffineMatrix& m)
			{m.GetFromAxis(W_Axis,this); return *this;}

	inline MemoryStream&
		MemoryStream_Read(
			MemoryStream *stream,
			AffineMatrix *output
		)
			{return stream->ReadBytes(output, sizeof(*output));}
	inline MemoryStream&
		MemoryStream_Write(
			MemoryStream *stream,
			const AffineMatrix *input
		)
			{return stream->WriteBytes(input, sizeof(*input));}

#endif

