/*****************************************************************************
 * $Id: eng_class.cc,v 1.29 2006/11/15 18:28:05 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Engine classes that serve as the engine's interface.
 *//*
 * LEGAL:   COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#define ENG_CLASS_CC 1
#include "eng.hh"
#include "eng_class.hh"
#include "eng_sort.hh"

////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////  Engine  /////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*****************************************************************************
 * Constructor/destructor.
 *****************************************************************************/
Engine::Engine( void )
:	mCacheWorldVertex( DEFAULT_ENGINE_CACHE_SIZE, Cache<WorldVertex>::ARRAY ),  // interim size
    mCacheNormals(     DEFAULT_ENGINE_CACHE_SIZE, Cache<Normal>::ARRAY )        // interim size
{
	// NOP
}
Engine::CheckBadCompiler::CheckBadCompiler( void )
{
#if GCC29
	// Why is this here instead of at main()?
	// Because Engine is a static object and is what's affected by bad compiler.
	cerr << "ERROR: gcc 2.9 compiles bad code from C++ virtual base classes" << endl;
	exit(1);
#endif
}
Engine::~Engine()
{
	// NOP
}

/*****************************************************************************
 * Substitute for a constructor.
 * Initialization is split around processing of cmd-line args because
 * some members are assigned by cmd-line args.
 * @pre Must be called at run-time, not load-time (by static constructor).
 *****************************************************************************/
void
Engine::InitPreCmdarg( void )
{
    mReady              = false;
	mTestFrameRate		= false;
	mSeed				= 0;
    mAtExitCalled       = false;
	mBusy				= 0;
	mVerbose			= 0;
	mQuiet				= 0;
	mSpeed				= eSpeed_NORMAL;
	mCacheSize			= DEFAULT_ENGINE_CACHE_SIZE;  // interim size
	mCollisions			= true;
    mTextureFilterFunc  = DefaultTargaFilterFunc;
	mStreamStatus		= &cout;
	mBackgroundRGBA.Set( RGB_SKYBLUE, 0.0 );
	mFogRGBA.Set( 0.57, 0.62, 0.67, 1.0 );
	mFogDensity			= 0.5;
#if SPEED
	mFSAA				= true;  // if video hw supports full-screen antialiasing
#else
	mFSAA				= false;
#endif
	mPerspective		= ePerspective_NORMAL;
	mPerspectiveCompensation = 0.0;
}
void Engine::InitPostCmdarg( void )
{
	// Caches are resized afterwards at eng_init.cc.
	SetCurrent( &mEye );
}

/*****************************************************************************
 * Set verbose level.
 * @return Previous verbose level.
 *****************************************************************************/
int
Engine::SetVerbose( int verbose )
{
	int prev = mVerbose;
	mVerbose = verbose;
	return prev;
}

/*****************************************************************************
 * Support for changing gfxsys perspective/frustum.
 *****************************************************************************/
void
Engine::SetPerspective( ePerspective perspective )
{
	// mPerspectiveCompensation is necessary to adjust
	// the viewplane distance etc for different perspectives.

    // The World object determines frustum's far plane.
    // But the frustrum's near plane is more dependent
    // on the gfxsys and viewport.
    
    const fp frustumFar = gWorld.GetFrustumFar();

	switch ( perspective )
	{
		case ePerspective_NORMAL: default:
			mPerspective = ePerspective_NORMAL;
			mPerspectiveCompensation = WORLD(0.0);
		break;

		case ePerspective_NEAR:
			mPerspective = ePerspective_NEAR;
			mPerspectiveCompensation = WORLD(400.0);
		break;

		case ePerspective_FAR:
			mPerspective = ePerspective_FAR;
			mPerspectiveCompensation = WORLD(1000.0);
		break;
	}

    // GfxsysSetFrustum() calls Engine::GetPerspective().
	if ( GFXSYS_IF_READY() )
        GfxsysSetFrustum( frustumFar );
}
// Allow use to cycle thru different perspectives.
void
Engine::CyclePerspective( void )
{
	switch ( mPerspective )
	{
		case ePerspective_NORMAL:
			SetPerspective( ePerspective_NEAR );
		break;

		case ePerspective_NEAR:
			SetPerspective( ePerspective_FAR );
		break;

		case ePerspective_FAR:
			SetPerspective( ePerspective_NORMAL );
		break;
	}
}

/*****************************************************************************
 * Misc.
 *****************************************************************************/
void
Engine::EnableFog( bool enable )
{
	GFX_FOG( enable, GetFogDensity(), GetFogRGBA() );
}
