// -*- C++ -*-
#ifndef RIAFFINETMATRIX2_H
#define RIAFFINETMATRIX2_H
/* Copyright 1998 
 * Thu Jul 29 16:09:32 1999  Brian Smits  (bes@phoenix.cs.utah.edu)
 * 
 * RiAffineTMatrix2.H
 * 
 *	
 * 
 * $Id: RiAffineTMatrix2.H,v 1.1 1999/10/01 18:39:02 bes Exp $ 
 * 
 */
#ifndef RICOMMON_H
#include <RiCommon.H>
#endif//

#ifndef RIVECTOR2_H
#include <RiVector2.H>
#endif

class RiTMatrix2Factory;


/***************************************************************
CLASS
    RiAffineTMatrix2
    An abstract class that represents a homegeneous transform
    matrix and its inverse.

DESCRIPTION
    This class is the base class for all transforms.  It uses
    column vectors and right-multiplication, so vnew = M*vold.
    Individual entries are gotten via the getData() member,
    which takes two indices and has the following pattern for
    rows and colums- getData(row,col):
           | 00 01 02 |
           | 10 11 12 |
           | 20 21 22 |
    For affine transforms, row 2 is implictly 0 0 1.
    There are three types of transforms for three types of
    data: locations, directions, and normals.  These get
    more efficient for more and more specific vector types.

WARNING
    RiAffineTMatrix2 currently stores 24 floats, so something such as a compact
    translate matrix cannot be derived effectively.
****************************************************************/


class RiAffineTMatrix2 {
public:
				////
    friend RiTMatrix2Factory;
				////
    RiAffineTMatrix2();
				//// changes a location (point)
    RiVector2 ApplyLocation( const RiVector2& v ) const;
				//// changes a direction (offset)
    RiVector2 ApplyDirection( const RiVector2& v ) const;
				//// changes a perpendicular (offset)
    RiVector2 ApplyNormal( const RiVector2& v ) const;

				//// changes a location (point)
    RiVector2 ApplyInverseLocation( const RiVector2& v ) const;
				//// changes a direction (offset)
    RiVector2 ApplyInverseDirection( const RiVector2& v ) const;
				//// changes a perpendicular (offset)
    RiVector2 ApplyInverseNormal( const RiVector2& v ) const;
				////
    RiAffineTMatrix2 operator*( const RiAffineTMatrix2& ) const;
				////
    RiReal GetData( int row, int col ) const;
private:
				////
    RiReal data[2][3];
				////
    RiReal idata[2][3];

};

ostream &operator<<(ostream &os, const RiAffineTMatrix2 &m);


inline RiAffineTMatrix2::RiAffineTMatrix2() {
#ifndef NDEBUG
    data[0][0] = data[0][1] = data[0][2] = RI_NAN;
    data[1][0] = data[1][1] = data[1][2] = RI_NAN;
#endif
}

// we must assume that the homogeneous coordinate gets changed.
// the homogeneous coordinate of v is assumed to be one.
inline RiVector2 RiAffineTMatrix2::ApplyLocation( const RiVector2& v ) const
{
    return RiVector2(data[0][0]*v[0] + data[0][1]*v[1] + data[0][2],
		     data[1][0]*v[0] + data[1][1]*v[1] + data[1][2]);
}

// we must assume that the homogeneous coordinate gets changed.
// the homogeneous coordinate of v is assumed to be zero.
inline RiVector2 RiAffineTMatrix2::ApplyDirection( const RiVector2& v ) const
{
    return RiVector2(data[0][0]*v[0] + data[0][1]*v[1],
		     data[1][0]*v[0] + data[1][1]*v[1]);
}

// normal vectors transform differently.  While tangent and
// other vectors transform as v' = Mv, normal vectors transform
// as v' = M'v where M' is the transpose of the inverse of M.
// See the OpenGL Programming Guide p 477 for a proof.
inline RiVector2 RiAffineTMatrix2::ApplyNormal( const RiVector2& v ) const
{
    return RiVector2(idata[0][0]*v[0] + idata[1][0]*v[1],
		     idata[0][1]*v[0] + idata[1][1]*v[1]);
}

inline RiVector2 RiAffineTMatrix2::ApplyInverseLocation( const RiVector2& v ) const
{
    return RiVector2(idata[0][0]*v[0] + idata[0][1]*v[1] + idata[0][2],
		     idata[1][0]*v[0] + idata[1][1]*v[1] + idata[1][2]);
}

inline RiVector2 RiAffineTMatrix2::ApplyInverseDirection( const RiVector2& v ) const
{
    return RiVector2(idata[0][0]*v[0] + idata[0][1]*v[1],
		     idata[1][0]*v[0] + idata[1][1]*v[1]);
}

inline RiVector2 RiAffineTMatrix2::ApplyInverseNormal( const RiVector2& v ) const
{
    return RiVector2(data[0][0]*v[0] + data[1][0]*v[1],
		     data[0][1]*v[0] + data[1][1]*v[1]);
}


#endif /* RIAFFINETMATRIX2_H */

