// disables renderer support for the Rift void R_VR_Disable() { R_DelIVBO(&hudVBO); R_BindFBO(&screenFBO); vrState.pixelScale = 1.0; if (hmd && hmd->disable) hmd->disable(); if (hud.valid) R_DelFBO(&hud); R_DelShaderProgram(&vr_shader_distort_norm); R_DelShaderProgram(&vr_shader_distort_chrm); }
void R_VR_EndFrame() { if (hmd && vr_enabled->value) { GL_Disable(GL_DEPTH_TEST); //draw the HUD into specific views R_VR_DrawHud(); // draw the HUD R_BindFBO(vrState.offscreen); GL_SetIdentity(GL_PROJECTION); GL_SetIdentity(GL_MODELVIEW); // tell the HMD renderer to draw composited scene hmd->present((qboolean) (loadingScreen || (vr_aimmode->value == 0))); } }
FBO_t *R_CreateReadyFBO(const char *name, float size) { int width, height; FBO_t *tmp; if (glConfig2.textureNPOTAvailable) { width = glConfig.vidWidth * size; height = glConfig.vidHeight * size; } else { width = NearestPowerOfTwo(glConfig.vidWidth * size); height = NearestPowerOfTwo(glConfig.vidHeight * size); } tmp = R_CreateFBO(name, width, height); R_BindFBO(tmp); return tmp; }
/* ================ Tess_StageIteratorSky All of the visible sky triangles are in tess Other things could be stuck in here, like birds in the sky, etc ================ */ void Tess_StageIteratorSky( void ) { // log this call if ( r_logFile->integer ) { // don't just call LogComment, or we will get // a call to va() every frame! GLimp_LogComment( va ( "--- Tess_StageIteratorSky( %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name, tess.numVertexes, tess.numIndexes / 3 ) ); } if ( r_fastsky->integer ) { return; } // trebor: HACK why does this happen with cg_draw2D 0 ? if ( tess.stageIteratorFunc2 == NULL ) { //tess.stageIteratorFunc2 = Tess_StageIteratorGeneric; ri.Error( ERR_FATAL, "tess.stageIteratorFunc == NULL" ); } GL_Cull(CT_TWO_SIDED); if ( tess.stageIteratorFunc2 == &Tess_StageIteratorDepthFill ) { // go through all the polygons and project them onto // the sky box to see which blocks on each side need // to be drawn Tess_ClipSkyPolygons(); // generate the vertexes for all the clouds, which will be drawn // by the generic shader routine BuildCloudData(); if ( tess.numVertexes || tess.multiDrawPrimitives ) { tess.stageIteratorFunc2(); } } else { if ( tess.stageIteratorFunc2 == &Tess_StageIteratorGBuffer ) { R_BindFBO( tr.geometricRenderFBO ); } // go through all the polygons and project them onto // the sky box to see which blocks on each side need // to be drawn Tess_ClipSkyPolygons(); // r_showSky will let all the sky blocks be drawn in // front of everything to allow developers to see how // much sky is getting sucked in if ( r_showSky->integer ) { glDepthRange( 0.0, 0.0 ); } else { glDepthRange( 1.0, 1.0 ); } // draw the outer skybox if ( tess.surfaceShader->sky.outerbox && tess.surfaceShader->sky.outerbox != tr.blackCubeImage ) { #if 1 R_BindVBO( tess.vbo ); R_BindIBO( tess.ibo ); gl_skyboxShader->BindProgram(); gl_skyboxShader->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin ); // in world space gl_skyboxShader->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); gl_skyboxShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); gl_skyboxShader->SetRequiredVertexPointers(); // bind u_ColorMap GL_SelectTexture( 0 ); GL_Bind( tess.surfaceShader->sky.outerbox ); DrawSkyBox( tess.surfaceShader ); #endif } // generate the vertexes for all the clouds, which will be drawn // by the generic shader routine BuildCloudData(); if ( tess.numVertexes || tess.multiDrawPrimitives ) { tess.stageIteratorFunc2(); } // Tr3B: TODO draw the inner skybox? if ( tess.stageIteratorFunc2 == Tess_StageIteratorGBuffer ) { R_BindNullFBO(); } if ( tess.stageIteratorFunc2 != Tess_StageIteratorDepthFill ) { // back to standard depth range glDepthRange( 0.0, 1.0 ); // note that sky was drawn so we will draw a sun later backEnd.skyRenderedThisView = qtrue; } } }
/* ================== GL_RenderView ================== */ static void D3D10_RenderView( void ) { if ( r_logFile->integer ) { // don't just call LogComment, or we will get a call to va() every frame! GLimp_LogComment( va ( "--- D3D10_RenderView( %i surfaces, %i interactions ) ---\n", backEnd.viewParms.numDrawSurfs, backEnd.viewParms.numInteractions ) ); } backEnd.pc.c_surfaces += backEnd.viewParms.numDrawSurfs; //if(r_deferredShading->integer && glConfig.framebufferObjectAvailable && glConfig.textureFloatAvailable && // glConfig.drawBuffersAvailable && glConfig.maxDrawBuffers >= 4) { int clearBits = 0; // clear the back buffer float ClearColor[ 4 ] = { 0.0f, 0.125f, 0.3f, 1.0f }; // red,green,blue,alpha dx.d3dDevice->ClearRenderTargetView( dx.renderTargetView, ClearColor ); #if 0 // render a triangle D3D10_TECHNIQUE_DESC techDesc; dx.genericTechnique->GetDesc( &techDesc ); for ( UINT p = 0; p < techDesc.Passes; ++p ) { dx.genericTechnique->GetPassByIndex( p )->Apply( 0 ); dx.d3dDevice->Draw( 3, 0 ); } #endif /* // sync with gl if needed if(r_finish->integer == 1 && !glState.finishCalled) { //qglFinish(); glState.finishCalled = qtrue; } if(r_finish->integer == 0) { glState.finishCalled = qtrue; } */ // we will need to change the projection matrix before drawing // 2D images again backEnd.projection2D = qfalse; // set the modelview matrix for the viewer SetViewportAndScissor(); // ensures that depth writes are enabled for the depth clear //GL_State(GLS_DEFAULT); // clear frame buffer objects //R_BindFBO(tr.deferredRenderFBO); //qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clearBits = GL_DEPTH_BUFFER_BIT; /* if(!(backEnd.refdef.rdflags & RDF_NOWORLDMODEL)) { clearBits |= GL_COLOR_BUFFER_BIT; GL_ClearColor(0.0f, 0.0f, 0.0f, 1.0f); // FIXME: get color of sky } qglClear(clearBits); R_BindFBO(tr.geometricRenderFBO); if(!(backEnd.refdef.rdflags & RDF_NOWORLDMODEL)) { clearBits = GL_COLOR_BUFFER_BIT; GL_ClearColor(0.0f, 0.0f, 0.0f, 1.0f); // FIXME: get color of sky } else { if(glConfig.framebufferBlitAvailable) { // copy color of the main context to deferredRenderFBO qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, tr.deferredRenderFBO->frameBuffer); qglBlitFramebufferEXT(0, 0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); } } qglClear(clearBits); */ /* if(r_deferredShading->integer == DS_PREPASS_LIGHTING) { R_BindFBO(tr.geometricRenderFBO); if(!(backEnd.refdef.rdflags & RDF_NOWORLDMODEL)) { clearBits = GL_COLOR_BUFFER_BIT; GL_ClearColor(0.0f, 0.0f, 0.0f, 1.0f); qglClear(clearBits); } } */ if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) ) { RB_Hyperspace(); return; } else { backEnd.isHyperspace = qfalse; } //glState.faceCulling = -1; // force face culling to set next time // we will only draw a sun if there was sky rendered in this view backEnd.skyRenderedThisView = qfalse; //GL_CheckErrors(); #if 0 if ( r_deferredShading->integer == DS_STANDARD ) { // draw everything that is opaque R_BindFBO( tr.deferredRenderFBO ); RB_RenderDrawSurfaces( qtrue, qfalse ); } #endif //D3D10_RenderDrawSurfacesIntoGeometricBuffer(); // try to cull lights using hardware occlusion queries //R_BindFBO(tr.deferredRenderFBO); //RB_RenderLightOcclusionQueries(); //if(r_deferredShading->integer == DS_PREPASS_LIGHTING) { /* if(r_shadows->integer >= 4) { // render dynamic shadowing and lighting using shadow mapping RB_RenderInteractionsDeferredShadowMapped(); } else */ { // render dynamic lighting // TODO D3D10_RenderInteractionsDeferredIntoLightBuffer(); } // render opaque surfaces using the light buffer results // TODo } /* // render global fog R_BindFBO(tr.deferredRenderFBO); RB_RenderUniformFog(); // render debug information R_BindFBO(tr.deferredRenderFBO); RB_RenderDebugUtils(); // scale down rendered HDR scene to 1 / 4th if(r_hdrRendering->integer) { if(glConfig.framebufferBlitAvailable) { qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, tr.deferredRenderFBO->frameBuffer); qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, tr.downScaleFBO_quarter->frameBuffer); qglBlitFramebufferEXT(0, 0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, glConfig.vidWidth * 0.25f, glConfig.vidHeight * 0.25f, GL_COLOR_BUFFER_BIT, GL_LINEAR); qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, tr.deferredRenderFBO->frameBuffer); qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, tr.downScaleFBO_64x64->frameBuffer); qglBlitFramebufferEXT(0, 0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 64, 64, GL_COLOR_BUFFER_BIT, GL_LINEAR); } else { // FIXME add non EXT_framebuffer_blit code } RB_CalculateAdaptation(); } else { if(glConfig.framebufferBlitAvailable) { // copy deferredRenderFBO to downScaleFBO_quarter qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, tr.deferredRenderFBO->frameBuffer); qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, tr.downScaleFBO_quarter->frameBuffer); qglBlitFramebufferEXT(0, 0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, glConfig.vidWidth * 0.25f, glConfig.vidHeight * 0.25f, GL_COLOR_BUFFER_BIT, GL_LINEAR); } else { // FIXME add non EXT_framebuffer_blit code } } GL_CheckErrors(); // render bloom post process effect RB_RenderBloom(); // copy offscreen rendered scene to the current OpenGL context RB_RenderDeferredShadingResultToFrameBuffer(); if(backEnd.viewParms.isPortal) { if(glConfig.framebufferBlitAvailable) { // copy deferredRenderFBO to portalRenderFBO qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, tr.deferredRenderFBO->frameBuffer); qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, tr.portalRenderFBO->frameBuffer); qglBlitFramebufferEXT(0, 0, tr.deferredRenderFBO->width, tr.deferredRenderFBO->height, 0, 0, tr.portalRenderFBO->width, tr.portalRenderFBO->height, GL_COLOR_BUFFER_BIT, GL_NEAREST); } else { // capture current color buffer GL_SelectTexture(0); GL_Bind(tr.portalRenderImage); qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, tr.portalRenderImage->uploadWidth, tr.portalRenderImage->uploadHeight); } backEnd.pc.c_portals++; } */ } backEnd.pc.c_views++; }
/* ============ 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; GL_CheckErrors(); // make sure the render thread is stopped R_SyncRenderThread(); if ( glConfig2.textureNPOTAvailable ) { width = glConfig.vidWidth; height = glConfig.vidHeight; } else { width = NearestPowerOfTwo( glConfig.vidWidth ); height = NearestPowerOfTwo( glConfig.vidHeight ); } 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_CreateFBODepthBuffer( tr.occlusionRenderFBO, GL_DEPTH_COMPONENT16 ); } else if ( glConfig.hardwareType == GLHW_NV_DX10 ) { R_CreateFBODepthBuffer( tr.occlusionRenderFBO, GL_DEPTH_COMPONENT24 ); } else if ( glConfig2.framebufferPackedDepthStencilAvailable ) { R_CreateFBOPackedDepthStencilBuffer( tr.occlusionRenderFBO, GL_DEPTH24_STENCIL8_EXT ); } else { 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 ] ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.shadowMapFBOImage[ i ]->texnum, 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 ] ); R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.sunShadowMapFBOImage[ i ]->texnum, 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 ( 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(); R_BindNullFBO(); }
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(); }
void R_VR_DrawHud() { float fov = vr_hud_fov->value; float depth = vr_hud_depth->value; int numsegments = vr_hud_segments->value; int index = 0; vec_t mat[4][4], temp[4][4]; if (!vr_enabled->value) return; // enable alpha testing so only pixels that have alpha info get written out // prevents black pixels from being rendered into the view GL_Enable(GL_ALPHA_TEST); GL_AlphaFunc(GL_GREATER, 0.0f); // if hud transparency is enabled, enable blending if (vr_hud_transparency->value) { GL_Enable(GL_BLEND); GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } // bind the texture GL_MBind(0, hud.texture); // disable this for the loading screens since they are not at 60fps if ((vr_hud_bounce->value > 0) && !loadingScreen && ((int32_t) vr_aimmode->value > 0)) { // load the quaternion directly into a rotation matrix vec4_t q; VR_GetOrientationEMAQuat(q); q[2] = -q[2]; QuatToRotation(q, mat); } else { // identity matrix TranslationMatrix(0,0,0,mat); } // set proper mode // glEnableClientState (GL_TEXTURE_COORD_ARRAY); // glEnableClientState (GL_VERTEX_ARRAY); glDisableClientState (GL_COLOR_ARRAY); // bind vertex buffer and set tex coord parameters R_BindIVBO(&hudVBO,NULL,0); glTexCoordPointer(2,GL_FLOAT,sizeof(vert_t),(void *)( sizeof(GL_FLOAT) * 3)); glVertexPointer(3,GL_FLOAT,sizeof(vert_t),NULL); for (index = 0; index < 2; index++) { // bind the eye FBO R_BindFBO(vrState.eyeFBO[index]); // set the perspective matrix for that eye R_PerspectiveScale(vrState.renderParams[index].projection, 0.24, 251.0); // build the eye translation matrix if (vr_autoipd->value) { TranslationMatrix(-vrState.renderParams[index].viewOffset[0], vrState.renderParams[index].viewOffset[1], vrState.renderParams[index].viewOffset[2], temp); } else { float viewOffset = (vr_ipd->value / 2000.0); TranslationMatrix((-1 + index * 2) * -viewOffset, 0, 0, temp); } // load the view matrix MatrixMultiply(temp, mat, temp); GL_LoadMatrix(GL_MODELVIEW, temp); // draw the hud for that eye R_DrawIVBO(&hudVBO); } // teardown R_ReleaseIVBO(); GL_MBind(0, 0); glEnableClientState (GL_COLOR_ARRAY); glTexCoordPointer (2, GL_FLOAT, sizeof(texCoordArray[0][0]), texCoordArray[0][0]); glVertexPointer (3, GL_FLOAT, sizeof(vertexArray[0]), vertexArray[0]); GL_Disable(GL_BLEND); GL_Disable(GL_ALPHA_TEST); }
void R_VR_StartFrame() { qboolean resolutionChanged = 0; qboolean hudChanged = 0; extern int32_t scr_draw_loading; if (!hmd || !hmd->frameStart || !hmd->getState) return; R_AntialiasSetFBOSize(vrState.offscreen); if (vrState.offscreen->width != screen.width || vrState.offscreen->height != screen.height) { screen.height = vrState.offscreen->height; screen.width = vrState.offscreen->width; resolutionChanged = true; } hmd->frameStart(resolutionChanged); hmd->getState(&vrState); if (vr_hud_width->modified || vr_hud_height->modified) { int width, height; width = vr_hud_width->value; height = vr_hud_height->value; if (width < 640) width = 640; if (height < 480) height = 480; Cvar_SetInteger("vr_hud_width",width); Cvar_SetInteger("vr_hud_height",height); vr_hud_width->modified = false; vr_hud_height->modified = false; Com_Printf("VR: New HUD resolution %ix%i\n",width,height); if (hud.width != width || hud.height != height) R_ResizeFBO(width,height,1,GL_RGBA8,&hud); } if (vr_hud_segments->modified) { // clamp value from 30-90 degrees if (vr_hud_segments->value < 0) Cvar_SetInteger("vr_hud_segments", 1); else if (vr_hud_segments->value > MAX_SEGMENTS) Cvar_SetValue("vr_hud_segments", MAX_SEGMENTS); vr_hud_segments->modified = false; hudChanged = true; } if (vr_hud_depth->modified) { if (vr_hud_depth->value < 0.25f) Cvar_SetValue("vr_hud_depth", 0.25); else if (vr_hud_depth->value > 250) Cvar_SetValue("vr_hud_depth", 250); vr_hud_depth->modified = false; hudChanged = true; } if (vr_hud_fov->modified) { // clamp value from 30-90 degrees if (vr_hud_fov->value < 30) Cvar_SetValue("vr_hud_fov", 30.0f); else if (vr_hud_fov->value > vrState.viewFovY * 2.0) Cvar_SetValue("vr_hud_fov", vrState.viewFovY * 2.0); vr_hud_fov->modified = false; hudChanged = true; } if (hudChanged) R_VR_GenerateHud(); if (resolutionChanged) { Com_Printf("VR: Calculated %.2f FOV\n", vrState.viewFovY); } GL_ClearColor(0.0, 0.0, 0.0, 0.0); R_BindFBO(vrState.eyeFBO[0]); R_Clear(); R_BindFBO(vrState.eyeFBO[1]); R_Clear(); R_BindFBO(&hud); R_Clear(); R_BindFBO(&screenFBO); GL_SetDefaultClearColor(); hudStale = 1; loadingScreen = (qboolean) (scr_draw_loading > 0 ? 1 : 0); }
/* ============ 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(); }