--- /dev/null
+//---------------------------------------------------------------------------
+// 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;
+}
--- /dev/null
+//------------------------------------------------------------------------------
+// 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__