/*****************************************************************************
 * $Id: eng_eye.hh,v 1.98 2006/10/25 02:24:10 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Eye (viewpoint) class.
 *//*
 * LEGAL:	COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#ifndef ENG_EYE_HH
#define ENG_EYE_HH 1

#include "eng_dyna.hh"

class EyeState;

////////////////////////////////////////////////////////////////////////////////
/// @class Eye
/// @brief Eye/viewpoint class.
/// The offsets in (origin of) the eye's matrix are negative (m[Ox,Oy,Oz]).
///
class Eye : public ObjectData, public Dyna
{
PREVENT_COPYING(Eye)
private:	typedef Dyna Parent;
public:						Eye( void );
public:						~Eye() { }
public:		void			FinalConstruction( void ) { }
public:		void			Draw( void ) { }  ///< (inherently drawn)
public:		const string	GetName( void ) { return string("Eye"); }
public:		void			Init( QuadrantPtrConst q, const Position& pos );
public:		void			Reset( void );
public:		void			Save( EyeState& state );
public:		void			Switch( EyeState& incoming, EyeState& outgoing );
public:		void			Rotate( uint axis, Degree deg );
public:		void			Translate( uint axis, fp inc ) { Translate( axis, inc, false ); }
public:		void			Translate( uint axis, fp inc, bool byChasePlane );
public:		void			LoadMatrix( const MatrixExt& xm );
public:		void			Fence( void );
public:		int				Animate( void );
/// True if eye is above "alt".  Eye offsets are negative.
public:		bool			IfAboveAltitude( fp alt ) { return -mCm[Oy] > alt; } 
public:		bool			IsRecalcNeeded( EyeVertex& prevEye/*IN/OUT*/, fp distThreshold );
public:		void			SetOrigin( uint Oxyz, fp coord );	
public:		Position		GetPosition( void )
			{
				// Eye matrix origin is negative.
				// Don't use ABS() as Fence() looks for sign change.
				return Position( -mXm[Ox], -mXm[Oy], -mXm[Oz] );
			}
// Position arg should have positive values.
public:		void			SetPosition( const Position& pos )
			{
				ASSERT( pos.x >= 0 && pos.y >= 0 && pos.z >= 0 );
				// Eye matrix origin is negative.
				mXm[Ox] = -pos.x;
				mXm[Oy] = -pos.y;
				mXm[Oz] = -pos.z;
				SyncMatrix();
			}
/// @return World vertex from eye vertex (reverse transformation thru transpose matrix).
public:     WorldVertex     ReverseTransformVertex( const EyeVertex& ev )
            {
                return TransformVertex<WorldVertex,EyeVertex,MatrixExt>( ev, mXmTranspose );
            }
/// Update single-precision matrix after extended-precision one is modified
/// And update transpose matrix.
private:	void        	SyncMatrix( void )
			{
				mChanged = true;
			#if ! SPEED
				CopyMatrix( mSm, mXm );
			#endif
                TransposeMatrix( mXmTranspose, mXm );
			}
/// Billboard needs the accumulated degree of roll.
public:     Degree          GetRollDeg( void ) const { return mRollDeg; }
public:		Bool			mInitialized;
public:		Bool			mChanged;
public:		enum eEyeMode	{ eEyeMode_PAN, eEyeMode_FLIGHT, eEyeMode_DEFAULT = eEyeMode_PAN };
public:		eEyeMode		mEyeMode;
private:	MatrixExt		mXmOrig;
private:    MatrixExt       mXmTranspose;  // maps eye vertexs back to world vertexs
private:    Degree          mRollDeg;      // for billboard only
};

////////////////////////////////////////////////////////////////////////////////
/// @brief Opaque structure used for switching views.
/// @remarks There is only one Eye object (for performance reasons).
/// The eye's matrix and few other members are changed during a view switch,
/// but most of the Eye members are left unchanged.  This approach of using an opaque struct
/// and changing a few members was chosen over using an Eye copy constructor to copy state
/// (the latter would be a disruptive and hard-to-maintain change as the Dyna/Object base classes
/// would need copy constructors, and worse, would require dangerous memberwise copying).
///
class EyeState
{
PREVENT_COPYING(EyeState)
public:		// no public members (opaque)
private:	MatrixExt		mXm;
private:	Eye::eEyeMode	mEyeMode;
friend class Eye;
};

#endif // ENG_EYE_HH
