/*****************************************************************************
 * $Id: eng_poly16.hh,v 1.18 2006/08/03 02:17:21 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Semi-deprecated 16-bit polygon data struct.
 *//*
 * LEGAL:	COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#ifndef ENG_POLY16_HH
#define ENG_POLY16_HH 1

/// @brief A Poly16 list is an array of 16-bit elements.
typedef uint16 Poly16;

////////////////////////////////////////////////////////////////////////////////
// Figurative variable-length structure of a polygon defined as Poly16 elements.
// struct Poly16Polygon
// {                        present?           elements:  desc:
//   Poly16 mHeader;        always             1          a combination of POLY16_* bits
//   Poly16 mColor[1|2];    always             1 or 2     either a 16-bit colormap index or a 4-byte RGBA
//   Poly16 mTexture[0|1];  if POLY16_TEXTURE  0 or 1     index within a Poly16tex array
//   Poly16 mVix[>=1];      always             >=1        terminated by last vix with POLY16_END bit set
// };

////////////////////////////////////////////////////////////////////////////////
// 4-byte RGBA packed into two 16-bits elements:
//
// Poly16[2] = { (red|green<<8), (blue|alpha<<8) }
//
// For portability, when defining a Poly16 array, use the POLY16_RGBA32 macro.
// Use POLY16_RGBA32_UNPACK() to unpack it.
// Otherwise, endian problems will result (casting Poly16[2] as uint*).

#define POLY16_RGBA32( R, G, B, A )    (R)|((G)<<8), (B)|((A)<<8)

#if ENG_POLY16_CC
static inline void
POLY16_RGBA32_UNPACK( uint8 rgba32[4], const Poly16 poly16[], uint idx )
{
	rgba32[0] =  poly16[idx]   & 0xff;			// r
	rgba32[1] = (poly16[idx]   & 0xff00) >> 8;	// g
	rgba32[2] =  poly16[idx+1] & 0xff;			// b
	rgba32[3] = (poly16[idx+1] & 0xff00) >> 8;	// a
}
#endif

// These are the only field offsets that are constant.
#define POLY16_IDX_HEADER	0
#define POLY16_IDX_COLOR	1

// Poly16 bits in the header and vix fields.
// Implied Poly16 bits:
// - POLY16_SOLID  if ! POLY16_WIREFRAME
// - POLY16_RGBA32 if ! POLY16_COLORMAP
// - POLY16_CULL   if ! POLY16_NO_CULL
#define POLY16_LIST_END			(1<<15) // 15 too	// this bit will be set in header
#define POLY16_END				(1<<15) // 15 too	// the last vix will have this bit set
#define POLY16_ESC				(1<<14)				// if set, a second 16-bit header field follows (future expansion)
#define POLY16_COLORMAP			(1<<13)
#define POLY16_WIREFRAME		(1<<12)
#define POLY16_TRANSLUCENT		(1<<11)
#define POLY16_NO_CULL			(1<<10)
#define POLY16_TEXTURE			(1<< 9)

/// @struct Poly16tex
/// @brief Struct for the texture of a Poly16.
/// An array can be constructed and referenced by the texture field in the Poly16 list.
#define POLY16TEX_MAX_COORDS	MAX_POLYGON_VERTEXS
#define POLY16TEX_END_COORD		(99999.0)		// terminates mCoords[]
struct Poly16tex
{
//PREVENT_COPYING(Poly16tex) // prevents static arrays
	const char*		mTextureName;
	const TexCoord2	mCoords[4+1];		// ought to be unspecified length, mCoords[], but g++ won't accept
};

// -----------------------------------------------------------------------------
// public functions:

class PolygonList;
void
PolygonListFromPoly16( PolygonList&           polygonList,
                       const Poly16* const    poly16,
                       const uint             poly16Elems,
                       const Poly16tex* const poly16tex,
                       const uint             poly16texElems,
                       const fp* const        colormapRGBA = NULL,
                       const uint             colormapRGBAElems = 0 );

void
Poly16VixRenumber( const uint base, const uint offs, Poly16* const poly16, const uint poly16Elems );

// -----------------------------------------------------------------------------
// private functions:

#if ENG_POLY16_CC

// Poly16idx*() return indexes within a Poly16 array.
// These field-parsing functions are built over one another in a relative way.

/*****************************************************************************
 * @return Index after the RGBA field.
 * @param	poly16
 *			Base of Poly16 array.
 * @param	idx
 *			Index of header.
 *****************************************************************************/
static inline uint
Poly16idxPastRgba( const Poly16 poly16[], uint idx )
{
	const Poly16 header = poly16[idx];
	++idx;						// skip header field
	if ( header & POLY16_COLORMAP )
		return idx + 1;			// skip colormap index
	else
		return idx + 2;			// skip 4-byte/32-bit RGBA (two 16-bit Poly16 elems)
}

/*****************************************************************************
 * @return Index after the texture index field.
 * OK to call whether or not a texture index field is present.
 * @param	poly16
 *			Base of Poly16 array.
 * @param	idx
 *			Index of header.
 *****************************************************************************/
static inline uint
Poly16idxPastTexture( const Poly16 poly16[], uint idx )
{
	const Poly16 header = poly16[idx];
	idx = Poly16idxPastRgba( poly16, idx );	// past preceding RGBA field
	if ( header & POLY16_TEXTURE )
		return idx + 1;						// texture field is present, skip it
	else
		return idx;							// no texture field
}

/*****************************************************************************
 * @return Index to the texture index field.
 * @pre POLY16_TEXTURE is set.
 * @param	poly16
 *			Base of Poly16 array.
 * @param	idx
 *			Index of header.
 *****************************************************************************/
static inline uint
Poly16idxTexture( const Poly16 poly16[], uint idx )
{
ASSERT( poly16[idx] & POLY16_TEXTURE );
	return Poly16idxPastRgba( poly16, idx );
}

/*****************************************************************************
 * @return Index to beginning of vertex index (vix) array.
 * @param	poly16
 *			Base of Poly16 array.
 * @param	idx
 *			Index of header.
 *****************************************************************************/
static inline uint
Poly16idxVixArray( const Poly16 poly16[], uint idx )
{
	return Poly16idxPastTexture( poly16, idx );
}

/*****************************************************************************
 * @return Count of vertex indexs in a polygon (equals vertex count).
 * @param	poly16
 *			Base of Poly16 array.
 * @param	idxVixArray
 *			Index of vix array.
 * @param	poly16Elems
 *			Amount of elements, not sizeof(), use ELEMS() macro.
 *****************************************************************************/
static inline uint
Poly16VixCnt( const Poly16 poly16[], uint idxVixArray, uint poly16Elems )
{
	// For each vertex in this polygon.  The last vix has POLY16_END bit set.
	uint cnt = 0; uint& idx = idxVixArray;
	do
	{
		++cnt; ++idx;
		ASSERT( cnt < MAX_POLYGON_VERTEXS );
		ASSERT( idx < poly16Elems );
	}
	while ( ! (poly16[idx] & POLY16_END) );
	return ++cnt;
}

#endif // ENG_POLY16_CC

// -----------------------------------------------------------------------------

#endif // ENG_POLY16_HH
