// File : RenderTexture.cpp
//---------------------------------------------------------------------------
// Copyright (c) 2002-2004 Mark J. Harris
//---------------------------------------------------------------------------
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any
// damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any
// purpose, including commercial applications, and to alter it and
// redistribute it freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you
//    must not claim that you wrote the original software. If you use
//    this software in a product, an acknowledgment in the product
//    documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and
//    must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
//    distribution.
//
// --------------------------------------------------------------------------
// Credits:
// Original RenderTexture class: Mark J. Harris
// Original Render to Depth Texture support: Thorsten Scheuermann
// Linux Copy-to-texture: Eric Werness
// OS X: Alexander Powell (someone please help)
// Various Bug Fixes: Daniel (Redge) Sperl 
//                    Bill Baxter
// Ubuntu 8.04 64bit: Geoff McLane - 2009-07-01
// to work even when version 1.2 is returned.
//
// --------------------------------------------------------------------------
/**
* @file RenderTexture.cpp
* 
* Implementation of class RenderTexture.  A multi-format render to 
* texture wrapper.
*/

/*
 * Changelog:
 *
 * Jan. 2005, Removed GLEW dependencies, Erik Hofman, Fred Bouvier
 * Nov. 2005, Use the simgear logging facility, Erik Hofman
 * Mar. 2006, Add MAC OS X support, Alexander Powell
 */

#ifdef HAVE_CONFIG_H
#  include <simgear_config.h>
#endif

#include <simgear/compiler.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/screen/extensions.hxx>
#include <simgear/screen/RenderTexture.h>

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdarg.h>

#include <cstring>

#ifdef _WIN32
#pragma comment(lib, "gdi32.lib") // required for GetPixelFormat()
#endif

using namespace std;

// DEBUG - add a lot of noise
//#ifndef _DEBUG
//#define _DEBUG
//#endif

#if defined (_DEBUG) 
const char * get_attr_name( int val, int * pdef );
#define dbg_printf printf
#else
#if defined (__GNUC__)
#define dbg_printf(format,args...) ((void)0)
#else // defined (__GNUC__)
#define dbg_printf
#endif // defined (__GNUC__)
#endif // defined (_DEBUG)

// CHOP/NOT CHOP SOME CODE TO GET SOMETHING WORKING!
#define ADD_QUERY_BUFFER    
#define ADD_GET_DRAWABLE
// =======================================


#ifdef _WIN32
static bool fctPtrInited = false;
/* WGL_ARB_pixel_format */
static wglChoosePixelFormatARBProc wglChoosePixelFormatARBPtr = 0;
static wglGetPixelFormatAttribivARBProc wglGetPixelFormatAttribivARBPtr = 0;
/* WGL_ARB_pbuffer */
static wglCreatePbufferARBProc wglCreatePbufferARBPtr = 0;
static wglGetPbufferDCARBProc wglGetPbufferDCARBPtr = 0;
static wglQueryPbufferARBProc wglQueryPbufferARBPtr = 0;
static wglReleasePbufferDCARBProc wglReleasePbufferDCARBPtr = 0;
static wglDestroyPbufferARBProc wglDestroyPbufferARBPtr = 0;
/* WGL_ARB_render_texture */
static wglBindTexImageARBProc wglBindTexImageARBPtr = 0;
static wglReleaseTexImageARBProc wglReleaseTexImageARBPtr = 0;

#elif defined( __MACH__ )
#else /* !_WIN32 */
static bool glXVersion1_3Present = false;
static glXChooseFBConfigProc glXChooseFBConfigPtr = 0;
static glXCreatePbufferProc glXCreatePbufferPtr = 0;
static glXCreateGLXPbufferProc glXCreateGLXPbufferPtr = 0;
static glXGetVisualFromFBConfigProc glXGetVisualFromFBConfigPtr = 0;
static glXCreateContextProc glXCreateContextPtr = 0;
static glXCreateContextWithConfigProc glXCreateContextWithConfigPtr = 0;
static glXDestroyPbufferProc glXDestroyPbufferPtr = 0;
static glXQueryDrawableProc glXQueryDrawablePtr = 0;
static glXQueryGLXPbufferSGIXProc glXQueryGLXPbufferSGIXPtr = 0;
#endif

//---------------------------------------------------------------------------
// Function      : RenderTexture::RenderTexture
// Description	 : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::RenderTexture()
* @brief Mode-string-based Constructor.
*/ 
RenderTexture::RenderTexture(const char *strMode)
:   _iWidth(0), 
    _iHeight(0), 
    _bIsTexture(false),
    _bIsDepthTexture(false),
    _bHasARBDepthTexture(true),            // [Redge]
#if defined(_WIN32) || defined(__MACH__)
    _eUpdateMode(RT_RENDER_TO_TEXTURE),
#else
    _eUpdateMode(RT_COPY_TO_TEXTURE),
#endif
    _bInitialized(false),
    _iNumAuxBuffers(0),
    _bIsBufferBound(false),
    _iCurrentBoundBuffer(0),
    _iNumDepthBits(0),
    _iNumStencilBits(0),
    _bFloat(false),
    _bDoubleBuffered(false),
    _bPowerOf2(true),
    _bRectangle(false),
    _bMipmap(false),
    _bShareObjects(false),
    _bCopyContext(false),
#ifdef _WIN32
    _hDC(NULL), 
    _hGLContext(NULL), 
    _hPBuffer(NULL),
    _hPreviousDC(0),
    _hPreviousContext(0),
#elif defined( __MACH__ )
    _hGLContext(NULL),
    _hPBuffer(0),
    _hPreviousContext(NULL),
#else
    _pDisplay(NULL),
    _hGLContext(NULL),
    _hPBuffer(0),
    _hPreviousDrawable(0),
    _hPreviousContext(0),
#endif
    _iTextureTarget(GL_NONE),
    _iTextureID(0),
    _iDepthTextureID(0),
    _pPoorDepthTexture(0) // [Redge]
{
    dbg_printf("RenderTexture::RenderTexture(%s) BGN instantiation.\n", strMode );
    _iNumColorBits[0] = _iNumColorBits[1] = 
        _iNumColorBits[2] = _iNumColorBits[3] = 0;

#ifdef _WIN32
    dbg_printf("RenderTexture::RenderTexture in _WIN32.\n" );
    _pixelFormatAttribs.push_back(WGL_DRAW_TO_PBUFFER_ARB);
    _pixelFormatAttribs.push_back(true);
    _pixelFormatAttribs.push_back(WGL_SUPPORT_OPENGL_ARB);
    _pixelFormatAttribs.push_back(true);
    
    _pbufferAttribs.push_back(WGL_PBUFFER_LARGEST_ARB);
    _pbufferAttribs.push_back(true);
#elif defined( __MACH__ )
    dbg_printf("RenderTexture::RenderTexture in __MACH__.\n" );
    //_pixelFormatAttribs.push_back(kCGLPFANoRecovery);
    _pixelFormatAttribs.push_back(kCGLPFAAccelerated);
    _pixelFormatAttribs.push_back(kCGLPFAWindow);
    _pixelFormatAttribs.push_back(kCGLPFAPBuffer);
#else
    dbg_printf("RenderTexture::RenderTexture !_WIN32 and !__MACH__.\n" );
    _pbufferAttribs.push_back(GLX_RENDER_TYPE_SGIX);
    _pbufferAttribs.push_back(GLX_RGBA_BIT_SGIX);
    _pbufferAttribs.push_back(GLX_DRAWABLE_TYPE_SGIX);
    _pbufferAttribs.push_back(GLX_PBUFFER_BIT_SGIX);
#endif

    _ParseModeString(strMode, _pixelFormatAttribs, _pbufferAttribs);

#ifdef _WIN32
    _pixelFormatAttribs.push_back(0);
    _pbufferAttribs.push_back(0);
#elif defined(__MACH__)
    _pixelFormatAttribs.push_back((CGLPixelFormatAttribute)0);
    _pbufferAttribs.push_back((CGLPixelFormatAttribute)0);
#else
    _pixelFormatAttribs.push_back(None);
#endif

    dbg_printf("RenderTexture::RenderTexture(%s) END instantiation. pf=%d pb=%d\n",
      strMode, (int)_pixelFormatAttribs.size(), (int)_pbufferAttribs.size() );

}


//---------------------------------------------------------------------------
// Function     	: RenderTexture::~RenderTexture
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::~RenderTexture()
* @brief Destructor.
*/ 
RenderTexture::~RenderTexture()
{
    dbg_printf("RenderTexture::~RenderTexture: destructor.\n" );
    _Invalidate();
}

 //---------------------------------------------------------------------------
// Function            : _cglcheckError
// Description     :
//---------------------------------------------------------------------------
/**
* @fn _cglCheckError()
* @brief Prints to stderr a description when an OS X error is found.
*/
#ifdef __MACH__
static void _cglCheckErrorHelper(CGLError err, char *sourceFile, int sourceLine)
{
# ifdef _DEBUG
    if (err)
    {
       fprintf(stderr, "RenderTexture CGL Error:  %s at (%s,%d)",
                        CGLErrorString(err), sourceFile, sourceLine);
    }
# endif
}

# define _cglCheckError(err) _cglCheckErrorHelper(err,__FILE__,__LINE__)

#endif


//---------------------------------------------------------------------------
// Function     	: _wglGetLastError
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn wglGetLastError()
* @brief Returns the last windows error generated.
*/ 
#ifdef _WIN32
void _wglGetLastError()
{
#ifdef _DEBUG
    
    DWORD err = GetLastError();
    switch(err)
    {
    case ERROR_INVALID_PIXEL_FORMAT:
        SG_LOG(SG_GL, SG_ALERT, 
                "RenderTexture Win32 Error:  ERROR_INVALID_PIXEL_FORMAT");
        break;
    case ERROR_NO_SYSTEM_RESOURCES:
        SG_LOG(SG_GL, SG_ALERT, 
                "RenderTexture Win32 Error:  ERROR_NO_SYSTEM_RESOURCES");
        break;
    case ERROR_INVALID_DATA:
        SG_LOG(SG_GL, SG_ALERT, 
                "RenderTexture Win32 Error:  ERROR_INVALID_DATA");
        break;
    case ERROR_INVALID_WINDOW_HANDLE:
        SG_LOG(SG_GL, SG_ALERT, 
                "RenderTexture Win32 Error:  ERROR_INVALID_WINDOW_HANDLE");
        break;
    case ERROR_RESOURCE_TYPE_NOT_FOUND:
        SG_LOG(SG_GL, SG_ALERT, 
                "RenderTexture Win32 Error:  ERROR_RESOURCE_TYPE_NOT_FOUND");
        break;
    case ERROR_SUCCESS:
        // no error
        break;
    default:
        LPVOID lpMsgBuf;
        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
            FORMAT_MESSAGE_FROM_SYSTEM | 
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            err,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
            (LPTSTR) &lpMsgBuf,
            0,
            NULL);
        
        SG_LOG(SG_GL, SG_ALERT, "RenderTexture Win32 Error " <<  err << ":" << lpMsgBuf);
        LocalFree( lpMsgBuf );
        break;
    }
    SetLastError(0);
    
#endif // _DEBUG
}
#endif

//---------------------------------------------------------------------------
// Function     	: PrintExtensionError
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn PrintExtensionError( char* strMsg, ... )
* @brief Prints an error about missing OpenGL extensions.
*/ 
void PrintExtensionError( const char* strMsg, ... )
{
    SG_LOG(SG_GL, SG_ALERT, 
            "Error: RenderTexture requires the following unsupported "
            "OpenGL extensions: ");
    char strBuffer[512];
    va_list args;
    va_start(args, strMsg);
    vsnprintf( strBuffer, 512, strMsg, args );
    va_end(args);
    
    SG_LOG(SG_GL, SG_ALERT, strMsg);
    dbg_printf("Error: RenderTexture requires the following unsupported OpenGL extensions: \n[%s]\n", strMsg);
}

