/*****************************************************************************
 * $Id: gfx_types.hh,v 1.108 2006/08/15 01:50:43 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Basic types.
 *//*
 * LEGAL:	COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#ifndef GFX_TYPES_HH
#define GFX_TYPES_HH 1

namespace gfx {

// Basic types must be fast.  Virtual functions incur overhead from C++ vtable.
#define virtual VIRTUAL_METHODS_IN_BASIC_TYPES_IS_TOO_SLOW

////////////////////////////////////////////////////////////////////////////////
// Basic types.
//
// Historical note: typedef fp was conditionally defined as float/double/long double
// but the code now in fact depends on fp being single-precision float/GLfloat.
typedef unsigned char	Bool;	///< byte-sized bool ("BOOL" used in Win32)
typedef unsigned char	uchar;
#if defined(_WIN32)
// These should be defined by POSIX sys/types.h for SV compatibility.
// Redefining them here in this namespace would cause compile problems.
typedef unsigned short	ushort;
typedef unsigned int	uint;
#endif // _WIN32
#if GFXSYS_OPENGL
typedef GLbyte			int8;
typedef GLubyte			uint8;
typedef GLshort			int16;
typedef GLushort		uint16;
typedef GLint			int32;
typedef GLuint			uint32;
typedef GLfloat			fp;
#else
typedef char			int8;
typedef unsigned char	uint8;
typedef short			int16;
typedef unsigned short	uint16;
typedef int				int32;
typedef unsigned int	uint32;
typedef float			fp;
#endif
// fpx is extended-precision float.
// fpx is used to maximize accuracy while rotating a matrix.
// If fpx is compiled as single-precision, speed is gained but accuracy is lost.
#if SPEED
typedef fp fpx;
#else
typedef double fpx;			// for compile-time checks, fpx ordinarily shouldn't be the same as fp
//typedef long double fpx;
#endif

////////////////////////////////////////////////////////////////////////////////
/// @brief Vertex index ("vix").
typedef uint16 Vix;
typedef uint16 Nix;  // index of a normal vector

////////////////////////////////////////////////////////////////////////////////
/// @brief Light-weight fixed-length Array class with index-checking (if DEBUG2).
/// @remarks The size of the array makes its type distinct from other Arrays
/// of different sizes.
/// Tested by gfx/tests/basic_types.cc.
template<uint cnt, typename T=int>
class Array
{
public:
	typedef T type;

public:
	/// Template arg cnt implicitly defines the array's length.
	Array( void )
	{
		// NOP
	}

	/// Construct all elements with the same value.
	explicit Array( T val )
	{
		Fill( val );
	}

	/// Copy constructor.
	Array( const Array<cnt,T>& src )
	{
		*this = src;	// ok, operator=() doesn't free anything
	}

	// Copy constructor from a C array.
	// This syntax, which would be convenient, the compiler won't accept: Array<> = { };
	Array( const T src[] )
	{
		for ( uint i = 0; i < cnt; ++i )
			mArray[i] = src[i];			
	}

	/// @return Amount of elements.
	uint GetCnt( void ) const
	{
		return cnt;
	}

	/// Assign every element the same value.
	void Fill( T val )
	{
		for ( uint i = 0; i < cnt; ++i )
			mArray[i] = val;
	}

	/// Catching access to an uninitialized element
	/// would be ideal but there's no way to tell
	/// if the element is being read or written.
	T& operator[]( uint i )					// compiled unless Array is const
	{
		ASSERT2( i < cnt );
		return mArray[i];
	}

	const T& operator[]( uint i ) const		// compiled if Array is const
	{
		ASSERT2( i < cnt );
		return mArray[i];
	}

	/// Amazing that a C++ compiler will accept how this type is written.
	Array<cnt,T>& operator=( const Array<cnt,T>& src )
	{
		for ( uint i = 0; i < cnt; ++i )
			mArray[i] = src.mArray[i];	// assign
		return *this;
	}

	bool operator==( const Array<cnt,T>& src ) const
	{
		for ( uint i = 0; i < cnt; ++i )
			if ( mArray[i] != src.mArray[i] ) return false; // different
		return true; // all elements equal
	}

	bool operator!=( const Array<cnt,T>& src ) const
	{
		// Same as operator==() but retvals opposite.
		for ( uint i = 0; i < cnt; ++i )
			if ( mArray[i] != src.mArray[i] ) return true; // different
		return false; // all elements equal
	}

	bool operator<( const Array<cnt,T>& src ) const
	{
		for ( uint i = 0; i < cnt; ++i )
		{
			if ( mArray[i] < src.mArray[i] )
				return true;
			else if ( mArray[i] > src.mArray[i] )
				return false;
			// continue, at this point, only know a subset is equal
		}
		return false; // all elements equal
	}

private:
	T	mArray[cnt];
};

////////////////////////////////////////////////////////////////////////////////
/// @brief 2D vector (can also represent a 2D point).
struct Vector2
{
	Vector2( void )
	{
	}

	explicit Vector2( fp X, fp Y )
	: x(X), y(Y)
	{
	}

	explicit Vector2( const fp f[2] )
	: x(f[XX]), y(f[YY])
	{
	}

	void Set( fp X, fp Y )
	{
		x = X;
		y = Y;
	}

	void Set( const fp f[2] )
	{
		x = f[0];
		y = f[1];
	}

	bool operator==( const Vector2& src ) const				// equal
	{
		return x == src.x
            && y == src.y;
	}

	bool operator!=( const Vector2& src ) const				// not equal
	{
		return x != src.x
            || y != src.y;
	}

	// operatorX() and operatorX=() have the same code.

	Vector2& operator+( const Vector2& src )				// add
	{
		x += src.x;
		y += src.y;
		return *this;
	}

	Vector2& operator+=( const Vector2& src )				// add, assign
	{
		x += src.x;
		y += src.y;
		return *this;
	}

	Vector2& operator-( const Vector2& src )				// subtract
	{
		x -= src.x;
		y -= src.y;
		return *this;
	}

	Vector2& operator-=( const Vector2& src )				// subtract, assign
	{
		x -= src.x;
		y -= src.y;
		return *this;
	}

	Vector2& operator*( const Vector2& src )				// mult
	{
		x *= src.x;
		y *= src.y;
		return *this;
	}

	Vector2& operator*=( const Vector2& src )				// mult, assign
	{
		x *= src.x;
		y *= src.y;
		return *this;
	}

	fp operator[]( uint i )
	{
		ASSERT2( i <= 1 );
		return reinterpret_cast<fp*>(&x)[i];
	}

	fp operator[]( uint i ) const
	{
		ASSERT2( i <= 1 );
		return reinterpret_cast<const fp*>(&x)[i];
	}

	fp x;
	fp y;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief 3D vector (can also represent a 3D point).
///
/// The derived Vertex classes have this peculiar overloaded assignent operator:
///     Vertex& operator=( const Vector3& src )
/// in order for this to compile:
///     Vertex v1, v2, v3;
///     v3 = v1 + v2;
/// The subtlety is that v1 + v2 return a base object.  But doesn't cause an
/// immediate compile error, as the compiler looks for a matching assignment operator.
///
struct Vector3
{
	Vector3( void )
	{
	}

	explicit Vector3( fp X, fp Y, fp Z )
	: x(X), y(Y), z(Z)
	{
	}

	explicit Vector3( const fp f[3] )
	: x(f[XX]), y(f[YY]), z(f[ZZ])
	{
	}

	void Set( fp X, fp Y, fp Z )
	{
		x = X;
		y = Y;
		z = Z;
	}

	void Set( const fp f[3] )
	{
		x = f[0];
		y = f[1];
		z = f[2];
	}

#if 0 // DEPRECATED
	// To manipulate Vertex as fp[3] (checked by SelfCheck()).
	fp* GetFP( void )
	{
		return &x;
	}		
	const fp* GetFPc( void ) const
	{
		return &x;
	}
#endif

	bool operator==( const Vector3& src ) const				// equal
	{
		return x == src.x
            && y == src.y
            && z == src.z;
	}

	bool operator!=( const Vector3& src ) const				// not equal
	{
		return x != src.x
            || y != src.y
            || z != src.z;
	}

	// operatorX() and operatorX=() have the same code.

	Vector3& operator+( const Vector3& src )				// add
	{
		x += src.x;
		y += src.y;
		z += src.z;
		return *this;
	}

	Vector3& operator+=( const Vector3& src )				// add, assign
	{
		x += src.x;
		y += src.y;
		z += src.z;
		return *this;
	}

	Vector3& operator-( const Vector3& src )				// subtract
	{
		x -= src.x;
		y -= src.y;
		z -= src.z;
		return *this;
	}

	Vector3& operator-=( const Vector3& src )				// subtract, assign
	{
		x -= src.x;
		y -= src.y;
		z -= src.z;
		return *this;
	}

	Vector3& operator*( const Vector3& src )				// mult
	{
		x *= src.x;
		y *= src.y;
		z *= src.z;
		return *this;
	}

	Vector3& operator*=( const Vector3& src )				// mult, assign
	{
		x *= src.x;
		y *= src.y;
		z *= src.z;
		return *this;
	}

	fp operator[]( uint i )
	{
		ASSERT2( i <= 2 );
		return reinterpret_cast<fp*>(&x)[i];
	}

	fp operator[]( uint i ) const
	{
		ASSERT2( i <= 2 );
		return reinterpret_cast<const fp*>(&x)[i];
	}

	fp	x;
	fp	y;
	fp	z;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief 3D vertex in local coordinate space.
struct LocalVertex : public Vector3
{
	explicit LocalVertex( fp X, fp Y, fp Z )
	: Vector3(X,Y,Z)
	{
		SET_TYPESIG(this,TYPESIG_LIB_VERTEX_LOCAL);
	}

	explicit LocalVertex( const fp f[3] )  // conversion
	: Vector3(f)
    {
		SET_TYPESIG(this,TYPESIG_LIB_VERTEX_LOCAL);
	}

	LocalVertex& operator=( const Vector3& src )  // see Vector3 comments
	{
		x = src.x;
		y = src.y;
		z = src.z;
		return *this;
	}

	// Type signature must follow x/y/z as struct is cast as fp[3].
	DECL_TYPESIG_AUTO( LocalVertex, TYPESIG_LIB_VERTEX_LOCAL )
};

////////////////////////////////////////////////////////////////////////////////
/// @brief 3D vertex in world coordinate space.
struct WorldVertex : public Vector3
{
	explicit WorldVertex( fp X, fp Y, fp Z )
	: Vector3(X,Y,Z)
	{
		SET_TYPESIG(this,TYPESIG_LIB_VERTEX_WORLD);
	}

	explicit WorldVertex( const fp f[3] )  // conversion
	: Vector3(f)
    {
		SET_TYPESIG(this,TYPESIG_LIB_VERTEX_WORLD);
	}

	WorldVertex& operator=( const Vector3& src )  // see Vector3 comments
	{
		x = src.x;
		y = src.y;
		z = src.z;
		return *this;
	}

	// Type signature must be last as struct is cast as fp[3].
	DECL_TYPESIG_AUTO( WorldVertex, TYPESIG_LIB_VERTEX_WORLD )
};

////////////////////////////////////////////////////////////////////////////////
/// @brief Vertex in eye coordinate space.
struct EyeVertex : public Vector3
{
	explicit EyeVertex( fp X, fp Y, fp Z )
	: Vector3(X,Y,Z)
	{
		SET_TYPESIG(this,TYPESIG_LIB_VERTEX_EYE);
	}

	explicit EyeVertex( const fp f[3] )  // conversion
	: Vector3(f)
    {
		SET_TYPESIG(this,TYPESIG_LIB_VERTEX_EYE);
	}

	EyeVertex& operator=( const Vector3& src )  // see Vector3 comments
	{
		x = src.x;
		y = src.y;
		z = src.z;
		return *this;
	}

	// Type signature must be last as struct is cast as fp[3].
	DECL_TYPESIG_AUTO( EyeVertex, TYPESIG_LIB_VERTEX_EYE )
};

////////////////////////////////////////////////////////////////////////////////
/// @brief Vertex in normal space.
struct NormalVertex : public Vector3
{
	explicit NormalVertex( fp X, fp Y, fp Z )
	: Vector3(X,Y,Z)
	{
		SET_TYPESIG(this,TYPESIG_LIB_VERTEX_NORMAL);
	}

	explicit NormalVertex( const fp f[3] )  // conversion
	: Vector3(f)
    {
		SET_TYPESIG(this,TYPESIG_LIB_VERTEX_NORMAL);
	}

	NormalVertex& operator=( const Vector3& src )  // see Vector3 comments
	{
		x = src.x;
		y = src.y;
		z = src.z;
		return *this;
	}

	// Type signature must be last as struct is cast as fp[3].
	DECL_TYPESIG_AUTO( NormalVertex, TYPESIG_LIB_VERTEX_NORMAL )
};

/*****************************************************************************
 * operator<<(VERTEX)
 *****************************************************************************/
