/*****************************************************************************
 * $Id: eng_view.hh,v 1.72 2006/10/27 03:16:50 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	View classes.
 * @verbatim
 *
 * A View object represents a viewport where the gfxsys renders into and
 * stores rendering state.  A viewport is a subdivision of the main window.
 * For example, the main view and radar are defined by separate View objects.
 *
 * ViewMain manages, contains, and switches View objects (besides managing its own viewport).
 * Some ViewMain methods/data can still be accessed regardless of the current view.
 * ViewMain can be rendered and is the main viewport (usually thru front cockpit).
 *
 * The rendering of View objects can be switched by calling ViewMain::Switch().
 * ViewMain::mCur points to the current View object to be rendered into.
 *
 * Don't confuse viewports and windows: viewports are contained inside the window.
 *
 * @endverbatim
 *//*
 * LEGAL:	COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#ifndef ENG_VIEW_HH
#define ENG_VIEW_HH 1

// View numbers are intended for non-View code.
#define VIEW_NUM()		(gEng.mView.GetViewNum())
#define	VIEWS_MAX		10

// Frame count initially begins at 1, not 0, to avoid problem of outside code
// determining if a per-frame calculation is needed by checking it agains a var
// that is usually 0 (initial calculation wouldn't be done).
// Outside could should initialize their frame count with FRAME_CNT_INVALID
// as another guard against this problem.
#define FRAME_CNT_INIT		1				// initial value of frame counts
#define FRAME_CNT_INVALID	(INT_LARGE)		// no frame count will ever equal this

class ViewMaster;

////////////////////////////////////////////////////////////////////////////////
/// @brief The View class holds the state of the renderer for a particular view.
/// @remarks This is contained privately by ViewMain.
class View
{
PREVENT_COPYING(View)
public:
	explicit		View( ViewMaster& viewMaster );
	virtual			~View( void ) { }
	virtual void	Reset( void ) = 0;
	virtual void	PreDraw( void );
	virtual void	Draw( void );
	virtual void	PostDraw( void );
	virtual void	Reshape( int w, int h ) = 0;
	virtual void	GrabFocus( void );
	uint			GetViewNum( void ) { return mViewNum; }
	void			SetVisi( bool f ) { mVisible = f; }
	void			SetViewportGeom( int x, int y, int w, int h );
	int				ViewportWidth( void ) { return mGeomViewport.w; }
	int				ViewportHeight( void ) { return mGeomViewport.h; }
	// GetViewFrameCnt():
	// Returns a per-view frame count starting at a per-view offset.
	// So for every view, it returns a different/unique value.
	// It's intended for outside code that needs to detect when
	// a view's frame changes or a frame is being rendered in a different view.
	//
	// GetTrueFrameCnt():
	// Returns a per-view frame count starting at 1.
	// Has limited usage.  An example is using it to compute FPS.
	//
	// GetAllFrameCnt():
	// Returns a total frame count in all views.
	uint			GetViewFrameCnt( void ) { return mViewFrameCnt; }
	uint			GetTrueFrameCnt( void ) { return mTrueFrameCnt; }
	uint			GetAllFrameCnt( void )  { return msAllFrameCnt; }
protected:
	void			ResetFrameCnt( void );
	void			IncFrameCnt( void ) { ++mViewFrameCnt; ++mTrueFrameCnt; } // inc per-view counts
public:
	virtual void	SetTexturing( bool f ) = 0;
	virtual bool	IfTexturing( void ) = 0;

public:
	ViewMaster&		mViewMaster;
	uint			mViewNum;
	uint			mRenderPass;		///< managed by DrawObjects()  0 = not rendering 1 = opaque pass 2 = blending pass
	Rect<int>		mRectTestViewport;	///< dedicated to TestViewport() (which is hi-freq)
protected:
	bool			mVisible;
	Geom<int>		mGeomViewport;		///< viewport geometry (not window) -- use SetViewportGeom() --
	int				mLocusX;			///< managed by DrawObjects()
	int				mLocusZ;			///< managed by DrawObjects()
	uint			mViewFrameCnt;		///< offset count of frames rendered in this view
	uint			mTrueFrameCnt;		///< true   count of frames rendered in this view
	static uint		msAllFrameCnt;		///< count of frames rendered in all views
	static uint		msViewCnt;			///< strictly for enumerating views, not for "for" loops
friend class ViewMaster;
};
#if DEBUG
typedef       SafePtr<View> ViewPtr;
typedef const SafePtr<View> ViewPtrConst;
#else
typedef View*       ViewPtr;
typedef View* const ViewPtrConst;
#endif

////////////////////////////////////////////////////////////////////////////////
/// @brief The ViewMaster class.
/// @remarks It contains and coordinates View objects.
class ViewMaster
{
PREVENT_COPYING(ViewMaster)
public:
					ViewMaster( void );
	virtual			~ViewMaster() { }
	void			AddView( ViewPtrConst view );
	void			AddViewPrimary( ViewPtrConst view );
	void			Reset( void );
	void			ResetFrames( void );
	void			DrawViews( void );
	void			Reshape( int w, int h );
	void			SwitchFocus( ViewPtrConst view );
	void			PreFrame( void );
	void			PostFrame( void );
	void			SetFreeze( bool f ) { mFreeze = f; }
	void			ToggleFreeze( void ) { mFreeze = ! mFreeze; }
	bool			IfFreeze( void ) { return mFreeze; }
	void			UpdateFPS( void );
	int				GetFPS( void ) { return mFPS; }
	int				GetWidth( void ) { return mGeom.w; }
	int				GetHeight( void ) { return mGeom.h; }
	void			SetGeom( int w, int h ) { mGeom.Set( 0, 0, w, h ); }
	const Geom<int>& GetGeom( void ) { return mGeom; }
	bool			IfBusy( void ) { return mBusyRendering; }
	void			PostRedisplayInput( void ) { ++mRedisplayInput; } ///< if keyboard/joystick caused transformation of an object
	void			ResetRedisplayInput( void ) { mRedisplayInput = 0; }
	bool			IfRedisplayInput( void ) { return mRedisplayInput > 0; }

	// Pass-thrus to current View object:
	bool			IfTexturing( void )	{ return mCur->IfTexturing(); }
	uint			GetViewNum( void )	{ return mCur->GetViewNum(); }
	const Rect<int>& GetRectTestViewport( void ) { return mCur->mRectTestViewport; }
	uint			GetRenderPass( void )		{ return mCur->mRenderPass; }
public:
	// See comments in View class:
    // Check NULL as these are called early in startup before any View exists.
	uint			GetViewFrameCnt( void )		{ return mCur != NULL ? mCur->GetViewFrameCnt() : FRAME_CNT_INIT; }
	uint			GetTrueFrameCnt( void )		{ return mCur != NULL ? mCur->GetTrueFrameCnt() : FRAME_CNT_INIT; }
	uint			GetAllFrameCnt( void )		{ return mCur != NULL ? mCur->GetAllFrameCnt()  : FRAME_CNT_INIT; }

public:
	ViewPtr 			mCur;				///< current View object (being rendered into)

private:
	bool				mReshaped;			///< true when geometry was reshaped (set)
	int					mBusyRendering;		///< true if busy rendering
	bool				mFreeze;			///< "pause" reserved for UNIX syscall
	Geom<int>			mGeom;				///< window/viewport geometry
    typedef std::list<ViewPtr>::iterator ViewItr;
	std::list<ViewPtr>  mViews; 			///< be careful as mViews[0] = ViewMain object
	ViewPtr 			mViewPrimary;
	int					mRedisplayInput;	///< if keyboard/joystick caused transformation of an object
	void				ResetFPS( void );
	int					mFPS;
	int					mFPSMilsecCountdown;
	int					mFPSPrevFrameCnt;
};

#endif // ENG_VIEW_HH
