/* ================== 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++; }
/* ================= RB_BeginDrawingView Any mirrored or portaled views have already been drawn, so prepare to actually render the visible surfaces for this view ================= */ void RB_BeginDrawingView( void ) { int clearBits = 0; // sync with gl if needed if ( r_finish->integer == 1 && !glState.finishCalled ) { glFinish(); 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 ); ////////// (SA) modified to ensure one glclear() per frame at most // clear relevant buffers clearBits = 0; clearBits |= GL_STENCIL_BUFFER_BIT; // ydnar: global q3 fog volume if ( tr.world && tr.world->globalFog >= 0 ) { clearBits |= GL_DEPTH_BUFFER_BIT; clearBits |= GL_COLOR_BUFFER_BIT; // glClearColor( tr.world->fogs[ tr.world->globalFog ].shader->fogParms.color[ 0 ] * tr.identityLight, tr.world->fogs[ tr.world->globalFog ].shader->fogParms.color[ 1 ] * tr.identityLight, tr.world->fogs[ tr.world->globalFog ].shader->fogParms.color[ 2 ] * tr.identityLight, 1.0 ); } else if ( skyboxportal ) { if ( backEnd.refdef.rdflags & RDF_SKYBOXPORTAL ) { // portal scene, clear whatever is necessary clearBits |= GL_DEPTH_BUFFER_BIT; if ( r_fastsky->integer || backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) { // fastsky: clear color // try clearing first with the portal sky fog color, then the world fog color, then finally a default clearBits |= GL_COLOR_BUFFER_BIT; if ( glfogsettings[ FOG_PORTALVIEW ].registered ) { glClearColor( glfogsettings[ FOG_PORTALVIEW ].color[ 0 ], glfogsettings[ FOG_PORTALVIEW ].color[ 1 ], glfogsettings[ FOG_PORTALVIEW ].color[ 2 ], glfogsettings[ FOG_PORTALVIEW ].color[ 3 ] ); } else if ( glfogNum > FOG_NONE && glfogsettings[ FOG_CURRENT ].registered ) { glClearColor( glfogsettings[ FOG_CURRENT ].color[ 0 ], glfogsettings[ FOG_CURRENT ].color[ 1 ], glfogsettings[ FOG_CURRENT ].color[ 2 ], glfogsettings[ FOG_CURRENT ].color[ 3 ] ); } else { // glClearColor ( 1.0, 0.0, 0.0, 1.0 ); // red clear for testing portal sky clear glClearColor( 0.5, 0.5, 0.5, 1.0 ); } } else { // rendered sky (either clear color or draw quake sky) if ( glfogsettings[ FOG_PORTALVIEW ].registered ) { glClearColor( glfogsettings[ FOG_PORTALVIEW ].color[ 0 ], glfogsettings[ FOG_PORTALVIEW ].color[ 1 ], glfogsettings[ FOG_PORTALVIEW ].color[ 2 ], glfogsettings[ FOG_PORTALVIEW ].color[ 3 ] ); if ( glfogsettings[ FOG_PORTALVIEW ].clearscreen ) { // portal fog requests a screen clear (distance fog rather than quake sky) clearBits |= GL_COLOR_BUFFER_BIT; } } } } else { // world scene with portal sky, don't clear any buffers, just set the fog color if there is one clearBits |= GL_DEPTH_BUFFER_BIT; // this will go when I get the portal sky rendering way out in the zbuffer (or not writing to zbuffer at all) if ( glfogNum > FOG_NONE && glfogsettings[ FOG_CURRENT ].registered ) { if ( backEnd.refdef.rdflags & RDF_UNDERWATER ) { if ( glfogsettings[ FOG_CURRENT ].mode == GL_LINEAR ) { clearBits |= GL_COLOR_BUFFER_BIT; } } else if ( !( r_portalsky->integer ) ) { // portal skies have been manually turned off, clear bg color clearBits |= GL_COLOR_BUFFER_BIT; } glClearColor( glfogsettings[ FOG_CURRENT ].color[ 0 ], glfogsettings[ FOG_CURRENT ].color[ 1 ], glfogsettings[ FOG_CURRENT ].color[ 2 ], glfogsettings[ FOG_CURRENT ].color[ 3 ] ); } else if ( !( r_portalsky->integer ) ) { // ydnar: portal skies have been manually turned off, clear bg color clearBits |= GL_COLOR_BUFFER_BIT; glClearColor( 0.5, 0.5, 0.5, 1.0 ); } } } else { // world scene with no portal sky clearBits |= GL_DEPTH_BUFFER_BIT; // NERVE - SMF - we don't want to clear the buffer when no world model is specified if ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) { clearBits &= ~GL_COLOR_BUFFER_BIT; } // -NERVE - SMF else if ( r_fastsky->integer || backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) { clearBits |= GL_COLOR_BUFFER_BIT; if ( glfogsettings[ FOG_CURRENT ].registered ) { // try to clear fastsky with current fog color glClearColor( glfogsettings[ FOG_CURRENT ].color[ 0 ], glfogsettings[ FOG_CURRENT ].color[ 1 ], glfogsettings[ FOG_CURRENT ].color[ 2 ], glfogsettings[ FOG_CURRENT ].color[ 3 ] ); } else { // glClearColor ( 0.0, 0.0, 1.0, 1.0 ); // blue clear for testing world sky clear glClearColor( 0.05, 0.05, 0.05, 1.0 ); // JPW NERVE changed per id req was 0.5s } } else { // world scene, no portal sky, not fastsky, clear color if fog says to, otherwise, just set the clearcolor if ( glfogsettings[ FOG_CURRENT ].registered ) { // try to clear fastsky with current fog color glClearColor( glfogsettings[ FOG_CURRENT ].color[ 0 ], glfogsettings[ FOG_CURRENT ].color[ 1 ], glfogsettings[ FOG_CURRENT ].color[ 2 ], glfogsettings[ FOG_CURRENT ].color[ 3 ] ); if ( glfogsettings[ FOG_CURRENT ].clearscreen ) { // world fog requests a screen clear (distance fog rather than quake sky) clearBits |= GL_COLOR_BUFFER_BIT; } } } } // ydnar: don't clear the color buffer when no world model is specified if ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) { clearBits &= ~GL_COLOR_BUFFER_BIT; } if ( clearBits ) { glClear( clearBits ); } //----(SA) done 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; }
/* ================= RB_BeginDrawingView Any mirrored or portaled views have already been drawn, so prepare to actually render the visible surfaces for this view ================= */ void RB_BeginDrawingView (void) { int clearBits = 0; // 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 relevant buffers clearBits = GL_DEPTH_BUFFER_BIT; if ( r_measureOverdraw->integer || r_shadows->integer == 2 ) { clearBits |= GL_STENCIL_BUFFER_BIT; } if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) { clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used qglClearColor( 0.8f, 0.7f, 0.4f, 1 ); // FIXME: get color of sky } 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; // clip to the plane of the portal if ( backEnd.viewParms.isPortal ) { float plane[4]; double plane2[4]; plane[0] = backEnd.viewParms.portalPlane.normal[0]; plane[1] = backEnd.viewParms.portalPlane.normal[1]; plane[2] = backEnd.viewParms.portalPlane.normal[2]; plane[3] = backEnd.viewParms.portalPlane.dist; plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane); plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane); plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane); plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3]; qglLoadMatrixf( s_flipMatrix ); qglClipPlane (GL_CLIP_PLANE0, plane2); qglEnable (GL_CLIP_PLANE0); } else { qglDisable (GL_CLIP_PLANE0); } }
/* ================= RB_BeginDrawingView Any mirrored or portaled views have already been drawn, so prepare to actually render the visible surfaces for this view ================= */ void RB_BeginDrawingView(void) { int clearBits = 0; // 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); ////////// (SA) modified to ensure one glclear() per frame at most // clear relevant buffers clearBits = 0; if(r_measureOverdraw->integer || r_shadows->integer == 2) { clearBits |= GL_STENCIL_BUFFER_BIT; } if(r_uiFullScreen->integer) { clearBits = GL_DEPTH_BUFFER_BIT; // (SA) always just clear depth for menus } else if(skyboxportal) { if(backEnd.refdef.rdflags & RDF_SKYBOXPORTAL) // portal scene, clear whatever is necessary { clearBits |= GL_DEPTH_BUFFER_BIT; if(r_fastsky->integer || backEnd.refdef.rdflags & RDF_NOWORLDMODEL) // fastsky: clear color { // try clearing first with the portal sky fog color, then the world fog color, then finally a default clearBits |= GL_COLOR_BUFFER_BIT; if(glfogsettings[FOG_PORTALVIEW].registered) { qglClearColor(glfogsettings[FOG_PORTALVIEW].color[0], glfogsettings[FOG_PORTALVIEW].color[1], glfogsettings[FOG_PORTALVIEW].color[2], glfogsettings[FOG_PORTALVIEW].color[3]); } else if(glfogNum > FOG_NONE && glfogsettings[FOG_CURRENT].registered) { qglClearColor(glfogsettings[FOG_CURRENT].color[0], glfogsettings[FOG_CURRENT].color[1], glfogsettings[FOG_CURRENT].color[2], glfogsettings[FOG_CURRENT].color[3]); } else { // qglClearColor ( 1.0, 0.0, 0.0, 1.0 ); // red clear for testing portal sky clear qglClearColor(0.5, 0.5, 0.5, 1.0); } } else // rendered sky (either clear color or draw quake sky) { if(glfogsettings[FOG_PORTALVIEW].registered) { qglClearColor(glfogsettings[FOG_PORTALVIEW].color[0], glfogsettings[FOG_PORTALVIEW].color[1], glfogsettings[FOG_PORTALVIEW].color[2], glfogsettings[FOG_PORTALVIEW].color[3]); if(glfogsettings[FOG_PORTALVIEW].clearscreen) // portal fog requests a screen clear (distance fog rather than quake sky) { clearBits |= GL_COLOR_BUFFER_BIT; } } } } else // world scene with portal sky, don't clear any buffers, just set the fog color if there is one { clearBits |= GL_DEPTH_BUFFER_BIT; // this will go when I get the portal sky rendering way out in the zbuffer (or not writing to zbuffer at all) if(glfogNum > FOG_NONE && glfogsettings[FOG_CURRENT].registered) { if(backEnd.refdef.rdflags & RDF_UNDERWATER) { if(glfogsettings[FOG_CURRENT].mode == GL_LINEAR) { clearBits |= GL_COLOR_BUFFER_BIT; } } else if(!(r_portalsky->integer)) // portal skies have been manually turned off, clear bg color { clearBits |= GL_COLOR_BUFFER_BIT; } qglClearColor(glfogsettings[FOG_CURRENT].color[0], glfogsettings[FOG_CURRENT].color[1], glfogsettings[FOG_CURRENT].color[2], glfogsettings[FOG_CURRENT].color[3]); } } } else // world scene with no portal sky { clearBits |= GL_DEPTH_BUFFER_BIT; // NERVE - SMF - we don't want to clear the buffer when no world model is specified if(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) { clearBits &= ~GL_COLOR_BUFFER_BIT; } // -NERVE - SMF // (SA) well, this is silly then else if(r_fastsky->integer) // || backEnd.refdef.rdflags & RDF_NOWORLDMODEL { clearBits |= GL_COLOR_BUFFER_BIT; if(glfogsettings[FOG_CURRENT].registered) // try to clear fastsky with current fog color { qglClearColor(glfogsettings[FOG_CURRENT].color[0], glfogsettings[FOG_CURRENT].color[1], glfogsettings[FOG_CURRENT].color[2], glfogsettings[FOG_CURRENT].color[3]); } else { // qglClearColor ( 0.0, 0.0, 1.0, 1.0 ); // blue clear for testing world sky clear qglClearColor(0.5, 0.5, 0.5, 1.0); } } else // world scene, no portal sky, not fastsky, clear color if fog says to, otherwise, just set the clearcolor { if(glfogsettings[FOG_CURRENT].registered) // try to clear fastsky with current fog color { qglClearColor(glfogsettings[FOG_CURRENT].color[0], glfogsettings[FOG_CURRENT].color[1], glfogsettings[FOG_CURRENT].color[2], glfogsettings[FOG_CURRENT].color[3]); if(glfogsettings[FOG_CURRENT].clearscreen) // world fog requests a screen clear (distance fog rather than quake sky) { clearBits |= GL_COLOR_BUFFER_BIT; } } } } if(clearBits) { qglClear(clearBits); } //----(SA) done 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; // clip to the plane of the portal if(backEnd.viewParms.isPortal) { float plane[4]; double plane2[4]; plane[0] = backEnd.viewParms.portalPlane.normal[0]; plane[1] = backEnd.viewParms.portalPlane.normal[1]; plane[2] = backEnd.viewParms.portalPlane.normal[2]; plane[3] = backEnd.viewParms.portalPlane.dist; plane2[0] = DotProduct(backEnd.viewParms.or.axis[0], plane); plane2[1] = DotProduct(backEnd.viewParms.or.axis[1], plane); plane2[2] = DotProduct(backEnd.viewParms.or.axis[2], plane); plane2[3] = DotProduct(plane, backEnd.viewParms.or.origin) - plane[3]; qglLoadMatrixf(s_flipMatrix); qglClipPlane(GL_CLIP_PLANE0, plane2); qglEnable(GL_CLIP_PLANE0); } else { qglDisable(GL_CLIP_PLANE0); } }
/* * RB_BeginDrawingView * * Any mirrored or portaled views have already been drawn, so prepare * to actually render the visible surfaces for this view */ void RB_BeginDrawingView(void) { int clearBits = 0; /* 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; if(glRefConfig.framebufferObject){ /* FIXME: HUGE HACK: render to the screen fbo if we've already postprocessed the frame and aren't drawing more world */ if(backEnd.viewParms.targetFbo == tr.renderFbo && backEnd.framePostProcessed && (backEnd.refdef.rdflags & RDF_NOWORLDMODEL)){ FBO_Bind(tr.screenScratchFbo); }else{ FBO_Bind(backEnd.viewParms.targetFbo); } } /* * set the modelview matrix for the viewer * */ SetViewportAndScissor(); /* ensures that depth writes are enabled for the depth clear */ GL_State(GLS_DEFAULT); /* clear relevant buffers */ clearBits = GL_DEPTH_BUFFER_BIT; if(r_measureOverdraw->integer || r_shadows->integer == 2){ clearBits |= GL_STENCIL_BUFFER_BIT; } if(r_fastsky->integer && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL)){ clearBits |= GL_COLOR_BUFFER_BIT; /* FIXME: only if sky shaders have been used */ #ifdef _DEBUG qglClearColor(0.8f, 0.7f, 0.4f, 1.0f); /* FIXME: get color of sky */ #else qglClearColor(0.0f, 0.0f, 0.0f, 1.0f); /* FIXME: get color of sky */ #endif } /* clear to white for shadow maps */ if(backEnd.viewParms.isShadowmap){ clearBits |= GL_COLOR_BUFFER_BIT; qglClearColor(1.0f, 1.0f, 1.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; #ifdef REACTION backEnd.hasSunFlare = qfalse; #endif /* clip to the plane of the portal */ if(backEnd.viewParms.isPortal){ float plane[4]; double plane2[4]; plane[0] = backEnd.viewParms.portalPlane.normal[0]; plane[1] = backEnd.viewParms.portalPlane.normal[1]; plane[2] = backEnd.viewParms.portalPlane.normal[2]; plane[3] = backEnd.viewParms.portalPlane.dist; plane2[0] = dotv3 (backEnd.viewParms.or.axis[0], plane); plane2[1] = dotv3 (backEnd.viewParms.or.axis[1], plane); plane2[2] = dotv3 (backEnd.viewParms.or.axis[2], plane); plane2[3] = dotv3 (plane, backEnd.viewParms.or.origin) - plane[3]; GL_SetModelviewMatrix(s_flipMatrix); } }
/* ============= RB_DrawSurfs ============= */ const void *RB_DrawSurfs( const void *data ) { const drawSurfsCommand_t *cmd; // finish any 2D drawing if needed if ( tess.numIndexes ) { RB_EndSurface(); } cmd = (const drawSurfsCommand_t *)data; backEnd.refdef = cmd->refdef; backEnd.viewParms = cmd->viewParms; // clear the z buffer, set the modelview, etc RB_BeginDrawingView (); if (glRefConfig.framebufferObject && (backEnd.viewParms.flags & VPF_DEPTHCLAMP) && glRefConfig.depthClamp) { qglEnable(GL_DEPTH_CLAMP); } if (glRefConfig.framebufferObject && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && (r_depthPrepass->integer || (backEnd.viewParms.flags & VPF_DEPTHSHADOW))) { FBO_t *oldFbo = glState.currentFBO; backEnd.depthFill = qtrue; qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); qglColorMask(!backEnd.colorMask[0], !backEnd.colorMask[1], !backEnd.colorMask[2], !backEnd.colorMask[3]); backEnd.depthFill = qfalse; if (tr.msaaResolveFbo) { // If we're using multisampling, resolve the depth first FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_DEPTH_BUFFER_BIT, GL_NEAREST); } else if (tr.renderFbo == NULL) { // If we're rendering directly to the screen, copy the depth to a texture GL_BindToTMU(tr.renderDepthImage, 0); qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0); } if (r_ssao->integer) { // need the depth in a texture we can do GL_LINEAR sampling on, so copy it to an HDR image FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, tr.hdrDepthFbo, NULL, NULL, NULL, 0); } if (r_sunlightMode->integer && backEnd.viewParms.flags & VPF_USESUNLIGHT) { vec4_t quadVerts[4]; vec2_t texCoords[4]; vec4_t box; FBO_Bind(tr.screenShadowFbo); box[0] = backEnd.viewParms.viewportX * tr.screenShadowFbo->width / (float)glConfig.vidWidth; box[1] = backEnd.viewParms.viewportY * tr.screenShadowFbo->height / (float)glConfig.vidHeight; box[2] = backEnd.viewParms.viewportWidth * tr.screenShadowFbo->width / (float)glConfig.vidWidth; box[3] = backEnd.viewParms.viewportHeight * tr.screenShadowFbo->height / (float)glConfig.vidHeight; qglViewport(box[0], box[1], box[2], box[3]); qglScissor(box[0], box[1], box[2], box[3]); box[0] = backEnd.viewParms.viewportX / (float)glConfig.vidWidth; box[1] = backEnd.viewParms.viewportY / (float)glConfig.vidHeight; box[2] = box[0] + backEnd.viewParms.viewportWidth / (float)glConfig.vidWidth; box[3] = box[1] + backEnd.viewParms.viewportHeight / (float)glConfig.vidHeight; texCoords[0][0] = box[0]; texCoords[0][1] = box[3]; texCoords[1][0] = box[2]; texCoords[1][1] = box[3]; texCoords[2][0] = box[2]; texCoords[2][1] = box[1]; texCoords[3][0] = box[0]; texCoords[3][1] = box[1]; box[0] = -1.0f; box[1] = -1.0f; box[2] = 1.0f; box[3] = 1.0f; VectorSet4(quadVerts[0], box[0], box[3], 0, 1); VectorSet4(quadVerts[1], box[2], box[3], 0, 1); VectorSet4(quadVerts[2], box[2], box[1], 0, 1); VectorSet4(quadVerts[3], box[0], box[1], 0, 1); GL_State( GLS_DEPTHTEST_DISABLE ); GLSL_BindProgram(&tr.shadowmaskShader); GL_BindToTMU(tr.renderDepthImage, TB_COLORMAP); if (r_shadowCascadeZFar->integer != 0) { GL_BindToTMU(tr.sunShadowDepthImage[0], TB_SHADOWMAP); GL_BindToTMU(tr.sunShadowDepthImage[1], TB_SHADOWMAP2); GL_BindToTMU(tr.sunShadowDepthImage[2], TB_SHADOWMAP3); GL_BindToTMU(tr.sunShadowDepthImage[3], TB_SHADOWMAP4); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP4, backEnd.refdef.sunShadowMvp[3]); } else { GL_BindToTMU(tr.sunShadowDepthImage[3], TB_SHADOWMAP); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[3]); } GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWORIGIN, backEnd.refdef.vieworg); { vec4_t viewInfo; vec3_t viewVector; float zmax = backEnd.viewParms.zFar; float ymax = zmax * tan(backEnd.viewParms.fovY * M_PI / 360.0f); float xmax = zmax * tan(backEnd.viewParms.fovX * M_PI / 360.0f); float zmin = r_znear->value; VectorScale(backEnd.refdef.viewaxis[0], zmax, viewVector); GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWFORWARD, viewVector); VectorScale(backEnd.refdef.viewaxis[1], xmax, viewVector); GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWLEFT, viewVector); VectorScale(backEnd.refdef.viewaxis[2], ymax, viewVector); GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWUP, viewVector); VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); GLSL_SetUniformVec4(&tr.shadowmaskShader, UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); } if (r_ssao->integer) { vec4_t quadVerts[4]; vec2_t texCoords[4]; FBO_Bind(tr.quarterFbo[0]); qglViewport(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); qglScissor(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); VectorSet4(quadVerts[0], -1, 1, 0, 1); VectorSet4(quadVerts[1], 1, 1, 0, 1); VectorSet4(quadVerts[2], 1, -1, 0, 1); VectorSet4(quadVerts[3], -1, -1, 0, 1); texCoords[0][0] = 0; texCoords[0][1] = 1; texCoords[1][0] = 1; texCoords[1][1] = 1; texCoords[2][0] = 1; texCoords[2][1] = 0; texCoords[3][0] = 0; texCoords[3][1] = 0; GL_State( GLS_DEPTHTEST_DISABLE ); GLSL_BindProgram(&tr.ssaoShader); GL_BindToTMU(tr.hdrDepthImage, TB_COLORMAP); { vec4_t viewInfo; float zmax = backEnd.viewParms.zFar; float zmin = r_znear->value; VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); GLSL_SetUniformVec4(&tr.ssaoShader, UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); FBO_Bind(tr.quarterFbo[1]); qglViewport(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height); qglScissor(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height); GLSL_BindProgram(&tr.depthBlurShader[0]); GL_BindToTMU(tr.quarterImage[0], TB_COLORMAP); GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); { vec4_t viewInfo; float zmax = backEnd.viewParms.zFar; float zmin = r_znear->value; VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); FBO_Bind(tr.screenSsaoFbo); qglViewport(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height); qglScissor(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height); GLSL_BindProgram(&tr.depthBlurShader[1]); GL_BindToTMU(tr.quarterImage[1], TB_COLORMAP); GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); { vec4_t viewInfo; float zmax = backEnd.viewParms.zFar; float zmin = r_znear->value; VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); } // reset viewport and scissor FBO_Bind(oldFbo); SetViewportAndScissor(); } if (glRefConfig.framebufferObject && (backEnd.viewParms.flags & VPF_DEPTHCLAMP) && glRefConfig.depthClamp) { qglDisable(GL_DEPTH_CLAMP); } if (!(backEnd.viewParms.flags & VPF_DEPTHSHADOW)) { RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); if (r_drawSun->integer) { RB_DrawSun(0.1, tr.sunShader); } if (r_drawSunRays->integer) { FBO_t *oldFbo = glState.currentFBO; FBO_Bind(tr.sunRaysFbo); qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); qglClear( GL_COLOR_BUFFER_BIT ); if (glRefConfig.occlusionQuery) { tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue; qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, tr.sunFlareQuery[tr.sunFlareQueryIndex]); } RB_DrawSun(0.3, tr.sunFlareShader); if (glRefConfig.occlusionQuery) { qglEndQueryARB(GL_SAMPLES_PASSED_ARB); } FBO_Bind(oldFbo); } // darken down any stencil shadows RB_ShadowFinish(); // add light flares on lights that aren't obscured RB_RenderFlares(); } if (glRefConfig.framebufferObject && tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) { FBO_Bind(NULL); GL_SelectTexture(TB_CUBEMAP); GL_BindToTMU(tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex], TB_CUBEMAP); qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP); GL_SelectTexture(0); } return (const void *)(cmd + 1); }
/* ================= RB_BeginDrawingView Any mirrored or portaled views have already been drawn, so prepare to actually render the visible surfaces for this view ================= */ void RB_BeginDrawingView (void) { int clearBits = 0; // 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; if (glRefConfig.framebufferObject) { // FIXME: HUGE HACK: render to the screen fbo if we've already postprocessed the frame and aren't drawing more world // drawing more world check is in case of double renders, such as skyportals if (backEnd.viewParms.targetFbo == NULL) { if (!tr.renderFbo || (backEnd.framePostProcessed && (backEnd.refdef.rdflags & RDF_NOWORLDMODEL))) { FBO_Bind(NULL); } else { FBO_Bind(tr.renderFbo); } } else { FBO_Bind(backEnd.viewParms.targetFbo); // FIXME: hack for cubemap testing if (tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) { //qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, backEnd.viewParms.targetFbo->colorImage[0]->texnum, 0); qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex]->texnum, 0); } } } // // set the modelview matrix for the viewer // SetViewportAndScissor(); // ensures that depth writes are enabled for the depth clear GL_State( GLS_DEFAULT ); // clear relevant buffers clearBits = GL_DEPTH_BUFFER_BIT; if ( r_measureOverdraw->integer || r_shadows->integer == 2 ) { clearBits |= GL_STENCIL_BUFFER_BIT; } if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) { clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used #ifdef _DEBUG qglClearColor( 0.8f, 0.7f, 0.4f, 1.0f ); // FIXME: get color of sky #else qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky #endif } // clear to white for shadow maps if (backEnd.viewParms.flags & VPF_SHADOWMAP) { clearBits |= GL_COLOR_BUFFER_BIT; qglClearColor( 1.0f, 1.0f, 1.0f, 1.0f ); } // clear to black for cube maps if (tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) { clearBits |= GL_COLOR_BUFFER_BIT; qglClearColor( 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; // clip to the plane of the portal if ( backEnd.viewParms.isPortal ) { #if 0 float plane[4]; double plane2[4]; plane[0] = backEnd.viewParms.portalPlane.normal[0]; plane[1] = backEnd.viewParms.portalPlane.normal[1]; plane[2] = backEnd.viewParms.portalPlane.normal[2]; plane[3] = backEnd.viewParms.portalPlane.dist; plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane); plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane); plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane); plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3]; #endif GL_SetModelviewMatrix( s_flipMatrix ); } }
/* ================= RB_BeginDrawingView Any mirrored or portaled views have already been drawn, so prepare to actually render the visible surfaces for this view ================= */ static void RB_BeginDrawingView (void) { int clearBits = GL_DEPTH_BUFFER_BIT; // 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 relevant buffers if ( r_measureOverdraw->integer || r_shadows->integer == 2 || tr_stencilled ) { clearBits |= GL_STENCIL_BUFFER_BIT; tr_stencilled = false; } if (skyboxportal) { if ( backEnd.refdef.rdflags & RDF_SKYBOXPORTAL ) { // portal scene, clear whatever is necessary if (r_fastsky->integer || (backEnd.refdef.rdflags & RDF_NOWORLDMODEL) ) { // fastsky: clear color // try clearing first with the portal sky fog color, then the world fog color, then finally a default clearBits |= GL_COLOR_BUFFER_BIT; if (tr.world && tr.world->globalFog != -1) { const fog_t *fog = &tr.world->fogs[tr.world->globalFog]; qglClearColor(fog->parms.color[0], fog->parms.color[1], fog->parms.color[2], 1.0f ); } else { qglClearColor ( 0.3f, 0.3f, 0.3f, 1.0 ); } } } } else { if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) && !g_bRenderGlowingObjects ) { if (tr.world && tr.world->globalFog != -1) { const fog_t *fog = &tr.world->fogs[tr.world->globalFog]; qglClearColor(fog->parms.color[0], fog->parms.color[1], fog->parms.color[2], 1.0f ); } else { qglClearColor( 0.3f, 0.3f, 0.3f, 1 ); // FIXME: get color of sky } clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used } } if ( !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) && ( r_DynamicGlow->integer && !g_bRenderGlowingObjects ) ) { if (tr.world && tr.world->globalFog != -1) { //this is because of a bug in multiple scenes I think, it needs to clear for the second scene but it doesn't normally. const fog_t *fog = &tr.world->fogs[tr.world->globalFog]; qglClearColor(fog->parms.color[0], fog->parms.color[1], fog->parms.color[2], 1.0f ); clearBits |= GL_COLOR_BUFFER_BIT; } } // If this pass is to just render the glowing objects, don't clear the depth buffer since // we're sharing it with the main scene (since the main scene has already been rendered). -AReis if ( g_bRenderGlowingObjects ) { clearBits &= ~GL_DEPTH_BUFFER_BIT; } if (clearBits) { 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; // clip to the plane of the portal if ( backEnd.viewParms.isPortal ) { float plane[4]; double plane2[4]; plane[0] = backEnd.viewParms.portalPlane.normal[0]; plane[1] = backEnd.viewParms.portalPlane.normal[1]; plane[2] = backEnd.viewParms.portalPlane.normal[2]; plane[3] = backEnd.viewParms.portalPlane.dist; plane2[0] = DotProduct (backEnd.viewParms.ori.axis[0], plane); plane2[1] = DotProduct (backEnd.viewParms.ori.axis[1], plane); plane2[2] = DotProduct (backEnd.viewParms.ori.axis[2], plane); plane2[3] = DotProduct (plane, backEnd.viewParms.ori.origin) - plane[3]; qglLoadMatrixf( s_flipMatrix ); qglClipPlane (GL_CLIP_PLANE0, plane2); qglEnable (GL_CLIP_PLANE0); } else { qglDisable (GL_CLIP_PLANE0); } }
/* ============= RB_DrawSurfs ============= */ const void *RB_DrawSurfs( const void *data ) { const drawSurfsCommand_t *cmd; // finish any 2D drawing if needed if ( tess.numIndexes ) { RB_EndSurface(); } cmd = (const drawSurfsCommand_t *)data; backEnd.refdef = cmd->refdef; backEnd.viewParms = cmd->viewParms; RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); // Dynamic Glow/Flares: /* The basic idea is to render the glowing parts of the scene to an offscreen buffer, then take that buffer and blur it. After it is sufficiently blurred, re-apply that image back to the normal screen using a additive blending. To blur the scene I use a vertex program to supply four texture coordinate offsets that allow 'peeking' into adjacent pixels. In the register combiner (pixel shader), I combine the adjacent pixels using a weighting factor. - Aurelio */ // Render dynamic glowing/flaring objects. if ( !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && g_bDynamicGlowSupported && r_DynamicGlow->integer ) { // Copy the normal scene to texture. qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, tr.sceneImage ); qglCopyTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight); qglDisable( GL_TEXTURE_RECTANGLE_EXT ); qglEnable( GL_TEXTURE_2D ); // Just clear colors, but leave the depth buffer intact so we can 'share' it. qglClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); qglClear( GL_COLOR_BUFFER_BIT ); // Render the glowing objects. g_bRenderGlowingObjects = true; RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); g_bRenderGlowingObjects = false; qglFinish(); // Copy the glow scene to texture. qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, tr.screenGlow ); qglCopyTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); qglDisable( GL_TEXTURE_RECTANGLE_EXT ); qglEnable( GL_TEXTURE_2D ); // Resize the viewport to the blur texture size. const int oldViewWidth = backEnd.viewParms.viewportWidth; const int oldViewHeight = backEnd.viewParms.viewportHeight; backEnd.viewParms.viewportWidth = r_DynamicGlowWidth->integer; backEnd.viewParms.viewportHeight = r_DynamicGlowHeight->integer; SetViewportAndScissor(); // Blur the scene. RB_BlurGlowTexture(); // Copy the finished glow scene back to texture. qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, tr.blurImage ); qglCopyTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, 0, 0, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); qglDisable( GL_TEXTURE_RECTANGLE_EXT ); qglEnable( GL_TEXTURE_2D ); // Set the viewport back to normal. backEnd.viewParms.viewportWidth = oldViewWidth; backEnd.viewParms.viewportHeight = oldViewHeight; SetViewportAndScissor(); qglClear( GL_COLOR_BUFFER_BIT ); // Draw the glow additively over the screen. RB_DrawGlowOverlay(); } return (const void *)(cmd + 1); }
/* ================= RB_BeginDrawingView Any mirrored or portaled views have already been drawn, so prepare to actually render the visible surfaces for this view ================= */ void RB_BeginDrawingView (void) { int clearBits = 0; // 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; if (glRefConfig.framebufferObject) { FBO_t *fbo = backEnd.viewParms.targetFbo; // FIXME: HUGE HACK: render to the screen fbo if we've already postprocessed the frame and aren't drawing more world // drawing more world check is in case of double renders, such as skyportals if (fbo == NULL && !(backEnd.framePostProcessed && (backEnd.refdef.rdflags & RDF_NOWORLDMODEL))) fbo = tr.renderFbo; if (tr.renderCubeFbo && fbo == tr.renderCubeFbo) { cubemap_t *cubemap = &tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex]; FBO_AttachImage(fbo, cubemap->image, GL_COLOR_ATTACHMENT0_EXT, backEnd.viewParms.targetFboLayer); } FBO_Bind(fbo); } // // set the modelview matrix for the viewer // SetViewportAndScissor(); // ensures that depth writes are enabled for the depth clear GL_State( GLS_DEFAULT ); // clear relevant buffers clearBits = GL_DEPTH_BUFFER_BIT; if ( r_measureOverdraw->integer || r_shadows->integer == 2 ) { clearBits |= GL_STENCIL_BUFFER_BIT; } if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) { clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used } // clear to black for cube maps if (tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) { clearBits |= GL_COLOR_BUFFER_BIT; } qglClear( clearBits ); if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) ) { RB_Hyperspace(); return; } else { backEnd.isHyperspace = qfalse; } // we will only draw a sun if there was sky rendered in this view backEnd.skyRenderedThisView = qfalse; // clip to the plane of the portal if ( backEnd.viewParms.isPortal ) { #if 0 float plane[4]; GLdouble plane2[4]; plane[0] = backEnd.viewParms.portalPlane.normal[0]; plane[1] = backEnd.viewParms.portalPlane.normal[1]; plane[2] = backEnd.viewParms.portalPlane.normal[2]; plane[3] = backEnd.viewParms.portalPlane.dist; plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane); plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane); plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane); plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3]; #endif GL_SetModelviewMatrix( s_flipMatrix ); } }
/* ============= RB_PostProcess ============= */ const void *RB_PostProcess(const void *data) { const postProcessCommand_t *cmd = data; FBO_t *srcFbo; ivec4_t srcBox, dstBox; qboolean autoExposure; // finish any 2D drawing if needed if(tess.numIndexes) RB_EndSurface(); if (!glRefConfig.framebufferObject || !r_postProcess->integer) { // do nothing return (const void *)(cmd + 1); } if (cmd) { backEnd.refdef = cmd->refdef; backEnd.viewParms = cmd->viewParms; } srcFbo = tr.renderFbo; if (tr.msaaResolveFbo) { // Resolve the MSAA before anything else // Can't resolve just part of the MSAA FBO, so multiple views will suffer a performance hit here FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); srcFbo = tr.msaaResolveFbo; } dstBox[0] = backEnd.viewParms.viewportX; dstBox[1] = backEnd.viewParms.viewportY; dstBox[2] = backEnd.viewParms.viewportWidth; dstBox[3] = backEnd.viewParms.viewportHeight; if (r_ssao->integer) { srcBox[0] = backEnd.viewParms.viewportX * tr.screenSsaoImage->width / (float)glConfig.vidWidth; srcBox[1] = backEnd.viewParms.viewportY * tr.screenSsaoImage->height / (float)glConfig.vidHeight; srcBox[2] = backEnd.viewParms.viewportWidth * tr.screenSsaoImage->width / (float)glConfig.vidWidth; srcBox[3] = backEnd.viewParms.viewportHeight * tr.screenSsaoImage->height / (float)glConfig.vidHeight; FBO_Blit(tr.screenSsaoFbo, srcBox, NULL, srcFbo, dstBox, NULL, NULL, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); } srcBox[0] = backEnd.viewParms.viewportX; srcBox[1] = backEnd.viewParms.viewportY; srcBox[2] = backEnd.viewParms.viewportWidth; srcBox[3] = backEnd.viewParms.viewportHeight; if (srcFbo) { if (r_hdr->integer && (r_toneMap->integer || r_forceToneMap->integer)) { autoExposure = r_autoExposure->integer || r_forceAutoExposure->integer; RB_ToneMap(srcFbo, srcBox, NULL, dstBox, autoExposure); } else if (r_cameraExposure->value == 0.0f) { FBO_FastBlit(srcFbo, srcBox, NULL, dstBox, GL_COLOR_BUFFER_BIT, GL_NEAREST); } else { vec4_t color; color[0] = color[1] = color[2] = pow(2, r_cameraExposure->value); //exp2(r_cameraExposure->value); color[3] = 1.0f; FBO_Blit(srcFbo, srcBox, NULL, NULL, dstBox, NULL, color, 0); } } if (r_drawSunRays->integer) RB_SunRays(NULL, srcBox, NULL, dstBox); if (1) RB_BokehBlur(NULL, srcBox, NULL, dstBox, backEnd.refdef.blurFactor); else RB_GaussianBlur(backEnd.refdef.blurFactor); #if 0 if (0) { vec4_t quadVerts[4]; vec2_t texCoords[4]; ivec4_t iQtrBox; vec4_t box; vec4_t viewInfo; static float scale = 5.0f; scale -= 0.005f; if (scale < 0.01f) scale = 5.0f; FBO_FastBlit(NULL, NULL, tr.quarterFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); iQtrBox[0] = backEnd.viewParms.viewportX * tr.quarterImage[0]->width / (float)glConfig.vidWidth; iQtrBox[1] = backEnd.viewParms.viewportY * tr.quarterImage[0]->height / (float)glConfig.vidHeight; iQtrBox[2] = backEnd.viewParms.viewportWidth * tr.quarterImage[0]->width / (float)glConfig.vidWidth; iQtrBox[3] = backEnd.viewParms.viewportHeight * tr.quarterImage[0]->height / (float)glConfig.vidHeight; qglViewport(iQtrBox[0], iQtrBox[1], iQtrBox[2], iQtrBox[3]); qglScissor(iQtrBox[0], iQtrBox[1], iQtrBox[2], iQtrBox[3]); VectorSet4(box, 0.0f, 0.0f, 1.0f, 1.0f); texCoords[0][0] = box[0]; texCoords[0][1] = box[3]; texCoords[1][0] = box[2]; texCoords[1][1] = box[3]; texCoords[2][0] = box[2]; texCoords[2][1] = box[1]; texCoords[3][0] = box[0]; texCoords[3][1] = box[1]; VectorSet4(box, -1.0f, -1.0f, 1.0f, 1.0f); VectorSet4(quadVerts[0], box[0], box[3], 0, 1); VectorSet4(quadVerts[1], box[2], box[3], 0, 1); VectorSet4(quadVerts[2], box[2], box[1], 0, 1); VectorSet4(quadVerts[3], box[0], box[1], 0, 1); GL_State(GLS_DEPTHTEST_DISABLE); VectorSet4(viewInfo, backEnd.viewParms.zFar / r_znear->value, backEnd.viewParms.zFar, 0.0, 0.0); viewInfo[2] = scale / (float)(tr.quarterImage[0]->width); viewInfo[3] = scale / (float)(tr.quarterImage[0]->height); FBO_Bind(tr.quarterFbo[1]); GLSL_BindProgram(&tr.depthBlurShader[2]); GL_BindToTMU(tr.quarterImage[0], TB_COLORMAP); GLSL_SetUniformVec4(&tr.depthBlurShader[2], UNIFORM_VIEWINFO, viewInfo); RB_InstantQuad2(quadVerts, texCoords); FBO_Bind(tr.quarterFbo[0]); GLSL_BindProgram(&tr.depthBlurShader[3]); GL_BindToTMU(tr.quarterImage[1], TB_COLORMAP); GLSL_SetUniformVec4(&tr.depthBlurShader[3], UNIFORM_VIEWINFO, viewInfo); RB_InstantQuad2(quadVerts, texCoords); SetViewportAndScissor(); FBO_FastBlit(tr.quarterFbo[1], NULL, NULL, NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); FBO_Bind(NULL); } #endif if (0 && r_sunlightMode->integer) { ivec4_t dstBox; VectorSet4(dstBox, 0, 0, 128, 128); FBO_BlitFromTexture(tr.sunShadowDepthImage[0], NULL, NULL, NULL, dstBox, NULL, NULL, 0); VectorSet4(dstBox, 128, 0, 128, 128); FBO_BlitFromTexture(tr.sunShadowDepthImage[1], NULL, NULL, NULL, dstBox, NULL, NULL, 0); VectorSet4(dstBox, 256, 0, 128, 128); FBO_BlitFromTexture(tr.sunShadowDepthImage[2], NULL, NULL, NULL, dstBox, NULL, NULL, 0); VectorSet4(dstBox, 384, 0, 128, 128); FBO_BlitFromTexture(tr.sunShadowDepthImage[3], NULL, NULL, NULL, dstBox, NULL, NULL, 0); } if (0) { ivec4_t dstBox; VectorSet4(dstBox, 256, glConfig.vidHeight - 256, 256, 256); FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, NULL, dstBox, NULL, NULL, 0); VectorSet4(dstBox, 512, glConfig.vidHeight - 256, 256, 256); FBO_BlitFromTexture(tr.screenShadowImage, NULL, NULL, NULL, dstBox, NULL, NULL, 0); } if (0) { ivec4_t dstBox; VectorSet4(dstBox, 256, glConfig.vidHeight - 256, 256, 256); FBO_BlitFromTexture(tr.sunRaysImage, NULL, NULL, NULL, dstBox, NULL, NULL, 0); } #if 0 if (r_cubeMapping->integer && tr.numCubemaps) { ivec4_t dstBox; int cubemapIndex = R_CubemapForPoint( backEnd.viewParms.or.origin ); if (cubemapIndex) { VectorSet4(dstBox, 0, glConfig.vidHeight - 256, 256, 256); //FBO_BlitFromTexture(tr.renderCubeImage, NULL, NULL, NULL, dstBox, &tr.testcubeShader, NULL, 0); FBO_BlitFromTexture(tr.cubemaps[cubemapIndex - 1].image, NULL, NULL, NULL, dstBox, &tr.testcubeShader, NULL, 0); } } #endif backEnd.framePostProcessed = qtrue; return (const void *)(cmd + 1); }
/* ================= RB_BeginDrawingView Any mirrored or portaled views have already been drawn, so prepare to actually render the visible surfaces for this view ================= */ void RB_BeginDrawingView( void ) { backEnd.frameViewCount++; // sync with gl if needed if ( r_finish->integer == 1 && !glState.finishCalled ) { glFinish (); glState.finishCalled = qtrue; } if ( r_finish->integer == 0 ) { glState.finishCalled = qtrue; } // we will need to change the projection matrix before drawing // 2D images again RB_SetProjection2D( qfalse ); // // set the modelview matrix for the viewer // SetViewportAndScissor(); // ensures that depth writes are enabled for the depth clear GL_State( GLS_DEFAULT ); glClear( GL_DEPTH_BUFFER_BIT ); if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) ) { RB_Hyperspace(); return; } else { backEnd.isHyperspace = qfalse; } R_StateForceReset( TSN_Cull ); // force face culling to set next time // we will only draw a sun if there was sky rendered in this view backEnd.skyRenderedThisView = qfalse; // clip to the plane of the portal if ( backEnd.viewParms.isPortal ) { float plane[4]; double plane2[4]; plane[0] = backEnd.viewParms.portalPlane.normal[0]; plane[1] = backEnd.viewParms.portalPlane.normal[1]; plane[2] = backEnd.viewParms.portalPlane.normal[2]; plane[3] = backEnd.viewParms.portalPlane.dist; plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane); plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane); plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane); plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3]; R_StateSetModelViewMatrixCountedRaw( s_flipMatrix ); glClipPlane (GL_CLIP_PLANE0, plane2); glEnable (GL_CLIP_PLANE0); } else { glDisable (GL_CLIP_PLANE0); } }