// Vector2.
static inline ostream&
operator<<( ostream& strm, const Vector2& v )
{
	ios::fmtflags savedFlags = strm.flags();
    strm << '('
         << GFX_OMANIP_FIELD(8) << v.x << ','
         << GFX_OMANIP_FIELD(8) << v.y << ')';
	strm.flags(savedFlags);
	return strm;
}
// Vector3 and derivations.
#define DEFINE_VERTEX_OPERATOR_OUT( VERTEX )					\
static inline ostream&											\
operator<<( ostream& strm, const VERTEX& v )					\
{																\
	ios::fmtflags savedFlags = strm.flags();					\
    strm << '('													\
         << GFX_OMANIP_FIELD(8) << v.x << ','					\
         << GFX_OMANIP_FIELD(8) << v.y << ','					\
         << GFX_OMANIP_FIELD(8) << v.z << ')';					\
	strm.flags(savedFlags);										\
	return strm;												\
}
DEFINE_VERTEX_OPERATOR_OUT(Vector3)
DEFINE_VERTEX_OPERATOR_OUT(LocalVertex)
DEFINE_VERTEX_OPERATOR_OUT(WorldVertex)
DEFINE_VERTEX_OPERATOR_OUT(EyeVertex)
DEFINE_VERTEX_OPERATOR_OUT(NormalVertex)

