From 73f9febe068910b1fcf219c8322bd54bd6b4e1d3 Mon Sep 17 00:00:00 2001 From: ehofman Date: Thu, 27 Jan 2005 10:39:15 +0000 Subject: [PATCH] Add Mark Haris' RenderTexture class based on SimGear's extesion support files. --- simgear/screen/Makefile.am | 5 +- simgear/screen/RenderTexture.cpp | 2206 ++++++++++++++++++++++++++++++ simgear/screen/RenderTexture.h | 363 +++++ 3 files changed, 2572 insertions(+), 2 deletions(-) create mode 100644 simgear/screen/RenderTexture.cpp create mode 100644 simgear/screen/RenderTexture.h diff --git a/simgear/screen/Makefile.am b/simgear/screen/Makefile.am index b711d219..743f2ad0 100644 --- a/simgear/screen/Makefile.am +++ b/simgear/screen/Makefile.am @@ -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 index 00000000..d104513d --- /dev/null +++ b/simgear/screen/RenderTexture.cpp @@ -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 +#include +#include + +#include +#include +#include +#include + +#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_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 &pfAttribs, + vector &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 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 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 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 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 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 RenderTexture::_ParseBitVector(string bitVector) +{ + vector pieces; + vector 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::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 index 00000000..b5e7b89f --- /dev/null +++ b/simgear/screen/RenderTexture.h @@ -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 + +#ifndef _WIN32 +#include +#endif +#include SG_GL_H +#include SG_GLX_H + +#include +#include + +/* 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. +* = +* 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 +* +* 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 +* must be either "32f" or "16f". If 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, ); +*/ +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 KeyVal; + + void _ParseModeString(const char *modeString, + std::vector &pixelFormatAttribs, + std::vector &pbufferAttribs); + + std::vector _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 _pixelFormatAttribs; + std::vector _pbufferAttribs; + +private: + // Using these could lead to some odd behavior + RenderTexture(const RenderTexture&); + RenderTexture& operator=(const RenderTexture&); +}; + +#endif //__RENDERTEXTURE2_HPP__ -- 2.39.5