// Author : Chris Tolley
// Date   : 7/06/2004
// matrix.h contains the class declaration for a 4x4 matrix class which is 
// compatable with OpenGL

#if !defined(AFX_MATRIX_H__F849F4E9_EE30_4018_B4DD_E50924946BCE__INCLUDED_)
#define AFX_MATRIX_H__F849F4E9_EE30_4018_B4DD_E50924946BCE__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <windows.h>
#include <gl/gl.h>

class matrix  
{
public:
	// Default Constructor
	matrix();

	// Constructor with arguments
	matrix( const float* mat );

	// Constructor with arguments
	matrix( const float a, const float b, const float c, const float d,
			const float e, const float f, const float g, const float h,
			const float i, const float j, const float k, const float l,
			const float m, const float n, const float o, const float p );

	// Copy Constructor
	matrix( const matrix& rhs );

	// Desturctor
	virtual ~matrix();

	// Sets the matrix to the identity matrix
	void LoadIdentity();

	// Zero's out all values in this matrix
	void Zero();

	// Returns the nth element of this matrix
	inline float& operator[] ( int n ) { return m_fMat[n]; };

	// Returns the values stored in this matrix
	inline float* get() { return &m_fMat[0]; };

	// Returns true if the two matrices are equal
	bool operator== ( const matrix& rhs ) const;

	// Returns true if the two matrices are not equal
	bool operator!= ( const matrix& rhs ) const;

	// Returns the product of this matrix and scalar
	matrix operator* ( const int scalar ) const;

	// Returns the product of these two matrices
	matrix operator* ( const matrix& rhs ) const;

	// Stores the result of multipling this matrix with rhs
	matrix& operator*= ( const matrix& rhs );

	// Returns the result of dividing this matrix with scalar
	matrix operator/ ( const int scalar ) const;

	// Returns the result of dividing this matrix with another
	matrix operator/ ( const matrix& rhs ) const;

	// Returns the sum of this matrix and scalar
	matrix operator+ ( const int scalar ) const;

	// Returns the sum of this matrix and rhs
	matrix operator+ ( const matrix& rhs ) const;

	// Stores the sum of the two matrices
	matrix operator+= ( const matrix& rhs );

	// Return the difference between this matrix and scalar
	matrix operator- ( const int scalar ) const;

	// Returns the difference between the two matrices
	matrix operator- ( const matrix& rhs ) const;

	// Stores the difference between the two matrices
	matrix operator-= ( const matrix& rhs );

	// Sets the rotational values
	void Rotate( const float x, const float y, const float z );

	// Sets the rotational values
	void Rotate( const float* rota );

	// Sets a translation
	void Translate( const float x, const float y, const float z );

	// Sets a translation
	void Translate( const float* tran );

	// Sets the scale values
	void Scale( const float x, const float y, const float z );

	// Sets the scale values
	void Scale( const float* sca );

	// Transforms these three points
	inline void Transform( float& x, float& y, float& z ) const;

	// Transforms these three points
	inline void Transform( float* pos ) const;
private:
	float m_fMat[16];
};


// Transforms these three points by the model's local coordinate system
inline void matrix::Transform( float& x, float& y, float& z ) const
{
	// Calculate the transformations
	float nx = ( x * m_fMat[0] + y * m_fMat[4] + 
				 z * m_fMat[ 8] + 1 * m_fMat[12] );

	float ny = ( x * m_fMat[1] + y * m_fMat[5] + 
				 z * m_fMat[ 9] + 1 * m_fMat[13] );
	
	float nz = ( x * m_fMat[2] + y * m_fMat[6] + 
				 z * m_fMat[10] + 1 * m_fMat[14] );

	// Set the transformations
	x = nx;
	y = ny;
	z = nz;
}// End matrix::Transform


// Transforms these three points by the model's local coordinate system
inline void matrix::Transform( float* pos ) const
{
	// Make this function a little easier
	float x = pos[0];
	float y = pos[1];
	float z = pos[2];

	// Calculate the transformations
	float nx = ( x * m_fMat[0] + y * m_fMat[4] + 
				 z * m_fMat[ 8] + 1 * m_fMat[12] );

	float ny = ( x * m_fMat[1] + y * m_fMat[5] + 
				 z * m_fMat[ 9] + 1 * m_fMat[13] );
	
	float nz = ( x * m_fMat[2] + y * m_fMat[6] + 
				 z * m_fMat[10] + 1 * m_fMat[14] );

	// Set the transformations
	pos[0] = nx;
	pos[1] = ny;
	pos[2] = nz;
}// End matrix::Transform
#endif // !defined(AFX_MATRIX_H__F849F4E9_EE30_4018_B4DD_E50924946BCE__INCLUDED_)