////////////////////////////////////////////////////////////////////////////////
/// @brief Element in an array of normal vectors.
struct Normal
{
	NormalVertex	mNorm;			// normal vector in normal coordinates (in normal space)
	Vix				mVixNormOrig;	// index into array of world vertexes of normal's origin

	DECL_TYPESIG_AUTO( Normal, TYPESIG_LIB_NORMAL )
};

////////////////////////////////////////////////////////////////////////////////
/// @brief Position.
/// @remarks The position of an object is in world space.
/// This typedef helps to distinguish an object's position vs. the world vertexs of its mesh.
typedef WorldVertex Position;

////////////////////////////////////////////////////////////////////////////////
/// @brief Position and radius.
/// @remarks Tested by gfx/tests/basic_types.cc.
class Posrad : public WorldVertex
{
private:
	typedef WorldVertex Parent;

public:
	Posrad( void )
	{
	}

	explicit Posrad( fp X, fp Y, fp Z, fp radius )
	{
		Set( X, Y, Z, radius );
	}

	explicit Posrad( const WorldVertex& pos, fp radius )
	{
		Set( pos.x, pos.y, pos.z, radius );
	}

	void Set( fp X, fp Y, fp Z, fp radius )
	{
		x = X;
		y = Y;
		z = Z;
		mRadius = radius;
	}