//---------------------------------------------------------------------------
// Function     	: RenderTexture::Initialize
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::Initialize(int width, int height, bool shareObjects, bool copyContext);
* @brief Initializes the RenderTexture, sharing display lists and textures if specified.
* 
* This function creates of the p-buffer.  It can only be called once a GL 
* context has already been created.  
*/ 
bool RenderTexture::Initialize(int width, int height,
                                bool shareObjects       /* = true */,
                                bool copyContext        /* = false */)
{
    assert(width > 0 && height > 0);

    dbg_printf("RenderTexture::Initialize w=%d h=%d\n", width, height );
    
    _iWidth = width; _iHeight = height;
    _bPowerOf2 = IsPowerOfTwo(width) && IsPowerOfTwo(height);

    _bShareObjects = shareObjects;
    _bCopyContext  = copyContext;

    // Check if this is an NVXX GPU and verify necessary extensions.
    if (!_VerifyExtensions()) {
       dbg_printf("RenderTexture::Initialize: _VerifyExtensions() FAILED - returning false.\n" );
       return false;
    }
    
    if (_bInitialized)
        _Invalidate();

#ifdef _WIN32
    // Get the current context.
    HDC hdc = wglGetCurrentDC();
    if (NULL == hdc)
        _wglGetLastError();
    HGLRC hglrc = wglGetCurrentContext();
    if (NULL == hglrc)
        _wglGetLastError();
    
    int iFormat = 0;
    unsigned int iNumFormats;
    
    if (_bCopyContext)
    {
        // Get the pixel format for the on-screen window.
        iFormat = GetPixelFormat(hdc);
        if (iFormat == 0)
        {
            SG_LOG(SG_GL, SG_ALERT, 
                    "RenderTexture Error: GetPixelFormat() failed.");
            return false;
        }
    }
    else 
    {
        if (!wglChoosePixelFormatARBPtr(hdc, &_pixelFormatAttribs[0], NULL, 
                                     1, &iFormat, &iNumFormats))
        {
            SG_LOG(SG_GL, SG_ALERT, 
                "RenderTexture Error: wglChoosePixelFormatARB() failed.");
            _wglGetLastError();
            return false;
        }
        if ( iNumFormats <= 0 )
        {
            SG_LOG(SG_GL, SG_ALERT, 
                    "RenderTexture Error: Couldn't find a suitable "
                    "pixel format.");
            _wglGetLastError();
            return false;
        }
    }
    
    // Create the p-buffer.    
    _hPBuffer = wglCreatePbufferARBPtr(hdc, iFormat, _iWidth, _iHeight, 
                                    &_pbufferAttribs[0]);
    if (!_hPBuffer)
    {
        SG_LOG(SG_GL, SG_ALERT, 
                "RenderTexture Error: wglCreatePbufferARB() failed.");
        _wglGetLastError();
        return false;
    }
    
    // Get the device context.
    _hDC = wglGetPbufferDCARBPtr( _hPBuffer);
    if ( !_hDC )
    {
        SG_LOG(SG_GL, SG_ALERT, 
                "RenderTexture Error: wglGetGetPbufferDCARB() failed.");
        _wglGetLastError();
        return false;
    }
    
    // Create a gl context for the p-buffer.
    if (_bCopyContext)
    {
        // Let's use the same gl context..
        // Since the device contexts are compatible (i.e. same pixelformat),
        // we should be able to use the same gl rendering context.
        _hGLContext = hglrc;
    }
    else
    {
        _hGLContext = wglCreateContext( _hDC );
        if ( !_hGLContext )
        {
            SG_LOG(SG_GL, SG_ALERT, 
                    "RenderTexture Error: wglCreateContext() failed.");
            _wglGetLastError();
            return false;
        }
    }
    
    // Share lists, texture objects, and program objects.
    if( _bShareObjects )
    {
        if( !wglShareLists(hglrc, _hGLContext) )
        {
            SG_LOG(SG_GL, SG_ALERT, 
                    "RenderTexture Error: wglShareLists() failed.");
            _wglGetLastError();
            return false;
        }
    }
    
    // Determine the actual width and height we were able to create.
    wglQueryPbufferARBPtr( _hPBuffer, WGL_PBUFFER_WIDTH_ARB, &_iWidth );
    wglQueryPbufferARBPtr( _hPBuffer, WGL_PBUFFER_HEIGHT_ARB, &_iHeight );
    
    _bInitialized = true;
    
    // get the actual number of bits allocated:
    int attrib = WGL_RED_BITS_ARB;
    //int bits[6];
    int value;
    _iNumColorBits[0] = 
        (wglGetPixelFormatAttribivARBPtr(_hDC, iFormat, 0, 1, &attrib, &value)) 
        ? value : 0;
    attrib = WGL_GREEN_BITS_ARB;
    _iNumColorBits[1] = 
        (wglGetPixelFormatAttribivARBPtr(_hDC, iFormat, 0, 1, &attrib, &value)) 
        ? value : 0;
    attrib = WGL_BLUE_BITS_ARB;
    _iNumColorBits[2] = 
        (wglGetPixelFormatAttribivARBPtr(_hDC, iFormat, 0, 1, &attrib, &value)) 
        ? value : 0;
    attrib = WGL_ALPHA_BITS_ARB;
    _iNumColorBits[3] = 
        (wglGetPixelFormatAttribivARBPtr(_hDC, iFormat, 0, 1, &attrib, &value)) 
        ? value : 0; 
    attrib = WGL_DEPTH_BITS_ARB;
    _iNumDepthBits = 
        (wglGetPixelFormatAttribivARBPtr(_hDC, iFormat, 0, 1, &attrib, &value)) 
        ? value : 0; 
    attrib = WGL_STENCIL_BITS_ARB;
    _iNumStencilBits = 
        (wglGetPixelFormatAttribivARBPtr(_hDC, iFormat, 0, 1, &attrib, &value)) 
        ? value : 0; 
    attrib = WGL_DOUBLE_BUFFER_ARB;
    _bDoubleBuffered = 
        (wglGetPixelFormatAttribivARBPtr(_hDC, iFormat, 0, 1, &attrib, &value)) 
        ? (value?true:false) : false; 
    
#if defined(_DEBUG) | defined(DEBUG)
    SG_LOG(SG_GL, SG_ALERT, "Created a " << _iWidth << "x" << _iHeight <<
        " RenderTexture with BPP(" <<
        _iNumColorBits[0] << "," << _iNumColorBits[1] << "," <<
        _iNumColorBits[2] << "," << _iNumColorBits[3] << ")");
    if (_iNumDepthBits) SG_LOG(SG_GL, SG_ALERT, " depth=" << _iNumDepthBits);
    if (_iNumStencilBits) SG_LOG(SG_GL, SG_ALERT, " stencil=" << _iNumStencilBits);
    if (_bDoubleBuffered) SG_LOG(SG_GL, SG_ALERT, " double buffered");
#endif

#elif defined( __MACH__ )
    // Get the current context.
    CGLContextObj hglrc = CGLGetCurrentContext();
    if (NULL == hglrc)
        fprintf(stderr, "Couldn't get current context!");
   
        CGLPixelFormatObj pixFormat = NULL;
        GLint iNumFormats;
        CGLError error;

        // Copy the _pixelFormatAttribs into another array to fix
        // typecast issues
        CGLPixelFormatAttribute *pixFormatAttribs =
            (CGLPixelFormatAttribute *)malloc(sizeof(CGLPixelFormatAttribute)
                                              * _pixelFormatAttribs.size());

        for (unsigned int ii = 0; ii < _pixelFormatAttribs.size(); ii++)
        {
            pixFormatAttribs[ii] =
                               (CGLPixelFormatAttribute)_pixelFormatAttribs[ii];
        }

        if (error =
           CGLChoosePixelFormat(&pixFormatAttribs[0], &pixFormat, &iNumFormats))
        {
            fprintf(stderr,
                    "RenderTexture Error: CGLChoosePixelFormat() failed.\n");
            _cglCheckError(error);
            return false;
        }
        if ( iNumFormats <= 0 )
        {
            SG_LOG(SG_GL, SG_ALERT,
                    "RenderTexture Error: Couldn't find a suitable "
                    "pixel format.");
            return false;
        }

        // Free the copy of the _pixelFormatAttribs array
        free(pixFormatAttribs);
   
       // Create the context.
       error = CGLCreateContext(pixFormat, (_bShareObjects)
                ? CGLGetCurrentContext() : NULL, &_hGLContext);
       if (error)
       {
           fprintf(stderr,
                   "RenderTexture Error: CGLCreateContext() failed.\n");
           _cglCheckError(error);
           return false;
       }
       CGLDestroyPixelFormat(pixFormat);
   
       // Create the p-buffer.
       error = CGLCreatePBuffer(_iWidth, _iHeight, (_bRectangle)
            ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D, GL_RGBA, 0, &_hPBuffer);
       if (error)
       {
           fprintf(stderr,
                   "RenderTexture Error: CGLCreatePBuffer() failed.\n");
           _cglCheckError(error);
           return false;
       }

       GLint screen;
       if (error = CGLGetVirtualScreen(CGLGetCurrentContext(), &screen))
       {
           _cglCheckError(error);
           return false;
       }
       if (error = CGLSetPBuffer(_hGLContext, _hPBuffer, 0, 0, screen))
       {
           _cglCheckError(error);
           return false;
       }
   
       // Determine the actual width and height we were able to create.
       //wglQueryPbufferARB( _hPBuffer, WGL_PBUFFER_WIDTH_ARB, &_iWidth );
       //wglQueryPbufferARB( _hPBuffer, WGL_PBUFFER_HEIGHT_ARB, &_iHeight );
   
       _bInitialized = true;
   
       /*
       // get the actual number of bits allocated:
       int attrib = WGL_RED_BITS_ARB;
       //int bits[6];
       int value;
       _iNumColorBits[0] =
            (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value))
            ? value : 0;
       attrib = WGL_GREEN_BITS_ARB;
       _iNumColorBits[1] =
            (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value))
            ? value : 0;
       attrib = WGL_BLUE_BITS_ARB;
       _iNumColorBits[2] =
            (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value))
            ? value : 0;
       attrib = WGL_ALPHA_BITS_ARB;
       _iNumColorBits[3] =
            (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value))
            ? value : 0;
       attrib = WGL_DEPTH_BITS_ARB;
       _iNumDepthBits =
            (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value))
            ? value : 0;
       attrib = WGL_STENCIL_BITS_ARB;
       _iNumStencilBits =
            (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value))
            ? value : 0;
       attrib = WGL_DOUBLE_BUFFER_ARB;
       _bDoubleBuffered =
            (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value))
             ? (value?true:false) : false;
       */

#if defined(_DEBUG) | defined(DEBUG)
       fprintf(stderr, "Created a %dx%d RenderTexture with BPP(%d, %d, %d, %d)",
           _iWidth, _iHeight,
           _iNumColorBits[0], _iNumColorBits[1],
           _iNumColorBits[2], _iNumColorBits[3]);
       if (_iNumDepthBits) fprintf(stderr, " depth=%d", _iNumDepthBits);
       if (_iNumStencilBits) fprintf(stderr, " stencil=%d", _iNumStencilBits);
       if (_bDoubleBuffered) fprintf(stderr, " double buffered");
       fprintf(stderr, "\n");
#endif

#else // !_WIN32, !__MACH_

    _pDisplay = glXGetCurrentDisplay();
    if ( !_pDisplay ) {
        dbg_printf("RenderTexture::Initialize: ERROR: glXGetCurrentDisplay() returned NULL! return false\n");
        return false;
    }
    dbg_printf("RenderTexture::Initialize: got glXGetCurrentDisplay() _pDisplay=[%p]\n", _pDisplay);
    // glXGetCurrentContext returns the current context, as specified by glXMakeCurrent.
    // If there is no current context, NULL is returned.
    GLXContext context = glXGetCurrentContext();
    if ( !context ) {
        dbg_printf("RenderTexture::Initialize: ERROR: glXGetCurrentContext() returned NULL! return false\n");
        return false;
    }
    dbg_printf("RenderTexture::Initialize: got glXGetCurrentContext() context=[%p]\n", context);
    int screen = DefaultScreen(_pDisplay);
    dbg_printf("RenderTexture::Initialize: DefaultScreen(_pDisplay) screen=%d\n", screen);
    
    XVisualInfo *visInfo = NULL;
    
    GLXFBConfig *fbConfigs;
    int nConfigs;
#ifdef _DEBUG
    dbg_printf("Using %d pixelFormatAttribs array\n", (int)_pixelFormatAttribs.size());
    size_t max = _pixelFormatAttribs.size() / 2;
    int dat = 0;
    size_t n;
    for (n = 0; n < max; n++) {
      const char * cp = get_attr_name(_pixelFormatAttribs[n*2], &dat);
      printf( "%s(%d) = %d (def=%d)\n",
       cp, _pixelFormatAttribs[n*2], _pixelFormatAttribs[(n*2)+1], dat );
    }
    n *= 2;
    if ( n < _pixelFormatAttribs.size() )
      printf( "Array ends with %d\n", _pixelFormatAttribs[n] );
    else
      printf( "WARNING: Array does not appear ODD! which is ODD\n" );
      
#endif
    fbConfigs = glXChooseFBConfigPtr(_pDisplay, screen, 
                                      &_pixelFormatAttribs[0], &nConfigs);
    // NOTE: ref: http://www.opengl.org/sdk/docs/man/xhtml/glXChooseFBConfig.xml says
    // Next, call glXGetFBConfigAttrib to retrieve additional attributes for the frame buffer configurations and then select between them.
    
    if (nConfigs <= 0 || !fbConfigs) 
    {
        SG_LOG(SG_GL, SG_ALERT,
            "RenderTexture Error: Couldn't find a suitable pixel format.");
        dbg_printf("RenderTexture Error: Couldn't find a suitable pixel format. return false\n");
        return false;
    }
    
    dbg_printf("RenderTexture::Initialize: glXChooseFBConfigPtr() nConfigs = %d, fbConfigs=[%p]\n", nConfigs, fbConfigs);
    
    int pbufAttrib[] = {
      GLX_PBUFFER_WIDTH,   _iWidth,
      GLX_PBUFFER_HEIGHT,  _iHeight,
      GLX_LARGEST_PBUFFER, False,
      None
    };
    // Pick the first returned format that will return a pbuffer
    // if (glXVersion1_3Present)
    if (glXCreatePbufferPtr && glXGetVisualFromFBConfigPtr && glXCreateContextPtr) 
    {
        dbg_printf("RenderTexture::Initialize: glXVersion1_3Present = TRUE\n");
        for (int i=0;i<nConfigs;i++)
        {
            _hPBuffer = glXCreatePbufferPtr(_pDisplay, fbConfigs[i], pbufAttrib);
            if (_hPBuffer)
            {
                XVisualInfo *visInfo = glXGetVisualFromFBConfigPtr(_pDisplay, fbConfigs[i]);

                _hGLContext = glXCreateContextPtr(_pDisplay, visInfo,
                                               _bShareObjects ? context : NULL,
                                               True);
                if (!_hGLContext)
                {
                    dbg_printf("RenderTexture Error: glXCreateContextPtr(_pDisplay, visInfo,..) FAILED! return false\n");
                    return false;
                }
                XFree( visInfo );
                break;
            }
        }
    }
    else
    {
#ifdef WIN32
        int iFormat = 0;
        int iNumFormats;
        int attrib = 0;
#endif
        dbg_printf("RenderTexture::Initialize: glXVersion1_3Present = FALSE w=%d h=%d\n", _iWidth, _iHeight);
        for (int i=0; i < nConfigs; i++)
        {
             dbg_printf("RenderTexture::Initialize: %d: glXCreateGLXPbufferPtr() get buffer ptr\n", (i + 1));
            _hPBuffer = glXCreateGLXPbufferPtr(_pDisplay, fbConfigs[i], 
                                               _iWidth, _iHeight,
                                               &pbufAttrib[0] ); //NULL);
            if (_hPBuffer) 
            {
                dbg_printf("RenderTexture::Initialize: %d: glXCreateGLXPbufferPtr() got buffer [%p]\n", (i + 1), (void*)_hPBuffer);
                _hGLContext = glXCreateContextWithConfigPtr(_pDisplay, 
                                                             fbConfigs[i], 
                                                             GLX_RGBA_TYPE, 
                                                             _bShareObjects ? context : NULL, 
                                                             True);
                dbg_printf("RenderTexture::Initialize: %d: glXCreateContextWithConfigPtr() _hGLContext=[%p]\n", (i + 1), _hGLContext);
                break;
            } else {
                dbg_printf("RenderTexture::Initialize: %d: glXCreateGLXPbufferPtr() NO buffer\n", (i + 1));
            }
        }
    }
    
    dbg_printf("RenderTexture::Initialize: doing XFree( fbConfigs=[%p].\n", fbConfigs);
    XFree( fbConfigs );
    
    if (!_hPBuffer)
    {
        SG_LOG(SG_GL, SG_ALERT, 
                "RenderTexture Error: glXCreateGLXPbufferPtr() failed.");
        dbg_printf("RenderTexture Error: glXCreateGLXPbufferPtr() failed.\n");
        return false;
    }
    
    if(!_hGLContext)
    {
        // Try indirect
        _hGLContext = glXCreateContext(_pDisplay, visInfo, 
                                       _bShareObjects ? context : NULL, False);
        if ( !_hGLContext )
        {
            SG_LOG(SG_GL, SG_ALERT, 
                    "RenderTexture Error: glXCreateContext() failed.");
            dbg_printf("RenderTexture Error: glXCreateContext() failed. return false\n");
            return false;
        }
    }
    
    // if (!glXVersion1_3Present)
    if ((!glXCreatePbufferPtr || !glXGetVisualFromFBConfigPtr || !glXCreateContextPtr) &&
        (!glXVersion1_3Present))
    {
#ifdef ADD_QUERY_BUFFER    
        dbg_printf("RenderTexture::Initialize: Doing glXQueryGLXPbufferSGIXPtr with GLX_WIDTH_SGIX\n");
        glXQueryGLXPbufferSGIXPtr(_pDisplay, _hPBuffer, GLX_WIDTH_SGIX, 
                                  (GLuint*)&_iWidth);
        dbg_printf("RenderTexture::Initialize: Doing glXQueryGLXPbufferSGIXPtr with GLX_HEIGHT_SGIX\n");
        glXQueryGLXPbufferSGIXPtr(_pDisplay, _hPBuffer, GLX_HEIGHT_SGIX, 
                                  (GLuint*)&_iHeight);
#else
        dbg_printf("RenderTexture::Initialize: SKIPPED doing glXQueryGLXPbufferSGIXPtr with GLX_WIDTH_SGIX and GLX_HEIGHT_SGIX\n");
#endif // #ifdef ADD_QUERY_BUFFER    
    }
    
    _bInitialized = true;
    dbg_printf( "RenderTexture::Initialize: _bIniialized set TRUE\n" );
    // XXX Query the color format
    
#endif

    
    // Now that the pbuffer is created, allocate any texture objects needed,
    // and initialize them (for CTT updates only).  These must be allocated
    // in the context of the pbuffer, though, or the RT won't work without
    // wglShareLists.
#ifdef _WIN32
    if (false == wglMakeCurrent( _hDC, _hGLContext))
    {
        _wglGetLastError();
        return false;
    }
#elif defined( __MACH__ )
    CGLError err;
    if (err = CGLSetCurrentContext(_hGLContext))
    {
        _cglCheckError(err);
        return false;
    }
#else

#ifdef ADD_GET_DRAWABLE
     dbg_printf( "RenderTexture::Initialize: doing glXGetCurrentContext()\n" );
    _hPreviousContext = glXGetCurrentContext();
     dbg_printf( "RenderTexture::Initialize: doing glXGetCurrentDrawable()\n" );
    _hPreviousDrawable = glXGetCurrentDrawable();
#else
    _hPreviousContext = context;
    _hPreviousDrawable = 0;
     dbg_printf( "RenderTexture::Initialize: SKIPPED doing glXGetCurrentContext(2nd) AND glXGetCurrentDrawable()\n" );
#endif // #ifdef ADD_GET_DRAWABLE
    
    dbg_printf( "RenderTexture::Initialize: doing glXMakeCurrent(_pDisplay(%p), _hPBuffer(%p), _hGLContext(%p))\n",
       _pDisplay, (void*)_hPBuffer, _hGLContext );
    if (False == glXMakeCurrent(_pDisplay, _hPBuffer, _hGLContext)) 
    {
        dbg_printf( "glXMakeCurrent(_pDisplay, _hPBuffer, _hGLContext) FAILED. return false\n" );
        return false;
    }
    
#endif
    
    bool result = _InitializeTextures();   
#ifdef _WIN32
    BindBuffer(WGL_FRONT_LEFT_ARB);
    _BindDepthBuffer();
#endif

    
#ifdef _WIN32 
    // make the previous rendering context current 
    if (false == wglMakeCurrent( hdc, hglrc))
    {
        _wglGetLastError();
        return false;
    }
#elif defined( __MACH__ )
    if (err = CGLSetCurrentContext(_hPreviousContext))
    {
        _cglCheckError(err);
        return false;
    }
#else
    if (False == glXMakeCurrent(_pDisplay, 
                                _hPreviousDrawable, _hPreviousContext))
    {
        dbg_printf("glXMakeCurrent(_pDisplay, _hPreviousDrawable, _hPreviousContext)) FAILED! return false\n" );
        return false;
    }
    
    if (glXVersion1_3Present)
    //if ((glXVersion1_3Present) ||
    //    (glXCreatePbufferPtr && glXGetVisualFromFBConfigPtr && glXCreateContextPtr && glXQueryDrawablePtr)) 
    {
        dbg_printf( "RenderTexture::Initialize: doing glXGetCurrentDrawable()\n" );
        GLXDrawable draw = glXGetCurrentDrawable();
        dbg_printf( "RenderTexture::Initialize: doing glXQueryDrawablePtr for GLX_WIDTH and GLX_HEIGHT\n" );
        glXQueryDrawablePtr(_pDisplay, draw, GLX_WIDTH, (unsigned int*)&_iWidth);
        glXQueryDrawablePtr(_pDisplay, draw, GLX_HEIGHT, (unsigned int*)&_iHeight);
    }
#endif

    dbg_printf( "RenderTexture::Initialize(w=%d,h=%d): returning %s\n", _iWidth, _iHeight, (result ? "TRUE" : "FALSE") );
    return result;
}


