/******************************************************************************
 * $Id: gfx_texture_opengl.hh,v 1.40 2006/10/26 03:05:10 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Texture classes (OpenGL).
 * @remarks
 *//*
 * LEGAL:	COPYRIGHT (C) 2006 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 ******************************************************************************/

#ifndef GFX_TEXTURE_OPENGL_HH
#define GFX_TEXTURE_OPENGL_HH 1

namespace gfx {

////////////////////////////////////////////////////////////////////////////////
/// @brief OpenGL Texture class.  Mostly OpenGL enums, a few static methods.
///
/// This base class is mostly orthogonal to its derived class because
/// 1D/2D/3D texture classes naturally don't have the exact same interfaces.
/// Texture2 was implemented to be optimal without any concern for code commonality
/// (Texture used to be a complex class with 2D/3D texture support but it devolved
/// into a tangled mess of #if/#endif).
///
class Texture
{
public:
    /*****************************************************************************
     * Texel format.
     * BGRA8 is the default.
     * BGRA8 is faster than RGBA8 on Nvidia cards (driver must swizzle RGBA8 to BGRA8).
     * Whether RGBA8 or BGRA8 format is compiled is abstracted by these macros.
     * Currently, only RGBA8 or BGRA8 texels are supported.
     *****************************************************************************/
    typedef uint32 Texel32;  ///< Texel32 abstracts BGRA8 or RGBA8 format

    /// Byte indexs that abstract RGBA/BGRA format of Texel32.
	/// Independent of CPU endianness.
    enum
    {
        #if COMPILE_TEXEL32_RGBA8
        TEXEL32_RR = 0,     // byte indexs
        TEXEL32_GG = 1,
        TEXEL32_BB = 2,
        TEXEL32_AA = 3,
        #else  // default BGRA8
        TEXEL32_BB = 0,
        TEXEL32_GG = 1,
        TEXEL32_RR = 2,
        TEXEL32_AA = 3,
        #endif
    };

    /// Bit shifts to Texel32 bytes.
	/// These depend on CPU endianness when uint32 is stored as uint8[4].
	/// uint8[4] must be in CPU-neutral byte-order defined by OpenGL.
    enum
    {
#if GFX_LITTLE_ENDIAN
        #if COMPILE_TEXEL32_RGBA8
        TEXEL32_RR_BIT_SHIFT = 0,		// RGBA
        TEXEL32_GG_BIT_SHIFT = 8,
        TEXEL32_BB_BIT_SHIFT = 16,
        TEXEL32_AA_BIT_SHIFT = 24,
		#else // default COMPILE_TEXEL32_BGRA8
        TEXEL32_BB_BIT_SHIFT = 0,		// BGRA
        TEXEL32_GG_BIT_SHIFT = 8,
        TEXEL32_RR_BIT_SHIFT = 16,
        TEXEL32_AA_BIT_SHIFT = 24,
		#endif
#else // GFX_BIG_ENDIAN
        #if COMPILE_TEXEL32_RGBA8		// RGBA
        TEXEL32_RR_BIT_SHIFT = 24,
        TEXEL32_GG_BIT_SHIFT = 16,
        TEXEL32_BB_BIT_SHIFT = 8,
        TEXEL32_AA_BIT_SHIFT = 0,
		#else // default COMPILE_TEXEL32_BGRA8
        TEXEL32_BB_BIT_SHIFT = 24,		// BGRA
        TEXEL32_GG_BIT_SHIFT = 16,
        TEXEL32_RR_BIT_SHIFT = 8,
        TEXEL32_AA_BIT_SHIFT = 0,
		#endif
#endif
    };

    /// Bytes in texel formats.  More readable than "4".
    enum
    {
        TEXEL32_LEN         = 4,
        TEXEL32_BGRA8_LEN   = 4,
        TEXEL32_RGBA8_LEN   = 4,
        TEXEL_DEFAULT_LEN   = 4,
    };

    /// Texel type.
    enum eTexelType
    {
        eTexelType_BGRA8    = GL_BGRA,  // GL_BGRA8 doesn't exist (RGBA8 does though)
    	eTexelType_RGBA8    = GL_RGBA,
        eTexelType_Texel32  = GL_BGRA,
    	eTexelType_DEFAULT  = GL_BGRA,  // faster than RGBA8
    };