	bool operator==( const Posrad& src ) const
	{
		return x == src.x
            && y == src.y
            && z == src.z
            && mRadius == src.mRadius;
	}

	bool operator!=( const Posrad& src ) const
	{
		return x != src.x
            || y != src.y
            || z != src.z
            || mRadius != src.mRadius;
	}

public:
	fp		mRadius;
};

static inline ostream&
operator<<( ostream& strm, const Posrad& o )
{
	ios::fmtflags savedFlags = strm.flags();
    strm << '('
         << "pos=" << GFX_OMANIP_FIELD(0) << static_cast<WorldVertex>(o) << ','
         << "rad=" << GFX_OMANIP_FIELD(0) << o.mRadius << ')';
	strm.flags(savedFlags);
	return strm;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief 2D position.
template<typename T>
struct Pos2d
{
	Pos2d( void )
	{
	}

	explicit Pos2d( T X, T Y )
	{
		Set( X, Y );
	}

	void Set( T X, T Y )
	{
		x = X; y = Y;
	}

	T	x;
	T	y;
};

template<typename T>
ostream&
operator<<( ostream& strm, const Pos2d<T>& o )
{
	ios::fmtflags savedFlags = strm.flags();
    strm << '('
         << GFX_OMANIP_FIELD(0) << o.x << ','
         << GFX_OMANIP_FIELD(0) << o.y << ')';
	strm.flags(savedFlags);
	return strm;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief 2D rectangle.
/// @pre Assumes (X1,Y1) < (X2,Y2).
/// @remarks This assumption speeds/reduces the code.
/// Profiling revealed Rect is used very frequently.
/// Tested by gfx/tests/basic_types.cc.
template<typename T>
class Rect
{
public:
	Rect( void )
	{
		//x1 = y1 = x2 = y2 = 0;		// Rect is used in hi-freq code
	}

	explicit Rect( T X1, T Y1, T X2, T Y2 )
	{
		Set( X1, Y1, X2, Y2 );
	}

	void Set( T X1, T Y1, T X2, T Y2 )
	{
		// Try to maintain assumption that (x1,y1) < (x2,y2).
		x1 = MIN( X1, X2 );
		y1 = MIN( Y1, Y2 );
		x2 = MAX( X1, X2 );
		y2 = MAX( Y1, Y2 );
	}

	/// @return True if a 2D point is inside this rectangle.
	bool IfInside( T x, T y ) const
	{
		return    x >= x1				// assumes (x1,y1) < (x2,y2)
               && x <= x2				// this could be recoded to not assume
               && y >= y1				// but it'd be slower
               && y <= y2;
	}

	/// @return True if the passed rectangle is entirely outside this one.
	bool IfOutside( const Rect<T>& rect ) const
	{
		return     rect.x1 > x2		// if to the right
                || rect.x2 < y1		// if to the left
                || rect.y1 > y2		// if below
                || rect.y2 < y1;	// if above
	}

	/// Grow rectangle (expand a corner) to enclose a point.
	void Grow( T x, T y )
	{
		// Try to maintain assumption that (x1,y1) < (x2,y2).
		x1 = MIN(x1,x);
		y1 = MIN(y1,y);
		x2 = MAX(x2,x);
		y2 = MAX(y2,y);
	}

public:
	T	x1;			// smaller x
	T	y1;			// smaller y
	T	x2;			// greater x
	T	y2;			// greater y
};

template<typename T>
ostream&
operator<<( ostream& strm, const Rect<T>& o )
{
	ios::fmtflags savedFlags = strm.flags();
    strm << '{'
         << "x1=" << GFX_OMANIP_FIELD(0) << o.x1 << ','
         << "y1=" << GFX_OMANIP_FIELD(0) << o.y1 << ','
         << "x2=" << GFX_OMANIP_FIELD(0) << o.x2 << ','
         << "y2=" << GFX_OMANIP_FIELD(0) << o.y2 << '}';
	strm.flags(savedFlags);
	return strm;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief 3D cube (a 3D extension of the Rect class).
/// @remarks Suggest to consider (x1,y1,z1) < (x2,y2,z2)
/// but the class code here doesn't assume that.
/// Tested by gfx/tests/basic_types.cc.
template<typename T>
class Cube
{
public:
	Cube( void )
	{
	}

	explicit Cube( const WorldVertex& v1, const WorldVertex& v2 )
	{
		Set( v1.x, v1.y, v1.z,
             v2.x, v2.y, v2.z );
	}

	explicit Cube( T X1, T Y1, T Z1,
          T X2, T Y2, T Z2 )
	{
		Set( X1, Y1, Z1,
             X2, Y2, Z2 );
	}

	void Set( T X1, T Y1, T Z1,
              T X2, T Y2, T Z2 )
	{
		x1 = MIN( X1, X2 );
		y1 = MIN( Y1, Y2 );
		z1 = MIN( Z1, Z2 );
		x2 = MAX( X1, X2 );
		y2 = MAX( Y1, Y2 );
		z2 = MAX( Z1, Z2 );
	}

	/// Set Cube to a single point.
	void Set( T X, T Y, T Z )
	{
		x1 = x2 = X;
		y1 = y2 = Y;
		z1 = z2 = Z;
	}

	void Set( const WorldVertex& wv )
	{
		x1 = x2 = wv.x;
		y1 = y2 = wv.y;
		z1 = z2 = wv.z;
	}

	/// Assumes (x1,y1,z1) < (x2,y2,z2).
	#define CUBE_IF_INSIDE( x, y, z )	\
		   x1 <= x && x <= x2			\
		&& y1 <= y && y <= y2			\
		&& z1 <= z && z <= z2
	/// @return True if a 3D point is inside this Cube.

	bool IfInside( T x, T y, T z ) const
	{
		return CUBE_IF_INSIDE( x, y, z );
	}

	/// @return True if a 3D point is inside this Cube.
	bool IfInside( const WorldVertex& pos ) const
	{
		return CUBE_IF_INSIDE( pos.x, pos.y, pos.z );
	}

	/// @returns True only if the Posrad-formed cube is entirely inside this Cube.
	/// Returns False if any part of the Posrad is outside this Cube.
	bool IfInside( const Posrad& posrad ) const
	{
		return    posrad.x - posrad.mRadius >= x1
		       && posrad.x + posrad.mRadius <= x2
		       && posrad.y - posrad.mRadius >= y1
	           && posrad.y + posrad.mRadius <= y2
		       && posrad.z - posrad.mRadius >= z1
	           && posrad.z + posrad.mRadius <= z2;
	}

	/// Grow cube (expand a corner) to enclose a position.
	void Grow( const WorldVertex& wv )
	{
		x1 = (T) Min( x1, (T)(wv.x) );
		y1 = (T) Min( y1, (T)(wv.y) );
		z1 = (T) Min( z1, (T)(wv.z) );
		x2 = (T) Max( x2, (T)(wv.x) );
		y2 = (T) Max( y2, (T)(wv.y) );
		z2 = (T) Max( z2, (T)(wv.z) );
	}

	/// Grow cube (expand a corner) to enclose a position,radius.
	void Grow( const Posrad& posrad )
	{
		x1 = (T) Min( x1, (T)(posrad.x - posrad.mRadius) );
		y1 = (T) Min( y1, (T)(posrad.y - posrad.mRadius) );
		z1 = (T) Min( z1, (T)(posrad.z - posrad.mRadius) );
		x2 = (T) Max( x2, (T)(posrad.x + posrad.mRadius) );
		y2 = (T) Max( y2, (T)(posrad.y + posrad.mRadius) );
		z2 = (T) Max( z2, (T)(posrad.z + posrad.mRadius) );
	}

	/// @return Approximate radius.
	T GetRadius( void ) const
	{
		// Radius is half the distance of furthest opposite sides.
		return Max( Max(x2-x1, y2-y1), z2-z1 ) / 2;
	}

	Position GetCenter( void ) const
	{
		return Position( x1 + (x2-x1)/2,
                         y1 + (y2-y1)/2,
                         z1 + (z2-z1)/2 );
	}

public:
	T	x1;			// smaller x
	T	y1;			// smaller y
	T	z1;			// smaller z
	T	x2;			// greater x
	T	y2;			// greater y
	T	z2;			// greater z
};

template<typename T>
ostream&
operator<<( ostream& strm, const Cube<T>& o )
{
	ios::fmtflags savedFlags = strm.flags();
    strm << '{'
         << "x1=" << GFX_OMANIP_FIELD(0) << o.x1 << ','
         << "y1=" << GFX_OMANIP_FIELD(0) << o.y1 << ','
         << "z1=" << GFX_OMANIP_FIELD(0) << o.z1 << ','
         << "x2=" << GFX_OMANIP_FIELD(0) << o.x2 << ','
         << "y2=" << GFX_OMANIP_FIELD(0) << o.y2 << ','
         << "z2=" << GFX_OMANIP_FIELD(0) << o.z2 << '}';
	strm.flags(savedFlags);
	return strm;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief 2D rectangle for 3D objects in world space (ignores Y altitude).
/// Defines the top-left and bottom-right corners of a 2D rectangle.
/// X,Z members are used instead of X,Y because this struct is used mostly
/// for ground-level objects where altitude (Y) is N/A.
struct RectXZ
{
	RectXZ( void )
	{
		SET_TYPESIG( this, TYPESIG_LIB_RECTXZ );
	}

	explicit RectXZ( const Posrad& posrad ) // conversion
	{
		SET_TYPESIG( this, TYPESIG_LIB_RECTXZ );
		mMinX = posrad.x - posrad.mRadius;
		mMaxX = posrad.x + posrad.mRadius; // ignore Y
		mMinZ = posrad.z - posrad.mRadius;
		mMaxZ = posrad.z + posrad.mRadius;
	}

	~RectXZ()
	{
		INVALIDATE_TYPESIG( this, TYPESIG_LIB_RECTXZ );
	}

	void Set( fp minX, fp maxX, fp minZ, fp maxZ )
	{
		mMinX = minX;
		mMaxX = maxX;
		mMinZ = minZ;
		mMaxZ = maxZ;
	}

	/// Grow rectangle (expand a corner) to enclose a point.
	void Grow( fp x, fp z )
	{
		mMinX = MIN(mMinX,x);
		mMinZ = MIN(mMinZ,z);
		mMaxX = MAX(mMaxX,x);
		mMaxZ = MAX(mMaxZ,z);
	}

	/// Grow rectangle (expand a corner) to enclose a position,radius.
	void Grow( const Posrad& posrad )
	{
		mMinX = Min( mMinX, posrad.x - posrad.mRadius );
		mMinZ = Min( mMinZ, posrad.z - posrad.mRadius );
		mMaxX = Max( mMaxX, posrad.x + posrad.mRadius );
		mMaxZ = Max( mMaxZ, posrad.z + posrad.mRadius );
	}

	/// If any part of another rectangle overlaps this one.
	bool IfOverlaps( const RectXZ& rect ) const
	{
		// True if entirely outside.
		bool outside =    (rect.mMinX < mMinX && rect.mMaxX < mMinX)
               		   || (rect.mMinX > mMaxX && rect.mMaxX > mMaxX)
              		   || (rect.mMinZ < mMinZ && rect.mMaxZ < mMinZ)
           			   || (rect.mMinZ > mMaxZ && rect.mMaxZ > mMaxZ);
		return ! outside; // true if partly/entirely inside
	}
	bool IfOverlaps( const Posrad& posrad ) const
	{
        return IfOverlaps( RectXZ(posrad) );
	}

	/// If another object is ENTIRELY inside this rectangle.
	bool IfInside( const Posrad& posrad ) const
	{
		return    (posrad.x - posrad.mRadius) >= mMinX
		       && (posrad.x + posrad.mRadius) <= mMaxX
			   && (posrad.z - posrad.mRadius) >= mMinZ
	           && (posrad.z + posrad.mRadius) <= mMaxZ;
	}

	bool IfInside( fp x, fp z ) const
	{
		return    x >= mMinX
               && x <= mMaxX
               && z >= mMinZ
               && z <= mMaxZ;
	}

	fp	mMinX;
	fp	mMaxX;
	fp	mMinZ;	// yes, Z instead of Y
	fp	mMaxZ;
	DECL_TYPESIG( TYPESIG_LIB_RECTXZ )
};

static inline ostream&
operator<<( ostream& strm, const RectXZ& o )
{
	ios::fmtflags savedFlags = strm.flags();
    strm << '{'
         << "minX=" << GFX_OMANIP_FIELD(0) << o.mMinX << ','
         << "maxX=" << GFX_OMANIP_FIELD(0) << o.mMaxX << ','
         << "minZ=" << GFX_OMANIP_FIELD(0) << o.mMinZ << ','
         << "maxZ=" << GFX_OMANIP_FIELD(0) << o.mMinX << '}';
	strm.flags(savedFlags);
	return strm;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief For window/viewport geometries (x/y/w/h).
template<typename T>
struct Geom
{
	Geom( void )
	{
	}

	~Geom( void )
	{
	}

	explicit Geom( T X, T Y, T W, T H )
	{
		Set( X, Y, W, H );
	}

	void Clear( void )
	{
		 x = y = w = h = 0;
	}

	void Set( T X, T Y, T W, T H )
	{
		x = X; y = Y; w = W; h = H;
	}

	template<typename T2> void Copy( const Geom<T2>& g )		// a C++ "member template"
	{
		x = g.x; y = g.y; w = g.w; h = g.h;
	}

	T	x;	// left
	T	y;	// top
	T	w;	// width
	T	h;	// height
};

template<typename T>
ostream&
operator<<( ostream& strm, const Geom<T>& o )
{
	ios::fmtflags savedFlags = strm.flags();
    strm << '{'
         << "x=" << GFX_OMANIP_FIELD(0) << o.x << ','
         << "y=" << GFX_OMANIP_FIELD(0) << o.y << ','
         << "w=" << GFX_OMANIP_FIELD(0) << o.w << ','
         << "h=" << GFX_OMANIP_FIELD(0) << o.h << '}';
	strm.flags(savedFlags);
	return strm;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief Basic string buffer class.
/// @remarks One purpose is to wrap a C++ string for sharing it.
/// For speed/convenience, to directly manipulate the C++ string and to avoid copying,
/// mBuf is exposed.  But the methods should be used whenever possible.
class StringBuf
{
public:
	void			Set( const char* buf )           { mBuf.assign( buf ); }
	void			Set( const char* buf, int len )  { mBuf.assign( buf, len ); }
	void			Set( const uchar* buf, int len ) { mBuf.assign( (char*)buf, len ); }
	void			Erase( void )				{ mBuf.erase(); }
	bool			IfEmpty( void )	const		{ return mBuf.size() == 0; }
	int				Size( void ) const			{ return mBuf.size(); }
	const string*	GetString( void ) const		{ return &mBuf; }
	const char*		GetChars( void ) const		{ return mBuf.c_str(); }
	const uchar*	GetUchars( void ) const		{ return (uchar*)mBuf.c_str(); }

public:
	string		mBuf;	///< public for speed/convenience but use methods if appropriate
};

#undef virtual

} // namespace gfx

#endif // GFX_TYPES_HH