//---------------------------------------------------------------------------
// Function     	: RenderTexture::_Invalidate
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::_Invalidate()
* @brief Returns the pbuffer memory to the graphics device.
* 
*/ 
bool RenderTexture::_Invalidate()
{
    dbg_printf( "RenderTexture::_Invalidate() called...\n" );
    
    _iNumColorBits[0] = _iNumColorBits[1] = 
        _iNumColorBits[2] = _iNumColorBits[3] = 0;
    _iNumDepthBits = 0;
    _iNumStencilBits = 0;
    
    if (_bIsTexture)
        glDeleteTextures(1, &_iTextureID);
    if (_bIsDepthTexture) 
    {
        // [Redge]
        if (!_bHasARBDepthTexture) delete[] _pPoorDepthTexture;
        // [/Redge]
        glDeleteTextures(1, &_iDepthTextureID);
    }
    
#ifdef _WIN32
    if ( _hPBuffer )
    {
        // Check if we are currently rendering in the pbuffer
        if (wglGetCurrentContext() == _hGLContext)
            wglMakeCurrent(0,0);
        if (!_bCopyContext) 
            wglDeleteContext( _hGLContext);
        wglReleasePbufferDCARBPtr( _hPBuffer, _hDC);
        wglDestroyPbufferARBPtr( _hPBuffer );
        _hPBuffer = 0;
        return true;
    }
#elif defined( __MACH__ )
    if ( _hPBuffer )
    {
        if (CGLGetCurrentContext() == _hGLContext)
            CGLSetCurrentContext(NULL);
        if (!_bCopyContext)
            CGLDestroyContext(_hGLContext);
        CGLDestroyPBuffer(_hPBuffer);
        _hPBuffer = NULL;
        return true;
    }
#else
    if ( _hPBuffer )
    {
        if(glXGetCurrentContext() == _hGLContext)
            // XXX I don't know if this is right at all
            glXMakeCurrent(_pDisplay, _hPBuffer, 0);
        glXDestroyPbufferPtr(_pDisplay, _hPBuffer);
        _hPBuffer = 0;
       dbg_printf( "RenderTexture::_Invalidate: glXDestroyPbufferPtr(_pDisplay, _hPBuffer); return true\n" );
        return true;
    }
#endif

    dbg_printf( "RenderTexture::_Invalidate: return false\n" );
    // [WVB] do we need to call _ReleaseBoundBuffers() too?
    return false;
}


//---------------------------------------------------------------------------
// Function     	: RenderTexture::Reset
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::Reset()
* @brief Resets the resolution of the offscreen buffer.
* 
* Causes the buffer to delete itself.  User must call Initialize() again
* before use.
*/ 
bool RenderTexture::Reset(const char *strMode, ...)
{
   dbg_printf("RenderTexure:Reset(): with %s\n", strMode);
   
    _iWidth = 0; _iHeight = 0; 
    _bIsTexture = false; _bIsDepthTexture = false,
    _bHasARBDepthTexture = true;
#if defined(_WIN32) || defined(__MACH__)
    _eUpdateMode = RT_RENDER_TO_TEXTURE;
#else
    _eUpdateMode = RT_COPY_TO_TEXTURE;
#endif
    _bInitialized = false;
    _iNumAuxBuffers = 0; 
    _bIsBufferBound = false;
    _iCurrentBoundBuffer = 0;
    _iNumDepthBits = 0; _iNumStencilBits = 0;
    _bDoubleBuffered = false;
    _bFloat = false; _bPowerOf2 = true;
    _bRectangle = false; _bMipmap = false; 
    _bShareObjects = false; _bCopyContext = false; 
    _iTextureTarget = GL_NONE; _iTextureID = 0; 
    _iDepthTextureID = 0;
    _pPoorDepthTexture = 0;
    _pixelFormatAttribs.clear();
    _pbufferAttribs.clear();
    if (IsInitialized())
    {
      if (!_Invalidate())
      {
        dbg_printf( "RenderTexture::Reset(): failed to invalidate. return false\n");
        return false;
      }
      else
      {
        dbg_printf( "RenderTexture::Reset(): was Initialized, and now _Invalidate() ok.");
      }
    }
    else
    {
      dbg_printf("RenderTexure:Reset(): previous NOT initialised!\n");
    }
    
    _iNumColorBits[0] = _iNumColorBits[1] = 
        _iNumColorBits[2] = _iNumColorBits[3] = 0;

#ifdef _WIN32
    _pixelFormatAttribs.push_back(WGL_DRAW_TO_PBUFFER_ARB);
    _pixelFormatAttribs.push_back(true);
    _pixelFormatAttribs.push_back(WGL_SUPPORT_OPENGL_ARB);
    _pixelFormatAttribs.push_back(true);
    
    _pbufferAttribs.push_back(WGL_PBUFFER_LARGEST_ARB);
    _pbufferAttribs.push_back(true);
#elif defined( __MACH__ )
    //_pixelFormatAttribs.push_back(kCGLPFANoRecovery);
    _pixelFormatAttribs.push_back(kCGLPFAAccelerated);
    _pixelFormatAttribs.push_back(kCGLPFAWindow);
    _pixelFormatAttribs.push_back(kCGLPFAPBuffer);
#else
    _pbufferAttribs.push_back(GLX_RENDER_TYPE_SGIX);
    _pbufferAttribs.push_back(GLX_RGBA_BIT_SGIX);
    _pbufferAttribs.push_back(GLX_DRAWABLE_TYPE_SGIX);
    _pbufferAttribs.push_back(GLX_PBUFFER_BIT_SGIX);
#endif

    va_list args;
    char strBuffer[256];
    va_start(args,strMode);
    vsnprintf( strBuffer, 256, strMode, args );
    va_end(args);

    _ParseModeString(strBuffer, _pixelFormatAttribs, _pbufferAttribs);

#ifdef _WIN32
    _pixelFormatAttribs.push_back(0);
    _pbufferAttribs.push_back(0);
#elif defined(__MACH__)
    _pixelFormatAttribs.push_back((CGLPixelFormatAttribute)0);
#else
    _pixelFormatAttribs.push_back(None);
#endif
    dbg_printf("RenderTexure:Reset(): returning true.\n");
    return true;
}

//------------------------------------------------------------------------------
// Function     	  : RenderTexture::Resize
// Description	    : 
//------------------------------------------------------------------------------
/**
 * @fn RenderTexture::Resize(int iWidth, int iHeight)
 * @brief Changes the size of the offscreen buffer.
 * 
 * Like Reset() this causes the buffer to delete itself.  
 * But unlike Reset(), this call re-initializes the RenderTexture.
 * Note that Resize() will not work after calling Reset(), or before
 * calling Initialize() the first time.
 */ 
bool RenderTexture::Resize(int iWidth, int iHeight)
{
    if (!_bInitialized) {
        SG_LOG(SG_GL, SG_ALERT, "RenderTexture::Resize(): must Initialize() first.");
        return false;
    }
    if (iWidth == _iWidth && iHeight == _iHeight) {
        return true;
    }
    
    // Do same basic work as _Invalidate, but don't reset all our flags
    if (_bIsTexture)
        glDeleteTextures(1, &_iTextureID);
    if (_bIsDepthTexture)
        glDeleteTextures(1, &_iDepthTextureID);
#ifdef _WIN32
    if ( _hPBuffer )
    {
        // Check if we are currently rendering in the pbuffer
        if (wglGetCurrentContext() == _hGLContext)
            wglMakeCurrent(0,0);
        if (!_bCopyContext) 
            wglDeleteContext( _hGLContext);
        wglReleasePbufferDCARBPtr( _hPBuffer, _hDC);
        wglDestroyPbufferARBPtr( _hPBuffer );
        _hPBuffer = 0;
        return true;
    }
#elif defined( __MACH__ )
    if ( _hPBuffer )
    {
        if (CGLGetCurrentContext() == _hGLContext)
            CGLSetCurrentContext(NULL);
        if (!_bCopyContext)
            CGLDestroyContext(_hGLContext);
        CGLDestroyPBuffer(_hPBuffer);
        _hPBuffer = NULL;
        return true;
    }
#else
    if ( _hPBuffer )
    {
        if(glXGetCurrentContext() == _hGLContext)
            // XXX I don't know if this is right at all
            glXMakeCurrent(_pDisplay, _hPBuffer, 0);
        glXDestroyPbufferPtr(_pDisplay, _hPBuffer);
        _hPBuffer = 0;
    }
#endif
    else {
        SG_LOG(SG_GL, SG_ALERT, "RenderTexture::Resize(): failed to resize.");
        return false;
    }
    _bInitialized = false;
    return Initialize(iWidth, iHeight, _bShareObjects, _bCopyContext);
}

//---------------------------------------------------------------------------
// Function     	: RenderTexture::BeginCapture
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::BeginCapture()
* @brief Activates rendering to the RenderTexture.
*/ 
bool RenderTexture::BeginCapture()
{
    if (!_bInitialized)
    {
        SG_LOG(SG_GL, SG_ALERT, 
                "RenderTexture::BeginCapture(): Texture is not initialized!");
        return false;
    }
#ifdef _WIN32
    // cache the current context so we can reset it when EndCapture() is called.
    _hPreviousDC      = wglGetCurrentDC();
    if (NULL == _hPreviousDC)
        _wglGetLastError();
    _hPreviousContext = wglGetCurrentContext();
    if (NULL == _hPreviousContext)
        _wglGetLastError();
#elif defined( __MACH__ )
    _hPreviousContext = CGLGetCurrentContext();
#else
    _hPreviousContext = glXGetCurrentContext();
    _hPreviousDrawable = glXGetCurrentDrawable();
#endif

    _ReleaseBoundBuffers();

    return _MakeCurrent();
}


//---------------------------------------------------------------------------
// Function     	: RenderTexture::EndCapture
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::EndCapture()
* @brief Ends rendering to the RenderTexture.
*/ 
bool RenderTexture::EndCapture()
{    
    if (!_bInitialized)
    {
        SG_LOG(SG_GL, SG_ALERT, 
                "RenderTexture::EndCapture() : Texture is not initialized!");
        return false;
    }

    glFlush();	// Added by a-lex

    _MaybeCopyBuffer();

#ifdef _WIN32
    // make the previous rendering context current 
    if (FALSE == wglMakeCurrent( _hPreviousDC, _hPreviousContext))
    {
        _wglGetLastError();
        return false;
    }
#elif defined( __MACH__ )
    CGLError err;
    if (err = CGLSetCurrentContext(_hPreviousContext))
    {
            _cglCheckError(err);
            return false;
    }
#else
    if (False == glXMakeCurrent(_pDisplay, _hPreviousDrawable, 
                                _hPreviousContext))
    {
        return false;
    }
#endif

    // rebind the textures to a buffers for RTT
    BindBuffer(_iCurrentBoundBuffer);
    _BindDepthBuffer();

    return true;
}

//---------------------------------------------------------------------------
// Function     	  : RenderTexture::BeginCapture(RenderTexture*)
// Description	    : 
//---------------------------------------------------------------------------
/**
 * @fn RenderTexture::BeginCapture(RenderTexture* other)
 * @brief Ends capture of 'other', begins capture on 'this'
 *
 * When performing a series of operations where you modify one texture after 
 * another, it is more efficient to use this method instead of the equivalent
 * 'EndCapture'/'BeginCapture' pair.  This method switches directly to the 
 * new context rather than changing to the default context, and then to the 
 * new context.
 *
 * RenderTexture doesn't have any mechanism for determining if 
 * 'current' really is currently active, so no error will be thrown 
 * if it is not. 
 */ 
