![]() |
|
| |
|
![]() |
#1 |
高级会员
注册日期: 06-11
帖子: 1527
精华: 15
现金: 6353 标准币
资产: 6353 标准币
![]() |
![]() 1.RenderTexture.h
//------------------------------------------------------------------------------ // 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 // Florian Kirsch // Andrew Wood // // ----------------------------------------------------------------------------- /** * @file RenderTexture.h * * Interface definition for class RenderTexture. A multi-format render to * texture wrapper. */ #ifndef __RENDERTEXTURE2_HPP__ #define __RENDERTEXTURE2_HPP__ #include <GL/glew.h> #ifdef _WIN32 #include <GL/wglew.h> #else #include <GL/glxew.h> #endif #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 * singlebuffer - do not 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__ |
![]() |
![]() |
GDT自动化论坛(仅游客可见) |
![]() |
#2 |
高级会员
注册日期: 06-11
帖子: 1527
精华: 15
现金: 6353 标准币
资产: 6353 标准币
![]() |
![]() 2.RenderTexture.cpp
//--------------------------------------------------------------------------- // 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 // Florian Kirsch // // -------------------------------------------------------------------------- /** * @file RenderTexture.cpp * * Implementation of class RenderTexture. A multi-format render to * texture wrapper. */ #pragma warning(disable:4786) #include "RenderTexture.h" #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; #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; // [Andrew Wood] //Add in pbufferAttribs. Needed to choose pixel format. (Especially for floating point) _pixelFormatAttribs.insert(_pixelFormatAttribs.begin(), _pbufferAttribs.begin(),_pbufferAttribs.end()); // [/Andrew Wood] 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 int i; for (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; // [Florian] Query the color format //XVisualInfo* visual = glXGetVisualFromFBConfigSGIX(_pDisplay, fbConfigs[i]); // [Andrew Wood] int iResult = 0; glXGetFBConfigAttribSGIX(_pDisplay, fbConfigs[i], GLX_RENDER_TYPE, &iResult); if (iResult == GLX_RGBA_BIT) { _iNumColorBits[0] = (glXGetFBConfigAttribSGIX(_pDisplay, fbConfigs[i], GLX_RED_SIZE, &iResult) == 0) ? iResult : 0; _iNumColorBits[1] = (glXGetFBConfigAttribSGIX(_pDisplay, fbConfigs[i], GLX_GREEN_SIZE, &iResult) == 0) ? iResult : 0; _iNumColorBits[2] = (glXGetFBConfigAttribSGIX(_pDisplay, fbConfigs[i], GLX_BLUE_SIZE, &iResult) == 0) ? iResult : 0; _iNumColorBits[3] = (glXGetFBConfigAttribSGIX(_pDisplay, fbConfigs[i], GLX_ALPHA_SIZE, &iResult) == 0) ? iResult : 0; _iNumDepthBits = (glXGetFBConfigAttribSGIX(_pDisplay, fbConfigs[i], GLX_DEPTH_SIZE, &iResult) == 0) ? iResult : 0; _iNumStencilBits = (glXGetFBConfigAttribSGIX(_pDisplay, fbConfigs[i], GLX_STENCIL_SIZE, &iResult) == 0) ? iResult : 0; _bDoubleBuffered = (glXGetFBConfigAttribSGIX(_pDisplay, fbConfigs[i], GLX_DOUBLEBUFFER, &iResult) == 0) ? (iResult?true:false) : false; } // [/Andrew Wood] //XFree(visual); // [/Florian] #endif #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 // 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 pfAttribs.push_back(GLX_RED_SIZE); pfAttribs.push_back(bitVec[0]); pfAttribs.push_back(GLX_GREEN_SIZE); pfAttribs.push_back(bitVec[1]); pfAttribs.push_back(GLX_BLUE_SIZE); pfAttribs.push_back(bitVec[2]); #endif _iNumComponents += 3; continue; } else if (kv.first == "rgb") 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 pfAttribs.push_back(GLX_RED_SIZE); pfAttribs.push_back(bitVec[0]); pfAttribs.push_back(GLX_GREEN_SIZE); pfAttribs.push_back(bitVec[1]); pfAttribs.push_back(GLX_BLUE_SIZE); pfAttribs.push_back(bitVec[2]); pfAttribs.push_back(GLX_ALPHA_SIZE); pfAttribs.push_back(bitVec[3]); #endif _iNumComponents = 4; continue; } else if (kv.first == "rgba") 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(GLX_SAMPLE_BUFFERS_ARB); pfAttribs.push_back(1); pfAttribs.push_back(GLX_SAMPLES_ARB); pfAttribs.push_back(strtol(kv.second.c_str(), 0, 10)); #endif continue; } if (kv.first == "doublebuffer" || kv.first == "double") { #ifdef _WIN32 pfAttribs.push_back(WGL_DOUBLE_BUFFER_ARB); pfAttribs.push_back(true); #else pfAttribs.push_back(GLX_DOUBLEBUFFER); pfAttribs.push_back(True); #endif continue; } // [Florian] if (kv.first == "singlebuffer" || kv.first == "single") { #ifdef _WIN32 pfAttribs.push_back(WGL_DOUBLE_BUFFER_ARB); pfAttribs.push_back(false); #else pfAttribs.push_back(GLX_DOUBLEBUFFER); pfAttribs.push_back(False); #endif continue; } // [/Florian] if (kv.first == "aux") { #ifdef _WIN32 pfAttribs.push_back(WGL_AUX_BUFFERS_ARB); #else pfAttribs.push_back(GLX_AUX_BUFFERS); #endif if (kv.second == "") pfAttribs.push_back(0); else pfAttribs.push_back(strtol(kv.second.c_str(), 0, 10)); continue; } if (token.find("tex") == 0) { _bIsTexture = true; if ((kv.first == "texRECT") && GLEW_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") && GLEW_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 (!WGLEW_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 (WGLEW_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 (GLXEW_NV_float_buffer) { pfAttribs.push_back(GLX_FLOAT_COMPONENTS_NV); pfAttribs.push_back(1); } #endif } else { #ifdef _WIN32 pfAttribs.push_back(WGL_PIXEL_TYPE_ARB); pfAttribs.push_back(WGL_TYPE_RGBA_ARB); #endif } // Set up texture binding for render to texture if (_bIsTexture && (RT_RENDER_TO_TEXTURE == _eUpdateMode)) { #ifdef _WIN32 if (_bFloat) { if (WGLEW_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 (!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 (_bRectangle && !GLEW_NV_texture_rectangle) { PrintExtensionError("GL_NV_texture_rectangle"); return false; } if (_bFloat && !(GLEW_NV_float_buffer || WGLEW_ATI_pixel_format_float)) { PrintExtensionError("GL_NV_float_buffer or GL_ATI_pixel_format_float"); return false; } if (_bFloat && _bIsTexture && !(GLEW_NV_float_buffer || GLEW_ATI_texture_float)) { PrintExtensionError("NV_float_buffer or ATI_texture_float"); } if (_bIsDepthTexture && !GLEW_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 (!GLXEW_SGIX_pbuffer) { PrintExtensionError("GLX_SGIX_pbuffer"); return false; } if (!GLXEW_SGIX_fbconfig) { PrintExtensionError("GLX_SGIX_fbconfig"); return false; } if (_bIsDepthTexture && !GLEW_ARB_depth_texture) { PrintExtensionError("GL_ARB_depth_texture"); return false; } if (_bFloat && _bIsTexture && !GLXEW_NV_float_buffer) { PrintExtensionError("GLX_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 && GLEW_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 (GLEW_NV_float_buffer) { iInternalFormat = (_iNumColorBits[0] > 16) ? GL_FLOAT_R32_NV : GL_FLOAT_R16_NV; } else if (GLEW_ATI_texture_float) { iInternalFormat = (_iNumColorBits[0] > 16) ? GL_LUMINANCE_FLOAT32_ATI : GL_LUMINANCE_FLOAT16_ATI; } iFormat = GL_LUMINANCE; break; case 2: if (GLEW_NV_float_buffer) { iInternalFormat = (_iNumColorBits[0] > 16) ? GL_FLOAT_RG32_NV : GL_FLOAT_RG16_NV; } else if (GLEW_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 (GLEW_NV_float_buffer) { iInternalFormat = (_iNumColorBits[0] > 16) ? GL_FLOAT_RGB32_NV : GL_FLOAT_RGB16_NV; } else if (GLEW_ATI_texture_float) { iInternalFormat = (_iNumColorBits[0] > 16) ? GL_RGB_FLOAT32_ATI : GL_RGB_FLOAT16_ATI; } iFormat = GL_RGB; break; case 4: if (GLEW_NV_float_buffer) { iInternalFormat = (_iNumColorBits[0] > 16) ? GL_FLOAT_RGBA32_NV : GL_FLOAT_RGBA16_NV; } else if (GLEW_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 (GLEW_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 (GLEW_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; } |
![]() |
![]() |
![]() |
#3 |
高级会员
注册日期: 06-11
帖子: 1527
精华: 15
现金: 6353 标准币
资产: 6353 标准币
![]() |
![]() 3.renderSCS.cpp
// OpenCSG - library for image-based CSG rendering for OpenGL // Copyright (C) 2002-2004 // Hasso-Plattner-Institute at the University of Potsdam, Germany, and Florian Kirsch // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License, // Version 2, as published by the Free Software Foundation. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // renderSCS.cpp // // stuff specific for the SCS algorithm // #include <opencsgConfig.h> #include <opencsg.h> #include "opencsgRender.h" #include "batch.h" #include "channelManager.h" #include "occlusionQuery.h" #include "openglHelper.h" #include "primitiveHelper.h" #include "scissorMemo.h" #include <map> namespace OpenCSG { namespace { ScissorMemo* scissor; struct RenderData { unsigned int stencilID_; }; std::map<Primitive*, RenderData> renderInfo_; RenderData* getRenderData(Primitive* primitive) { RenderData* dta = &(renderInfo_.find(primitive))->second; return dta; } class SCSChannelManager : public ChannelManagerForBatches { public: virtual void merge(); }; void SCSChannelManager::merge() { setupProjectiveTexture(); glEnable(GL_ALPHA_TEST); glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glDepthMask(GL_TRUE); std::vector<Channel> channels = occupied(); for (std::vector<Channel>::const_iterator c = channels.begin(); c!=channels.end(); ++c) { setupTexEnv(*c); scissor->recall(*c); scissor->enable(); const std::vector<Primitive*> primitives = getPrimitives(*c); for (std::vector<Primitive*>::const_iterator j = primitives.begin(); j != primitives.end(); ++j) { glCullFace((*j)->getOperation() == Intersection ? GL_BACK : GL_FRONT); RenderData* primitiveData = getRenderData(*j); unsigned char id = primitiveData->stencilID_; glAlphaFunc(GL_EQUAL, static_cast<float>(id) / 255.0f); (*j)->render(); } } scissor->disable(); resetProjectiveTexture(); clear(); } class IDGenerator { public: IDGenerator() { currentID_ = 0; }; unsigned int newID() { return ++currentID_; }; private: unsigned int currentID_; }; IDGenerator* IDGenerator_; SCSChannelManager* channelMgr; void renderIntersectedFront(const std::vector<Primitive*>& primitives) { const int numberOfPrimitives = primitives.size(); glDepthMask(GL_TRUE); // optimization for only one shape if (numberOfPrimitives == 1) { channelMgr->renderToChannel(true); glDepthFunc(GL_GREATER); glCullFace(GL_BACK); glEnable(GL_CULL_FACE); RenderData* primitiveData = getRenderData(primitives[0]); GLubyte b = primitiveData->stencilID_; glColor4ub(b, b, b, b); primitives[0]->render(); glDisable(GL_CULL_FACE); glDepthFunc(GL_LESS); return; } // draw furthest front face channelMgr->renderToChannel(true); glStencilMask(OpenGL::stencilMask); glDepthFunc(GL_GREATER); glCullFace(GL_BACK); glEnable(GL_CULL_FACE); { for (std::vector<Primitive*>::const_iterator i = primitives.begin(); i != primitives.end(); ++i) { RenderData* primitiveData = getRenderData(*i); GLubyte b = primitiveData->stencilID_; glColor4ub(b, b, b, b); (*i)->render(); } } // count back faces behind furthest front face channelMgr->renderToChannel(false); glStencilFunc(GL_ALWAYS, 0, OpenGL::stencilMask); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); glEnable(GL_STENCIL_TEST); glDepthMask(GL_FALSE); glCullFace(GL_FRONT); { for (std::vector<Primitive*>::const_iterator i = primitives.begin(); i != primitives.end(); ++i) { (*i)->render(); } } // where #back faces behind furthest front face != #intersected shapes // ->reset fragment channelMgr->renderToChannel(true); glStencilFunc(GL_NOTEQUAL, numberOfPrimitives, OpenGL::stencilMask); glDepthFunc(GL_ALWAYS); glDepthRange(0.0, 0.0); glDepthMask(GL_TRUE); glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); glDisable(GL_CULL_FACE); glColor4ub(0, 0, 0, 0); OpenGL::drawQuad(); glDepthRange(0.0, 1.0); glDepthFunc(GL_LESS); glDisable(GL_STENCIL_TEST); } void subtractPrimitives(std::vector<Batch>::const_iterator begin, std::vector<Batch>::const_iterator end, const unsigned int iterations) { if (begin == end) { return; } glStencilMask(OpenGL::stencilMask); glEnable(GL_STENCIL_TEST); glEnable(GL_CULL_FACE); int stencilref = 0; int sense = 1; unsigned int changes = 0; std::vector<Batch>::const_iterator i = begin; do { // create a distinct reference value ++stencilref; if (stencilref == OpenGL::stencilMax) { glClear(GL_STENCIL_BUFFER_BIT); stencilref = 1; } channelMgr->renderToChannel(false); glDepthFunc(GL_LESS); glDepthMask(GL_FALSE); glStencilFunc(GL_ALWAYS, stencilref, OpenGL::stencilMask); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glCullFace(GL_BACK); { for (Batch::const_iterator j = i->begin(); j != i->end(); ++j) { (*j)->render(); } } // where front faces have been visible, render back faces channelMgr->renderToChannel(true); glDepthFunc(GL_GREATER); glDepthMask(GL_TRUE); glCullFace(GL_FRONT); glStencilFunc(GL_EQUAL, stencilref, OpenGL::stencilMask); glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); { for (Batch::const_iterator j = i->begin(); j != i->end(); ++j) { RenderData* primitiveData = getRenderData(*j); GLubyte b = primitiveData->stencilID_; glColor4ub(b, b, b, b); (*j)->render(); } } if (sense == 1) { ++i; if (i == end) { sense = 0; --i; if (i == begin) break; // only one subtracted shape --i; ++changes; } } else { if (i == begin) { sense = 1; ++i; ++changes; } else { --i; } } } while (changes < iterations); glDisable(GL_STENCIL_TEST); } void subtractPrimitivesWithOcclusionQueries(std::vector<Batch>::const_iterator begin, std::vector<Batch>::const_iterator end) { const unsigned int numberOfBatches = end - begin; if (numberOfBatches == 0) { return; } glStencilMask(OpenGL::stencilMask); glEnable(GL_STENCIL_TEST); glEnable(GL_CULL_FACE); OpenGL::OcclusionQuery* occlusionTest = OpenGL::getOcclusionQuery(); std::vector<unsigned int> fragmentcount(numberOfBatches, 0); int stencilref = 0; std::vector<Batch>::const_iterator i = begin; unsigned int shapesWithoutUpdate = 0; unsigned int shapeCount = 0; int idx=0; do { // create a distinct reference value ++stencilref; if (stencilref == OpenGL::stencilMax) { glClear(GL_STENCIL_BUFFER_BIT); stencilref = 1; } channelMgr->renderToChannel(false); glDepthFunc(GL_LESS); glDepthMask(GL_FALSE); glStencilFunc(GL_ALWAYS, stencilref, OpenGL::stencilMask); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glCullFace(GL_BACK); occlusionTest->beginQuery(); { for (Batch::const_iterator j = i->begin(); j != i->end(); ++j) { (*j)->render(); } } occlusionTest->endQuery(); // the fragment count query could occur here, but benches show that // the algorithm is faster if the query is delayed. // where front faces have been visible, render back faces channelMgr->renderToChannel(true); glDepthFunc(GL_GREATER); glDepthMask(GL_TRUE); glCullFace(GL_FRONT); glStencilFunc(GL_EQUAL, stencilref, OpenGL::stencilMask); glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); { for (Batch::const_iterator j = i->begin(); j != i->end(); ++j) { RenderData* primitiveData = getRenderData(*j); GLubyte b = primitiveData->stencilID_; glColor4ub(b, b, b, b); (*j)->render(); } } unsigned int newFragmentCount = occlusionTest->getQueryResult(); if (newFragmentCount != fragmentcount[idx]) { fragmentcount[idx] = newFragmentCount; shapesWithoutUpdate = 0; } else { ++shapesWithoutUpdate; } ++i; ++idx; if (i == end) { i = begin; idx = 0; } ++shapeCount; if (shapeCount >= (numberOfBatches) * (numberOfBatches) - (numberOfBatches) + 1) break; } while (shapesWithoutUpdate < numberOfBatches); delete occlusionTest; glDisable(GL_STENCIL_TEST); } void renderIntersectedBack(const std::vector<Primitive*>& primitives) { // where a back face of intersected shape is in front of any subtracted shape // mask fragment as invisible. Updating depth calues is not necessary, so when // having IDs, this is kind of simple. channelMgr->renderToChannel(true); glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); glDepthMask(GL_FALSE); glDepthFunc(GL_LESS); glColor4ub(0, 0, 0, 0); for (std::vector<Primitive*>::const_iterator i = primitives.begin(); i != primitives.end(); ++i) { (*i)->render(); } glDepthMask(GL_TRUE); } } // unnamed namespace void renderSCS(const std::vector<Primitive*>& primitives, DepthComplexityAlgorithm algorithm) { renderInfo_.clear(); IDGenerator_ = new IDGenerator(); channelMgr = new SCSChannelManager; scissor = new ScissorMemo; std::vector<Primitive*> intersected; std::vector<Primitive*> subtracted; { for (std::vector<Primitive*>::const_iterator itr = primitives.begin(); itr != primitives.end(); ++itr) { { RenderData dta; dta.stencilID_ = IDGenerator_->newID(); renderInfo_.insert(std::make_pair(*itr, dta)); } Operation operation= (*itr)->getOperation(); if (operation == Intersection) { intersected.push_back(*itr); } else if (operation == Subtraction) { subtracted.push_back(*itr); } } } Batcher subtractedBatches(subtracted); scissor->setIntersected(intersected); scissor->setCurrent(intersected); unsigned int depthComplexity = 0; if (algorithm == DepthComplexitySampling) { scissor->enable(); glClear(GL_STENCIL_BUFFER_BIT); depthComplexity = std::min(OpenGL::calcMaxDepthComplexity(subtracted, scissor->getCurrentArea()), subtractedBatches.size()); } channelMgr->request(); channelMgr->renderToChannel(true); scissor->enable(); scissor->store(channelMgr->current()); glDepthMask(GL_TRUE); glStencilMask(OpenGL::stencilMask); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClearDepth(0.0); // near clipping plane! essential for algorithm! glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glClearDepth(1.0); renderIntersectedFront(intersected); switch (algorithm) { case NoDepthComplexitySampling: subtractPrimitives(subtractedBatches.begin(), subtractedBatches.end(), subtractedBatches.size()); break; case OcclusionQuery: subtractPrimitivesWithOcclusionQueries(subtractedBatches.begin(), subtractedBatches.end()); break; case DepthComplexitySampling: subtractPrimitives(subtractedBatches.begin(), subtractedBatches.end(), depthComplexity); break; } renderIntersectedBack(intersected); scissor->disable(); channelMgr->store(channelMgr->current(), primitives, 0); channelMgr->free(); delete scissor; delete channelMgr; delete IDGenerator_; } } // namespace OpenCSG |
![]() |
![]() |