/**************************************************************************
  dumb3d.hpp - A simple linear algebra library for 3D.

 **************************************************************************/
/**************************************************************************

    (C) Copyright 1994 Microsoft Corp.  All rights reserved.

    You have a royalty-free right to use, modify, reproduce and 
    distribute the Sample Files (and/or any modified version) in 
    any way you find useful, provided that you agree that 
    Microsoft has no warranty obligations or liability for any 
    Sample Application Files which are modified. 

 **************************************************************************/

#if !defined(DUMB3D_HPP)
#define DUMB3D_HPP

/*----------------------------------------------------------------------------

This header contains the declarations for the dumb3d functions.

*/


// real type

typedef float real;


#define M_PI            3.14159265358979323846


// forward declarations

class point_4;
class vector_4;
class matrix_4x4;

/*----------------------------------------------------------------------------

globally useful functions.

*/

inline vector_4 operator-( point_4 const &Operand1, point_4 const &Operand2 );

inline vector_4 operator+( vector_4 const &Operand1,
    vector_4 const &Operand2 );

inline vector_4 operator-( vector_4 const &Operand1,
    vector_4 const &Operand2 );

inline vector_4 operator*( vector_4 const &Multiplicand,
    real const &Multiplier );

inline vector_4 operator*( real const &Multiplier,
    vector_4 const &Multiplicand );
    
inline point_4 operator+( point_4 const &Operand1, vector_4 const &Operand2 );
inline point_4 operator-( point_4 const &Operand1, vector_4 const &Operand2 );
inline point_4 operator+( vector_4 const &Operand2, point_4 const &Operand1 );

inline vector_4 operator-( vector_4 const &Operand1 );

inline vector_4 CrossProduct( vector_4 const &Operand1,
    vector_4 const &Operand2 );

inline real DotProduct( vector_4 const &Operand1, vector_4 const &Operand2 );

matrix_4x4 operator*( matrix_4x4 const &Multiplicand,
    matrix_4x4 const &Multiplier );

vector_4 operator*( matrix_4x4 const &Multiplicand,
    vector_4 const &Multiplier );

point_4 operator*( matrix_4x4 const &Multiplicand,
    point_4 const &Multiplier );




/*----------------------------------------------------------------------------

quadruple.  Base class for homogeneous vectors and points.

*/

class quadruple
{
public:

  inline real GetElement( int Row ) const;

  inline real GetX( void ) const;
  inline real GetY( void ) const;
  inline real GetZ( void ) const;
  inline real GetW( void ) const;

  inline void SetElement( int Row, real Value );

  inline void SetX( real Value );
  inline void SetY( real Value );
  inline void SetZ( real Value );
  inline void SetW( real Value );


protected:

  inline quadruple( void );
  inline quadruple( real X, real Y, real Z, real W );
  inline quadruple( quadruple const & );
  inline quadruple &operator=( quadruple const & );
  
  real aElements[4];
};


/*----------------------------------------------------------------------------

point_4.  This class represents a homogeneous 3D point.

*/

class point_4 :
  public quadruple
{
public:

  inline point_4( void );
  inline point_4( real X, real Y, real Z );

  inline void Homogenize( void );
};

/*----------------------------------------------------------------------------

vector_4.  This class represents a homogeneous 3D vector.

*/

class vector_4 :
  public quadruple
{
public:

  inline vector_4( void );
  inline vector_4( real X, real Y, real Z );

  vector_4 &Normalize( void );
};



/*----------------------------------------------------------------------------

matrix_4x4.  This class represents row major 4x4 homogeneous matrices.

*/

class matrix_4x4
{
public:

  matrix_4x4( void );

  matrix_4x4 &ConcatenateXRotation( real Degrees );
  matrix_4x4 &ConcatenateYRotation( real Degrees );
  matrix_4x4 &ConcatenateZRotation( real Degrees );

  matrix_4x4 &ConcatenateXTranslation( real Distance );
  matrix_4x4 &ConcatenateYTranslation( real Distance );
  matrix_4x4 &ConcatenateZTranslation( real Distance );

  inline real GetElement( int Row, int Column ) const;
  inline matrix_4x4 &SetElement( int Row, int Column, real Value );

  
protected:

  enum do_not_initialize { DoNotInitialize };

  inline matrix_4x4( do_not_initialize );

  real aElements[4][4];
};

/*----------------------------------------------------------------------------

view transform.

*/

class view_transform :
  public matrix_4x4
{
public:

  view_transform( point_4 const &Viewpoint, vector_4 const &ViewDirection,
    vector_4 const &Up );
};


/*----------------------------------------------------------------------------

inline function definitions.

*/


inline vector_4 operator-( point_4 const &Operand1, point_4 const &Operand2 )
{
  return vector_4(Operand1.GetX() - Operand2.GetX(),
          Operand1.GetY() - Operand2.GetY(),
          Operand1.GetZ() - Operand2.GetZ());
}

inline vector_4 operator+( vector_4 const &Operand1,
    vector_4 const &Operand2 )
{
  return vector_4(Operand1.GetX() + Operand2.GetX(),
          Operand1.GetY() + Operand2.GetY(),
          Operand1.GetZ() + Operand2.GetZ());
}

inline vector_4 operator-( vector_4 const &Operand1,
    vector_4 const &Operand2 )
{
  return vector_4(Operand1.GetX() - Operand2.GetX(),
          Operand1.GetY() - Operand2.GetY(),
          Operand1.GetZ() - Operand2.GetZ());
}