bool RenderTexture::BeginCapture(RenderTexture* current)
{
    // bool bContextReset = false;
    
    if (current == this) {
        return true; // no switch necessary
    }
    if (!current) {
        // treat as normal Begin if current is 0.
        return BeginCapture();
    }
    if (!_bInitialized)
    {
        SG_LOG(SG_GL, SG_ALERT, 
            "RenderTexture::BeginCapture(RenderTexture*): Texture is not initialized!");
        return false;
    }
    if (!current->_bInitialized)
    {
        SG_LOG(SG_GL, SG_ALERT, 
            "RenderTexture::BeginCapture(RenderTexture): 'current' texture is not initialized!");
        return false;
    }
    
    // Sync current pbuffer with its CTT texture if necessary
    current->_MaybeCopyBuffer();

    // pass along the previous context so we can reset it when 
    // EndCapture() is called.
#ifdef _WIN32
    _hPreviousDC      = current->_hPreviousDC;
    if (NULL == _hPreviousDC)
        _wglGetLastError();
    _hPreviousContext = current->_hPreviousContext;
    if (NULL == _hPreviousContext)
        _wglGetLastError();
#elif defined( __MACH__ )
    _hPreviousContext = current->_hPreviousContext;
#else
    _hPreviousContext = current->_hPreviousContext;
    _hPreviousDrawable = current->_hPreviousDrawable;
#endif    

    // Unbind textures before making context current
    if (!_ReleaseBoundBuffers()) 
      return false;

    // Make the pbuffer context current
    if (!_MakeCurrent())
        return false;

    // Rebind buffers of initial RenderTexture
    current->BindBuffer(_iCurrentBoundBuffer);
    current->_BindDepthBuffer();
    
    return true;
}



//---------------------------------------------------------------------------
// Function     	: RenderTexture::Bind
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::Bind()
* @brief Binds RGB texture.
*/ 
void RenderTexture::Bind() const 
{ 
    if (_bInitialized && _bIsTexture) 
    {
        glBindTexture(_iTextureTarget, _iTextureID);
    }    
}


//---------------------------------------------------------------------------
// Function     	: RenderTexture::BindDepth
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::BindDepth()
* @brief Binds depth texture.
*/ 
void RenderTexture::BindDepth() const 
{ 
    if (_bInitialized && _bIsDepthTexture) 
    {
        glBindTexture(_iTextureTarget, _iDepthTextureID); 
    }
}


//---------------------------------------------------------------------------
// Function     	: RenderTexture::BindBuffer
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::BindBuffer()
* @brief Associate the RTT texture id with 'iBuffer' (e.g. WGL_FRONT_LEFT_ARB)
*/ 
bool RenderTexture::BindBuffer( int iBuffer )
{ 
    // Must bind the texture too
    if (_bInitialized && _bIsTexture) 
    {
        glBindTexture(_iTextureTarget, _iTextureID);
        
#ifdef _WIN32
        if (RT_RENDER_TO_TEXTURE == _eUpdateMode && _bIsTexture &&
            (!_bIsBufferBound || _iCurrentBoundBuffer != iBuffer))
        {
            if (FALSE == wglBindTexImageARBPtr(_hPBuffer, iBuffer))
            {
                //  WVB: WGL API considers binding twice to the same buffer
                //  to be an error.  But we don't want to 
                //_wglGetLastError();
                //return false;
                SetLastError(0);
            }
            _bIsBufferBound = true;
            _iCurrentBoundBuffer = iBuffer;
        }
#elif defined(__MACH__)
    if (RT_RENDER_TO_TEXTURE == _eUpdateMode && _bIsTexture &&
         (!_bIsBufferBound || _iCurrentBoundBuffer != iBuffer))
    {
        CGLError err;
        if (err=CGLTexImagePBuffer(CGLGetCurrentContext(), _hPBuffer, iBuffer))
        {
            _cglCheckError(err);
        }
        _bIsBufferBound = true;
        _iCurrentBoundBuffer = iBuffer;
     }
#endif
    }    
    return true;
}


//---------------------------------------------------------------------------
// Function     	: RenderTexture::BindDepthBuffer
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::_BindDepthBuffer()
* @brief Associate the RTT depth texture id with the depth buffer
*/ 
bool RenderTexture::_BindDepthBuffer() const
{
#ifdef WIN32
    if (_bInitialized && _bIsDepthTexture && 
        RT_RENDER_TO_TEXTURE == _eUpdateMode)
    {
        glBindTexture(_iTextureTarget, _iDepthTextureID);
        if (FALSE == wglBindTexImageARBPtr(_hPBuffer, WGL_DEPTH_COMPONENT_NV))
        {
            _wglGetLastError();
            return false;
        }
    }
#elif defined(__MACH__)
    if (_bInitialized && _bIsDepthTexture &&
        RT_RENDER_TO_TEXTURE == _eUpdateMode)
    {
        glBindTexture(_iTextureTarget, _iDepthTextureID);
        //if (FALSE == CGLTexImagePBuffer(<#CGLContextObj ctx#>,<#CGLPBufferObj pbuffer#>,<#unsigned long source#>)(_hPBuffer, WGL_DEPTH_COMPONENT_NV))
        //{
        //    _wglGetLastError();
        //    return false;
        //}
    }
#endif
    return true;
}

