//------------------------------------------------------------------------------ // File : RenderTexture.cpp //------------------------------------------------------------------------------ // Copyright 2002 Mark J. Harris and // The University of North Carolina at Chapel Hill //------------------------------------------------------------------------------ // Permission to use, copy, modify, distribute and sell this software and its // documentation for any purpose is hereby granted without fee, provided that // the above copyright notice appear in all copies and that both that copyright // notice and this permission notice appear in supporting documentation. // Binaries may be compiled with this software without any royalties or // restrictions. // // The author(s) and The University of North Carolina at Chapel Hill make no // representations about the suitability of this software for any purpose. // It is provided "as is" without express or implied warranty. // // ----------------------------------------------------------------------------- // 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. */ #include "RenderTexture.h" #include #include #include #include #include //------------------------------------------------------------------------------ // Function : IsPowerOfTwo // Description : //------------------------------------------------------------------------------ /** * @fn IsPowerOfTwo(int n) * @brief Returns true if /param n is an integer power of 2. * * Taken from Steve Baker's Cute Code Collection. */ bool IsPowerOfTwo(int n) { return ((n&(n-1))==0); } //------------------------------------------------------------------------------ // Function : RenderTexture::RenderTexture // Description : //------------------------------------------------------------------------------ /** * @fn RenderTexture::RenderTexture() * @brief Constructor. */ RenderTexture::RenderTexture(int iWidth, int iHeight, bool bIsTexture /* = true */, bool bIsDepthTexture /* = false */) : _iWidth(iWidth), _iHeight(iHeight), _bIsTexture(bIsTexture), _bIsDepthTexture(bIsDepthTexture), _bHasArbDepthTexture(true), // [Redge] _eUpdateMode(RT_RENDER_TO_TEXTURE), _bInitialized(false), _bFloat(false), _bRectangle(false), _bHasDepth(false), _bHasStencil(false), _bMipmap(false), _bAnisoFilter(false), #ifdef _WIN32 _hDC(NULL), _hGLContext(NULL), _hPBuffer(NULL), _hPreviousDC(0), _hPreviousContext(0), #else _pDpy(NULL), _hGLContext(NULL), _hPBuffer(0), _hPreviousContext(0), _hPreviousDrawable(0), #endif _iTextureTarget(GL_NONE), _iTextureID(0), _pPoorDepthTexture(0) // [Redge] { assert(iWidth > 0 && iHeight > 0); _iBits[0] = _iBits[1] = _iBits[2] = _iBits[3] = 0; _bRectangle = !(IsPowerOfTwo(iWidth) && IsPowerOfTwo(iHeight)); } //------------------------------------------------------------------------------ // 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 RenderTexture::_wglGetLastError() { #ifdef _DEBUG DWORD err = GetLastError(); switch(err) { case ERROR_INVALID_PIXEL_FORMAT: fprintf(stderr, "Win32 Error: ERROR_INVALID_PIXEL_FORMAT\n"); break; case ERROR_NO_SYSTEM_RESOURCES: fprintf(stderr, "Win32 Error: ERROR_NO_SYSTEM_RESOURCES\n"); break; case ERROR_INVALID_DATA: fprintf(stderr, "Win32 Error: ERROR_INVALID_DATA\n"); break; case ERROR_INVALID_WINDOW_HANDLE: fprintf(stderr, "Win32 Error: ERROR_INVALID_WINDOW_HANDLE\n"); break; case ERROR_RESOURCE_TYPE_NOT_FOUND: fprintf(stderr, "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, "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); exit(1); } //------------------------------------------------------------------------------ // Function : RenderTexture::Initialize // Description : //------------------------------------------------------------------------------ /** * @fn RenderTexture::Initialize(bool bShare, bool bDepth, bool bStencil, bool bMipmap, bool bAnisoFilter, 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 * or aniso filtering 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 */) { #ifdef _WIN32 if (!WGLEW_ARB_pbuffer) { PrintExtensionError("WGL_ARB_pbuffer"); return false; } if (!WGLEW_ARB_pixel_format) { PrintExtensionError("WGL_ARB_pixel_format"); return false; } if (_bIsTexture && !WGLEW_ARB_render_texture) { PrintExtensionError("WGL_ARB_render_texture"); return false; } if (_bIsDepthTexture && !GLEW_ARB_depth_texture) { // [Redge] #if defined(_DEBUG) | defined(DEBUG) fprintf(stderr, "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 (!GLXEW_SGIX_pbuffer) { PrintExtensionError("GLX_SGIX_pbuffer"); return false; } if (!GLXEW_SGIX_fbconfig) { PrintExtensionError("GLX_SGIX_fbconfig"); return false; } if (_bIsDepthTexture) { PrintExtensionError("I don't know"); return false; } if (updateMode == RT_RENDER_TO_TEXTURE) { PrintExtensionError("Some GLX render texture extension"); } #endif if (_bInitialized) _Invalidate(); _bFloat = (iRBits > 8 || iGBits > 8 || iBBits > 8 || iABits > 8); bool bNVIDIA = true; #ifdef _WIN32 if (_bFloat && !GLEW_NV_float_buffer) { bNVIDIA = false; if (!WGLEW_ATI_pixel_format_float) { PrintExtensionError("GL_NV_float_buffer or GL_ATI_pixel_format_float"); return false; } } if (_bFloat && _bIsTexture && !bNVIDIA && !GLEW_ATI_texture_float) { PrintExtensionError("NV_float_buffer or ATI_texture_float"); } #else if (_bFloat && _bIsTexture && !GLXEW_NV_float_buffer) { PrintExtensionError("GLX_NV_float_buffer"); return false; } #endif if (!_bFloat && !GLEW_NV_texture_rectangle) { bNVIDIA = false; } _bRectangle = _bRectangle || (_bFloat && bNVIDIA); if(_bIsDepthTexture) _bHasDepth = true; // we need depth for a depth texture... else _bHasDepth = bDepth; _bHasStencil = bStencil; _bMipmap = false; // until it is enabled. _bAnisoFilter = false; // until it is enabled. _eUpdateMode = updateMode; GLuint iWGLTextureTarget = 0; GLuint iBindTarget = 0; GLuint iTextureFormat = 0; GLuint iDepthBindTarget = 0; GLuint iDepthTextureFormat = 0; if (_bIsTexture) glGenTextures(1, &_iTextureID); if (_bIsDepthTexture) glGenTextures(1, &_iDepthTextureID); // Determine the appropriate texture formats and filtering modes. if (_bIsTexture) { if (_bFloat) { if (!bNVIDIA && _bRectangle) { fprintf(stderr, "RenderTexture Error: ATI textures must be power-of-two-dimensioned.\n"); return false; } if (bNVIDIA) _iTextureTarget = GL_TEXTURE_RECTANGLE_NV; else _iTextureTarget = GL_TEXTURE_2D; glBindTexture(_iTextureTarget, _iTextureID); // We'll use clamp to edge as the default texture wrap mode for all tex types glTexParameteri( _iTextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri( _iTextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri( _iTextureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri( _iTextureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); if (bMipmap) { fprintf(stderr, "RenderTexture Error: float textures do not support mipmaps\n"); return false; } if (RT_COPY_TO_TEXTURE == _eUpdateMode) { GLuint iInternalFormat; GLuint iFormat; if (iABits > 0) { if (bNVIDIA) iInternalFormat = (iABits > 16) ? GL_FLOAT_RGBA32_NV : GL_FLOAT_RGBA16_NV; else iInternalFormat = (iABits > 16) ? GL_RGBA_FLOAT32_ATI : GL_RGBA_FLOAT16_ATI; iFormat = GL_RGBA; } else if (iBBits > 0) { if (bNVIDIA) iInternalFormat = (iBBits > 16) ? GL_FLOAT_RGB32_NV : GL_FLOAT_RGB16_NV; else iInternalFormat = (iBBits > 16) ? GL_RGB_FLOAT32_ATI : GL_RGB_FLOAT16_ATI; iFormat = GL_RGB; } else if (iGBits > 0) { if (bNVIDIA) iInternalFormat = (iGBits > 16) ? GL_FLOAT_RG32_NV : GL_FLOAT_RG16_NV; else iInternalFormat = (iGBits > 16) ? GL_LUMINANCE_ALPHA_FLOAT32_ATI : GL_LUMINANCE_ALPHA_FLOAT16_ATI; iFormat = GL_LUMINANCE_ALPHA; } else { if (bNVIDIA) iInternalFormat = (iRBits > 16) ? GL_FLOAT_R32_NV : GL_FLOAT_R16_NV; else iInternalFormat = (iRBits > 16) ? GL_LUMINANCE_FLOAT32_ATI : GL_LUMINANCE_FLOAT16_ATI; iFormat = GL_LUMINANCE; } // Allocate the texture image (but pass it no data for now). glTexImage2D(_iTextureTarget, 0, iInternalFormat, _iWidth, _iHeight, 0, iFormat, GL_FLOAT, NULL); } else { #ifdef _WIN32 if (bNVIDIA) iWGLTextureTarget = WGL_TEXTURE_RECTANGLE_NV; else iWGLTextureTarget = WGL_TEXTURE_2D_ARB; if (iABits > 0) { if (bNVIDIA) { iBindTarget = WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV; iTextureFormat = WGL_TEXTURE_FLOAT_RGBA_NV; } else { iBindTarget = WGL_BIND_TO_TEXTURE_RGBA_ARB; iTextureFormat = WGL_TEXTURE_RGBA_ARB; } } else if (iBBits > 0) { if (bNVIDIA) { iBindTarget = WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV; iTextureFormat = WGL_TEXTURE_FLOAT_RGB_NV; } else { iBindTarget = WGL_BIND_TO_TEXTURE_RGB_ARB; iTextureFormat = WGL_TEXTURE_RGB_ARB; } } else if (iGBits > 0) { if (bNVIDIA) { iBindTarget = WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV; iTextureFormat = WGL_TEXTURE_FLOAT_RG_NV; } else { iBindTarget = WGL_BIND_TO_TEXTURE_RGB_ARB; iTextureFormat = WGL_TEXTURE_RGB_ARB; } } else { if (bNVIDIA) { iBindTarget = WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV; iTextureFormat = WGL_TEXTURE_FLOAT_R_NV; } else { iBindTarget = WGL_BIND_TO_TEXTURE_RGB_ARB; iTextureFormat = WGL_TEXTURE_RGB_ARB; } } #else if defined(DEBUG) || defined(_DEBUG) printf("RenderTexture Error: Render-to-Texture not supported in Linux\n"); #endif } } else { if (!_bRectangle) { _iTextureTarget = GL_TEXTURE_2D; glBindTexture(_iTextureTarget, _iTextureID); // We'll use clamp to edge as the default texture wrap mode for all tex types glTexParameteri( _iTextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri( _iTextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri( _iTextureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); if (bMipmap) { _bMipmap = true; glTexParameteri( _iTextureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Generate mipmap automatically if supported if (GLEW_SGIS_generate_mipmap) { glTexParameteri( _iTextureTarget, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); } else { PrintExtensionError("GL_SGIS_generate_mipmap"); } } else { glTexParameteri( _iTextureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } // Set anisotropic filter to the max ratio if (bAnisoFilter) { if (GLEW_EXT_texture_filter_anisotropic) { _bAnisoFilter = true; float rMaxAniso; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &rMaxAniso); glTexParameterf( _iTextureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, rMaxAniso); } } if (RT_COPY_TO_TEXTURE == _eUpdateMode) { GLuint iInternalFormat; GLuint iFormat; if (iABits > 0) { 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); } else { #ifdef _WIN32 iWGLTextureTarget = WGL_TEXTURE_2D_ARB; if (iABits > 0) { iBindTarget = WGL_BIND_TO_TEXTURE_RGBA_ARB; iTextureFormat = WGL_TEXTURE_RGBA_ARB; } else { iBindTarget = WGL_BIND_TO_TEXTURE_RGB_ARB; iTextureFormat = WGL_TEXTURE_RGB_ARB; } #endif } } else { if (!bNVIDIA) { fprintf(stderr, "RenderTexture Error: ATI textures must be power-of-two-dimensioned.\n"); return false; } _iTextureTarget = GL_TEXTURE_RECTANGLE_NV; glBindTexture(_iTextureTarget, _iTextureID); glTexParameteri( _iTextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri( _iTextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri( _iTextureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri( _iTextureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); if (bMipmap) { fprintf(stderr, "RenderTexture Error: rectangle textures do not support mipmaps\n"); return false; } if (RT_COPY_TO_TEXTURE == _eUpdateMode) { GLuint iInternalFormat; GLuint iFormat; if (iABits > 0) { 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); } else { #ifdef _WIN32 iWGLTextureTarget = WGL_TEXTURE_RECTANGLE_NV; if (iABits > 0) { iBindTarget = WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV; iTextureFormat = WGL_TEXTURE_RGBA_ARB; } else { iBindTarget = WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV; iTextureFormat= WGL_TEXTURE_RGB_ARB; } #endif } } } } if (_bIsDepthTexture) { if (!bNVIDIA && _bRectangle) { fprintf(stderr, "RenderTexture Error: ATI textures must be power-of-two-dimensioned.\n"); return false; } if (!_iTextureTarget) _iTextureTarget = _bRectangle ? GL_TEXTURE_RECTANGLE_NV : GL_TEXTURE_2D; glBindTexture(_iTextureTarget, _iDepthTextureID); // We'll use clamp to edge as the default texture wrap mode for all tex types glTexParameteri( _iTextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri( _iTextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri( _iTextureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri( _iTextureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // user will need to set up hardware shadow mapping himself (using ARB_shadow) 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] } else // RENDER_TO_TEXTURE { #ifdef _WIN32 if(_bRectangle) { if (!iWGLTextureTarget) iWGLTextureTarget = WGL_TEXTURE_RECTANGLE_NV; iDepthBindTarget = WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV; iDepthTextureFormat = WGL_TEXTURE_DEPTH_COMPONENT_NV; } else { if (!iWGLTextureTarget) iWGLTextureTarget = WGL_TEXTURE_2D_ARB; iDepthBindTarget = WGL_BIND_TO_TEXTURE_DEPTH_NV; iDepthTextureFormat = WGL_TEXTURE_DEPTH_COMPONENT_NV; } #endif } } #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; int attribChooseList[50]; int attribCreateList[50]; int attribChoose = 0; int attribCreate = 0; // Setup the attrib list for wglChoosePixelFormat() attribChooseList[attribChoose++] = WGL_RED_BITS_ARB; attribChooseList[attribChoose++] = iRBits; attribChooseList[attribChoose++] = WGL_GREEN_BITS_ARB; attribChooseList[attribChoose++] = iGBits; attribChooseList[attribChoose++] = WGL_BLUE_BITS_ARB; attribChooseList[attribChoose++] = iBBits; attribChooseList[attribChoose++] = WGL_ALPHA_BITS_ARB; attribChooseList[attribChoose++] = iABits; if (_bFloat) { if (bNVIDIA) { attribChooseList[attribChoose++] = WGL_FLOAT_COMPONENTS_NV; attribChooseList[attribChoose++] = GL_TRUE; } else { attribChooseList[attribChoose++] = WGL_PIXEL_TYPE_ARB; attribChooseList[attribChoose++] = WGL_TYPE_RGBA_FLOAT_ATI; } } attribChooseList[attribChoose++] = WGL_STENCIL_BITS_ARB; attribChooseList[attribChoose++] = (bStencil) ? 8 : 0; attribChooseList[attribChoose++] = WGL_DEPTH_BITS_ARB; attribChooseList[attribChoose++] = (bDepth) ? 24 : 0; attribChooseList[attribChoose++] = WGL_DRAW_TO_PBUFFER_ARB; attribChooseList[attribChoose++] = GL_TRUE; if (_bIsTexture && RT_RENDER_TO_TEXTURE == _eUpdateMode) { attribChooseList[attribChoose++] = iBindTarget; attribChooseList[attribChoose++] = GL_TRUE; } if (_bIsDepthTexture && RT_RENDER_TO_TEXTURE == _eUpdateMode) { attribChooseList[attribChoose++] = iDepthBindTarget; attribChooseList[attribChoose++] = GL_TRUE; } attribChooseList[attribChoose++] = 0; // Setup the attrib list for wglCreatePbuffer() if ((_bIsTexture || _bIsDepthTexture) && RT_RENDER_TO_TEXTURE == _eUpdateMode) { attribCreateList[attribCreate++] = WGL_TEXTURE_TARGET_ARB; attribCreateList[attribCreate++] = iWGLTextureTarget; } if (_bIsTexture && RT_RENDER_TO_TEXTURE == _eUpdateMode) { attribCreateList[attribCreate++] = WGL_TEXTURE_FORMAT_ARB; attribCreateList[attribCreate++] = iTextureFormat; /*attribCreateList[attribCreate++] = WGL_TEXTURE_TARGET_ARB; attribCreateList[attribCreate++] = iWGLTextureTarget;*/ attribCreateList[attribCreate++] = WGL_MIPMAP_TEXTURE_ARB; attribCreateList[attribCreate++] = (bMipmap) ? GL_TRUE : GL_FALSE; } if (_bIsDepthTexture && RT_RENDER_TO_TEXTURE == _eUpdateMode) { attribCreateList[attribCreate++] = WGL_DEPTH_TEXTURE_FORMAT_NV; attribCreateList[attribCreate++] = iDepthTextureFormat; } attribCreateList[attribCreate++] = WGL_PBUFFER_LARGEST_ARB; attribCreateList[attribCreate++] = GL_FALSE; attribCreateList[attribCreate++] = 0; if (!wglChoosePixelFormatARB( hdc, attribChooseList, NULL, 1, &iFormat, &iNumFormats)) { fprintf(stderr, "RenderTexture::Initialize() creation error: wglChoosePixelFormatARB() failed.\n"); _wglGetLastError(); return false; } if ( iNumFormats <= 0 ) { fprintf(stderr, "RenderTexture::Initialize() creation error: Couldn't find a suitable pixel format.\n"); _wglGetLastError(); return false; } // Create the p-buffer. _hPBuffer = wglCreatePbufferARB( hdc, iFormat, _iWidth, _iHeight, attribCreateList ); if (!_hPBuffer) { fprintf(stderr, "RenderTexture::Initialize() pbuffer creation error: wglCreatePbufferARB() failed\n"); _wglGetLastError(); return false; } // Get the device context. _hDC = wglGetPbufferDCARB( _hPBuffer); if ( !_hDC ) { fprintf(stderr, "RenderTexture::Initialize() creation error: wglGetGetPbufferDCARB() failed\n"); _wglGetLastError(); return false; } // Create a gl context for the p-buffer. _hGLContext = wglCreateContext( _hDC ); if ( !_hGLContext ) { fprintf(stderr, "RenderTexture::Initialize() creation error: wglCreateContext() failed\n"); _wglGetLastError(); return false; } // Share lists, texture objects, and program objects. if( bShare ) { if( !wglShareLists(hglrc, _hGLContext) ) { fprintf(stderr, "RenderTexture::Initialize() creation error: wglShareLists() failed\n" ); _wglGetLastError(); return false; } } // bind the pbuffer to the render texture object if (_bIsTexture && RT_RENDER_TO_TEXTURE == _eUpdateMode) { glBindTexture(_iTextureTarget, _iTextureID); if (wglBindTexImageARB(_hPBuffer, WGL_FRONT_LEFT_ARB) == FALSE) { _wglGetLastError(); return false; } } if (_bIsDepthTexture && RT_RENDER_TO_TEXTURE == _eUpdateMode) { glBindTexture(_iTextureTarget, _iDepthTextureID); if (wglBindTexImageARB(_hPBuffer, WGL_DEPTH_COMPONENT_NV) == FALSE) { _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 value; _iBits[0] = (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value)) ? value : iRBits; attrib = WGL_GREEN_BITS_ARB; _iBits[1] = (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value)) ? value : iGBits; attrib = WGL_BLUE_BITS_ARB; _iBits[2] = (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value)) ? value : iBBits; attrib = WGL_ALPHA_BITS_ARB; _iBits[3] = (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value)) ? value : iABits; attrib = WGL_DEPTH_BITS_ARB; _iBits[4] = (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value)) ? value : 0; attrib = WGL_STENCIL_BITS_ARB; _iBits[5] = (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value)) ? value : 0; #if defined(_DEBUG) | defined(DEBUG) fprintf(stderr, "Created a %dx%d RenderTexture with BPP(%d, %d, %d, %d)", _iWidth, _iHeight, _iBits[0], _iBits[1], _iBits[2], _iBits[3]); if (_iBits[4]) fprintf(stderr, " depth=%d", _iBits[4]); if (_iBits[5]) fprintf(stderr, " stencil=%d", _iBits[5]); fprintf(stderr, "\n"); #endif #else _pDpy = glXGetCurrentDisplay(); GLXContext context = glXGetCurrentContext(); int screen = DefaultScreen(_pDpy); XVisualInfo *visInfo; int iFormat = 0; int iNumFormats; int fbAttribs[50]; int attrib = 0; fbAttribs[attrib++] = GLX_RENDER_TYPE_SGIX; fbAttribs[attrib++] = GLX_RGBA_BIT_SGIX; fbAttribs[attrib++] = GLX_DRAWABLE_TYPE_SGIX; fbAttribs[attrib++] = GLX_PBUFFER_BIT_SGIX; fbAttribs[attrib++] = GLX_STENCIL_SIZE; fbAttribs[attrib++] = (bStencil) ? 8 : 0; fbAttribs[attrib++] = GLX_DEPTH_SIZE; fbAttribs[attrib++] = (bDepth) ? 24 : 0; if (_bFloat) { fbAttribs[attrib++] = GLX_RED_SIZE; fbAttribs[attrib++] = iRBits; fbAttribs[attrib++] = GLX_GREEN_SIZE; fbAttribs[attrib++] = iGBits; fbAttribs[attrib++] = GLX_BLUE_SIZE; fbAttribs[attrib++] = iBBits; fbAttribs[attrib++] = GLX_ALPHA_SIZE; fbAttribs[attrib++] = iABits; fbAttribs[attrib++] = GLX_FLOAT_COMPONENTS_NV; fbAttribs[attrib++] = 1; } fbAttribs[attrib++] = None; GLXFBConfigSGIX *fbConfigs; int nConfigs; fbConfigs = glXChooseFBConfigSGIX(_pDpy, screen, fbAttribs, &nConfigs); if (nConfigs == 0 || !fbConfigs) { fprintf(stderr, "RenderTexture::Initialize() creation 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