inline vector_4 operator-( vector_4 const &Operand1 )
{
  return vector_4(-Operand1.GetX(),-Operand1.GetY(),-Operand1.GetZ());
}

inline vector_4 operator*( vector_4 const &Multiplicand,
    real const &Multiplier )
{
  return vector_4(Multiplicand.GetX() * Multiplier,
          Multiplicand.GetY() * Multiplier,
          Multiplicand.GetZ() * Multiplier);
}

inline vector_4 operator*( real const &Multiplier,
    vector_4 const &Multiplicand ) 
{
  return vector_4(Multiplicand.GetX() * Multiplier,
          Multiplicand.GetY() * Multiplier,
          Multiplicand.GetZ() * Multiplier);
}
    
inline point_4 operator+( point_4 const &Operand1, vector_4 const &Operand2 )
{
  return point_4(Operand1.GetX() + Operand2.GetX(),
          Operand1.GetY() + Operand2.GetY(),
          Operand1.GetZ() + Operand2.GetZ());
}

inline point_4 operator-( point_4 const &Operand1, vector_4 const &Operand2 )
{
  return point_4(Operand1.GetX() - Operand2.GetX(),
          Operand1.GetY() - Operand2.GetY(),
          Operand1.GetZ() - Operand2.GetZ());
}

inline point_4 operator+( vector_4 const &Operand1, point_4 const &Operand2 )
{
  return Operand2 + Operand1;
}

inline vector_4 CrossProduct( vector_4 const &Operand1,
    vector_4 const &Operand2 )
{
  real X = Operand1.GetY() * Operand2.GetZ() -
        Operand1.GetZ() * Operand2.GetY();
  real Y = Operand1.GetZ() * Operand2.GetX() -
        Operand1.GetX() * Operand2.GetZ();
  real Z = Operand1.GetX() * Operand2.GetY() -
        Operand1.GetY() * Operand2.GetX();

  return vector_4(X,Y,Z);
}

inline real DotProduct( vector_4 const &Operand1, vector_4 const &Operand2 )
{
  return Operand1.GetX() * Operand2.GetX() +
      Operand1.GetY() * Operand2.GetY() +
      Operand1.GetZ() * Operand2.GetZ();
}


inline real quadruple::GetElement( int Row ) const
{
  return aElements[Row];
}

inline real quadruple::GetX( void ) const
{
  return aElements[0];
}

inline real quadruple::GetY( void ) const
{
  return aElements[1];
}

inline real quadruple::GetZ( void ) const
{
  return aElements[2];
}

inline real quadruple::GetW( void ) const
{
  return aElements[3];
}

inline void quadruple::SetElement( int Row, real Value )
{
  aElements[Row] = Value;
}

inline void quadruple::SetX( real Value )
{
  aElements[0] = Value;
}

inline void quadruple::SetY( real Value )
{
  aElements[1] = Value;
}

inline void quadruple::SetZ( real Value )
{
  aElements[2] = Value;
}

inline void quadruple::SetW( real Value )
{
  aElements[3] = Value;
}

inline void point_4::Homogenize( void )
{
  aElements[0] = aElements[0] / aElements[3];
  aElements[1] = aElements[1] / aElements[3];
  aElements[2] = aElements[2] / aElements[3];
}

inline quadruple::quadruple( void )
{
  aElements[0] = aElements[1] = aElements[2] = aElements[3] = 0;
}

inline quadruple::quadruple( real X, real Y, real Z, real W )
{
  aElements[0] = X;
  aElements[1] = Y;
  aElements[2] = Z;
  aElements[3] = W;
}

inline quadruple::quadruple( quadruple const &Source )
{
  aElements[0] = Source.aElements[0];
  aElements[1] = Source.aElements[1];
  aElements[2] = Source.aElements[2];
  aElements[3] = Source.aElements[3];
}

inline quadruple &quadruple::operator=( quadruple const &Source )
{
  aElements[0] = Source.aElements[0];
  aElements[1] = Source.aElements[1];
  aElements[2] = Source.aElements[2];
  aElements[3] = Source.aElements[3];

  return *this;
}

inline point_4::point_4( void ) :
  quadruple(0,0,0,1)
{

}

inline point_4::point_4( real X, real Y, real Z ) :
  quadruple(X,Y,Z,1)
{
#if 0
  char aBuffer[100];
  sprintf(aBuffer,"X: %f Y: %f Z: %f",X,Y,Z);
  MessageBox(0,aBuffer,"foobar",MB_OK);
  sprintf(aBuffer,"X: %f Y: %f Z: %f W:%f",aElements[0],aElements[1],
    aElements[2],aElements[3]);
  MessageBox(0,aBuffer,"foobar",MB_OK);
#endif
}

inline vector_4::vector_4( void ) :
  quadruple(0,0,0,0)
{

}

inline vector_4::vector_4( real X, real Y, real Z ) :
  quadruple(X,Y,Z,0)
{

}

inline real matrix_4x4::GetElement( int Row, int Column ) const
{
  return aElements[Row][Column];
}

inline matrix_4x4 &matrix_4x4::SetElement( int Row, int Column, real Value )
{
  aElements[Row][Column] = Value;

  return *this;
}

inline matrix_4x4::matrix_4x4( do_not_initialize )
{

}

#endif