//---------------------------------------------------------------------------
// Function     	: RenderTexture::_ParseModeString
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::_ParseModeString()
* @brief Parses the user-specified mode string for RenderTexture parameters.
*/ 
void RenderTexture::_ParseModeString(const char *modeString, 
                                     vector<int> &pfAttribs, 
                                     vector<int> &pbAttribs)
{
    dbg_printf("RenderTexture::_ParseModeString(%s). BGN vf=%d vp=%d\n", modeString, (int)pfAttribs.size(), (int)pbAttribs.size() );
    if (!modeString || strcmp(modeString, "") == 0)
        return;

	_iNumComponents = 0;
#if defined(_WIN32) || defined(__MACH__)
    _eUpdateMode = RT_RENDER_TO_TEXTURE;
#else
    _eUpdateMode = RT_COPY_TO_TEXTURE;
#endif
    
    int  iDepthBits = 0;
    bool bHasStencil = false;
    bool bBind2D   = false;
    bool bBindRECT = false;
    bool bBindCUBE = false;
    
    char *mode = strdup(modeString);
    

    vector<string> tokens;
    char *buf = strtok(mode, " ");
    while (buf != NULL)
    {
        tokens.push_back(buf);
        buf = strtok(NULL, " ");
    }
    free(mode);
    for (unsigned int i = 0; i < tokens.size(); i++)
    {
        string token = tokens[i];

        KeyVal kv = _GetKeyValuePair(token);
        
        
        if (kv.first == "rgb" && (_iNumComponents <= 1))
        {           
            if (kv.second.find("f") != kv.second.npos)
                _bFloat = true;

            vector<int> bitVec = _ParseBitVector(kv.second);

            if (bitVec.size() < 3) // expand the scalar to a vector
            {
                bitVec.push_back(bitVec[0]);
                bitVec.push_back(bitVec[0]);
            }

#ifdef _WIN32
            pfAttribs.push_back(WGL_RED_BITS_ARB);
            pfAttribs.push_back(bitVec[0]);
            pfAttribs.push_back(WGL_GREEN_BITS_ARB);
            pfAttribs.push_back(bitVec[1]);
            pfAttribs.push_back(WGL_BLUE_BITS_ARB);
            pfAttribs.push_back(bitVec[2]);
#elif defined( __MACH__ )
# if 0
            pfAttribs.push_back(AGL_RED_SIZE);
            pfAttribs.push_back(bitVec[0]);
            pfAttribs.push_back(AGL_GREEN_SIZE);
            pfAttribs.push_back(bitVec[1]);
            pfAttribs.push_back(AGL_BLUE_SIZE);
            pfAttribs.push_back(bitVec[2]);
# else
            pfAttribs.push_back(kCGLPFAColorSize);
            pfAttribs.push_back(bitVec[0] + bitVec[1] + bitVec[2]);
# endif
#else
            pfAttribs.push_back(GLX_RED_SIZE);
            pfAttribs.push_back(bitVec[0]);
            pfAttribs.push_back(GLX_GREEN_SIZE);
            pfAttribs.push_back(bitVec[1]);
            pfAttribs.push_back(GLX_BLUE_SIZE);
            pfAttribs.push_back(bitVec[2]);
#endif
	    _iNumComponents += 3;
            continue;
        }
		else if (kv.first == "rgb")
       {
            SG_LOG(SG_GL, SG_ALERT, 
                    "RenderTexture Warning: mistake in components definition "
                    "(rgb + " << _iNumComponents << ").");
            dbg_printf("RenderTexture Warning 1: mistake in components definition "
                    "(rgb + %d).\n", _iNumComponents );
       }
        
        if (kv.first == "rgba" && (_iNumComponents == 0))
        {
            if (kv.second.find("f") != kv.second.npos)
                _bFloat = true;

            vector<int> bitVec = _ParseBitVector(kv.second);

            if (bitVec.size() < 4) // expand the scalar to a vector
            {
                bitVec.push_back(bitVec[0]);
                bitVec.push_back(bitVec[0]);
                bitVec.push_back(bitVec[0]);
            }

#ifdef _WIN32
            pfAttribs.push_back(WGL_RED_BITS_ARB);
            pfAttribs.push_back(bitVec[0]);
            pfAttribs.push_back(WGL_GREEN_BITS_ARB);
            pfAttribs.push_back(bitVec[1]);
            pfAttribs.push_back(WGL_BLUE_BITS_ARB);
            pfAttribs.push_back(bitVec[2]);
            pfAttribs.push_back(WGL_ALPHA_BITS_ARB);
            pfAttribs.push_back(bitVec[3]);
#elif defined( __MACH__ )
# if 0 
            pfAttribs.push_back(AGL_RED_SIZE);
            pfAttribs.push_back(bitVec[0]);
            pfAttribs.push_back(AGL_GREEN_SIZE);
            pfAttribs.push_back(bitVec[1]);
            pfAttribs.push_back(AGL_BLUE_SIZE);
            pfAttribs.push_back(bitVec[2]);
            pfAttribs.push_back(AGL_ALPHA_SIZE);
            pfAttribs.push_back(bitVec[3]);
# else
            pfAttribs.push_back(kCGLPFAColorSize);
            pfAttribs.push_back(bitVec[0] + bitVec[1] + bitVec[2] + bitVec[3]);
            //pfAttribs.push_back(kCGLPFAAlphaSize);
            //pfAttribs.push_back(bitVec[3]);
            // printf("Color size: %d\n", bitVec[0] + bitVec[1] + bitVec[2] + bitVec[3]);

# endif
#else
            pfAttribs.push_back(GLX_RED_SIZE);
            pfAttribs.push_back(bitVec[0]);
            pfAttribs.push_back(GLX_GREEN_SIZE);
            pfAttribs.push_back(bitVec[1]);
            pfAttribs.push_back(GLX_BLUE_SIZE);
            pfAttribs.push_back(bitVec[2]);
            pfAttribs.push_back(GLX_ALPHA_SIZE);
            pfAttribs.push_back(bitVec[3]);
#endif
	    _iNumComponents = 4;
            continue;
        }
		else if (kv.first == "rgba") 
      {
            SG_LOG(SG_GL, SG_ALERT, 
                    "RenderTexture Warning: mistake in components definition "
                    "(rgba + " << _iNumComponents << ").");
            dbg_printf("RenderTexture Warning 2: mistake in components definition "
                    "(rgb + %d).\n", _iNumComponents );
      }
        
        if (kv.first == "r" && (_iNumComponents <= 1))
        {
            if (kv.second.find("f") != kv.second.npos)
                _bFloat = true;

            vector<int> bitVec = _ParseBitVector(kv.second);

#ifdef _WIN32
            pfAttribs.push_back(WGL_RED_BITS_ARB);
            pfAttribs.push_back(bitVec[0]);
#elif defined( __MACH__ )
# if 0
            pfAttribs.push_back(AGL_RED_SIZE);
            pfAttribs.push_back(bitVec[0]);
# else
            pfAttribs.push_back(kCGLPFAColorSize);
            pfAttribs.push_back(bitVec[0]);
# endif
#else
            pfAttribs.push_back(GLX_RED_SIZE);
            pfAttribs.push_back(bitVec[0]);
#endif
			_iNumComponents++;
            continue;
        }
	else if (kv.first == "r") 
   {
            SG_LOG(SG_GL, SG_ALERT, 
                    "RenderTexture Warning: mistake in components definition "
                    "(r + " << _iNumComponents << ").");
            dbg_printf("RenderTexture Warning 3: mistake in components definition "
                    "(rgb + %d).\n", _iNumComponents );
   }
        if (kv.first == "rg" && (_iNumComponents <= 1))
        {
            if (kv.second.find("f") != kv.second.npos)
                _bFloat = true;

            vector<int> bitVec = _ParseBitVector(kv.second);

            if (bitVec.size() < 2) // expand the scalar to a vector
            {
                bitVec.push_back(bitVec[0]);
            }

#ifdef _WIN32
            pfAttribs.push_back(WGL_RED_BITS_ARB);
            pfAttribs.push_back(bitVec[0]);
            pfAttribs.push_back(WGL_GREEN_BITS_ARB);
            pfAttribs.push_back(bitVec[1]);
#elif defined( __MACH__ )
# if 0
            pfAttribs.push_back(AGL_RED_SIZE);
            pfAttribs.push_back(bitVec[0]);
            pfAttribs.push_back(AGL_GREEN_SIZE);
            pfAttribs.push_back(bitVec[1]);
# else
            pfAttribs.push_back(kCGLPFAColorSize);
            pfAttribs.push_back(bitVec[0] + bitVec[1]);
# endif
#else
            pfAttribs.push_back(GLX_RED_SIZE);
            pfAttribs.push_back(bitVec[0]);
            pfAttribs.push_back(GLX_GREEN_SIZE);
            pfAttribs.push_back(bitVec[1]);
#endif
			_iNumComponents += 2;
            continue;
        }
		else if (kv.first == "rg") 
      {
            SG_LOG(SG_GL, SG_ALERT, 
                    "RenderTexture Warning: mistake in components definition "
                    "(rg + " << _iNumComponents << ").");
            dbg_printf("RenderTexture Warning 4: mistake in components definition "
                    "(rgb + %d).\n", _iNumComponents );
      }

        if (kv.first == "depth")
        {
            if (kv.second == "")
                iDepthBits = 24;
            else
                iDepthBits = strtol(kv.second.c_str(), 0, 10);
            continue;
        }

        if (kv.first == "stencil")
        {
            bHasStencil = true;
#ifdef _WIN32
            pfAttribs.push_back(WGL_STENCIL_BITS_ARB);
#elif defined( __MACH__ )
# if 0
            pfAttribs.push_back(AGL_STENCIL_SIZE);
# else
            pfAttribs.push_back(kCGLPFAStencilSize);
# endif
#else
            pfAttribs.push_back(GLX_STENCIL_SIZE);
#endif
            if (kv.second == "")
                pfAttribs.push_back(8);
            else
                pfAttribs.push_back(strtol(kv.second.c_str(), 0, 10));
            continue;
        }

        if (kv.first == "samples")
        {
#ifdef _WIN32
            pfAttribs.push_back(WGL_SAMPLE_BUFFERS_ARB);
            pfAttribs.push_back(1);
            pfAttribs.push_back(WGL_SAMPLES_ARB);
            pfAttribs.push_back(strtol(kv.second.c_str(), 0, 10));
#elif defined( __MACH__ )
# if 0
            pfAttribs.push_back(AGL_SAMPLE_BUFFERS_ARB);
            pfAttribs.push_back(1);
            pfAttribs.push_back(AGL_SAMPLES_ARB);
# else
            pfAttribs.push_back(kCGLPFAMultisample);
            pfAttribs.push_back(kCGLPFASamples);
# endif
            pfAttribs.push_back(strtol(kv.second.c_str(), 0, 10));
#else
	    pfAttribs.push_back(GLX_SAMPLE_BUFFERS_ARB);
	    pfAttribs.push_back(1);
	    pfAttribs.push_back(GLX_SAMPLES_ARB);
            pfAttribs.push_back(strtol(kv.second.c_str(), 0, 10));
#endif
            continue;

        }

        if (kv.first == "doublebuffer" || kv.first == "double")
        {
#ifdef _WIN32
            pfAttribs.push_back(WGL_DOUBLE_BUFFER_ARB);
            pfAttribs.push_back(true);
#elif defined( __MACH__ )
# if 0
            pfAttribs.push_back(AGL_DOUBLEBUFFER);
            pfAttribs.push_back(True);
# else
            pfAttribs.push_back(kCGLPFADoubleBuffer);
# endif
#else
            pfAttribs.push_back(GLX_DOUBLEBUFFER);
            pfAttribs.push_back(True);
#endif
            continue;
        }  
        
        if (kv.first == "aux")
        {
#ifdef _WIN32
            pfAttribs.push_back(WGL_AUX_BUFFERS_ARB);
#elif defined( __MACH__ )
# if 0
            pfAttribs.push_back(AGL_AUX_BUFFERS);
# else
            pfAttribs.push_back(kCGLPFAAuxBuffers);
# endif
#else
            pfAttribs.push_back(GLX_AUX_BUFFERS);
#endif
            if (kv.second == "")
                pfAttribs.push_back(0);
            else
                pfAttribs.push_back(strtol(kv.second.c_str(), 0, 10));
            continue;
        }
        
        if (token.find("tex") == 0)
        {            
            _bIsTexture = true;
            
            if ((kv.first == "texRECT") && (GL_NV_texture_rectangle ||
                                            GL_EXT_texture_rectangle))
            {
                _bRectangle = true;
                bBindRECT = true;
            }
            else if (kv.first == "texCUBE")
            {
                bBindCUBE = true;
            }
            else
            {
                bBind2D = true;
            }

            continue;
        }

        if (token.find("depthTex") == 0)
        {
            _bIsDepthTexture = true;
            
            if ((kv.first == "depthTexRECT") && (GL_NV_texture_rectangle ||
                                                 GL_EXT_texture_rectangle))
            {
                _bRectangle = true;
                bBindRECT = true;
            }
            else if (kv.first == "depthTexCUBE")
            {
                bBindCUBE = true;
            }
            else
            {
                bBind2D = true;
            }

            continue;
        }

        if (kv.first == "mipmap")
        {
            _bMipmap = true;    
            continue;
        }

        if (kv.first == "rtt")
        {
            _eUpdateMode = RT_RENDER_TO_TEXTURE;
            continue;
        }
        
        if (kv.first == "ctt")
        {
            _eUpdateMode = RT_COPY_TO_TEXTURE;
            continue;
        }

        SG_LOG(SG_GL, SG_ALERT, 
                "RenderTexture Error: Unknown pbuffer attribute: " <<
                token.c_str());
        dbg_printf("RenderTexture Error: Uknown pbuffer attribute: %s\n",
            token.c_str() );
    }

    // Processing of some options must be last because of interactions.

    // Check for inconsistent texture targets
    if (_bIsTexture && _bIsDepthTexture && !(bBind2D ^ bBindRECT ^ bBindCUBE))
    {
        SG_LOG(SG_GL, SG_ALERT,
                "RenderTexture Warning: Depth and Color texture targets "
                "should match.");
        dbg_printf( "RenderTexture Warning: Depth and Color texture targets should match.\n");
    }

    // Apply default bit format if none specified
#ifdef _WIN32
    if (0 == _iNumComponents)
    {
        pfAttribs.push_back(WGL_RED_BITS_ARB);
        pfAttribs.push_back(8);
        pfAttribs.push_back(WGL_GREEN_BITS_ARB);
        pfAttribs.push_back(8);
        pfAttribs.push_back(WGL_BLUE_BITS_ARB);
        pfAttribs.push_back(8);
        pfAttribs.push_back(WGL_ALPHA_BITS_ARB);
        pfAttribs.push_back(8);
        _iNumComponents = 4;
    }
#endif

    // Depth bits
    if (_bIsDepthTexture && !iDepthBits)
        iDepthBits = 24;

#ifdef _WIN32
    pfAttribs.push_back(WGL_DEPTH_BITS_ARB);
#elif defined( __MACH__ )
# if 0
    pfAttribs.push_back(AGL_DEPTH_SIZE);
# else
    pfAttribs.push_back(kCGLPFADepthSize);
# endif
#else
    pfAttribs.push_back(GLX_DEPTH_SIZE);
#endif
    pfAttribs.push_back(iDepthBits); // default
    
    if (!bHasStencil)
    {
#ifdef _WIN32
        pfAttribs.push_back(WGL_STENCIL_BITS_ARB);
        pfAttribs.push_back(0);
#elif defined( __MACH__ )
# if 0
        pfAttribs.push_back(AGL_STENCIL_SIZE);
# else
        pfAttribs.push_back(kCGLPFAStencilSize);
# endif
        pfAttribs.push_back(0);
#else
        pfAttribs.push_back(GLX_STENCIL_SIZE);
        pfAttribs.push_back(0);
#endif

    }
    if (_iNumComponents < 4)
    {
        // Can't do this right now -- on NVIDIA drivers, currently get 
        // a non-functioning pbuffer if ALPHA_BITS=0 and 
        // WGL_BIND_TO_TEXTURE_RGB_ARB=true
        
        //pfAttribs.push_back(WGL_ALPHA_BITS_ARB); 
        //pfAttribs.push_back(0);
    }

#ifdef _WIN32
    if (!WGL_NV_render_depth_texture && _bIsDepthTexture && (RT_RENDER_TO_TEXTURE == _eUpdateMode))
    {
#if defined(DEBUG) || defined(_DEBUG)
        SG_LOG(SG_GL, SG_ALERT, "RenderTexture Warning: No support found for "
                "render to depth texture.");
#endif
        dbg_printf("RenderTexture Warning: No support found for render to depth texture.\n");
        _bIsDepthTexture = false;
    }
#endif
    
    if ((_bIsTexture || _bIsDepthTexture) && 
        (RT_RENDER_TO_TEXTURE == _eUpdateMode))
    {
#ifdef _WIN32                   
        if (bBindRECT)
        {
            pbAttribs.push_back(WGL_TEXTURE_TARGET_ARB);
            pbAttribs.push_back(WGL_TEXTURE_RECTANGLE_NV);
        }
        else if (bBindCUBE)
        {
            pbAttribs.push_back(WGL_TEXTURE_TARGET_ARB);
            pbAttribs.push_back(WGL_TEXTURE_CUBE_MAP_ARB);
        }
        else if (bBind2D)
        {
            pbAttribs.push_back(WGL_TEXTURE_TARGET_ARB);
            pbAttribs.push_back(WGL_TEXTURE_2D_ARB);
        }
            
        if (_bMipmap)
        {
            pbAttribs.push_back(WGL_MIPMAP_TEXTURE_ARB);
            pbAttribs.push_back(true);
        }
#elif defined(__MACH__)
#elif defined(DEBUG) || defined(_DEBUG)
        SG_LOG(SG_GL, SG_INFO, "RenderTexture Error: Render to Texture not "
               "supported in Linux or MacOS");
#endif  
    }

    // Set the pixel type
    if (_bFloat)
    {
#ifdef _WIN32
        if (WGL_NV_float_buffer)
        {
            pfAttribs.push_back(WGL_PIXEL_TYPE_ARB);
            pfAttribs.push_back(WGL_TYPE_RGBA_ARB);

            pfAttribs.push_back(WGL_FLOAT_COMPONENTS_NV);
            pfAttribs.push_back(true);
        }
        else
        {
            pfAttribs.push_back(WGL_PIXEL_TYPE_ARB);
            pfAttribs.push_back(WGL_TYPE_RGBA_FLOAT_ATI);
        }
#elif defined( __MACH__ )
        // if (GL_MACH_float_pixels) // FIXME
        {
            pfAttribs.push_back(kCGLPFAColorFloat);
        }
#else
        if (GLX_NV_float_buffer)
        {
            pfAttribs.push_back(GLX_FLOAT_COMPONENTS_NV);
            pfAttribs.push_back(1);
        }
#endif
    }
    else
    {
#ifdef _WIN32
        pfAttribs.push_back(WGL_PIXEL_TYPE_ARB);
        pfAttribs.push_back(WGL_TYPE_RGBA_ARB);
#endif
    }

    // Set up texture binding for render to texture
    if (_bIsTexture && (RT_RENDER_TO_TEXTURE == _eUpdateMode))
    {
        
#ifdef _WIN32
        if (_bFloat)
        {
            if (WGL_NV_float_buffer)
            {
                switch(_iNumComponents)
                {
                case 1:
                    pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV);
                    pfAttribs.push_back(true);
                    
                    pbAttribs.push_back(WGL_TEXTURE_FORMAT_ARB);
                    pbAttribs.push_back(WGL_TEXTURE_FLOAT_R_NV);
                    break;
                case 2:
                    pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV);
                    pfAttribs.push_back(true);
                    
                    pbAttribs.push_back(WGL_TEXTURE_FORMAT_ARB);
                    pbAttribs.push_back(WGL_TEXTURE_FLOAT_RG_NV);
                    break;
                case 3:
                    pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV);
                    pfAttribs.push_back(true);
                    
                    pbAttribs.push_back(WGL_TEXTURE_FORMAT_ARB);
                    pbAttribs.push_back(WGL_TEXTURE_FLOAT_RGB_NV);
                    break;
                case 4:
                    pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV);
                    pfAttribs.push_back(true);
                    
                    pbAttribs.push_back(WGL_TEXTURE_FORMAT_ARB);
                    pbAttribs.push_back(WGL_TEXTURE_FLOAT_RGBA_NV);
                    break;
                default:
                    SG_LOG(SG_GL, SG_ALERT, 
                            "RenderTexture Warning: Bad number of components "
                            "(r=1,rg=2,rgb=3,rgba=4): " <<
                            _iNumComponents);
                    dbg_printf("RenderTexture Warning 1: Bad number of components (r=1,rg=2,rgb=3,rgba=4): %d\n",
                            _iNumComponents);
                    break;
                }
            }
            else
            {
                if (4 == _iNumComponents)
                {
                    pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RGBA_ARB);
                    pfAttribs.push_back(true);
                    
                    pbAttribs.push_back(WGL_TEXTURE_FORMAT_ARB);
                    pbAttribs.push_back(WGL_TEXTURE_RGBA_ARB);
                }
                else 
                {
                    // standard ARB_render_texture only supports 3 or 4 channels
                    pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RGB_ARB);
                    pfAttribs.push_back(true);
                    
                    pbAttribs.push_back(WGL_TEXTURE_FORMAT_ARB);
                    pbAttribs.push_back(WGL_TEXTURE_RGB_ARB);
                }
            }
            
        } 
        else
        {
            switch(_iNumComponents)
            {
            case 3:
                pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RGB_ARB);
                pfAttribs.push_back(true);
                
                pbAttribs.push_back(WGL_TEXTURE_FORMAT_ARB);
                pbAttribs.push_back(WGL_TEXTURE_RGB_ARB);
                break;
            case 4:
                pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RGBA_ARB);
                pfAttribs.push_back(true);
                
                pbAttribs.push_back(WGL_TEXTURE_FORMAT_ARB);
                pbAttribs.push_back(WGL_TEXTURE_RGBA_ARB);
                break;
            default:
                SG_LOG(SG_GL, SG_ALERT, 
                        "RenderTexture Warning: Bad number of components "
                        "(r=1,rg=2,rgb=3,rgba=4): " << _iNumComponents);
                dbg_printf("RenderTexture Warning 2: Bad number of components (r=1,rg=2,rgb=3,rgba=4): %d\n",
                            _iNumComponents);
                break;
            }
        }
#elif defined(__MACH__)
        if (_bFloat)
        {
                       /*
            //if (WGLEW_NV_float_buffer)       // FIXME
            {
                switch(_iNumComponents)
                {
                case 1:
                    pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV);
                    pfAttribs.push_back(true);

                    pbAttribs.push_back(WGL_TEXTURE_FORMAT_ARB);
                    pbAttribs.push_back(WGL_TEXTURE_FLOAT_R_NV);
                    break;
                case 2:
                    pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV);
                    pfAttribs.push_back(true);

                    pbAttribs.push_back(WGL_TEXTURE_FORMAT_ARB);
                    pbAttribs.push_back(WGL_TEXTURE_FLOAT_RG_NV);
                    break;
                case 3:
                    pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV);
                    pfAttribs.push_back(true);

                    pbAttribs.push_back(WGL_TEXTURE_FORMAT_ARB);
                    pbAttribs.push_back(WGL_TEXTURE_FLOAT_RGB_NV);
                    break;
                case 4:
                    pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV);
                    pfAttribs.push_back(true);

                    pbAttribs.push_back(WGL_TEXTURE_FORMAT_ARB);
                    pbAttribs.push_back(WGL_TEXTURE_FLOAT_RGBA_NV);
                    break;
                default:
                    fprintf(stderr,
                            "RenderTexture Warning: Bad number of components "
                            "(r=1,rg=2,rgb=3,rgba=4): %d.\n",
                            _iNumComponents);
                    break;
                }
           }
            else
            {
                if (4 == _iNumComponents)
                {
                    pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RGBA_ARB);
                    pfAttribs.push_back(true);

                    pbAttribs.push_back(WGL_TEXTURE_FORMAT_ARB);
                    pbAttribs.push_back(WGL_TEXTURE_RGBA_ARB);
                }
                else
                {
                    // standard ARB_render_texture only supports 3 or 4 channels
                    pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RGB_ARB);
                    pfAttribs.push_back(true);

                    pbAttribs.push_back(WGL_TEXTURE_FORMAT_ARB);
                    pbAttribs.push_back(WGL_TEXTURE_RGB_ARB);
                }
            }
            */
        }
        else
        {
                       /*
            switch(_iNumComponents)
            {
            case 3:
                pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RGB_ARB);
                pfAttribs.push_back(true);

                pbAttribs.push_back(WGL_TEXTURE_FORMAT_ARB);
                pbAttribs.push_back(WGL_TEXTURE_RGB_ARB);
                break;
            case 4:
                pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RGBA_ARB);
                pfAttribs.push_back(true);

                pbAttribs.push_back(WGL_TEXTURE_FORMAT_ARB);
                pbAttribs.push_back(WGL_TEXTURE_RGBA_ARB);
                break;
            default:
                fprintf(stderr,
                        "RenderTexture Warning: Bad number of components "
                        "(r=1,rg=2,rgb=3,rgba=4): %d.\n", _iNumComponents);
                break;
            }
                       */
        }
#elif defined(DEBUG) || defined(_DEBUG)
        SG_LOG(SG_GL, SG_ALERT, 
                "RenderTexture Error: Render to Texture not supported in Linux or MacOS");
