void R_AttachColorBufferToFBO(FBO_t *fbo, int format, int target, image_t *texture, int index) { R_CreateFBOColorBuffer(fbo, format, index); R_AttachFBOTexture2D(target, texture->texnum, index); fbo->colorBuffers[index].texture = texture; }
void R_InitFBOs(void) { int i; int width, height; Ren_Developer("------- R_InitFBOs -------\n"); if (!glConfig2.framebufferObjectAvailable) { return; } R_CheckDefaultBuffer(); tr.numFBOs = 0; GL_CheckErrors(); // make sure the render thread is stopped R_IssuePendingRenderCommands(); { // forward shading if (glConfig2.textureNPOTAvailable) { width = glConfig.vidWidth; height = glConfig.vidHeight; } else { width = NearestPowerOfTwo(glConfig.vidWidth); height = NearestPowerOfTwo(glConfig.vidHeight); } // deferredRender FBO for the HDR or LDR context tr.deferredRenderFBO = R_CreateFBO("_deferredRender", width, height); R_BindFBO(tr.deferredRenderFBO); if (r_hdrRendering->integer && glConfig2.textureFloatAvailable) { R_CreateFBOColorBuffer(tr.deferredRenderFBO, GL_RGBA16F_ARB, 0); } else { R_CreateFBOColorBuffer(tr.deferredRenderFBO, GL_RGBA, 0); } R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.deferredRenderFBOImage->texnum, 0); R_CreateFBODepthBuffer(tr.deferredRenderFBO, GL_DEPTH_COMPONENT24_ARB); R_AttachFBOTextureDepth(tr.depthRenderImage->texnum); R_CheckFBO(tr.deferredRenderFBO); } if (glConfig2.framebufferBlitAvailable) { if (glConfig2.textureNPOTAvailable) { width = glConfig.vidWidth; height = glConfig.vidHeight; } else { width = NearestPowerOfTwo(glConfig.vidWidth); height = NearestPowerOfTwo(glConfig.vidHeight); } tr.occlusionRenderFBO = R_CreateFBO("_occlusionRender", width, height); R_BindFBO(tr.occlusionRenderFBO); #if 0 if (glConfig2.framebufferPackedDepthStencilAvailable) { //R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_ALPHA32F_ARB, 0); R_CreateFBOPackedDepthStencilBuffer(tr.occlusionRenderFBO, GL_DEPTH24_STENCIL8); } else { //R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_RGBA, 0); R_CreateFBODepthBuffer(tr.occlusionRenderFBO, GL_DEPTH_COMPONENT24); } #else R_CreateFBODepthBuffer(tr.occlusionRenderFBO, GL_DEPTH_COMPONENT24); #endif R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_RGBA, 0); R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.occlusionRenderFBOImage->texnum, 0); R_CheckFBO(tr.occlusionRenderFBO); } if (r_shadows->integer >= SHADOWING_ESM16 && glConfig2.textureFloatAvailable) { // shadowMap FBOs for shadow mapping offscreen rendering for (i = 0; i < MAX_SHADOWMAPS; i++) { width = height = shadowMapResolutions[i]; tr.shadowMapFBO[i] = R_CreateFBO(va("_shadowMap%d", i), width, height); R_BindFBO(tr.shadowMapFBO[i]); if (r_shadows->integer == SHADOWING_ESM32) { R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_ALPHA32F_ARB, 0); } else if (r_shadows->integer == SHADOWING_VSM32) { R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_LUMINANCE_ALPHA32F_ARB, 0); } else if (r_shadows->integer == SHADOWING_EVSM32) { if (r_evsmPostProcess->integer) { R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_ALPHA32F_ARB, 0); } else { R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_RGBA32F_ARB, 0); } } else { R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_RGBA16F_ARB, 0); } R_CreateFBODepthBuffer(tr.shadowMapFBO[i], GL_DEPTH_COMPONENT24_ARB); R_CheckFBO(tr.shadowMapFBO[i]); } // sun requires different resolutions for (i = 0; i < MAX_SHADOWMAPS; i++) { width = height = sunShadowMapResolutions[i]; tr.sunShadowMapFBO[i] = R_CreateFBO(va("_sunShadowMap%d", i), width, height); R_BindFBO(tr.sunShadowMapFBO[i]); if (r_shadows->integer == SHADOWING_ESM32) { R_CreateFBOColorBuffer(tr.sunShadowMapFBO[i], GL_ALPHA32F_ARB, 0); } else if (r_shadows->integer == SHADOWING_VSM32) { R_CreateFBOColorBuffer(tr.sunShadowMapFBO[i], GL_LUMINANCE_ALPHA32F_ARB, 0); } else if (r_shadows->integer == SHADOWING_EVSM32) { if (!r_evsmPostProcess->integer) { R_CreateFBOColorBuffer(tr.sunShadowMapFBO[i], GL_RGBA32F_ARB, 0); } } else { R_CreateFBOColorBuffer(tr.sunShadowMapFBO[i], GL_RGBA16F_ARB, 0); } R_CreateFBODepthBuffer(tr.sunShadowMapFBO[i], GL_DEPTH_COMPONENT24_ARB); if (r_shadows->integer == SHADOWING_EVSM32 && r_evsmPostProcess->integer) { R_AttachFBOTextureDepth(tr.sunShadowMapFBOImage[i]->texnum); /* Since we don't have a color attachment the framebuffer will be considered incomplete. Consequently, we must inform the driver that we do not wish to render to the color buffer. We do this with a call to set the draw-buffer and read-buffer to GL_NONE: */ glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE); } R_CheckFBO(tr.sunShadowMapFBO[i]); } } { if (glConfig2.textureNPOTAvailable) { width = glConfig.vidWidth; height = glConfig.vidHeight; } else { width = NearestPowerOfTwo(glConfig.vidWidth); height = NearestPowerOfTwo(glConfig.vidHeight); } // portalRender FBO for portals, mirrors, water, cameras et cetera tr.portalRenderFBO = R_CreateFBO("_portalRender", width, height); R_BindFBO(tr.portalRenderFBO); if (r_hdrRendering->integer && glConfig2.textureFloatAvailable) { R_CreateFBOColorBuffer(tr.portalRenderFBO, GL_RGBA16F_ARB, 0); } else { R_CreateFBOColorBuffer(tr.portalRenderFBO, GL_RGBA, 0); } R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.portalRenderImage->texnum, 0); R_CheckFBO(tr.portalRenderFBO); } { if (glConfig2.textureNPOTAvailable) { width = glConfig.vidWidth * 0.25f; height = glConfig.vidHeight * 0.25f; } else { width = NearestPowerOfTwo(glConfig.vidWidth * 0.25f); height = NearestPowerOfTwo(glConfig.vidHeight * 0.25f); } tr.downScaleFBO_quarter = R_CreateFBO("_downScale_quarter", width, height); R_BindFBO(tr.downScaleFBO_quarter); if (r_hdrRendering->integer && glConfig2.textureFloatAvailable) { R_CreateFBOColorBuffer(tr.downScaleFBO_quarter, GL_RGBA16F_ARB, 0); } else { R_CreateFBOColorBuffer(tr.downScaleFBO_quarter, GL_RGBA, 0); } R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.downScaleFBOImage_quarter->texnum, 0); R_CheckFBO(tr.downScaleFBO_quarter); tr.downScaleFBO_64x64 = R_CreateFBO("_downScale_64x64", 64, 64); R_BindFBO(tr.downScaleFBO_64x64); if (r_hdrRendering->integer && glConfig2.textureFloatAvailable) { R_CreateFBOColorBuffer(tr.downScaleFBO_64x64, GL_RGBA16F_ARB, 0); } else { R_CreateFBOColorBuffer(tr.downScaleFBO_64x64, GL_RGBA, 0); } R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.downScaleFBOImage_64x64->texnum, 0); R_CheckFBO(tr.downScaleFBO_64x64); #if 0 tr.downScaleFBO_16x16 = R_CreateFBO("_downScale_16x16", 16, 16); R_BindFBO(tr.downScaleFBO_16x16); if (r_hdrRendering->integer && glConfig2.textureFloatAvailable) { R_CreateFBOColorBuffer(tr.downScaleFBO_16x16, GL_RGBA16F_ARB, 0); } else { R_CreateFBOColorBuffer(tr.downScaleFBO_16x16, GL_RGBA, 0); } R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.downScaleFBOImage_16x16->texnum, 0); R_CheckFBO(tr.downScaleFBO_16x16); tr.downScaleFBO_4x4 = R_CreateFBO("_downScale_4x4", 4, 4); R_BindFBO(tr.downScaleFBO_4x4); if (r_hdrRendering->integer && glConfig2.textureFloatAvailable) { R_CreateFBOColorBuffer(tr.downScaleFBO_4x4, GL_RGBA16F_ARB, 0); } else { R_CreateFBOColorBuffer(tr.downScaleFBO_4x4, GL_RGBA, 0); } R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.downScaleFBOImage_4x4->texnum, 0); R_CheckFBO(tr.downScaleFBO_4x4); tr.downScaleFBO_1x1 = R_CreateFBO("_downScale_1x1", 1, 1); R_BindFBO(tr.downScaleFBO_1x1); if (r_hdrRendering->integer && glConfig2.textureFloatAvailable) { R_CreateFBOColorBuffer(tr.downScaleFBO_1x1, GL_RGBA16F_ARB, 0); } else { R_CreateFBOColorBuffer(tr.downScaleFBO_1x1, GL_RGBA, 0); } R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.downScaleFBOImage_1x1->texnum, 0); R_CheckFBO(tr.downScaleFBO_1x1); #endif if (glConfig2.textureNPOTAvailable) { width = glConfig.vidWidth * 0.25f; height = glConfig.vidHeight * 0.25f; } else { width = NearestPowerOfTwo(glConfig.vidWidth * 0.25f); height = NearestPowerOfTwo(glConfig.vidHeight * 0.25f); } tr.contrastRenderFBO = R_CreateFBO("_contrastRender", width, height); R_BindFBO(tr.contrastRenderFBO); if (r_hdrRendering->integer && glConfig2.textureFloatAvailable) { R_CreateFBOColorBuffer(tr.contrastRenderFBO, GL_RGBA16F_ARB, 0); } else { R_CreateFBOColorBuffer(tr.contrastRenderFBO, GL_RGBA, 0); } R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.contrastRenderFBOImage->texnum, 0); R_CheckFBO(tr.contrastRenderFBO); for (i = 0; i < 2; i++) { tr.bloomRenderFBO[i] = R_CreateFBO(va("_bloomRender%d", i), width, height); R_BindFBO(tr.bloomRenderFBO[i]); if (r_hdrRendering->integer && glConfig2.textureFloatAvailable) { R_CreateFBOColorBuffer(tr.bloomRenderFBO[i], GL_RGBA16F_ARB, 0); } else { R_CreateFBOColorBuffer(tr.bloomRenderFBO[i], GL_RGBA, 0); } R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.bloomRenderFBOImage[i]->texnum, 0); R_CheckFBO(tr.bloomRenderFBO[i]); } } GL_CheckErrors(); R_BindNullFBO(); }
/* ============ R_InitFBOs ============ */ void R_InitFBOs( void ) { int i; int width, height; ri.Printf( PRINT_DEVELOPER, "------- R_InitFBOs -------\n" ); if ( !glConfig2.framebufferObjectAvailable ) { return; } tr.numFBOs = 0; #if !defined( USE_D3D10 ) GL_CheckErrors(); #endif // make sure the render thread is stopped R_SyncRenderThread(); #if defined( USE_D3D10 ) // TODO #else if ( DS_STANDARD_ENABLED() ) { // geometricRender FBO as G-Buffer for deferred shading ri.Printf( PRINT_ALL, "Deferred Shading enabled\n" ); if ( glConfig2.textureNPOTAvailable ) { width = glConfig.vidWidth; height = glConfig.vidHeight; } else { width = NearestPowerOfTwo( glConfig.vidWidth ); height = NearestPowerOfTwo( glConfig.vidHeight ); } tr.geometricRenderFBO = R_CreateFBO( "_geometricRender", width, height ); R_BindFBO( tr.geometricRenderFBO ); #if 0 if ( glConfig2.framebufferPackedDepthStencilAvailable ) { R_AttachFBOTexturePackedDepthStencil( tr.depthRenderImage->texnum ); } else if ( glConfig.hardwareType == GLHW_ATI || glConfig.hardwareType == GLHW_ATI_DX10 ) // || glConfig.hardwareType == GLHW_NV_DX10) { R_AttachFBOTextureDepth( tr.depthRenderImage->texnum ); } else #endif { R_AttachFBOTextureDepth( tr.depthRenderImage->texnum ); } // enable all attachments as draw buffers //glDrawBuffers(4, geometricRenderTargets); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.deferredRenderFBOImage->texnum, 0 ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.deferredDiffuseFBOImage->texnum, 1 ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.deferredNormalFBOImage->texnum, 2 ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.deferredSpecularFBOImage->texnum, 3 ); R_CheckFBO( tr.geometricRenderFBO ); } else { // forward shading if ( glConfig2.textureNPOTAvailable ) { width = glConfig.vidWidth; height = glConfig.vidHeight; } else { width = NearestPowerOfTwo( glConfig.vidWidth ); height = NearestPowerOfTwo( glConfig.vidHeight ); } // deferredRender FBO for the HDR or LDR context tr.deferredRenderFBO = R_CreateFBO( "_deferredRender", width, height ); R_BindFBO( tr.deferredRenderFBO ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.deferredRenderFBOImage->texnum, 0 ); #if 0 if ( glConfig2.framebufferPackedDepthStencilAvailable ) { R_AttachFBOTexturePackedDepthStencil( tr.depthRenderImage->texnum ); } else if ( glConfig.hardwareType == GLHW_ATI || glConfig.hardwareType == GLHW_ATI_DX10 ) // || glConfig.hardwareType == GLHW_NV_DX10) { R_AttachFBOTextureDepth( tr.depthRenderImage->texnum ); } else #endif { R_AttachFBOTextureDepth( tr.depthRenderImage->texnum ); } R_CheckFBO( tr.deferredRenderFBO ); } if ( glConfig2.framebufferBlitAvailable ) { if ( glConfig2.textureNPOTAvailable ) { width = glConfig.vidWidth; height = glConfig.vidHeight; } else { width = NearestPowerOfTwo( glConfig.vidWidth ); height = NearestPowerOfTwo( glConfig.vidHeight ); } tr.occlusionRenderFBO = R_CreateFBO( "_occlusionRender", width, height ); R_BindFBO( tr.occlusionRenderFBO ); if ( glConfig.hardwareType == GLHW_ATI_DX10 ) { //R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_ALPHA16F, 0); R_CreateFBODepthBuffer( tr.occlusionRenderFBO, GL_DEPTH_COMPONENT16 ); } else if ( glConfig.hardwareType == GLHW_NV_DX10 ) { //R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_ALPHA32F, 0); R_CreateFBODepthBuffer( tr.occlusionRenderFBO, GL_DEPTH_COMPONENT24 ); } else if ( glConfig2.framebufferPackedDepthStencilAvailable ) { //R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_ALPHA32F, 0); R_CreateFBOPackedDepthStencilBuffer( tr.occlusionRenderFBO, GL_DEPTH24_STENCIL8_EXT ); } else { //R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_RGBA, 0); R_CreateFBODepthBuffer( tr.occlusionRenderFBO, GL_DEPTH_COMPONENT24 ); } R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.occlusionRenderFBOImage->texnum, 0 ); R_CheckFBO( tr.occlusionRenderFBO ); } if ( r_shadows->integer >= SHADOWING_ESM16 && glConfig2.textureFloatAvailable ) { // shadowMap FBOs for shadow mapping offscreen rendering for ( i = 0; i < MAX_SHADOWMAPS; i++ ) { width = height = shadowMapResolutions[ i ]; tr.shadowMapFBO[ i ] = R_CreateFBO( va( "_shadowMap%d", i ), width, height ); R_BindFBO( tr.shadowMapFBO[ i ] ); if ( ( glConfig.driverType == GLDRV_OPENGL3 ) || ( glConfig.hardwareType == GLHW_NV_DX10 || glConfig.hardwareType == GLHW_ATI_DX10 ) ) { if ( r_shadows->integer == SHADOWING_ESM32 ) { R_CreateFBOColorBuffer( tr.shadowMapFBO[ i ], GL_ALPHA32F_ARB, 0 ); } else if ( r_shadows->integer == SHADOWING_VSM32 ) { R_CreateFBOColorBuffer( tr.shadowMapFBO[ i ], GL_LUMINANCE_ALPHA32F_ARB, 0 ); } else if ( r_shadows->integer == SHADOWING_EVSM32 ) { if ( r_evsmPostProcess->integer ) { R_CreateFBOColorBuffer( tr.shadowMapFBO[ i ], GL_ALPHA32F_ARB, 0 ); } else { R_CreateFBOColorBuffer( tr.shadowMapFBO[ i ], GL_RGBA32F, 0 ); } } else { R_CreateFBOColorBuffer( tr.shadowMapFBO[ i ], GL_RGBA16F, 0 ); } } else { if ( r_shadows->integer == SHADOWING_ESM16 ) { R_CreateFBOColorBuffer( tr.shadowMapFBO[ i ], GL_ALPHA16F_ARB, 0 ); } else if ( r_shadows->integer == SHADOWING_VSM16 ) { R_CreateFBOColorBuffer( tr.shadowMapFBO[ i ], GL_LUMINANCE_ALPHA16F_ARB, 0 ); } else { R_CreateFBOColorBuffer( tr.shadowMapFBO[ i ], GL_RGBA16F, 0 ); } } R_CreateFBODepthBuffer( tr.shadowMapFBO[ i ], GL_DEPTH_COMPONENT24 ); R_CheckFBO( tr.shadowMapFBO[ i ] ); } // sun requires different resolutions for ( i = 0; i < MAX_SHADOWMAPS; i++ ) { width = height = sunShadowMapResolutions[ i ]; tr.sunShadowMapFBO[ i ] = R_CreateFBO( va( "_sunShadowMap%d", i ), width, height ); R_BindFBO( tr.sunShadowMapFBO[ i ] ); if ( ( glConfig.driverType == GLDRV_OPENGL3 ) || ( glConfig.hardwareType == GLHW_NV_DX10 || glConfig.hardwareType == GLHW_ATI_DX10 ) ) { if ( r_shadows->integer == SHADOWING_ESM32 ) { R_CreateFBOColorBuffer( tr.sunShadowMapFBO[ i ], GL_ALPHA32F_ARB, 0 ); } else if ( r_shadows->integer == SHADOWING_VSM32 ) { R_CreateFBOColorBuffer( tr.sunShadowMapFBO[ i ], GL_LUMINANCE_ALPHA32F_ARB, 0 ); } else if ( r_shadows->integer == SHADOWING_EVSM32 ) { if ( !r_evsmPostProcess->integer ) { R_CreateFBOColorBuffer( tr.sunShadowMapFBO[ i ], GL_RGBA32F, 0 ); } } else { R_CreateFBOColorBuffer( tr.sunShadowMapFBO[ i ], GL_RGBA16F, 0 ); } } else { if ( r_shadows->integer == SHADOWING_ESM16 ) { R_CreateFBOColorBuffer( tr.sunShadowMapFBO[ i ], GL_ALPHA16F_ARB, 0 ); } else if ( r_shadows->integer == SHADOWING_VSM16 ) { R_CreateFBOColorBuffer( tr.sunShadowMapFBO[ i ], GL_LUMINANCE_ALPHA16F_ARB, 0 ); } else { R_CreateFBOColorBuffer( tr.sunShadowMapFBO[ i ], GL_RGBA16F, 0 ); } } R_CreateFBODepthBuffer( tr.sunShadowMapFBO[ i ], GL_DEPTH_COMPONENT24 ); if ( r_shadows->integer == SHADOWING_EVSM32 && r_evsmPostProcess->integer ) { R_AttachFBOTextureDepth( tr.sunShadowMapFBOImage[ i ]->texnum ); /* Since we don't have a color attachment, the framebuffer will be considered incomplete. Consequently, we must inform the driver that we do not wish to render to the color buffer. We do this with a call to set the draw-buffer and read-buffer to GL_NONE: */ glDrawBuffer( GL_NONE ); glReadBuffer( GL_NONE ); } R_CheckFBO( tr.sunShadowMapFBO[ i ] ); } } { if ( glConfig2.textureNPOTAvailable ) { width = glConfig.vidWidth; height = glConfig.vidHeight; } else { width = NearestPowerOfTwo( glConfig.vidWidth ); height = NearestPowerOfTwo( glConfig.vidHeight ); } // portalRender FBO for portals, mirrors, water, cameras et cetera tr.portalRenderFBO = R_CreateFBO( "_portalRender", width, height ); R_BindFBO( tr.portalRenderFBO ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.portalRenderImage->texnum, 0 ); R_CheckFBO( tr.portalRenderFBO ); } { if ( glConfig2.textureNPOTAvailable ) { width = glConfig.vidWidth * 0.25f; height = glConfig.vidHeight * 0.25f; } else { width = NearestPowerOfTwo( glConfig.vidWidth * 0.25f ); height = NearestPowerOfTwo( glConfig.vidHeight * 0.25f ); } tr.downScaleFBO_quarter = R_CreateFBO( "_downScale_quarter", width, height ); R_BindFBO( tr.downScaleFBO_quarter ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.downScaleFBOImage_quarter->texnum, 0 ); R_CheckFBO( tr.downScaleFBO_quarter ); tr.downScaleFBO_64x64 = R_CreateFBO( "_downScale_64x64", 64, 64 ); R_BindFBO( tr.downScaleFBO_64x64 ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.downScaleFBOImage_64x64->texnum, 0 ); R_CheckFBO( tr.downScaleFBO_64x64 ); #if 0 tr.downScaleFBO_16x16 = R_CreateFBO( "_downScale_16x16", 16, 16 ); R_BindFBO( tr.downScaleFBO_16x16 ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.downScaleFBOImage_16x16->texnum, 0 ); R_CheckFBO( tr.downScaleFBO_16x16 ); tr.downScaleFBO_4x4 = R_CreateFBO( "_downScale_4x4", 4, 4 ); R_BindFBO( tr.downScaleFBO_4x4 ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.downScaleFBOImage_4x4->texnum, 0 ); R_CheckFBO( tr.downScaleFBO_4x4 ); tr.downScaleFBO_1x1 = R_CreateFBO( "_downScale_1x1", 1, 1 ); R_BindFBO( tr.downScaleFBO_1x1 ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.downScaleFBOImage_1x1->texnum, 0 ); R_CheckFBO( tr.downScaleFBO_1x1 ); #endif if ( glConfig2.textureNPOTAvailable ) { width = glConfig.vidWidth * 0.25f; height = glConfig.vidHeight * 0.25f; } else { width = NearestPowerOfTwo( glConfig.vidWidth * 0.25f ); height = NearestPowerOfTwo( glConfig.vidHeight * 0.25f ); } tr.contrastRenderFBO = R_CreateFBO( "_contrastRender", width, height ); R_BindFBO( tr.contrastRenderFBO ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.contrastRenderFBOImage->texnum, 0 ); R_CheckFBO( tr.contrastRenderFBO ); for ( i = 0; i < 2; i++ ) { tr.bloomRenderFBO[ i ] = R_CreateFBO( va( "_bloomRender%d", i ), width, height ); R_BindFBO( tr.bloomRenderFBO[ i ] ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.bloomRenderFBOImage[ i ]->texnum, 0 ); R_CheckFBO( tr.bloomRenderFBO[ i ] ); } } GL_CheckErrors(); #endif // defined(USE_D3D10) R_BindNullFBO(); }