    /// OpenGL dimension enum.
    enum eTextureDim
    {
    	eTextureDim_2D = GL_TEXTURE_2D,
        GP_TEXTURE_2D  = GL_TEXTURE_2D,  // synonym
    };

    /// Texture minification filter and magnification filter control.
    enum eMinFilter
    {
    	eMinFilter_DEFAULT					= GL_NEAREST,
    	eMinFilter_NEAREST					= GL_NEAREST,
    	eMinFilter_LINEAR					= GL_LINEAR,
    	eMinFilter_NEAREST_MIPMAP_NEAREST	= GL_NEAREST_MIPMAP_NEAREST,
    	eMinFilter_NEAREST_MIPMAP_LINEAR	= GL_NEAREST_MIPMAP_LINEAR,
    	eMinFilter_LINEAR_MIPMAP_NEAREST	= GL_LINEAR_MIPMAP_NEAREST,
    	eMinFilter_LINEAR_MIPMAP_LINEAR		= GL_LINEAR_MIPMAP_LINEAR,
    };
    enum eMagFilter
    {
    	eMagFilter_DEFAULT					= GL_NEAREST,
    	eMagFilter_NEAREST					= GL_NEAREST,
    	eMagFilter_LINEAR					= GL_LINEAR,
    	// Magnfication filter doesn't apply to mipmaps.
    };

    /// Texture wrapping control.
    enum eWrap
    {
    	eWrap_DEFAULT				= GL_REPEAT,
    	eWrap_REPEAT				= GL_REPEAT,
    	eWrap_CLAMP                 = GL_CLAMP,
    	eWrap_CLAMP_TO_EDGE     	= GL_CLAMP_TO_EDGE,
    	eWrap_CLAMP_TO_BORDER		= GL_CLAMP,
    };

    /// Texture function.
    /// The resulting fragment is function of the texture image and the "texture function".
    enum eFunc
    {
    	eFunc_DEFAULT				= GL_MODULATE,
    	eFunc_MODULATE          	= GL_MODULATE,
    	eFunc_DECAL                 = GL_DECAL,
    	eFunc_REPLACE				= GL_REPLACE,
    	eFunc_BLEND                 = GL_BLEND,
    };

    /// Misc enums
	enum
    {
        TEXTURE_ID_INVALID = 0,     // OpenGL defines 0 to mean no texture
    };

    /*****************************************************************************
     * Create a Texel32 from BGRA components.
     *****************************************************************************/
    static inline Texel32
    MakeTexel32( uint b, uint g, uint r, uint a )
    {
        return (b << TEXEL32_BB_BIT_SHIFT)
             | (g << TEXEL32_GG_BIT_SHIFT)
             | (r << TEXEL32_RR_BIT_SHIFT)
             | (a << TEXEL32_AA_BIT_SHIFT);
    }

    /*****************************************************************************
     * See man glTexImage2D.
     * format has a bit suffix: RGBA8, BGRA8, etc.
     * internalFormat is just RGBA or BGRA (not bit suffix).
     *****************************************************************************/
    static GLenum
    GetTexelInternalFormat( UNUSED eTexelType texelType )
    {
    	return GL_RGBA;
    }
    static GLenum
    GetTexelFormat( eTexelType texelType )
    {
    	return texelType;
    }

    /*****************************************************************************
     * @return How many bytes a texel has.
     *****************************************************************************/
    static uint
    TexelTypeToTexelLen( eTexelType texelType )
    {
        uint texelLen = 0;
        switch ( texelType )
        {
            case eTexelType_BGRA8: texelLen = TEXEL32_BGRA8_LEN; break;
            case eTexelType_RGBA8: texelLen = TEXEL32_RGBA8_LEN; break;
            default: ASSERT(0); break;
        }
        ASSERT( texelLen > 0 );
    	return texelLen;
    }

};

} // namespace gfx

#include "gfx_tga.hh"
#include "gfx_texture2_opengl.hh"

#endif // GFX_TEXTURE_OPENGL_HH
