]> git.mxchange.org Git - simgear.git/commitdiff
Add Mark Haris' RenderTexture class based on SimGear's extesion support files.
authorehofman <ehofman>
Thu, 27 Jan 2005 10:39:15 +0000 (10:39 +0000)
committerehofman <ehofman>
Thu, 27 Jan 2005 10:39:15 +0000 (10:39 +0000)
simgear/screen/Makefile.am
simgear/screen/RenderTexture.cpp [new file with mode: 0644]
simgear/screen/RenderTexture.h [new file with mode: 0644]

index b711d219dd4ba135af39796b9fc01f374b4c796d..743f2ad065649a66ce232b07ea131f781aa4dc33 100644 (file)
@@ -12,7 +12,7 @@ IMAGE_SERVER_INCL =
 IMAGE_SERVER_SRCS = 
 endif
 
-noinst_HEADERS = colours.h
+noinst_HEADERS = colours.h RenderTexture.h
 
 include_HEADERS = \
        colors.hxx \
@@ -29,6 +29,7 @@ libsgscreen_a_SOURCES = \
        screen-dump.cxx \
        tr.cxx \
        extensions.cxx \
+       RenderTexture.cpp \
        win32-printer.h
 
-INCLUDES = -I$(top_srcdir)
+INCLUDES = -I$(top_srcdir) -DGLX_GLXEXT_PROTOTYPES
diff --git a/simgear/screen/RenderTexture.cpp b/simgear/screen/RenderTexture.cpp
new file mode 100644 (file)
index 0000000..d104513
--- /dev/null
@@ -0,0 +1,2206 @@
+//---------------------------------------------------------------------------
+// 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
+// Various Bug Fixes: Daniel (Redge) Sperl 
+//                    Bill Baxter
+//
+// --------------------------------------------------------------------------
+/**
+* @file RenderTexture.cpp
+* 
+* Implementation of class RenderTexture.  A multi-format render to 
+* texture wrapper.
+*/
+#pragma warning(disable:4786)
+
+/*
+ * Changelog:
+ *
+ * Jan. 2005, Removed GLEW dependencies, Erik Hofman
+ */
+
+
+#include <simgear/compiler.h>
+#include <simgear/screen/RenderTexture.h>
+#include <simgear/screen/extensions.hxx>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#ifdef _WIN32
+#pragma comment(lib, "gdi32.lib") // required for GetPixelFormat()
+#endif
+
+using namespace std;
+
+//---------------------------------------------------------------------------
+// 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]
+#ifdef _WIN32
+    _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),
+#else
+    _pDisplay(NULL),
+    _hGLContext(NULL),
+    _hPBuffer(0),
+    _hPreviousContext(0),
+    _hPreviousDrawable(0),
+#endif
+    _iTextureTarget(GL_NONE),
+    _iTextureID(0),
+    _iDepthTextureID(0),
+    _pPoorDepthTexture(0) // [Redge]
+{
+    _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);
+#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
+
+    _ParseModeString(strMode, _pixelFormatAttribs, _pbufferAttribs);
+
+#ifdef _WIN32
+    _pixelFormatAttribs.push_back(0);
+    _pbufferAttribs.push_back(0);
+#else
+    _pixelFormatAttribs.push_back(None);
+#endif
+}
+
+
+//---------------------------------------------------------------------------
+// Function            : RenderTexture::~RenderTexture
+// Description     : 
+//---------------------------------------------------------------------------
+/**
+* @fn RenderTexture::~RenderTexture()
+* @brief Destructor.
+*/ 
+RenderTexture::~RenderTexture()
+{
+    _Invalidate();
+}
+
+
+//---------------------------------------------------------------------------
+// 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:
+        fprintf(stderr, 
+                "RenderTexture Win32 Error:  ERROR_INVALID_PIXEL_FORMAT\n");
+        break;
+    case ERROR_NO_SYSTEM_RESOURCES:
+        fprintf(stderr, 
+                "RenderTexture Win32 Error:  ERROR_NO_SYSTEM_RESOURCES\n");
+        break;
+    case ERROR_INVALID_DATA:
+        fprintf(stderr, 
+                "RenderTexture Win32 Error:  ERROR_INVALID_DATA\n");
+        break;
+    case ERROR_INVALID_WINDOW_HANDLE:
+        fprintf(stderr, 
+                "RenderTexture Win32 Error:  ERROR_INVALID_WINDOW_HANDLE\n");
+        break;
+    case ERROR_RESOURCE_TYPE_NOT_FOUND:
+        fprintf(stderr, 
+                "RenderTexture Win32 Error:  ERROR_RESOURCE_TYPE_NOT_FOUND\n");
+        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);
+        
+        fprintf(stderr, "RenderTexture Win32 Error %d: %s\n", 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( char* strMsg, ... )
+{
+    fprintf(stderr, 
+            "Error: RenderTexture requires the following unsupported "
+            "OpenGL extensions: \n");
+    char strBuffer[512];
+    va_list args;
+    va_start(args, strMsg);
+#ifdef _WIN32
+    _vsnprintf( strBuffer, 512, strMsg, args );
+#else
+    vsnprintf( strBuffer, 512, strMsg, args );
+#endif
+    va_end(args);
+    
+    fprintf(stderr, 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);
+
+    _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())
+        return false;
+    
+    if (_bInitialized)
+        _Invalidate();
+
+#if _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)
+        {
+            fprintf(stderr, 
+                    "RenderTexture Error: GetPixelFormat() failed.\n");
+            return false;
+        }
+    }
+    else 
+    {
+        if (!wglChoosePixelFormatARB(hdc, &_pixelFormatAttribs[0], NULL, 
+                                     1, &iFormat, &iNumFormats))
+        {
+            fprintf(stderr, 
+                "RenderTexture Error: wglChoosePixelFormatARB() failed.\n");
+            _wglGetLastError();
+            return false;
+        }
+        if ( iNumFormats <= 0 )
+        {
+            fprintf(stderr, 
+                    "RenderTexture Error: Couldn't find a suitable "
+                    "pixel format.\n");
+            _wglGetLastError();
+            return false;
+        }
+    }
+    
+    // Create the p-buffer.    
+    _hPBuffer = wglCreatePbufferARB(hdc, iFormat, _iWidth, _iHeight, 
+                                    &_pbufferAttribs[0]);
+    if (!_hPBuffer)
+    {
+        fprintf(stderr, 
+                "RenderTexture Error: wglCreatePbufferARB() failed.\n");
+        _wglGetLastError();
+        return false;
+    }
+    
+    // Get the device context.
+    _hDC = wglGetPbufferDCARB( _hPBuffer);
+    if ( !_hDC )
+    {
+        fprintf(stderr, 
+                "RenderTexture Error: wglGetGetPbufferDCARB() failed.\n");
+        _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 )
+        {
+            fprintf(stderr, 
+                    "RenderTexture Error: wglCreateContext() failed.\n");
+            _wglGetLastError();
+            return false;
+        }
+    }
+    
+    // Share lists, texture objects, and program objects.
+    if( _bShareObjects )
+    {
+        if( !wglShareLists(hglrc, _hGLContext) )
+        {
+            fprintf(stderr, 
+                    "RenderTexture Error: wglShareLists() failed.\n");
+            _wglGetLastError();
+            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
+    _pDisplay = glXGetCurrentDisplay();
+    GLXContext context = glXGetCurrentContext();
+    int screen = DefaultScreen(_pDisplay);
+    XVisualInfo *visInfo;
+    
+    int iFormat = 0;
+    int iNumFormats;
+    int attrib = 0;
+    
+    GLXFBConfigSGIX *fbConfigs;
+    int nConfigs;
+    
+    fbConfigs = glXChooseFBConfigSGIX(_pDisplay, screen, 
+                                      &_pixelFormatAttribs[0], &nConfigs);
+    
+    if (nConfigs == 0 || !fbConfigs) 
+    {
+        fprintf(stderr,
+            "RenderTexture Error: Couldn't find a suitable pixel format.\n");
+        return false;
+    }
+    
+    // Pick the first returned format that will return a pbuffer
+    for (int i=0;i<nConfigs;i++)
+    {
+        _hPBuffer = glXCreateGLXPbufferSGIX(_pDisplay, fbConfigs[i], 
+                                            _iWidth, _iHeight, NULL);
+        if (_hPBuffer) 
+        {
+            _hGLContext = glXCreateContextWithConfigSGIX(_pDisplay, 
+                                                         fbConfigs[i], 
+                                                         GLX_RGBA_TYPE, 
+                                                         _bShareObjects ? context : NULL, 
+                                                         True);
+            break;
+        }
+    }
+    
+    if (!_hPBuffer)
+    {
+        fprintf(stderr, 
+                "RenderTexture Error: glXCreateGLXPbufferSGIX() failed.\n");
+        return false;
+    }
+    
+    if(!_hGLContext)
+    {
+        // Try indirect
+        _hGLContext = glXCreateContext(_pDisplay, visInfo, 
+                                       _bShareObjects ? context : NULL, False);
+        if ( !_hGLContext )
+        {
+            fprintf(stderr, 
+                    "RenderTexture Error: glXCreateContext() failed.\n");
+            return false;
+        }
+    }
+    
+    glXQueryGLXPbufferSGIX(_pDisplay, _hPBuffer, GLX_WIDTH_SGIX, 
+                           (GLuint*)&_iWidth);
+    glXQueryGLXPbufferSGIX(_pDisplay, _hPBuffer, GLX_HEIGHT_SGIX, 
+                           (GLuint*)&_iHeight);
+    
+    _bInitialized = true;
+    
+    // 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;
+    }
+#else
+    _hPreviousContext = glXGetCurrentContext();
+    _hPreviousDrawable = glXGetCurrentDrawable();
+    
+    if (False == glXMakeCurrent(_pDisplay, _hPBuffer, _hGLContext)) 
+    {
+        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;
+    }
+#else
+    if (False == glXMakeCurrent(_pDisplay, 
+                                _hPreviousDrawable, _hPreviousContext))
+    {
+        return false;
+    }
+#endif
+
+    return result;
+}
+
+
+//---------------------------------------------------------------------------
+// Function            : RenderTexture::_Invalidate
+// Description     : 
+//---------------------------------------------------------------------------
+/**
+* @fn RenderTexture::_Invalidate()
+* @brief Returns the pbuffer memory to the graphics device.
+* 
+*/ 
+bool RenderTexture::_Invalidate()
+{
+    _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);
+    }
+    
+#if _WIN32
+    if ( _hPBuffer )
+    {
+        // Check if we are currently rendering in the pbuffer
+        if (wglGetCurrentContext() == _hGLContext)
+            wglMakeCurrent(0,0);
+        if (!_bCopyContext) 
+            wglDeleteContext( _hGLContext);
+        wglReleasePbufferDCARB( _hPBuffer, _hDC);
+        wglDestroyPbufferARB( _hPBuffer );
+        _hPBuffer = 0;
+        return true;
+    }
+#else
+    if ( _hPBuffer )
+    {
+        if(glXGetCurrentContext() == _hGLContext)
+            // XXX I don't know if this is right at all
+            glXMakeCurrent(_pDisplay, _hPBuffer, 0);
+        glXDestroyGLXPbufferSGIX(_pDisplay, _hPBuffer);
+        _hPBuffer = 0;
+        return true;
+    }
+#endif
+
+    // [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, ...)
+{
+    _iWidth = 0; _iHeight = 0; 
+    _bIsTexture = false; _bIsDepthTexture = false,
+    _bHasARBDepthTexture = true;
+#ifdef _WIN32
+    _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() && !_Invalidate())
+    {
+        fprintf(stderr, "RenderTexture::Reset(): failed to invalidate.\n");
+        return false;
+    }
+    
+    _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);
+#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);
+#ifdef _WIN32
+    _vsnprintf( strBuffer, 256, strMode, args );
+#else
+    vsnprintf( strBuffer, 256, strMode, args );
+#endif
+    va_end(args);
+
+    _ParseModeString(strBuffer, _pixelFormatAttribs, _pbufferAttribs);
+
+#ifdef _WIN32
+    _pixelFormatAttribs.push_back(0);
+    _pbufferAttribs.push_back(0);
+#else
+    _pixelFormatAttribs.push_back(None);
+#endif
+    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) {
+        fprintf(stderr, "RenderTexture::Resize(): must Initialize() first.\n");
+        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);
+        wglReleasePbufferDCARB( _hPBuffer, _hDC);
+        wglDestroyPbufferARB( _hPBuffer );
+        _hPBuffer = 0;
+        return true;
+    }
+#else
+    if ( _hPBuffer )
+    {
+        if(glXGetCurrentContext() == _hGLContext)
+            // XXX I don't know if this is right at all
+            glXMakeCurrent(_pDisplay, _hPBuffer, 0);
+        glXDestroyGLXPbufferSGIX(_pDisplay, _hPBuffer);
+        _hPBuffer = 0;
+    }
+#endif
+    else {
+        fprintf(stderr, "RenderTexture::Resize(): failed to resize.\n");
+        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)
+    {
+        fprintf(stderr, 
+                "RenderTexture::BeginCapture(): Texture is not initialized!\n");
+        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();
+#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)
+    {
+        fprintf(stderr, 
+                "RenderTexture::EndCapture() : Texture is not initialized!\n");
+        return false;
+    }
+
+    _MaybeCopyBuffer();
+
+#ifdef _WIN32
+    // make the previous rendering context current 
+    if (FALSE == wglMakeCurrent( _hPreviousDC, _hPreviousContext))
+    {
+        _wglGetLastError();
+        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)
+    {
+        fprintf(stderr, 
+            "RenderTexture::BeginCapture(RenderTexture*): Texture is not initialized!\n");
+        return false;
+    }
+    if (!current->_bInitialized)
+    {
+        fprintf(stderr, 
+            "RenderTexture::BeginCapture(RenderTexture): 'current' texture is not initialized!\n");
+        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();
+#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);
+        
+#if _WIN32
+        if (RT_RENDER_TO_TEXTURE == _eUpdateMode && _bIsTexture &&
+            (!_bIsBufferBound || _iCurrentBoundBuffer != iBuffer))
+        {
+            if (FALSE == wglBindTexImageARB(_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;
+        }
+#endif
+    }    
+    return true;
+}
+
+
+//---------------------------------------------------------------------------
+// Function            : RenderTexture::BindBuffer
+// 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 == wglBindTexImageARB(_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)
+{
+    if (!modeString || strcmp(modeString, "") == 0)
+        return;
+
+       _iNumComponents = 0;
+#ifdef _WIN32
+    _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, " ");
+    }
+
+    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]);
+#else
+# ifndef sgi
+            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
+#endif
+                       _iNumComponents += 3;
+            continue;
+        }
+               else if (kv.first == "rgb") 
+            fprintf(stderr, 
+                    "RenderTexture Warning: 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]);
+#else
+# ifndef sgi
+            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
+#endif
+                       _iNumComponents = 4;
+            continue;
+        }
+               else if (kv.first == "rgba") 
+            fprintf(stderr, 
+                    "RenderTexture Warning: mistake in components definition "
+                    "(rgba + %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]);
+#else
+            pfAttribs.push_back(GLX_RED_SIZE);
+            pfAttribs.push_back(bitVec[0]);
+#endif
+                       _iNumComponents++;
+            continue;
+        }
+               else if (kv.first == "r") 
+            fprintf(stderr, 
+                    "RenderTexture Warning: mistake in components definition "
+                    "(r + %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]);
+#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") 
+            fprintf(stderr, 
+                    "RenderTexture Warning: mistake in components definition "
+                    "(rg + %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);
+#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));
+#else
+           pfAttribs.push_back(GL_SAMPLE_BUFFERS_ARB);
+           pfAttribs.push_back(1);
+           pfAttribs.push_back(GL_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);
+#else
+            pfAttribs.push_back(GL_DOUBLEBUFFER);
+            pfAttribs.push_back(True);
+#endif
+            continue;
+        }  
+        
+        if (kv.first == "aux")
+        {
+#ifdef _WIN32
+            pfAttribs.push_back(WGL_AUX_BUFFERS_ARB);
+#else
+            pfAttribs.push_back(GL_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)
+            {
+                _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)
+            {
+                _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;
+        }
+
+        fprintf(stderr, 
+                "RenderTexture Error: Unknown 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))
+    {
+        fprintf(stderr,
+                "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);
+#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);
+#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)
+        fprintf(stderr, "RenderTexture Warning: No support found for "
+                "render to depth texture.\n");
+#endif
+        _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(DEBUG) || defined(_DEBUG)
+        printf("RenderTexture Error: Render to Texture not "
+               "supported in Linux\n");
+#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);
+        }
+#else
+        if (GL_NV_float_buffer)
+        {
+            pfAttribs.push_back(GL_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:
+                    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)
+        fprintf(stderr, 
+                "RenderTexture Error: Render to Texture not supported in "
+                "Linux\n");
+#endif  
+    }
+        
+    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(DEBUG) || defined(_DEBUG)
+        printf("RenderTexture Error: Render to Texture not supported in "
+               "Linux\n");
+#endif 
+    }
+}
+
+//---------------------------------------------------------------------------
+// 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(", \n", 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()
+{
+#ifdef _WIN32
+    if (!WGL_ARB_pbuffer)
+    {
+        PrintExtensionError("WGL_ARB_pbuffer");
+        return false;
+    }
+    if (!WGL_ARB_pixel_format)
+    {
+        PrintExtensionError("WGL_ARB_pixel_format");
+        return false;
+    }
+    if (_bIsTexture && !WGL_ARB_render_texture)
+    {
+        PrintExtensionError("WGL_ARB_render_texture");
+        return false;
+    }
+    if (_bRectangle && !GL_NV_texture_rectangle)
+    {
+        PrintExtensionError("GL_NV_texture_rectangle");
+        return false;
+    }
+    if (_bFloat && !(GL_NV_float_buffer || WGL_ATI_pixel_format_float))
+    {
+        PrintExtensionError("GL_NV_float_buffer or GL_ATI_pixel_format_float");
+        return false;
+    
+    }
+    if (_bFloat && _bIsTexture && !(GL_NV_float_buffer || GL_ATI_texture_float))
+    {
+        PrintExtensionError("NV_float_buffer or ATI_texture_float");
+    }
+    if (_bIsDepthTexture && !GL_ARB_depth_texture)
+    {
+        // [Redge]
+#if defined(_DEBUG) | defined(DEBUG)
+        fprintf(stderr, 
+                "RenderTexture Warning: "
+                "OpenGL extension GL_ARB_depth_texture not available.\n"
+                "         Using glReadPixels() to emulate behavior.\n");
+#endif   
+        _bHasARBDepthTexture = false;
+        //PrintExtensionError("GL_ARB_depth_texture");
+        //return false;
+        // [/Redge]
+    }
+    SetLastError(0);
+#else
+    if (!GLX_SGIX_pbuffer)
+    {
+        PrintExtensionError("GL_SGIX_pbuffer");
+        return false;
+    }
+    if (!GLX_SGIX_fbconfig)
+    {
+        PrintExtensionError("GL_SGIX_fbconfig");
+        return false;
+    }
+    if (_bIsDepthTexture && !GL_ARB_depth_texture)
+    {
+        PrintExtensionError("GL_ARB_depth_texture");
+        return false;
+    }
+    if (_bFloat && _bIsTexture && !GL_NV_float_buffer)
+    {
+        PrintExtensionError("GL_NV_float_buffer");
+        return false;
+    }
+    if (_eUpdateMode == RT_RENDER_TO_TEXTURE)
+    {
+        PrintExtensionError("Some GLX render texture extension: FIXME!");
+        return false;
+    }
+#endif
+  
+    return true;
+}
+
+//---------------------------------------------------------------------------
+// Function            : RenderTexture::_InitializeTextures
+// Description     : 
+//---------------------------------------------------------------------------
+/**
+* @fn RenderTexture::_InitializeTextures()
+* @brief Initializes the state of textures used by the RenderTexture.
+*/ 
+bool RenderTexture::_InitializeTextures()
+{
+    // Determine the appropriate texture formats and filtering modes.
+    if (_bIsTexture || _bIsDepthTexture)
+    {
+        if (_bRectangle && GL_NV_texture_rectangle)
+            _iTextureTarget = GL_TEXTURE_RECTANGLE_NV;
+        else
+            _iTextureTarget = GL_TEXTURE_2D;
+    }
+
+    if (_bIsTexture)
+    {
+        glGenTextures(1, &_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)
+                {
+                    fprintf(stderr, 
+                        "RenderTexture Error: mipmapped float textures not "
+                        "supported.\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:
+                    printf("RenderTexture Error: "
+                           "Invalid number of components: %d\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, &_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]
+        }
+    }
+
+    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]
+        }
+    }
+    
+#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 == wglReleaseTexImageARB(_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 == wglReleaseTexImageARB(_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;
+    }
+#else
+    if (false == glXMakeCurrent(_pDisplay, _hPBuffer, _hGLContext)) 
+    {
+        return false;
+    }
+#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),
+    _bDoubleBuffered(false),
+    _bFloat(false),
+    _bPowerOf2(true),
+    _bRectangle(false),
+    _bMipmap(false),
+    _bShareObjects(false),
+    _bCopyContext(false),
+#ifdef _WIN32
+    _hDC(NULL), 
+    _hGLContext(NULL), 
+    _hPBuffer(NULL),
+    _hPreviousDC(0),
+    _hPreviousContext(0),
+#else
+    _pDisplay(NULL),
+    _hGLContext(NULL),
+    _hPBuffer(0),
+    _hPreviousContext(0),
+    _hPreviousDrawable(0),
+#endif
+    _iTextureTarget(GL_NONE),
+    _iTextureID(0),
+    _iDepthTextureID(0),
+    _pPoorDepthTexture(0) // [Redge]
+{
+    assert(width > 0 && height > 0);
+#if defined DEBUG || defined _DEBUG
+    fprintf(stderr, 
+            "RenderTexture Warning: Deprecated Contructor interface used.\n");
+#endif
+    
+    _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
+    fprintf(stderr, 
+            "RenderTexture Warning: Deprecated Initialize() interface used.\n");
+#endif   
+
+    // 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];
+        sprintf(bitVector,
+            "%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 && 
+            ((!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 && 
+            ((!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);
+#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);
+#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)
+{
+    fprintf(stderr, 
+            "RenderTexture Warning: Deprecated Reset() interface used.\n");
+
+    if (!_Invalidate())
+    {
+        fprintf(stderr, "RenderTexture::Reset(): failed to invalidate.\n");
+        return false;
+    }
+    _iWidth     = iWidth;
+    _iHeight    = iHeight;
+    
+    return true;
+}
diff --git a/simgear/screen/RenderTexture.h b/simgear/screen/RenderTexture.h
new file mode 100644 (file)
index 0000000..b5e7b89
--- /dev/null
@@ -0,0 +1,363 @@
+//------------------------------------------------------------------------------
+// File : RenderTexture.h
+//------------------------------------------------------------------------------
+// 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 code: Mark J. Harris
+// Original Render-to-depth-texture support: Thorsten Scheuermann
+// Linux Copy-to-texture: Eric Werness
+// Various Bug Fixes: Daniel (Redge) Sperl 
+//                    Bill Baxter
+//
+// -----------------------------------------------------------------------------
+/**
+* @file RenderTexture.h
+* 
+* Interface definition for class RenderTexture.  A multi-format render to 
+* texture wrapper.
+*/
+#ifndef __RENDERTEXTURE2_HPP__
+#define __RENDERTEXTURE2_HPP__
+
+
+/*
+ * Changelog:
+ *
+ * Jan. 2005, Removed GLEW dependencies, Erik Hofman
+ */
+#include <simgear/compiler.h>
+
+#ifndef _WIN32
+#include <X11/Xlib.h>
+#endif
+#include SG_GL_H
+#include SG_GLX_H
+
+#include <string>
+#include <vector>
+
+/* The pixel format for the pbuffer is controlled by the mode string passed
+* into the PBuffer constructor. This string can have the following attributes:
+*
+* To specify the pixel format, use the following syntax.
+*   <channels>=<bits>
+* <channels> must match one of the following.
+*
+* r                       - r pixel format (for float buffer).
+* rg              - rg pixel format (for float buffer).
+* rgb          - rgb pixel format. 8 bit or 16/32 bit in float buffer mode
+* rgba         - same as "rgb alpha" string
+*
+* <bits> can either be a scalar--meaning the same bit depth for each 
+* channel-- or a 2-, 3-, 4-component vector matching the specified number of 
+* channels. Vector components should be comma separated. An optional 'f' 
+* suffix on the bit depth specifies float components.  In this case <bits> 
+* must be either "32f" or "16f".  If <bits> is empty, the default 8 bits per
+* channel will be used.
+*   r=32f
+*   rg=16f
+*   rgb=8
+*   rgb=5,6,5
+*
+* The following other attributes are supported.
+*
+* depth=n      - must have n-bit depth buffer, omit n for default (24 bits)
+* stencil=n    - must have n-bit stencil buffer, omit n for default (8 bits)
+* samples=n    - must support n-sample antialiasing (n can be 2 or 4)
+* aux=n        - must have n AUX buffers
+* doublebuffer - must support double buffered rendering
+* 
+* tex2D
+* texRECT
+* texCUBE  - must support binding pbuffer as texture to specified target
+*          - binding the depth buffer is also supported by specifying
+* depthTex2D
+* depthTexRECT
+* depthTexCUBE
+*          - Both depth and color texture binding, may be specified, but
+*            the targets must match!
+*            For example: "tex2D depthTex2D" or "texRECT depthTexRECT"
+*
+* rtt
+* ctt      - These mutually exclusive options specify the update method used
+*            for render textures that support texture binding. "rtt"
+*            indicates that render to texture will be used to update the 
+*            texture. "ctt" indicates that copy to texture will be used 
+*            (i.e. glCopyTexSubImage2D()). "rtt" is the default if neither is 
+*            specified, and one of the "tex*" options above is. 
+* 
+*
+*---------------------------------------------------------------------------
+*
+* USAGE NOTES:
+*
+* * Texture Parameters:
+*   The default texture wrap mode is GL_CLAMP_TO_EDGE for all textures, and
+*   the default texture filtering modes (min and mag) are GL_NEAREST. 
+*   To change these parameters, simply bind the RenderTexture (using the
+*   Bind() method), and set them the way you would for any GL texture object.
+*   The same goes for depth textures.
+*
+* * Enabling Mipmapping:
+*   This is similar to the texture parameters above.  When "rtt" is specified
+*   in the mode string, "mipmap" must also be specified in order to enable
+*   a mipmapped pbuffer.  Then, the mipmaps must be created by enabling the
+*   GL_SGIS_GENERATE_MIPMAP texture parameter in the same way as above, and
+*   the min filter mode must be set to a mipmap filter mode, as with any
+*   mipmapped texture object.
+*
+* * Enabling Anisotropic Filtering  
+*   As with the texture parameters above, except as in the following code:
+*   glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, max);
+*   glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, <value < max>);
+*/
+class RenderTexture
+{
+public: // enums
+    enum UpdateMode
+    {
+        RT_RENDER_TO_TEXTURE,
+        RT_COPY_TO_TEXTURE
+    };
+    
+public: // interface
+    // ctor / dtor
+    RenderTexture(const char *strMode="rgb tex2D");
+    ~RenderTexture();
+    
+    //! Call this once before use.  Set bShare to true to share lists, textures, 
+    //! and program objects between the render texture context and the 
+    //! current active GL context.
+    bool Initialize(int width, int height, 
+                    bool shareObjects=true, 
+                    bool copyContext=false);
+
+    // !Change the render texture format.
+    bool Reset(const char* strMode,...);
+    // !Change the size of the render texture.
+    bool Resize(int width, int height);
+    
+    // !Begin drawing to the texture. (i.e. use as "output" texture)
+    bool BeginCapture();
+    // !Ends drawing to 'current', begins drawing to this RenderTexture
+    bool BeginCapture(RenderTexture* current);
+    // !End drawing to the texture.
+    bool EndCapture();
+    
+    // !Bind the texture to the active texture unit for use as an "input" texture
+    void Bind() const;
+
+    // !Bind the depth texture to the active texture unit for use as an "input" texture
+    void BindDepth() const; 
+
+    // !Associate the RTT texture with 'iBuffer' (default is WGL_FRONT_LEFT_ARB) 
+    bool BindBuffer( int iBuffer );
+
+    //! Enables the texture target appropriate for this render texture.
+    void EnableTextureTarget() const 
+    { if (_bInitialized) glEnable(_iTextureTarget); }
+    //! Disables the texture target appropriate for this render texture.
+    void DisableTextureTarget() const 
+    { if (_bInitialized) glDisable(_iTextureTarget); }
+    
+    //! Returns the texture ID.  Useful in Cg applications.
+    unsigned int GetTextureID() const  { return _iTextureID; }
+    //! Returns the depth texture ID.  Useful in Cg applications.
+    unsigned int GetDepthTextureID() const { return _iDepthTextureID; }
+    //! Returns the texture target this texture is bound to.
+    unsigned int GetTextureTarget() const { return _iTextureTarget; }
+    //! Conversion operator allows RenderTexture to be passed to GL calls
+    operator unsigned int()const{return _iTextureID;}     
+    
+    //! Returns the width of the offscreen buffer.
+    int GetWidth() const            { return _iWidth;  } 
+    //! Returns the width of the offscreen buffer.
+    int GetHeight() const           { return _iHeight; }
+    //! Returns the maximum S texture coordinate.
+    int GetMaxS() const      { return IsRectangleTexture() ? _iWidth : 1; }                  
+    //! Returns the maximum T texture coordinate.
+    int GetMaxT() const      { return IsRectangleTexture() ? _iHeight : 1; }                  
+    
+    //! Returns the number of red bits allocated.
+    int GetRedBits() const          { return _iNumColorBits[0]; }
+    //! Returns the number of green bits allocated.
+    int GetGreenBits() const        { return _iNumColorBits[1]; }
+    //! Returns the number of blue bits allocated.
+    int GetBlueBits() const         { return _iNumColorBits[2]; }
+    //! Returns the number of alpha bits allocated.
+    int GetAlphaBits() const        { return _iNumColorBits[3]; }
+
+    //! Returns the number of depth bits allocated.
+    int GetDepthBits() const        { return _iNumDepthBits; }
+    //! Returns the number of stencil bits allocated.
+    int GetStencilBits() const      { return _iNumStencilBits; }
+    
+    //! True if this RenderTexture has been properly initialized.
+    bool IsInitialized() const      { return _bInitialized; }
+    //! True if this is a texture and not just an offscreen buffer.
+    bool IsTexture() const          { return _bIsTexture; }
+    //! True if this is a depth texture and not just an offscreen buffer.
+    bool IsDepthTexture() const     { return _bIsDepthTexture; }
+    //! True if this is a floating point buffer / texture.
+    bool IsFloatTexture() const     { return _bFloat; }
+    //! True if this is a double-buffered pbuffer
+    bool IsDoubleBuffered() const   { return _bDoubleBuffered; }
+    //! True if this texture has non-power-of-two dimensions.
+    bool IsRectangleTexture() const { return _bRectangle; }
+    //! True if this texture has non-power-of-two dimensions.
+    //! True if this pbuffer has a depth buffer.
+    bool HasDepth() const           { return (_iNumDepthBits > 0); }
+    //! True if this pbuffer has a stencil buffer.
+    bool HasStencil() const         { return (_iNumStencilBits > 0); }
+    //! True if this texture has mipmaps.
+    bool IsMipmapped() const        { return _bMipmap; }
+
+    /**
+    * @fn IsPowerOfTwo(int n)
+    * @brief Returns true if /param n is an integer power of 2.
+    * 
+    * Taken from Steve Baker's Cute Code Collection. 
+    * http://www.sjbaker.org/steve/software/cute_code.html
+    */ 
+    static bool IsPowerOfTwo(int n) { return ((n&(n-1))==0); }
+
+
+    /////////////////////////////////////////////////////////////////////////
+    // This is the deprecated (old) interface.  It will likely be removed
+    // in a future version, so it is recommended that you transition to the 
+    // new mode-string-based interface.
+    RenderTexture(int width, int height,
+                   bool bIsTexture = true,
+                   bool bIsDepthTexture = false);
+    //
+    // Call this once before use.  Set bShare to true to share lists, 
+    // textures, and program objects between the render texture context 
+    // and the current active GL context. [deprecated]
+    bool 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,
+// Only Win32 has RT now, so only make it default there
+#ifdef _WIN32
+                    UpdateMode   updateMode = RT_RENDER_TO_TEXTURE
+#else
+                    UpdateMode   updateMode = RT_COPY_TO_TEXTURE
+#endif
+                    );
+    // !Change the render texture resolution. [deprecated]
+    bool Reset(int iWidth, int iHeight);
+    //
+    /////////////////////////////////////////////////////////////////////////
+
+
+protected: // methods
+    bool         _Invalidate();
+
+    typedef std::pair<std::string, std::string> KeyVal;
+
+    void _ParseModeString(const char *modeString, 
+                          std::vector<int> &pixelFormatAttribs, 
+                          std::vector<int> &pbufferAttribs);
+
+    std::vector<int> _ParseBitVector(std::string bitVector);
+    KeyVal _GetKeyValuePair(std::string token);
+
+
+    bool _VerifyExtensions();
+    bool _InitializeTextures();
+    
+    void _MaybeCopyBuffer();
+    bool _ReleaseBoundBuffers();
+    bool _MakeCurrent();
+    bool _BindDepthBuffer( ) const;
+
+protected: // data
+    int          _iWidth;     // width of the pbuffer
+    int          _iHeight;    // height of the pbuffer
+    
+    bool         _bIsTexture;
+    bool         _bIsDepthTexture;
+    bool         _bHasARBDepthTexture; // [Redge]
+    
+    UpdateMode   _eUpdateMode;
+        
+    bool         _bInitialized;
+    
+    unsigned int _iNumAuxBuffers;
+    bool         _bIsBufferBound;
+    int          _iCurrentBoundBuffer;
+    
+    unsigned int _iNumComponents;
+    unsigned int _iNumColorBits[4];
+    unsigned int _iNumDepthBits;
+    unsigned int _iNumStencilBits;
+
+    
+    bool         _bFloat;
+    bool         _bDoubleBuffered;
+    bool         _bPowerOf2;
+    bool         _bRectangle;
+    bool         _bMipmap;
+    
+    bool         _bShareObjects;
+    bool         _bCopyContext;
+    
+#ifdef _WIN32
+    HDC          _hDC;        // Handle to a device context.
+    HGLRC        _hGLContext; // Handle to a GL context.
+    HPBUFFERARB  _hPBuffer;   // Handle to a pbuffer.
+    
+    HDC          _hPreviousDC;
+    HGLRC        _hPreviousContext;
+#else
+    Display     *_pDisplay;
+    GLXContext   _hGLContext;
+    GLXPbuffer   _hPBuffer;
+    
+    GLXDrawable  _hPreviousDrawable;
+    GLXContext   _hPreviousContext;
+#endif
+    
+    // Texture stuff
+    GLenum       _iTextureTarget;
+    unsigned int _iTextureID;
+    unsigned int _iDepthTextureID;
+    
+    unsigned short* _pPoorDepthTexture; // [Redge]
+
+    std::vector<int> _pixelFormatAttribs;
+    std::vector<int> _pbufferAttribs;
+
+private:
+    // Using these could lead to some odd behavior
+    RenderTexture(const RenderTexture&);
+    RenderTexture& operator=(const RenderTexture&);
+};
+
+#endif //__RENDERTEXTURE2_HPP__