/***************************************************************************
 *                          Zanoza Modeler v2.x                            *
 *      This is unpublished propietary source code of Zanoza Software.     *
 *      The copyright notice does not evidence any actual or intended      *
 *                    publication of such source code.                     *
 *                                                                         *
 *                   Copyright (c) 2002 Zanoza Software.                   *
 *                                                                         *
 *                        All rights reserved.                             *
 ***************************************************************************
 *--------------------------------------------------------------------------
 * @author:   Oleg M.
 *--------------------------------------------------------------------------
 * @purpose:  ZModeler's native 4x4 matrix
 *--------------------------------------------------------------------------
 * @histroy: 08.03.2003. Created
 */
#ifndef zmatrix_h_included
#define zmatrix_h_included

#ifndef zsequence_h_included
# include "zsequence.h"
#endif

//------------------------------------------------------
//  ZMatrix - ZModeler's native 4x4 matrix
//------------------------------------------------------
class DLL_LINKAGE ZMatrix
{
public:
  ZMatrix();
  ZMatrix(const float* initdata);
  ZMatrix(const ZMatrix& matrix);
  ~ZMatrix();

public:
  //
  // access grants
  //
  float& operator [] ( int value );
  float& operator () ( int iRow, int iCol );
  float  operator () ( int iRow, int iCol ) const;

public:
  //
  // casting operators
  //
  operator float* ();
  operator const float* () const;

public:
  //
  // assignment operators
  //
  ZMatrix& operator =  ( const ZMatrix& mat);
  ZMatrix& operator *= ( const ZMatrix& mat);
  ZMatrix& operator += ( const ZMatrix& mat);
  ZMatrix& operator -= ( const ZMatrix& mat);
  ZMatrix& operator *= ( float v);
  ZMatrix& operator /= ( float v);

public:
  //
  // unary operators
  //
  ZMatrix operator + () const;
  ZMatrix operator - () const;
  ZMatrix operator ! () const; //inverse

public:
  //
  // binary operators
  //
  ZMatrix operator * ( const ZMatrix& mat) const;
  ZMatrix operator + ( const ZMatrix& mat) const;
  ZMatrix operator - ( const ZMatrix& mat) const;
  ZMatrix operator * ( float v) const;
  ZMatrix operator / ( float v) const;

  bool operator == ( const ZMatrix& mat) const;
  bool operator != ( const ZMatrix& mat) const;

public:
  //
  // adjacent transformation
  //
  friend DLL_LINKAGE ZMatrix operator * ( float v, const ZMatrix& mt);
  friend DLL_LINKAGE ZPoint3D operator*(const ZMatrix& mat, const ZPoint3D& vect);
  friend DLL_LINKAGE ZPoint3D operator*(const ZPoint3D& vect, const ZMatrix& mat);


public:
  //
  // operations
  //
  bool isIdentity()   const;
  // determines transposed and/or rotated but not scaled identity
  bool isIdentityScale(float epsilon = MINFLOAT) const;
  void setIdentity();
  bool equals(const ZMatrix& mat, float epsilon = MINFLOAT) const;
  float determinant3() const; //as 3x3
  float determinant() const;  //as 4x4
  void transpose3();          //as 3x3
  void transpose();           //as 4x4


  void noTranslation();
  void noRotation();
  void noScale();
  void getDirection(const core::eAxis axis, ZVector& dir) const;
  void setDirection(const core::eAxis axis, const ZVector dir);
  void setTranslation(const ZPoint3D pos);
  void getTranslation(ZPoint3D& pos) const;
  void setTranslation(const core::eAxis axis, const float value);
  void getTranslation(const core::eAxis axis, float& value) const;
  void setRotation(const core::eAxis axis, const ZAngle angle);
  void getRotation(const core::eAxis axis, ZAngle& angle) const;
  void setRotation(const ZAngle yaw, const ZAngle pitch, const ZAngle roll);
  void getRotation(ZAngle& yaw, ZAngle& pitch, ZAngle& roll) const;
  // use rotate instead of setRotation to care scale and translation
  void rotate(const core::eAxis axis, const ZAngle angle);
  void rotate(const ZVector& axis, const ZAngle angle, const ZPoint3D* pBase = NULL);
  void rotate(const ZAngle yaw, const ZAngle pitch, const ZAngle roll);
  void setScale(const core::eAxis axis, const float value);
  void getScale(const core::eAxis axis, float& value) const;
  void setScale(const float xScale, const float yScale, const float zScale, bool bTrans = false);
  void setFromToUp(const ZPoint3D& from, const ZPoint3D& to, const ZVector& up);
  void setProjection(const ZAngle fFOV, const float fAspect, const float fNearPlane, const float fFarPlane);
  void invert3();  //as 3x3
  void invert();   //as 4x4
  // applies to the world*view*projection matrix to convert
  // 3D point to the screen coordinates.
  ZPoint convertToScreen(ZPoint3D& point, ZRect& rectViewport);
private:
  //
  // data members
  //
  union
  {
    float m[16];
    struct
    {
      float m00, m01, m02, m03;
      float m10, m11, m12, m13;
      float m20, m21, m22, m23;
      float m30, m31, m32, m33;
    };
  };
};


typedef ZSequence<ZMatrix>  ZMatrixSeq;


#endif //zmatrix_h_included