#endif  
      dbg_printf( "RenderTexture Error 1: Render to Texture not supported in Linux or MacOS\n");
    }
        
    if (_bIsDepthTexture && (RT_RENDER_TO_TEXTURE == _eUpdateMode))
    {  
#ifdef _WIN32
        if (_bRectangle)
        {
            pfAttribs.push_back(WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV);
            pfAttribs.push_back(true);
        
            pbAttribs.push_back(WGL_DEPTH_TEXTURE_FORMAT_NV);
            pbAttribs.push_back(WGL_TEXTURE_DEPTH_COMPONENT_NV);
        }
        else 
        {
            pfAttribs.push_back(WGL_BIND_TO_TEXTURE_DEPTH_NV);
            pfAttribs.push_back(true);
        
            pbAttribs.push_back(WGL_DEPTH_TEXTURE_FORMAT_NV);
            pbAttribs.push_back(WGL_TEXTURE_DEPTH_COMPONENT_NV);
        }
#elif defined(__MACH__)
#elif defined(DEBUG) || defined(_DEBUG)
        SG_LOG(SG_GL, SG_INFO, "RenderTexture Error: Render to Texture not supported in "
               "Linux or MacOS");
#endif 
      dbg_printf( "RenderTexture Error 2: Render to Texture not supported in Linux or MacOS\n");
    }
    dbg_printf("RenderTexture::_ParseModeString(%s). END vf=%d vp=%d\n", modeString, (int)pfAttribs.size(), (int)pbAttribs.size() );

}

//---------------------------------------------------------------------------
// Function     	: RenderTexture::_GetKeyValuePair
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::_GetKeyValuePair()
* @brief Parses expressions of the form "X=Y" into a pair (X,Y).
*/ 
RenderTexture::KeyVal RenderTexture::_GetKeyValuePair(string token)
{
    string::size_type pos = 0;
    if ((pos = token.find("=")) != token.npos)
    {
        string key = token.substr(0, pos);
        string value = token.substr(pos+1, token.length()-pos+1);
        return KeyVal(key, value);
    }
    else
        return KeyVal(token, "");
}

//---------------------------------------------------------------------------
// Function     	: RenderTexture::_ParseBitVector
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::_ParseBitVector()
* @brief Parses expressions of the form "=r,g,b,a" into a vector: (r,g,b,a)
*/ 
vector<int> RenderTexture::_ParseBitVector(string bitVector)
{
    vector<string> pieces;
    vector<int> bits;

    if (bitVector == "")
    {
        bits.push_back(8);  // if a depth isn't specified, use default 8 bits
        return bits;
    }

    string::size_type pos = 0; 
    string::size_type nextpos = 0;
    do
    { 
        nextpos = bitVector.find_first_of(", ", pos);
        pieces.push_back(string(bitVector, pos, nextpos - pos)); 
        pos = nextpos+1; 
    } while (nextpos != bitVector.npos );

    for ( vector<string>::iterator it = pieces.begin(); it != pieces.end(); it++)
    {
        bits.push_back(strtol(it->c_str(), 0, 10));
    }
    
    return bits;
}

//---------------------------------------------------------------------------
// Function     	: RenderTexture::_VerifyExtensions
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::_VerifyExtensions()
* @brief Checks that the necessary extensions are available based on RT mode.
*/ 
bool RenderTexture::_VerifyExtensions()
{
   dbg_printf("RenderTexture::_VerifyExtensions() called...\n");
#ifdef _WIN32
	// a second call to _VerifyExtensions will allways return true, causing a crash
	// if the extension is not supported
    if ( true || !fctPtrInited )
    {
        fctPtrInited = true;
        wglGetExtensionsStringARBProc wglGetExtensionsStringARBPtr = (wglGetExtensionsStringARBProc)wglGetProcAddress( "wglGetExtensionsStringARB" );
        if ( wglGetExtensionsStringARBPtr == 0 )
        {
            PrintExtensionError("WGL_ARB_extensions_string");
            return false;
        }
        string wglExtensionsString = wglGetExtensionsStringARBPtr( wglGetCurrentDC() );
        if ( SGSearchExtensionsString( wglExtensionsString.c_str(), "WGL_ARB_pixel_format" ) )
        {
            wglChoosePixelFormatARBPtr = (wglChoosePixelFormatARBProc)SGLookupFunction("wglChoosePixelFormatARB");
            wglGetPixelFormatAttribivARBPtr = (wglGetPixelFormatAttribivARBProc)SGLookupFunction("wglGetPixelFormatAttribivARB");
        }
        else
        {
            PrintExtensionError("WGL_ARB_pixel_format");
            return false;
        }
        if ( SGSearchExtensionsString( wglExtensionsString.c_str(), "WGL_ARB_pbuffer" ) )
        {
            wglCreatePbufferARBPtr = (wglCreatePbufferARBProc)SGLookupFunction("wglCreatePbufferARB");
            wglGetPbufferDCARBPtr = (wglGetPbufferDCARBProc)SGLookupFunction("wglGetPbufferDCARB");
            wglQueryPbufferARBPtr = (wglQueryPbufferARBProc)SGLookupFunction("wglQueryPbufferARB");
            wglReleasePbufferDCARBPtr = (wglReleasePbufferDCARBProc)SGLookupFunction("wglReleasePbufferDCARB");
            wglDestroyPbufferARBPtr = (wglDestroyPbufferARBProc)SGLookupFunction("wglDestroyPbufferARB");
        }
        else
        {
            PrintExtensionError("WGL_ARB_pbuffer");
            return false;
        }
        if ( SGSearchExtensionsString( wglExtensionsString.c_str(), "WGL_ARB_render_texture" ) )
        {
            wglBindTexImageARBPtr = (wglBindTexImageARBProc)SGLookupFunction("wglBindTexImageARB");
            wglReleaseTexImageARBPtr = (wglReleaseTexImageARBProc)SGLookupFunction("wglReleaseTexImageARB");
        }
        else if ( _bIsTexture )
        {
            PrintExtensionError("WGL_ARB_render_texture");
            return false;
        }
        if (_bRectangle && !SGIsOpenGLExtensionSupported( "GL_NV_texture_rectangle" ))
        {
            PrintExtensionError("GL_NV_texture_rectangle");
            return false;
        }
        if (_bFloat && !(SGIsOpenGLExtensionSupported( "GL_NV_float_buffer" ) ||
            SGSearchExtensionsString( wglExtensionsString.c_str(), "WGL_ATI_pixel_format_float" )))
        {
            PrintExtensionError("GL_NV_float_buffer or GL_ATI_pixel_format_float");
            return false;
        
        }
        if (_bFloat && _bIsTexture && !(SGIsOpenGLExtensionSupported( "GL_NV_float_buffer" ) || SGIsOpenGLExtensionSupported( "GL_ATI_texture_float" )))
        {
            PrintExtensionError("NV_float_buffer or ATI_texture_float");
        }
        if (_bIsDepthTexture && !SGIsOpenGLExtensionSupported( "GL_ARB_depth_texture" ))
        {
            // [Redge]
#if defined(_DEBUG) | defined(DEBUG)
            SG_LOG(SG_GL, SG_ALERT, 
                    "RenderTexture Warning: "
                    "OpenGL extension GL_ARB_depth_texture not available."
                    "         Using glReadPixels() to emulate behavior.");
#endif   
            _bHasARBDepthTexture = false;
            //PrintExtensionError("GL_ARB_depth_texture");
            //return false;
            // [/Redge]
        }
        SetLastError(0);
    }
#elif defined( __MACH__ )
    // FIXME! Check extensions!
#else
    Display* dpy = glXGetCurrentDisplay();
    int minor = 0, major = 0;
    if (!dpy) {
        dbg_printf("_VerifyExtensions: glXGetCurrentDisplay() returned NULL! returning false\n");
        return false;
    }
    if (!glXQueryVersion(dpy, &major, &minor)) 
    {
        dbg_printf("_VerifyExtensions: glXQueryVersion(dpy, &major, &minor) FAILED! returning false\n");
        return false;
    }
    else
    {
        dbg_printf("_VerifyExtensions: glXQueryVersion(dpy, major=%d, minor=%d)\n", major, minor);
    }

    int screen = DefaultScreen(dpy);
    const char* extString = glXQueryExtensionsString(dpy, screen);
    dbg_printf("_VerifyExtensions: glXQueryExtensionsString(dpy, screen) returned -\n[%s]\n",
      (extString ? extString : "<NULL>") );
    if (!SGSearchExtensionsString(extString, "GLX_SGIX_fbconfig") ||
        !SGSearchExtensionsString(extString, "GLX_SGIX_pbuffer"))
    {
        dbg_printf("_VerifyExtensions: glXQueryExtensionsString(dpy,screen) does NOT contain GLX_SGIX_fbconfig or GLX_SGIX_pbuffer!\n" );
        const char * extClient = glXGetClientString( dpy, GLX_EXTENSIONS );
        if (!extClient ||
            !SGSearchExtensionsString(extClient, "GLX_SGIX_fbconfig") ||
            !SGSearchExtensionsString(extClient, "GLX_SGIX_pbuffer"))
        {
            dbg_printf("_VerifyExtensions: AND glXGetClientString(dpy,GLX_EXTENSIONS) also! returning false\n" );
            return false;
        }
        else
        {
            dbg_printf("_VerifyExtensions: BUT glXGetClientString(dpy,GLX_EXTENSIONS) returned \n[%s]\n", extClient );
            dbg_printf("Since this DOES contain fbconfig and pbuffer, continuing...\n");
        }
    }
    // First try the glX version 1.3 functions.
    glXChooseFBConfigPtr = (glXChooseFBConfigProc)SGLookupFunction("glXChooseFBConfig");
    glXCreatePbufferPtr = (glXCreatePbufferProc)SGLookupFunction("glXCreatePbuffer");
    glXGetVisualFromFBConfigPtr = (glXGetVisualFromFBConfigProc)SGLookupFunction("glXGetVisualFromFBConfig");
    glXCreateContextPtr = (glXCreateContextProc)SGLookupFunction("glXCreateContext");
    glXDestroyPbufferPtr = (glXDestroyPbufferProc)SGLookupFunction("glXDestroyPbuffer");
    glXQueryDrawablePtr = (glXQueryDrawableProc)SGLookupFunction("glXQueryDrawable");

    if (((1 <= major && 3 <= minor) || 2 <= major) &&
        glXChooseFBConfigPtr &&
        glXCreatePbufferPtr &&
        glXGetVisualFromFBConfigPtr &&
        glXCreateContextPtr &&
        glXDestroyPbufferPtr &&
        glXQueryDrawablePtr) {
        dbg_printf("_VerifyExtensions: setting glXVersion1_3Present TRUE\n" );
        glXVersion1_3Present = true;
    }
    else
    {
        dbg_printf("_VerifyExtensions: setting glXVersion1_3Present FALSE\n Reason: " );
        if ( !((1 <= major && 3 <= minor) || 2 <= major) ) { dbg_printf( "Version wrong %d.%d ", major, minor ); }
        if ( !glXChooseFBConfigPtr ) { dbg_printf( "missing glXChooseFBConfigPtr " ); }
        if ( !glXCreatePbufferPtr ) { dbg_printf( "missing glXCreatePbufferPtr " ); }
        if ( !glXGetVisualFromFBConfigPtr ) { dbg_printf( "missing glXGetVisualFromFBConfigPtr " ); }
        if ( !glXCreateContextPtr ) { dbg_printf( "missing glXCreateContextPtr " ); }
        if ( !glXDestroyPbufferPtr ) { dbg_printf( "missing glXDestroyPbufferPtr " ); }
        if ( !glXQueryDrawablePtr ) { dbg_printf( "missing glXQueryDrawablePtr " ); }
        dbg_printf("\n");
        
        glXChooseFBConfigPtr = (glXChooseFBConfigProc)SGLookupFunction("glXChooseFBConfigSGIX");
        glXCreateGLXPbufferPtr = (glXCreateGLXPbufferProc)SGLookupFunction("glXCreateGLXPbufferSGIX");
        glXGetVisualFromFBConfigPtr =  (glXGetVisualFromFBConfigProc)SGLookupFunction("glXGetVisualFromFBConfigSGIX");
        glXCreateContextWithConfigPtr = (glXCreateContextWithConfigProc)SGLookupFunction("glXCreateContextWithConfigSGIX");
        glXDestroyPbufferPtr = (glXDestroyPbufferProc)SGLookupFunction("glXDestroyGLXPbufferSGIX");
        glXQueryGLXPbufferSGIXPtr = (glXQueryGLXPbufferSGIXProc)SGLookupFunction("glXQueryGLXPbufferSGIX");

        if (!glXChooseFBConfigPtr ||
            !glXCreateGLXPbufferPtr ||
            !glXGetVisualFromFBConfigPtr ||
            !glXCreateContextWithConfigPtr ||
            !glXDestroyPbufferPtr ||
            !glXQueryGLXPbufferSGIXPtr)
            {
               dbg_printf("_VerifyExtensions: some pointer is NULL! return false\n" );
               if ( !glXCreateGLXPbufferPtr ) {
                  dbg_printf("RenderTexture::Initialize: ERROR glXCreateGLXPbufferPtr = NULL!\n");
               } else if ( !glXCreateContextWithConfigPtr ) {
                  dbg_printf("RenderTexture::Initialize: ERROR glXCreateContextWithConfigPtr = NULL!\n");
               } else if ( !glXVersion1_3Present && !glXQueryGLXPbufferSGIXPtr ) {
                  dbg_printf("RenderTexture::Initialize: ERROR glXQueryGLXPbufferSGIXPtr = NULL!\n");
               }
               return false;
            } else {
               dbg_printf("_VerifyExtensions: appear to have all 'procs' glXCreateGLXPbufferPtr=[%p]\n", glXCreateGLXPbufferPtr );
            }
    }

    if (_bIsDepthTexture && !GL_ARB_depth_texture)
    {
        PrintExtensionError("GL_ARB_depth_texture");
        return false;
    }
    if (_bFloat && _bIsTexture && !GLX_NV_float_buffer)
    {
        PrintExtensionError("GLX_NV_float_buffer");
        return false;
    }
    if (_eUpdateMode == RT_RENDER_TO_TEXTURE)
    {
        PrintExtensionError("Some GLX render texture extension: Please implement me!");
        return false;
    }
#endif
  
    dbg_printf("RenderTexture::_VerifyExtensions: return true.\n");
    return true;
}

