/*****************************************************************************
 * $Id: eng_funcs2.hh,v 1.30 2006/08/01 23:14:02 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Various small functions: function macros, inline functions, template functions.
 * @remarks	This .hh file is one of the last to be #included which is suited
 *          to macros that depend on prior declarations.
 *          Writing "inline" in template functions does increase speed (gcc 3.4).
 *//*
 * LEGAL:	COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#ifndef ENG_FUNCS2_HH
#define ENG_FUNCS2_HH 1

////////////////////////////////////////////////////////////////////////////////
/////////////////////////// function macros ////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*****************************************************************************
 * To be used in an Object method.
 * Do visibility tests, return if object's width in pixels is too small.
 *****************************************************************************/
#define OBJECT_RETURN_IF_TOO_SMALL( PIXELS ) if ( Visible() < (PIXELS) ) return;

////////////////////////////////////////////////////////////////////////////////
/////////////////////////// inline functions ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*****************************************************************************
 * Vertex transformation: local --> world
 *****************************************************************************/
// Transform one vertex.
template<typename MATRIX>
inline void
TRANSFORM_VERTEX( WorldVertex& wv, const LocalVertex& lv, const MATRIX& m )
{
	RotTrans( wv, lv, m );
}
// Transform an array of vertexs.
template<typename MATRIX>
inline void
TRANSFORM_VERTEX( WorldVertex* wv, const LocalVertex* lv, const uint vcnt, const MATRIX& m )
{
ASSERT( vcnt > 0 && vcnt < MAX_VERTEXS );
	for ( uint i = 0; i < vcnt; ++i )
	{
CHECK_TYPESIG( &wv[i], TYPESIG_LIB_VERTEX_WORLD );
		TRANSFORM_VERTEX( wv[i], lv[i], m );
	}
}

/*****************************************************************************
 * Vertex transformation: world --> eye
 *****************************************************************************/
// Transform one vertex.
static inline void
TRANSFORM_VERTEX( EyeVertex& ev, const WorldVertex& wv )
{
	gEng.TransformVertex( ev, wv );
}
// Submit transformed vertex to gfxsys (hence the GFX_ prefix).
static inline void
GFX_TRANSFORM_VERTEX( const WorldVertex& wv )
{
	EyeVertex ev;
	gEng.TransformVertex( ev, wv );
	GFX_VERTEXV( &ev );
}
// Transform an array of vertexs.
static inline void
TRANSFORM_VERTEX( EyeVertex* ev, const WorldVertex* wv, const uint vcnt )
{
ASSERT( vcnt > 0 && vcnt < MAX_VERTEXS );
	for ( uint i = 0; i < vcnt; ++i )
	{
CHECK_TYPESIG( &wv[i], TYPESIG_LIB_VERTEX_WORLD );
CHECK_TYPESIG( &ev[i], TYPESIG_LIB_VERTEX_EYE );
		TRANSFORM_VERTEX( ev[i], wv[i] );
	}
}
// Transform the Z coord.
// Useful for testing if an object is facing by calculating only eye Z.
static inline fp
TRANSFORM_Z( const WorldVertex& wv )
{
	return gEng.TransformZ( wv );
}

/*****************************************************************************
 * Transform an array of vertex: local --> world --> eye
 * @param	ve
 * @param	lv
 * @param	vcnt
 * @param	matrixWorldEye
 *			Matrix that maps local coordinates all the way to the eye coordinates.
 *          This is the product of matrix multiplication of a Dyna matrix and Eye matrix.
 *****************************************************************************/
template<typename MATRIX>
inline void
TRANSFORM_VERTEX( EyeVertex* ev, const LocalVertex* lv, const uint vcnt, const MATRIX& matrixWorldEye )
{
ASSERT( vcnt > 0 && vcnt < MAX_VERTEXS );
	for ( uint i = 0; i < vcnt; ++i )
	{
CHECK_TYPESIG( &ev[i], TYPESIG_LIB_VERTEX_EYE );
		RotTrans( ev[i], lv[i], matrixWorldEye );
	}
}

////////////////////////////////////////////////////////////////////////////////
///////////////////////// template functions ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*****************************************************************************
 * Call the Animate() method of every object in a list.
 * Returns the accumulation of every Animate() method, ie, true if redisplay needed.
 * @param	dlist
 *****************************************************************************/
template<typename T>
int
AnimateList( const Dlist<T>& dlist )
{
CHECK_TYPESIG( &dlist, TYPESIG_LIB_DLIST );
 
	int redisplay = 0;

	// Using a sentinel in the list (it isn't NULL-terminated).
	for ( const Dlink<T>* dlink = dlist.ForStart(); dlist.ForTest(dlink); dlist.ForNext(dlink) )
	{
CHECK_TYPESIG( dlink, TYPESIG_LIB_DLINK );
		T* object = dlink->mObj;
CHECK_TYPESIG( object, TYPESIG_OBJECT );
		redisplay |= object->Animate();
	}
	return redisplay;
}

/*****************************************************************************
 * Draw Objects in a list.
 *****************************************************************************/
template<typename T>
void
DrawObjectList( const Dlist<T>& dlist )
{
CHECK_TYPESIG( &dlist, TYPESIG_LIB_DLIST );
	for ( const Dlink<T>* dlink = dlist.ForStart(); dlist.ForTest(dlink); dlist.ForNext(dlink) )
	{
CHECK_TYPESIG( dlink, TYPESIG_LIB_DLINK );
CHECK_TYPESIG( dlink->mObj, TYPESIG_OBJECT );
		Object* object = dlink->mObj;
		object->Draw();
	}
}

#endif // ENG_FUNCS2_HH
