Beispiel #1
0
// 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);
}
Beispiel #2
0
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)));
	}
}
Beispiel #3
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;
}
Beispiel #4
0
/*
================
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();
}
Beispiel #7
0
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();
}
Beispiel #8
0
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);
}
Beispiel #9
0
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);
}
Beispiel #10
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();
}