//---------------------------------------------------------------------------
// Function     	: RenderTexture::_InitializeTextures
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::_InitializeTextures()
* @brief Initializes the state of textures used by the RenderTexture.
*/ 
bool RenderTexture::_InitializeTextures()
{
   dbg_printf( "RenderTexture::_InitializeTextures() called\n" );
    // Determine the appropriate texture formats and filtering modes.
    
    if (_bIsTexture || _bIsDepthTexture)
    {
        if (_bRectangle && GL_NV_texture_rectangle)
            _iTextureTarget = GL_TEXTURE_RECTANGLE_NV;
        else if (_bRectangle && GL_EXT_texture_rectangle)
            _iTextureTarget = GL_TEXTURE_RECTANGLE_EXT;
        else
            _iTextureTarget = GL_TEXTURE_2D;
    }

    if (_bIsTexture)
    {
        glGenTextures(1, (GLuint*)&_iTextureID);
        glBindTexture(_iTextureTarget, _iTextureID);  
        
        // Use clamp to edge as the default texture wrap mode for all tex
        glTexParameteri(_iTextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(_iTextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
        // Use NEAREST as the default texture filtering mode.
        glTexParameteri(_iTextureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(_iTextureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);


        if (RT_COPY_TO_TEXTURE == _eUpdateMode)
        {
            GLuint iInternalFormat;
            GLuint iFormat;

            if (_bFloat)
            {                             
                if (_bMipmap)
                {
                    SG_LOG(SG_GL, SG_ALERT, 
                        "RenderTexture Error: mipmapped float textures not "
                        "supported.");
                    dbg_printf( "RenderTexture Error: mipmapped float textures not supported. return false\n");
                    return false;
                }
            
                switch(_iNumComponents) 
                {
                case 1:
                    if (GL_NV_float_buffer)
                    {
                        iInternalFormat = (_iNumColorBits[0] > 16) ? 
                            GL_FLOAT_R32_NV : GL_FLOAT_R16_NV;
                    }
                    else if (GL_ATI_texture_float)
                    {
                        iInternalFormat = (_iNumColorBits[0] > 16) ? 
                            GL_LUMINANCE_FLOAT32_ATI : 
                            GL_LUMINANCE_FLOAT16_ATI;
                    }
                    iFormat = GL_LUMINANCE;
                	break;
                case 2:
                    if (GL_NV_float_buffer)
                    {
                        iInternalFormat = (_iNumColorBits[0] > 16) ? 
                            GL_FLOAT_RG32_NV : GL_FLOAT_RG16_NV;
                    }
                    else if (GL_ATI_texture_float)
                    {
                        iInternalFormat = (_iNumColorBits[0] > 16) ? 
                            GL_LUMINANCE_ALPHA_FLOAT32_ATI : 
                            GL_LUMINANCE_ALPHA_FLOAT16_ATI;
                    }
                    iFormat = GL_LUMINANCE_ALPHA;
                	break;
                case 3:
                    if (GL_NV_float_buffer)
                    {
                        iInternalFormat = (_iNumColorBits[0] > 16) ? 
                            GL_FLOAT_RGB32_NV : GL_FLOAT_RGB16_NV;
                    }
                    else if (GL_ATI_texture_float)
                    {
                        iInternalFormat = (_iNumColorBits[0] > 16) ? 
                            GL_RGB_FLOAT32_ATI : GL_RGB_FLOAT16_ATI;
                    }
                    iFormat = GL_RGB;
                    break;
                case 4:
                    if (GL_NV_float_buffer)
                    {
                        iInternalFormat = (_iNumColorBits[0] > 16) ? 
                            GL_FLOAT_RGBA32_NV : GL_FLOAT_RGBA16_NV;
                    }
                    else if (GL_ATI_texture_float)
                    {
                        iInternalFormat = (_iNumColorBits[0] > 16) ? 
                            GL_RGBA_FLOAT32_ATI : GL_RGBA_FLOAT16_ATI;
                    }
                    iFormat = GL_RGBA;
                    break;
                default:
                    SG_LOG(SG_GL, SG_INFO, "RenderTexture Error: "
                           "Invalid number of components: " <<
                           _iNumComponents);
                    dbg_printf( "RenderTexture Error: Invalid number of components: %d - return false\n",
                        _iNumComponents);
                    return false;
                }
            }
            else // non-float
            {                        
                if (4 == _iNumComponents)
                {
                    iInternalFormat = GL_RGBA8;
                    iFormat = GL_RGBA;
                }
                else 
                {
                    iInternalFormat = GL_RGB8;
                    iFormat = GL_RGB;
                }
            }
        
            // Allocate the texture image (but pass it no data for now).
            glTexImage2D(_iTextureTarget, 0, iInternalFormat, 
                         _iWidth, _iHeight, 0, iFormat, GL_FLOAT, NULL);
        } 
    }
  
    if (_bIsDepthTexture)
    { 
        glGenTextures(1, (GLuint*)&_iDepthTextureID);
        glBindTexture(_iTextureTarget, _iDepthTextureID);  
        
        // Use clamp to edge as the default texture wrap mode for all tex
        glTexParameteri(_iTextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(_iTextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
        // Use NEAREST as the default texture filtering mode.
        glTexParameteri(_iTextureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(_iTextureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
               
        if (RT_COPY_TO_TEXTURE == _eUpdateMode)
        {
            // [Redge]
            if (_bHasARBDepthTexture) 
            {
                // Allocate the texture image (but pass it no data for now).
                glTexImage2D(_iTextureTarget, 0, GL_DEPTH_COMPONENT, 
                             _iWidth, _iHeight, 0, GL_DEPTH_COMPONENT, 
                             GL_FLOAT, NULL);
            } 
            else 
            {
                // allocate memory for depth texture
                // Since this is slow, we warn the user in debug mode. (above)
                _pPoorDepthTexture = new unsigned short[_iWidth * _iHeight];
                glTexImage2D(_iTextureTarget, 0, GL_LUMINANCE16, 
                             _iWidth, _iHeight, 0, GL_LUMINANCE, 
                             GL_UNSIGNED_SHORT, _pPoorDepthTexture);
            }
            // [/Redge]
        }
    }

    dbg_printf( "RenderTexture::_InitializeTextures() returning true\n" );
    return true;
}


//---------------------------------------------------------------------------
// Function     	: RenderTexture::_MaybeCopyBuffer
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::_MaybeCopyBuffer()
* @brief Does the actual copying for RenderTextures with RT_COPY_TO_TEXTURE
*/ 
void RenderTexture::_MaybeCopyBuffer()
{
#ifdef _WIN32
    if (RT_COPY_TO_TEXTURE == _eUpdateMode)
    {
        if (_bIsTexture)
        {
            glBindTexture(_iTextureTarget, _iTextureID);
            glCopyTexSubImage2D(_iTextureTarget, 
                                0, 0, 0, 0, 0, _iWidth, _iHeight);
        }
        if (_bIsDepthTexture)
        {
            glBindTexture(_iTextureTarget, _iDepthTextureID);
            // HOW TO COPY DEPTH TEXTURE??? Supposedly this just magically works...
            // [Redge]
            if (_bHasARBDepthTexture) 
            {
                glCopyTexSubImage2D(_iTextureTarget, 0, 0, 0, 0, 0, 
                                    _iWidth, _iHeight);
            } 
            else 
            {
                // no 'real' depth texture available, so behavior has to be emulated
                // using glReadPixels (beware, this is (naturally) slow ...)
                glReadPixels(0, 0, _iWidth, _iHeight, GL_DEPTH_COMPONENT, 
                             GL_UNSIGNED_SHORT, _pPoorDepthTexture);
                glTexImage2D(_iTextureTarget, 0, GL_LUMINANCE16,
                             _iWidth, _iHeight, 0, GL_LUMINANCE, 
                             GL_UNSIGNED_SHORT, _pPoorDepthTexture);
            }
            // [/Redge]
        }
    }
    
#elif defined(__MACH__)
    if (RT_COPY_TO_TEXTURE == _eUpdateMode)
    {
       if (_bIsTexture)
       {
         glBindTexture(_iTextureTarget, _iTextureID);
         glCopyTexSubImage2D(_iTextureTarget, 0, 0, 0, 0, 0, _iWidth, _iHeight);
       }
       if (_bIsDepthTexture)
       {
         glBindTexture(_iTextureTarget, _iDepthTextureID);
         assert(_bHasARBDepthTexture);
         glCopyTexSubImage2D(_iTextureTarget, 0, 0, 0, 0, 0, _iWidth, _iHeight);
       }
    }
#else
    if (_bIsTexture)
    {
      glBindTexture(_iTextureTarget, _iTextureID);
      glCopyTexSubImage2D(_iTextureTarget, 0, 0, 0, 0, 0, _iWidth, _iHeight);
    }
    if (_bIsDepthTexture)
    {
      glBindTexture(_iTextureTarget, _iDepthTextureID);
      assert(_bHasARBDepthTexture);
      glCopyTexSubImage2D(_iTextureTarget, 0, 0, 0, 0, 0, _iWidth, _iHeight);
    }
#endif

}

//---------------------------------------------------------------------------
// Function     	: RenderTexture::_ReleaseBoundBuffers
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::_ReleaseBoundBuffers()
* @brief Releases buffer bindings on RenderTextures with RT_RENDER_TO_TEXTURE
*/ 
bool RenderTexture::_ReleaseBoundBuffers()
{
#ifdef _WIN32
    if (_bIsTexture && RT_RENDER_TO_TEXTURE == _eUpdateMode)
    {
        glBindTexture(_iTextureTarget, _iTextureID);
        
        // release the pbuffer from the render texture object
        if (0 != _iCurrentBoundBuffer && _bIsBufferBound)
        {
            if (FALSE == wglReleaseTexImageARBPtr(_hPBuffer, _iCurrentBoundBuffer))
            {
                _wglGetLastError();
                return false;
            }
            _bIsBufferBound = false;
        }
    }
    
    if (_bIsDepthTexture && RT_RENDER_TO_TEXTURE == _eUpdateMode)
    {
        glBindTexture(_iTextureTarget, _iDepthTextureID);
        
        // release the pbuffer from the render texture object
        if (FALSE == wglReleaseTexImageARBPtr(_hPBuffer, WGL_DEPTH_COMPONENT_NV))
        {
            _wglGetLastError();
            return false;
        }
    }
    
#else
    // textures can't be bound in Linux
#endif
    return true;
}

//---------------------------------------------------------------------------
// Function     	: RenderTexture::_MakeCurrent
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::_MakeCurrent()
* @brief Makes the RenderTexture's context current
*/ 
bool RenderTexture::_MakeCurrent() 
{
#ifdef _WIN32
    // make the pbuffer's rendering context current.
    if (FALSE == wglMakeCurrent( _hDC, _hGLContext))
    {
        _wglGetLastError();
        return false;
    }
#elif defined( __MACH__ )
    CGLError err;

    if (err = CGLSetCurrentContext(_hGLContext))
    {
        _cglCheckError(err);
        return false;
    }
#else
static GLXContext last_hGLContext = 0;
    if (false == glXMakeCurrent(_pDisplay, _hPBuffer, _hGLContext)) 
    {
        dbg_printf( "_MakeCurrent: glXMakeCurrent FAILED! returning false\n");
        return false;
    }

    if ( last_hGLContext != _hGLContext ) {
      last_hGLContext = _hGLContext;
      dbg_printf( "_MakeCurrent: glXMakeCurrent set to [%p] SUCCESS! returning true\n", _hGLContext );
    }
#endif
    return true;
}

/////////////////////////////////////////////////////////////////////////////
//
// Begin Deprecated Interface
//
/////////////////////////////////////////////////////////////////////////////

//---------------------------------------------------------------------------
// Function      : RenderTexture::RenderTexture
// Description	 : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::RenderTexture()
* @brief Constructor.
*/ 
RenderTexture::RenderTexture(int width, int height,
                               bool bIsTexture /* = true */,
                               bool bIsDepthTexture /* = false */)
:   _iWidth(width), 
    _iHeight(height), 
    _bIsTexture(bIsTexture),
    _bIsDepthTexture(bIsDepthTexture),
    _bHasARBDepthTexture(true),            // [Redge]
    _eUpdateMode(RT_RENDER_TO_TEXTURE),
    _bInitialized(false),
    _iNumAuxBuffers(0),
    _iCurrentBoundBuffer(0),
    _iNumDepthBits(0),
    _iNumStencilBits(0),
    _bFloat(false),
    _bDoubleBuffered(false),
    _bPowerOf2(true),
    _bRectangle(false),
    _bMipmap(false),
    _bShareObjects(false),
    _bCopyContext(false),
#ifdef _WIN32
    _hDC(NULL), 
    _hGLContext(NULL), 
    _hPBuffer(NULL),
    _hPreviousDC(0),
    _hPreviousContext(0),
#elif defined( __MACH__ )
    _hGLContext(NULL),
    _hPBuffer(NULL),
    _hPreviousContext(NULL),
#else
    _pDisplay(NULL),
    _hGLContext(NULL),
    _hPBuffer(0),
    _hPreviousDrawable(0),
    _hPreviousContext(0),
#endif
    _iTextureTarget(GL_NONE),
    _iTextureID(0),
    _iDepthTextureID(0),
    _pPoorDepthTexture(0) // [Redge]
{
    assert(width > 0 && height > 0);
#if defined DEBUG || defined _DEBUG
    SG_LOG(SG_GL, SG_ALERT, 
            "RenderTexture Warning: Deprecated Contructor interface used.");
#endif
    dbg_printf("RenderTexture Warning: Deprecated Contructor interface used.\n");
    
    _iNumColorBits[0] = _iNumColorBits[1] = 
        _iNumColorBits[2] = _iNumColorBits[3] = 0;
    _bPowerOf2 = IsPowerOfTwo(width) && IsPowerOfTwo(height);
}

//------------------------------------------------------------------------------
// Function     	: RenderTexture::Initialize
// Description	    : 
//------------------------------------------------------------------------------
/**
* @fn RenderTexture::Initialize(bool bShare, bool bDepth, bool bStencil, bool bMipmap, unsigned int iRBits, unsigned int iGBits, unsigned int iBBits, unsigned int iABits);
* @brief Initializes the RenderTexture, sharing display lists and textures if specified.
* 
* This function actually does the creation of the p-buffer.  It can only be called 
* once a GL context has already been created.  Note that if the texture is not
* power of two dimensioned, or has more than 8 bits per channel, enabling mipmapping
* will cause an error.
*/ 
bool RenderTexture::Initialize(bool         bShare       /* = true */, 
                                bool         bDepth       /* = false */, 
                                bool         bStencil     /* = false */, 
                                bool         bMipmap      /* = false */, 
                                bool         bAnisoFilter /* = false */,
                                unsigned int iRBits       /* = 8 */, 
                                unsigned int iGBits       /* = 8 */, 
                                unsigned int iBBits       /* = 8 */, 
                                unsigned int iABits       /* = 8 */,
                                UpdateMode   updateMode   /* = RT_RENDER_TO_TEXTURE */)
{   
    if (0 == _iWidth || 0 == _iHeight)
        return false;

#if defined DEBUG || defined _DEBUG
    SG_LOG(SG_GL, SG_ALERT, 
            "RenderTexture Warning: Deprecated Initialize() interface used.");
#endif   
    dbg_printf("RenderTexture Warning: Deprecated Initialize() interface used.\n");

    // create a mode string.
    string mode = "";
    if (bDepth)
        mode.append("depth ");
    if (bStencil)
        mode.append("stencil ");
    if (bMipmap)
        mode.append("mipmap ");
    if (iRBits + iGBits + iBBits + iABits > 0)
    {
        if (iRBits > 0)
            mode.append("r");
        if (iGBits > 0)
            mode.append("g");
        if (iBBits > 0)
            mode.append("b");
        if (iABits > 0)
            mode.append("a");
        mode.append("=");
        char bitVector[100];
        snprintf( bitVector, 100,
            "%d%s,%d%s,%d%s,%d%s",
            iRBits, (iRBits >= 16) ? "f" : "",
            iGBits, (iGBits >= 16) ? "f" : "",
            iBBits, (iBBits >= 16) ? "f" : "",
            iABits, (iABits >= 16) ? "f" : "");
        mode.append(bitVector);
        mode.append(" ");
    }
    if (_bIsTexture)
    {
        if ((GL_NV_texture_rectangle || GL_EXT_texture_rectangle) && 
            ((!IsPowerOfTwo(_iWidth) || !IsPowerOfTwo(_iHeight))
              || iRBits >= 16 || iGBits > 16 || iBBits > 16 || iABits >= 16))
            mode.append("texRECT ");
        else
            mode.append("tex2D ");
    }
    if (_bIsDepthTexture)
    {
        if ((GL_NV_texture_rectangle || GL_EXT_texture_rectangle) && 
            ((!IsPowerOfTwo(_iWidth) || !IsPowerOfTwo(_iHeight))
              || iRBits >= 16 || iGBits > 16 || iBBits > 16 || iABits >= 16))
            mode.append("texRECT ");
        else
            mode.append("tex2D ");
    }
    if (RT_COPY_TO_TEXTURE == updateMode)
        mode.append("ctt");

    _pixelFormatAttribs.clear();
    _pbufferAttribs.clear();

#ifdef _WIN32
    _pixelFormatAttribs.push_back(WGL_DRAW_TO_PBUFFER_ARB);
    _pixelFormatAttribs.push_back(true);
    _pixelFormatAttribs.push_back(WGL_SUPPORT_OPENGL_ARB);
    _pixelFormatAttribs.push_back(true);
    
    _pbufferAttribs.push_back(WGL_PBUFFER_LARGEST_ARB);
    _pbufferAttribs.push_back(true);
#elif defined( __MACH__ )
    //_pixelFormatAttribs.push_back(kCGLPFANoRecovery);
    _pixelFormatAttribs.push_back(kCGLPFAAccelerated);
    _pixelFormatAttribs.push_back(kCGLPFAWindow);
    _pixelFormatAttribs.push_back(kCGLPFAPBuffer);
#else
    _pixelFormatAttribs.push_back(GLX_RENDER_TYPE_SGIX);
    _pixelFormatAttribs.push_back(GLX_RGBA_BIT_SGIX);
    _pixelFormatAttribs.push_back(GLX_DRAWABLE_TYPE_SGIX);
    _pixelFormatAttribs.push_back(GLX_PBUFFER_BIT_SGIX);
#endif

    _ParseModeString(mode.c_str(), _pixelFormatAttribs, _pbufferAttribs);

#ifdef _WIN32
    _pixelFormatAttribs.push_back(0);
    _pbufferAttribs.push_back(0);
#elif defined(__MACH__)
    _pixelFormatAttribs.push_back(0);
#else
    _pixelFormatAttribs.push_back(None);
#endif

    Initialize(_iWidth, _iHeight, bShare);
    
    return true;
}


//---------------------------------------------------------------------------
// Function     	: RenderTexture::Reset
// Description	    : 
//---------------------------------------------------------------------------
/**
* @fn RenderTexture::Reset(int iWidth, int iHeight, unsigned int iMode, bool bIsTexture, bool bIsDepthTexture)
* @brief Resets the resolution of the offscreen buffer.
* 
* Causes the buffer to delete itself.  User must call Initialize() again
* before use.
*/ 
bool RenderTexture::Reset(int iWidth, int iHeight)
{
    SG_LOG(SG_GL, SG_ALERT, 
            "RenderTexture Warning: Deprecated Reset() interface used.");
            
    dbg_printf("RenderTexture Warning: Deprecated Reset(x,y) interface used.\n");

    if (!_Invalidate())
    {
        SG_LOG(SG_GL, SG_ALERT, "RenderTexture::Reset(): failed to invalidate.");
        dbg_printf( "RenderTexture::Reset(x,y): failed to invalidate. returning false\n");
        return false;
    }
    _iWidth     = iWidth;
    _iHeight    = iHeight;
    
    dbg_printf( "RenderTexture::Reset(x,y): succeeded. returning true\n");
    return true;
}

#if defined( _DEBUG ) && !defined( _WIN32 ) && !defined( __MACH__ )
/* just some DEBUG ONLY code, to show the 'attributes' */

typedef struct tagPXATTS {
   int attr;
   const char * name;
   const char * desc;
   int def;
}PXATTS, * PPXATTS;

static PXATTS pxAtts[] = {
   { GLX_FBCONFIG_ID, "GLX_FBCONFIG_ID",
     "followed by a valid XID that indicates the desired GLX frame buffer configuration. "
     "When a GLX_FBCONFIG_ID is specified, all attributes are ignored. The default value is GLX_DONT_CARE.",
     GLX_DONT_CARE },
   { GLX_BUFFER_SIZE, "GLX_BUFFER_SIZE",
   "Must be followed by a nonnegative integer that indicates the desired color index buffer size."
   "The smallest index buffer of at least the specified size is preferred. This attribute is ignored if GLX_COLOR_INDEX_BIT is not set "
   "in GLX_RENDER_TYPE. The default value is 0.",
    0 },
   { GLX_LEVEL, "GLX_LEVEL",
   "Must be followed by an integer buffer-level specification. This specification is honored exactly."
   "Buffer level 0 corresponds to the default frame buffer of the display. "
   "Buffer level 1 is the first overlay frame buffer, level two the second overlay frame buffer, and so on."
   "Negative buffer levels correspond to underlay frame buffers. The default value is 0.",
    0 },
   { GLX_DOUBLEBUFFER, "GLX_DOUBLEBUFFER",
   "Must be followed by True or False. If True is specified, then only double-buffered frame buffer configurations are considered;"
   "if False is specified, then only single-buffered frame buffer configurations are considered. The default value is GLX_DONT_CARE.",
    GLX_DONT_CARE },
   { GLX_STEREO, "GLX_STEREO",
   "Must be followed by True or False. If True is specified, then only stereo frame buffer configurations are considered;"
   " if False is specified, then only monoscopic frame buffer configurations are considered. The default value is False.",
   False },
   { GLX_AUX_BUFFERS, "GLX_AUX_BUFFERS",
   "Must be followed by a nonnegative integer that indicates the desired number of auxiliary buffers."
   " Configurations with the  smallest number of auxiliary buffers that meet or exceed the specified number are preferred."
   " The default value is 0.",
   0 },
   { GLX_RED_SIZE, "GLX_RED_SIZE",
   "must be followed by a nonnegative minimum size",
   0 },
   { GLX_GREEN_SIZE, "GLX_GREEN_SIZE",
   "must be followed by a nonnegative minimum size",
   0 },
   { GLX_BLUE_SIZE, "GLX_BLUE_SIZE",
   "must be followed by a nonnegative minimum size",
   0 },
   { GLX_ALPHA_SIZE, "GLX_ALPHA_SIZE",
   "Each attribute, if present, must be followed by a nonnegative minimum size specification or GLX_DONT_CARE."
   " The largest available total RGBA color buffer size (sum of GLX_RED_SIZE, GLX_GREEN_SIZE, GLX_BLUE_SIZE, and GLX_ALPHA_SIZE) "
   " of at least the minimum size specified for each color component is preferred. If the requested number of bits for a color "
   " component is 0 or GLX_DONT_CARE, it is not considered. The default value for each color component is 0.",
   0 },
   { GLX_DEPTH_SIZE, "GLX_DEPTH_SIZE",
   "Must be followed by a nonnegative minimum size specification. If this value is zero, "
   "frame buffer configurations with no depth buffer are preferred."
   "Otherwise, the largest available depth buffer of at least the minimum size is preferred. The default value is 0.",
   0 },
   { GLX_STENCIL_SIZE, "GLX_STENCIL_SIZE",
   "Must be followed by a nonnegative integer that indicates the desired number of stencil bitplanes."
   "The smallest stencil buffer of at least the specified size is preferred. If the desired value is zero,"
   " frame buffer configurations with no stencil buffer are preferred. The default value is 0.",
   0 },
   { GLX_ACCUM_RED_SIZE, "GLX_ACCUM_RED_SIZE",
   "Must be followed by a nonnegative minimum size specification. If this value is zero, "
   " frame buffer configurations with no red accumulation buffer are preferred."
   " Otherwise, the largest possible red accumulation buffer of at least the minimum size is preferred. The default value is 0.",
   0 },
   { GLX_ACCUM_GREEN_SIZE, "GLX_ACCUM_GREEN_SIZE",
   "Must be followed by a nonnegative minimum size specification. If this value is zero, "
   "frame buffer configurations with no green accumulation buffer are preferred. "
   "Otherwise, the largest possible green accumulation buffer of at least the minimum size is preferred. The default value is 0.",
   0 },
   { GLX_ACCUM_BLUE_SIZE, "GLX_ACCUM_BLUE_SIZE",
   "Must be followed by a nonnegative minimum size specification. If this value is zero, "
   "frame buffer configurations with no blue accumulation buffer are preferred. "
   "Otherwise, the largest possible blue accumulation buffer of at least the minimum size is preferred. The default value is 0.",
   0 },
   { GLX_ACCUM_ALPHA_SIZE, "GLX_ACCUM_ALPHA_SIZE",
   "Must be followed by a nonnegative minimum size specification. If this value is zero, "
   "frame buffer configurations with no alpha accumulation buffer are preferred. "
   "Otherwise, the largest possible alpha accumulation buffer of at least the minimum size is preferred. The default value is 0.",
   0 },
   { GLX_RENDER_TYPE, "GLX_RENDER_TYPE",
   "Must be followed by a mask indicating which OpenGL rendering modes the frame buffer configuration must support. "
   "Valid bits are GLX_RGBA_BIT and GLX_COLOR_INDEX_BIT. If the mask is set to GLX_RGBA_BIT | GLX_COLOR_INDEX_BIT, "
   "then only frame buffer configurations that can be bound to both RGBA contexts and color index contexts will be considered. "
   "The default value is GLX_RGBA_BIT.",
    GLX_RGBA_BIT },
   { GLX_DRAWABLE_TYPE, "GLX_DRAWABLE_TYPE",
   "Must be followed by a mask indicating which GLX drawable types the frame buffer configuration must support. "
   "Valid bits are GLX_WINDOW_BIT, GLX_PIXMAP_BIT, and GLX_PBUFFER_BIT. For example, if mask is set to "
   "GLX_WINDOW_BIT | GLX_PIXMAP_BIT,  only frame buffer configurations that support both windows and GLX pixmaps "
   "will be considered. The default value is GLX_WINDOW_BIT.", 
   GLX_WINDOW_BIT },
   { GLX_X_RENDERABLE, "GLX_X_RENDERABLE",
   "Must be followed by True or False. If True is specified, then only frame buffer configurations that "
   "have associated X visuals (and can be used to render to Windows and/or GLX pixmaps) will be considered. "
   "The default value is GLX_DONT_CARE. ",
   GLX_DONT_CARE },
   { GLX_X_VISUAL_TYPE, "GLX_X_VISUAL_TYPE",
   "Must be followed by one of GLX_TRUE_COLOR, GLX_DIRECT_COLOR, GLX_PSEUDO_COLOR, GLX_STATIC_COLOR, "
   "GLX_GRAY_SCALE, or GLX_STATIC_GRAY, indicating the desired X visual type. "
   "Not all frame buffer configurations have an associated X visual. If GLX_DRAWABLE_TYPE is specified in attrib_list and the "
   "mask that follows does not have GLX_WINDOW_BIT set, then this value is ignored. It is also ignored if "
   "GLX_X_RENDERABLE is specified as False. RGBA rendering may be supported for visuals of type "
   "GLX_TRUE_COLOR, GLX_DIRECT_COLOR, GLX_PSEUDO_COLOR, or GLX_STATIC_COLOR, "
   "but color index rendering is only supported for visuals of type GLX_PSEUDO_COLOR or GLX_STATIC_COLOR "
   "(i.e., single-channel visuals). The tokens GLX_GRAY_SCALE and GLX_STATIC_GRAY will "
   "not match current OpenGL enabled visuals, but are included for future use."
   "The default value for GLX_X_VISUAL_TYPE is GLX_DONT_CARE.",
   GLX_DONT_CARE },
   { GLX_CONFIG_CAVEAT, "GLX_CONFIG_CAVEAT",
   "Must be followed by one of GLX_NONE, GLX_SLOW_CONFIG, GLX_NON_CONFORMANT_CONFIG. "
   "If GLX_NONE is specified, then only frame buffer configurations with "
   "no caveats will be considered; if GLX_SLOW_CONFIG is specified, then only slow frame buffer configurations will be considered; if "
   "GLX_NON_CONFORMANT_CONFIG is specified, then only nonconformant frame buffer configurations will be considered."
   "The default value is GLX_DONT_CARE.",
   GLX_DONT_CARE },
   { GLX_TRANSPARENT_TYPE, "GLX_TRANSPARENT_TYPE",
   "Must be followed by one of GLX_NONE, GLX_TRANSPARENT_RGB, GLX_TRANSPARENT_INDEX. "
   "If GLX_NONE is specified, then only opaque frame buffer configurations will be considered; "
   "if GLX_TRANSPARENT_RGB is specified, then only transparent frame buffer configurations that support RGBA rendering will be considered; "
   "if GLX_TRANSPARENT_INDEX is specified, then only transparent frame buffer configurations that support color index rendering will be considered."
   "The default value is GLX_NONE.",
    GLX_NONE },
   { GLX_TRANSPARENT_INDEX_VALUE, "GLX_TRANSPARENT_INDEX_VALUE",
   "Must be followed by an integer value indicating the transparent index value; the value must be between 0 and the maximum "
   "frame buffer value for indices. Only frame buffer configurations that use the "
   "specified transparent index value will be considered. The default value is GLX_DONT_CARE. "
   "This attribute is ignored unless GLX_TRANSPARENT_TYPE is included in attrib_list and specified as GLX_TRANSPARENT_INDEX.",
   GLX_DONT_CARE },
   { GLX_TRANSPARENT_RED_VALUE, "GLX_TRANSPARENT_RED_VALUE",
   "Must be followed by an integer value indicating the transparent red value; the value must be between 0 and the maximum "
   "frame buffer value for red. Only frame buffer configurations that use the specified transparent red value will be considered. "
   "The default value is GLX_DONT_CARE. This attribute is ignored unless GLX_TRANSPARENT_TYPE is included in "
   "attrib_list and specified as GLX_TRANSPARENT_RGB.",
   GLX_DONT_CARE },
   { GLX_TRANSPARENT_GREEN_VALUE, "GLX_TRANSPARENT_GREEN_VALUE",
   "Must be followed by an integer value indicating the transparent green value; the value must be between 0 and the maximum "
   "frame buffer value for green. Only frame buffer configurations that use the specified transparent green value will be considered."
   "The default value is GLX_DONT_CARE. This attribute is "
   "ignored unless GLX_TRANSPARENT_TYPE is included in attrib_list and specified as GLX_TRANSPARENT_RGB.",
   GLX_DONT_CARE },
   { GLX_TRANSPARENT_BLUE_VALUE, "GLX_TRANSPARENT_BLUE_VALUE",
   "Must be followed by an integer value indicating the transparent blue value; the value must be between 0 and the maximum "
   "frame buffer value for blue. Only frame buffer configurations that use the specified transparent blue value will be considered."
   "The default value is GLX_DONT_CARE. This attribute is ignored unless GLX_TRANSPARENT_TYPE is included in "
   "attrib_list and specified as GLX_TRANSPARENT_RGB. ",
   GLX_DONT_CARE },
   { GLX_TRANSPARENT_ALPHA_VALUE, "GLX_TRANSPARENT_ALPHA_VALUE",
   "Must be followed by an integer value indicating the transparent alpha value; the value must be between 0 and the maximum "
   "frame buffer value for alpha. Only frame buffer configurations that use the "
   "specified transparent alpha value will be considered. The default value is GLX_DONT_CARE.",
   GLX_DONT_CARE },
   { 0, NULL, NULL, -1 }
};

const char * get_attr_name( int val, int * pdef )
{
   PPXATTS pat = &pxAtts[0];
   while( pat->name )
   {
      if ( pat->attr == val ) {
         *pdef = pat->def;
         return pat->name;
      }
      pat++;
   }
   *pdef = -1;
   return "VALUE NOT IN LIST";
}

#endif
// eof - RenderTexture.cpp
