/*****************************************************************************
 * $Id: gfx_rgb.hh,v 1.42 2006/11/25 17:11:33 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	RGB color definitions.
 *//*
 * LEGAL:	COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#ifndef GFX_RGB_HH
#define GFX_RGB_HH 1

namespace gfx {

// Index to bytes of RGBA object.
// In OpenGL contenxt, RGBA byte-order is independent of CPU endianness.
// Eg, OpenGL glColor4ubv() always expects red at GLubyte[0].
enum { RR, GG, BB, AA };

#define RGBA_LEN	4
#define RGBA8_LEN	4
#define BGRA_LEN	4
#define BGRA8_LEN	4

////////////////////////////////////////////////////////////////////////////////
/// @brief RGBA class.  Based on uint8[4].  Can output/convert to fp[4].
///
class RGBA
{
public:
	RGBA( void )
	{
		*reinterpret_cast<uint32*>( mRgba ) = 0;
	}
	explicit RGBA( const uint8 rgba[4] )
	{
		// rgba[4] input is implicity clamped to a byte.
		*reinterpret_cast<uint32*>( mRgba ) = *reinterpret_cast<const uint32*>( rgba );
	}
	explicit RGBA( const fp rgba[4] )
	{
		Set( rgba[RR], rgba[GG], rgba[BB], rgba[AA] );
	}
	RGBA( int r, int g, int b, int a )
	{
		Set( r, g, b, a );
	}
	RGBA( fp r, fp g, fp b, fp a )
	{
		Set( r, g, b, a );
	}
	RGBA( const RGBA& src ) // copy constructor
	{
		*reinterpret_cast<uint32*>( mRgba ) = *reinterpret_cast<const uint32*>( src.mRgba );
	}
	void Set( const uint8 rgba[4] )
	{
		*reinterpret_cast<uint32*>( mRgba ) = *reinterpret_cast<const uint32*>( rgba );
	}
	void Set( int r, int g, int b, int a )
	{
		mRgba[RR] = ClampFF( r );
		mRgba[GG] = ClampFF( g );
		mRgba[BB] = ClampFF( b );
		mRgba[AA] = ClampFF( a );
	}
	void Set( fp r, fp g, fp b, fp a )
	{
		mRgba[RR] = ClampFF( uint(r * 256.0) );
		mRgba[GG] = ClampFF( uint(g * 256.0) );
		mRgba[BB] = ClampFF( uint(b * 256.0) );
		mRgba[AA] = ClampFF( uint(a * 256.0) );
	}
	void Set( int same )
	{
		mRgba[RR] = mRgba[GG] = mRgba[BB] = mRgba[AA] = same;
	}
	const uint8* Get( void ) const
	{
		return mRgba;
	}
	// RGBA object --> fp[4] (rare).
	void Get4f( fp out[4]/*OUT*/ ) const
	{
		out[RR] = mRgba[RR] / 256.0;
		out[GG] = mRgba[GG] / 256.0;
		out[BB] = mRgba[BB] / 256.0;
		out[AA] = mRgba[AA] / 256.0;
	}
	// RGBA object --> uint[4]
	void Get4ub( uint8 out[4]/*OUT*/ ) const
	{
		*reinterpret_cast<uint32*>( out ) = *reinterpret_cast<const uint32*>( mRgba );
	}
	RGBA& operator=( const RGBA& src )
	{
		*reinterpret_cast<uint32*>( mRgba ) = *reinterpret_cast<const uint32*>( src.mRgba );
		return *this;
	}
	bool operator==( const RGBA& src ) const
	{
		return *reinterpret_cast<const uint32*>( mRgba ) == *reinterpret_cast<const uint32*>( src.mRgba );
	}
	bool LessThan( const RGBA& src ) const
	{
		return *reinterpret_cast<const uint32*>( mRgba ) < *reinterpret_cast<const uint32*>( src.mRgba );
	}
	uint8& operator[]( uint i )
	{
		ASSERT2( i < 4 );
		return mRgba[i];
	}
	const uint8& operator[]( uint i ) const	// compiled when object is const
	{
		ASSERT2( i < 4 );
		return mRgba[i];
	}
	bool IfZero( void ) const
	{
		return *reinterpret_cast<const uint32*>( mRgba ) == 0;
	}

private:
	uint8	mRgba[4];
};

/*****************************************************************************
 * operator<() as a function (for STL).
 * FYI: operator<() as a class method doesn't work with STL.
 *****************************************************************************/
static inline bool
operator<( const RGBA src1, const RGBA src2 )
{
	// Call class method which can access private members.
	return src1.LessThan( src2 );
}

/*****************************************************************************
 * operator<<()
 *****************************************************************************/
static inline ostream&
operator<<( ostream& strm, const RGBA rgba )
{
	ios::fmtflags savedFlags = strm.flags();
    strm << '('
         << GFX_OMANIP_FIELD(4) << uint(rgba[RR]) << ','  // print numbers, not chars
         << GFX_OMANIP_FIELD(4) << uint(rgba[GG]) << ','  // (uint8 is uchar)
         << GFX_OMANIP_FIELD(4) << uint(rgba[BB]) << ','
         << GFX_OMANIP_FIELD(4) << uint(rgba[AA]) << ')';
	strm.flags(savedFlags);
	return strm;
}

////////////////////////////////////////////////////////////////////////////////

#define RGB_BROWN		0.7,	0.35,	0.2
#define RGB_GRAY		0.55,	0.55,	0.55
#define RGB_GREEN		0.05,	0.9,	0.05
#define RGB_DARK_GREEN	0.05,	0.5,	0.05
#define RGB_DARK_GREEN2	0.05,	0.45,	0.05
#define RGB_PURPLE		0.6,	0.1,	0.6
#define RGB_RED			0.8,	0.1,	0.1
#define RGB_BLUE		0.1,	0.1,	0.8
#define RGB_SKYBLUE		0.2,	0.6,	0.99
#define RGB_SHADOW		0.35,	0.35,	0.35
#define RGB_WHITE		0.95,	0.95,	0.95
#define RGB_YELLOW		1.0,    1.0,    0.0

} // namespace gfx

#endif // GFX_RGB_HH
