From: havoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Date: Sun, 16 Oct 2011 09:38:54 +0000 (+0000)
Subject: overhauling a lot of functions to allow fbo rendering
X-Git-Tag: xonotic-v0.6.0~252
X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=fc1e676d51f9156f5f667eb6d0c89816f3d06cb2;p=xonotic%2Fdarkplaces.git

overhauling a lot of functions to allow fbo rendering

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11425 d7cf8633-e32d-0410-b094-e92efae38249
::stable-branch::merge=4e36d3ccde0581e22d4b96214247bb8f98b6bca6
---

diff --git a/cl_screen.c b/cl_screen.c
index b84b9874..6f66856f 100644
--- a/cl_screen.c
+++ b/cl_screen.c
@@ -2037,7 +2037,7 @@ static void SCR_DrawLoadingScreen_SharedSetup (qboolean clear)
 //	CHECKGLERROR
 	r_refdef.draw2dstage = true;
 	R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, vid.width, vid.height, 0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100, NULL);
-	R_Mesh_ResetRenderTargets();
+	R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
 	R_SetViewport(&viewport);
 	GL_ColorMask(1,1,1,1);
 	// when starting up a new video mode, make sure the screen is cleared to black
@@ -2308,7 +2308,7 @@ void CL_UpdateScreen(void)
 #endif
 
 	R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, vid.width, vid.height, 0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100, NULL);
-	R_Mesh_ResetRenderTargets();
+	R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
 	R_SetViewport(&viewport);
 	GL_ScissorTest(false);
 	GL_ColorMask(1,1,1,1);
diff --git a/gl_backend.c b/gl_backend.c
index a89ef857..9a5b6028 100644
--- a/gl_backend.c
+++ b/gl_backend.c
@@ -1336,38 +1336,6 @@ void R_Mesh_SetRenderTargetsD3D9(IDirect3DSurface9 *depthsurface, IDirect3DSurfa
 }
 #endif
 
-void R_Mesh_ResetRenderTargets(void)
-{
-	switch(vid.renderpath)
-	{
-	case RENDERPATH_GL11:
-	case RENDERPATH_GL13:
-	case RENDERPATH_GL20:
-	case RENDERPATH_GLES1:
-	case RENDERPATH_GLES2:
-		if (gl_state.framebufferobject)
-		{
-			gl_state.framebufferobject = 0;
-			qglBindFramebufferEXT(GL_FRAMEBUFFER, gl_state.defaultframebufferobject);
-		}
-		break;
-	case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
-		R_Mesh_SetRenderTargetsD3D9(gl_state.d3drt_backbufferdepthsurface, gl_state.d3drt_backbuffercolorsurface, NULL, NULL, NULL);
-#endif
-		break;
-	case RENDERPATH_D3D10:
-		Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-		break;
-	case RENDERPATH_D3D11:
-		Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-		break;
-	case RENDERPATH_SOFT:
-		DPSOFTRAST_SetRenderTargets(vid.width, vid.height, vid.softdepthpixels, vid.softpixels, NULL, NULL, NULL);
-		break;
-	}
-}
-
 void R_Mesh_SetRenderTargets(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4)
 {
 	unsigned int i;
@@ -2546,7 +2514,7 @@ void GL_ReadPixelsBGRA(int x, int y, int width, int height, unsigned char *outpi
 void R_Mesh_Start(void)
 {
 	BACKENDACTIVECHECK
-	R_Mesh_ResetRenderTargets();
+	R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
 	R_Mesh_SetUseVBO();
 	if (gl_printcheckerror.integer && !gl_paranoid.integer)
 	{
@@ -3191,7 +3159,7 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
 // restores backend state, used when done with 3D rendering
 void R_Mesh_Finish(void)
 {
-	R_Mesh_ResetRenderTargets();
+	R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
 }
 
 r_meshbuffer_t *R_Mesh_CreateMeshBuffer(const void *data, size_t size, const char *name, qboolean isindexbuffer, qboolean isdynamic, qboolean isindex16)
diff --git a/gl_backend.h b/gl_backend.h
index 0a352336..86b2d310 100644
--- a/gl_backend.h
+++ b/gl_backend.h
@@ -52,8 +52,6 @@ void GL_Clear(int mask, const float *colorvalue, float depthvalue, int stencilva
 void GL_ReadPixelsBGRA(int x, int y, int width, int height, unsigned char *outpixels);
 int R_Mesh_CreateFramebufferObject(rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4);
 void R_Mesh_DestroyFramebufferObject(int fbo);
-void R_Mesh_ResetRenderTargets(void);
-void R_Mesh_SetMainRenderTargets(void);
 void R_Mesh_SetRenderTargets(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4);
 
 unsigned int GL_Backend_CompileProgram(int vertexstrings_count, const char **vertexstrings_list, int geometrystrings_count, const char **geometrystrings_list, int fragmentstrings_count, const char **fragmentstrings_list);
diff --git a/gl_draw.c b/gl_draw.c
index 86976c85..b6a670f1 100644
--- a/gl_draw.c
+++ b/gl_draw.c
@@ -1074,7 +1074,7 @@ static void _DrawQ_Setup(void)
 	r_refdef.draw2dstage = 1;
 	CHECKGLERROR
 	R_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height, 0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100, NULL);
-	R_Mesh_ResetRenderTargets();
+	R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
 	R_SetViewport(&viewport);
 	GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
 	GL_DepthFunc(GL_LEQUAL);
diff --git a/gl_rmain.c b/gl_rmain.c
index 2468c3d6..0082d614 100644
--- a/gl_rmain.c
+++ b/gl_rmain.c
@@ -5338,15 +5338,7 @@ void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
 	*outheight = (int)ceil(height * scale);
 }
 
-void R_Mesh_SetMainRenderTargets(void)
-{
-	if (r_fb.fbo_framebuffer)
-		R_Mesh_SetRenderTargets(r_fb.fbo_framebuffer, r_fb.texture_framebufferdepth, r_fb.texture_framebuffercolor, NULL, NULL, NULL);
-	else
-		R_Mesh_ResetRenderTargets();
-}
-
-void R_SetupView(qboolean allowwaterclippingplane)
+void R_SetupView(qboolean allowwaterclippingplane, int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
 	const float *customclipplane = NULL;
 	float plane[4];
@@ -5372,7 +5364,7 @@ void R_SetupView(qboolean allowwaterclippingplane)
 		R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, vid.height - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
 	else
 		R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, vid.height - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
-	R_Mesh_SetMainRenderTargets();
+	R_Mesh_SetRenderTargets(fbo, depthtexture, colortexture, NULL, NULL, NULL);
 	R_SetViewport(&r_refdef.view.viewport);
 	if (r_refdef.view.useclipplane && allowwaterclippingplane && vid.renderpath == RENDERPATH_SOFT)
 	{
@@ -5429,14 +5421,14 @@ void R_EntityMatrix(const matrix4x4_t *matrix)
 	}
 }
 
-void R_ResetViewRendering2D(void)
+void R_ResetViewRendering2D(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
 	r_viewport_t viewport;
 	DrawQ_Finish();
 
 	// GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
 	R_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, 0, 0, 1, 1, -10, 100, NULL);
-	R_Mesh_ResetRenderTargets();
+	R_Mesh_SetRenderTargets(fbo, depthtexture, colortexture, NULL, NULL, NULL);
 	R_SetViewport(&viewport);
 	GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
 	GL_Color(1, 1, 1, 1);
@@ -5469,11 +5461,11 @@ void R_ResetViewRendering2D(void)
 	GL_CullFace(GL_NONE);
 }
 
-void R_ResetViewRendering3D(void)
+void R_ResetViewRendering3D(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
 	DrawQ_Finish();
 
-	R_SetupView(true);
+	R_SetupView(true, fbo, depthtexture, colortexture);
 	GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
 	GL_Color(1, 1, 1, 1);
 	GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
@@ -5521,8 +5513,8 @@ static void R_RenderView_UpdateViewVectors(void)
 	Matrix4x4_Invert_Simple(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
 }
 
-void R_RenderScene(void);
-void R_RenderWaterPlanes(void);
+void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
+void R_RenderWaterPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
 
 static void R_Water_StartFrame(void)
 {
@@ -5725,7 +5717,7 @@ void R_Water_AddWaterPlane(msurface_t *surface, int entno)
 extern cvar_t r_drawparticles;
 extern cvar_t r_drawdecals;
 
-static void R_Water_ProcessPlanes(void)
+static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
 	int myscissor[4];
 	r_refdef_view_t originalview;
@@ -5802,7 +5794,7 @@ static void R_Water_ProcessPlanes(void)
 			r_refdef.view = myview;
 			if(r_water_scissormode.integer)
 			{
-				R_SetupView(true);
+				R_SetupView(true, fbo, depthtexture, colortexture);
 				if(R_ScissorForBBox(p->mins, p->maxs, myscissor))
 					continue; // FIXME the plane then still may get rendered but with broken texture, but it sure won't be visible
 			}
@@ -5825,7 +5817,7 @@ static void R_Water_ProcessPlanes(void)
 			}
 
 			r_fb.water.hideplayer = r_water_hideplayer.integer >= 2;
-			R_ResetViewRendering3D();
+			R_ResetViewRendering3D(fbo, depthtexture, colortexture);
 			R_ClearScreen(r_refdef.fogenabled);
 			if(r_water_scissormode.integer & 2)
 				R_View_UpdateWithScissor(myscissor);
@@ -5833,7 +5825,7 @@ static void R_Water_ProcessPlanes(void)
 				R_View_Update();
 			if(r_water_scissormode.integer & 1)
 				GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
-			R_RenderScene();
+			R_RenderScene(fbo, depthtexture, colortexture);
 
 			R_Mesh_CopyToTexture(p->texture_reflection, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
 			r_fb.water.hideplayer = false;
@@ -5846,7 +5838,7 @@ static void R_Water_ProcessPlanes(void)
 			r_refdef.view = myview;
 			if(r_water_scissormode.integer)
 			{
-				R_SetupView(true);
+				R_SetupView(true, fbo, depthtexture, colortexture);
 				if(R_ScissorForBBox(p->mins, p->maxs, myscissor))
 					continue; // FIXME the plane then still may get rendered but with broken texture, but it sure won't be visible
 			}
@@ -5872,7 +5864,7 @@ static void R_Water_ProcessPlanes(void)
 
 			PlaneClassify(&r_refdef.view.clipplane);
 
-			R_ResetViewRendering3D();
+			R_ResetViewRendering3D(fbo, depthtexture, colortexture);
 			R_ClearScreen(r_refdef.fogenabled);
 			if(r_water_scissormode.integer & 2)
 				R_View_UpdateWithScissor(myscissor);
@@ -5880,7 +5872,7 @@ static void R_Water_ProcessPlanes(void)
 				R_View_Update();
 			if(r_water_scissormode.integer & 1)
 				GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
-			R_RenderScene();
+			R_RenderScene(fbo, depthtexture, colortexture);
 
 			R_Mesh_CopyToTexture(p->texture_refraction, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
 			r_fb.water.hideplayer = false;
@@ -5928,10 +5920,10 @@ static void R_Water_ProcessPlanes(void)
 
 			r_fb.water.hideplayer = false;
 
-			R_ResetViewRendering3D();
+			R_ResetViewRendering3D(fbo, depthtexture, colortexture);
 			R_ClearScreen(r_refdef.fogenabled);
 			R_View_Update();
-			R_RenderScene();
+			R_RenderScene(fbo, depthtexture, colortexture);
 
 			R_Mesh_CopyToTexture(p->texture_camera, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
 			r_fb.water.hideplayer = false;
@@ -5941,7 +5933,7 @@ static void R_Water_ProcessPlanes(void)
 	if(vid.renderpath==RENDERPATH_SOFT) DPSOFTRAST_ClipPlane(0, 0, 0, 1);
 	r_fb.water.renderingscene = false;
 	r_refdef.view = originalview;
-	R_ResetViewRendering3D();
+	R_ResetViewRendering3D(fbo, depthtexture, colortexture);
 	R_ClearScreen(r_refdef.fogenabled);
 	R_View_Update();
 	goto finish;
@@ -6027,8 +6019,8 @@ void R_Bloom_StartFrame(void)
 	}
 	else
 	{
-		for (screentexturewidth  = 1;screentexturewidth  < vid.width               ;screentexturewidth  *= 2);
-		for (screentextureheight = 1;screentextureheight < vid.height              ;screentextureheight *= 2);
+		for (screentexturewidth  = 1;screentexturewidth  < vid.width       ;screentexturewidth  *= 2);
+		for (screentextureheight = 1;screentextureheight < vid.height      ;screentextureheight *= 2);
 		for (bloomtexturewidth   = 1;bloomtexturewidth   < r_fb.bloomwidth ;bloomtexturewidth   *= 2);
 		for (bloomtextureheight  = 1;bloomtextureheight  < r_fb.bloomheight;bloomtextureheight  *= 2);
 	}
@@ -6122,7 +6114,7 @@ void R_Bloom_StartFrame(void)
 		r_fb.texturetype = textype;
 	}
 
-	// when doing a reduced render (HDR) we want to use a smaller area
+	// bloom texture is a different resolution
 	r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.height);
 	r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
 	r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
@@ -6194,7 +6186,7 @@ void R_Bloom_CopyBloomTexture(float colorscale)
 
 	// scale down screen texture to the bloom texture size
 	CHECKGLERROR
-	R_Mesh_SetMainRenderTargets();
+	R_Mesh_SetRenderTargets(r_fb.fbo_framebuffer, r_fb.texture_framebufferdepth, r_fb.texture_framebuffercolor, NULL, NULL, NULL);
 	R_SetViewport(&r_fb.viewport);
 	GL_BlendFunc(GL_ONE, GL_ZERO);
 	GL_Color(colorscale, colorscale, colorscale, 1);
@@ -6239,7 +6231,7 @@ void R_Bloom_MakeTexture(void)
 
 	r_refdef.stats.bloom++;
 
-	R_ResetViewRendering2D();
+	R_ResetViewRendering2D(r_fb.fbo_framebuffer, r_fb.texture_framebufferdepth, r_fb.texture_framebuffercolor);
 
 	// we have a bloom image in the framebuffer
 	CHECKGLERROR
@@ -6335,7 +6327,7 @@ void R_HDR_RenderBloomTexture(void)
 	r_refdef.view.showdebug = false;
 	r_refdef.view.colorscale *= r_bloom_colorscale.value / bound(1, r_hdr_range.value, 16);
 
-	R_ResetViewRendering3D();
+	R_ResetViewRendering3D(r_fb.fbo_framebuffer, r_fb.texture_framebufferdepth, r_fb.texture_framebuffercolor);
 
 	R_ClearScreen(r_refdef.fogenabled);
 	if (r_timereport_active)
@@ -6348,13 +6340,13 @@ void R_HDR_RenderBloomTexture(void)
 	// only do secondary renders with HDR if r_hdr is 2 or higher
 	r_fb.water.numwaterplanes = 0;
 	if (r_fb.water.enabled)
-		R_RenderWaterPlanes();
+		R_RenderWaterPlanes(r_fb.fbo_framebuffer, r_fb.texture_framebufferdepth, r_fb.texture_framebuffercolor);
 
 	r_refdef.view.showdebug = true;
-	R_RenderScene();
+	R_RenderScene(r_fb.fbo_framebuffer, r_fb.texture_framebufferdepth, r_fb.texture_framebuffercolor);
 	r_fb.water.numwaterplanes = 0;
 
-	R_ResetViewRendering2D();
+	R_ResetViewRendering2D(r_fb.fbo_framebuffer, r_fb.texture_framebufferdepth, r_fb.texture_framebuffercolor);
 
 	R_Bloom_CopyHDRTexture();
 	R_Bloom_MakeTexture();
@@ -6365,14 +6357,14 @@ void R_HDR_RenderBloomTexture(void)
 	r_refdef.view.height = oldheight;
 	r_refdef.view.colorscale = oldcolorscale;
 
-	R_ResetViewRendering3D();
+	R_ResetViewRendering3D(r_fb.fbo_framebuffer, r_fb.texture_framebufferdepth, r_fb.texture_framebuffercolor);
 
 	R_ClearScreen(r_refdef.fogenabled);
 	if (r_timereport_active)
 		R_TimeReport("viewclear");
 }
 
-static void R_BlendView(void)
+static void R_BlendView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
 	unsigned int permutation;
 	float uservecs[4][4];
@@ -6397,8 +6389,7 @@ static void R_BlendView(void)
 			// make sure the buffer is available
 			if (r_bloom_blur.value < 1) { Cvar_SetValueQuick(&r_bloom_blur, 1); }
 
-			R_ResetViewRendering2D();
-			R_Mesh_SetMainRenderTargets();
+			R_ResetViewRendering2D(fbo, depthtexture, colortexture);
 
 			if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))
 			{
@@ -6473,13 +6464,13 @@ static void R_BlendView(void)
 			R_Mesh_CopyToTexture(r_fb.texture_screen, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
 			r_refdef.stats.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
 		}
-		else if (!r_fb.texture_bloom)
+		else
 		{
 			// we may still have to do view tint...
 			if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
 			{
 				// apply a color tint to the whole view
-				R_ResetViewRendering2D();
+				R_ResetViewRendering2D(0, NULL, NULL);
 				GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
 				R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
 				R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, true);
@@ -6511,7 +6502,7 @@ static void R_BlendView(void)
 		if (r_glsl_postprocess_uservec4_enable.integer)
 			sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
 
-		R_ResetViewRendering2D();
+		R_ResetViewRendering2D(0, NULL, NULL);
 		GL_Color(1, 1, 1, 1);
 		GL_BlendFunc(GL_ONE, GL_ZERO);
 
@@ -6587,7 +6578,7 @@ static void R_BlendView(void)
 		if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
 		{
 			// apply a color tint to the whole view
-			R_ResetViewRendering2D();
+			R_ResetViewRendering2D(0, NULL, NULL);
 			GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
 			R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
 			R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, true);
@@ -6600,7 +6591,7 @@ static void R_BlendView(void)
 
 matrix4x4_t r_waterscrollmatrix;
 
-void R_UpdateFog(void) // needs to be called before HDR subrender too, as that changes colorscale!
+void R_UpdateFog(void)
 {
 	// Nehahra fog
 	if (gamemode == GAME_NEHAHRA)
@@ -6847,6 +6838,9 @@ extern cvar_t r_shadow_bouncegrid;
 void R_RenderView(void)
 {
 	matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
+	int fbo;
+	rtexture_t *depthtexture;
+	rtexture_t *colortexture;
 
 	dpsoftrast_test = r_test.integer;
 
@@ -6876,6 +6870,7 @@ void R_RenderView(void)
 	if (r_refdef.view.isoverlay)
 	{
 		// TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
+		R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
 		GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
 		R_TimeReport("depthclear");
 
@@ -6884,7 +6879,7 @@ void R_RenderView(void)
 		r_fb.water.enabled = false;
 		r_fb.water.numwaterplanes = 0;
 
-		R_RenderScene();
+		R_RenderScene(0, NULL, NULL);
 
 		r_refdef.view.matrix = originalmatrix;
 
@@ -6907,13 +6902,18 @@ void R_RenderView(void)
 	R_Bloom_StartFrame();
 	R_Water_StartFrame();
 
+	// now we probably have an fbo to render into
+	fbo = r_fb.fbo_framebuffer;
+	depthtexture = r_fb.texture_framebufferdepth;
+	colortexture = r_fb.texture_framebuffercolor;
+
 	CHECKGLERROR
 	if (r_timereport_active)
 		R_TimeReport("viewsetup");
 
-	R_ResetViewRendering3D();
+	R_ResetViewRendering3D(fbo, depthtexture, colortexture);
 
-	if (r_refdef.view.clear || r_refdef.fogenabled)
+	if (r_refdef.view.clear || r_refdef.fogenabled || fbo)
 	{
 		R_ClearScreen(r_refdef.fogenabled);
 		if (r_timereport_active)
@@ -6941,12 +6941,12 @@ void R_RenderView(void)
 
 	r_fb.water.numwaterplanes = 0;
 	if (r_fb.water.enabled)
-		R_RenderWaterPlanes();
+		R_RenderWaterPlanes(fbo, depthtexture, colortexture);
 
-	R_RenderScene();
+	R_RenderScene(fbo, depthtexture, colortexture);
 	r_fb.water.numwaterplanes = 0;
 
-	R_BlendView();
+	R_BlendView(fbo, depthtexture, colortexture);
 	if (r_timereport_active)
 		R_TimeReport("blendview");
 
@@ -6958,7 +6958,7 @@ void R_RenderView(void)
 	CHECKGLERROR
 }
 
-void R_RenderWaterPlanes(void)
+void R_RenderWaterPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
 	if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
 	{
@@ -6977,7 +6977,7 @@ void R_RenderWaterPlanes(void)
 
 	if (r_fb.water.numwaterplanes)
 	{
-		R_Water_ProcessPlanes();
+		R_Water_ProcessPlanes(fbo, depthtexture, colortexture);
 		if (r_timereport_active)
 			R_TimeReport("waterscenes");
 	}
@@ -6990,11 +6990,11 @@ extern cvar_t cl_locs_show;
 static void R_DrawLocs(void);
 static void R_DrawEntityBBoxes(void);
 static void R_DrawModelDecals(void);
-extern void R_DrawModelShadows(void);
-extern void R_DrawModelShadowMaps(void);
+extern void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
+extern void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
 extern cvar_t cl_decals_newsystem;
 extern qboolean r_shadow_usingdeferredprepass;
-void R_RenderScene(void)
+void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
 	qboolean shadowmapping = false;
 
@@ -7037,15 +7037,15 @@ void R_RenderScene(void)
 		if (skyrendermasked && skyrenderlater)
 		{
 			// we have to force off the water clipping plane while rendering sky
-			R_SetupView(false);
+			R_SetupView(false, fbo, depthtexture, colortexture);
 			R_Sky();
-			R_SetupView(true);
+			R_SetupView(true, fbo, depthtexture, colortexture);
 			if (r_timereport_active)
 				R_TimeReport("sky");
 		}
 	}
 
-	R_Shadow_PrepareLights();
+	R_Shadow_PrepareLights(fbo, depthtexture, colortexture);
 	if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
 		R_Shadow_PrepareModelShadows();
 	if (r_timereport_active)
@@ -7072,8 +7072,9 @@ void R_RenderScene(void)
 
 	if (r_shadows.integer >= 2 && shadowmapping && r_refdef.lightmapintensity > 0)
 	{
-		R_DrawModelShadowMaps();
-		R_ResetViewRendering3D();
+		R_ResetViewRendering3D(fbo, depthtexture, colortexture);
+		R_DrawModelShadowMaps(fbo, depthtexture, colortexture);
+		R_ResetViewRendering3D(fbo, depthtexture, colortexture);
 		// don't let sound skip if going slow
 		if (r_refdef.scene.extraupdate)
 			S_ExtraUpdate ();
@@ -7100,8 +7101,9 @@ void R_RenderScene(void)
 
 	if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && !r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
 	{
-		R_DrawModelShadows();
-		R_ResetViewRendering3D();
+		R_ResetViewRendering3D(fbo, depthtexture, colortexture);
+		R_DrawModelShadows(fbo, depthtexture, colortexture);
+		R_ResetViewRendering3D(fbo, depthtexture, colortexture);
 		// don't let sound skip if going slow
 		if (r_refdef.scene.extraupdate)
 			S_ExtraUpdate ();
@@ -7120,8 +7122,9 @@ void R_RenderScene(void)
 
 	if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
 	{
-		R_DrawModelShadows();
-		R_ResetViewRendering3D();
+		R_ResetViewRendering3D(fbo, depthtexture, colortexture);
+		R_DrawModelShadows(fbo, depthtexture, colortexture);
+		R_ResetViewRendering3D(fbo, depthtexture, colortexture);
 		// don't let sound skip if going slow
 		if (r_refdef.scene.extraupdate)
 			S_ExtraUpdate ();
@@ -7230,7 +7233,7 @@ void R_RenderScene(void)
 	if (r_refdef.scene.extraupdate)
 		S_ExtraUpdate ();
 
-	R_ResetViewRendering2D();
+	R_ResetViewRendering2D(fbo, depthtexture, colortexture);
 }
 
 static const unsigned short bboxelements[36] =
diff --git a/r_shadow.c b/r_shadow.c
index a3d8220a..26cc9531 100644
--- a/r_shadow.c
+++ b/r_shadow.c
@@ -261,6 +261,11 @@ rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
 rtexture_t *r_shadow_prepasslightingdiffusetexture;
 rtexture_t *r_shadow_prepasslightingspeculartexture;
 
+// keep track of the provided framebuffer info
+static int r_shadow_fb_fbo;
+static rtexture_t *r_shadow_fb_depthtexture;
+static rtexture_t *r_shadow_fb_colortexture;
+
 // lights are reloaded when this changes
 char r_shadow_mapname[MAX_QPATH];
 
@@ -2015,10 +2020,10 @@ void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
 
 void R_Shadow_RenderMode_Reset(void)
 {
-	R_Mesh_SetMainRenderTargets();
+	R_Mesh_ResetTextureState();
+	R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
 	R_SetViewport(&r_refdef.view.viewport);
 	GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
-	R_Mesh_ResetTextureState();
 	GL_DepthRange(0, 1);
 	GL_DepthTest(true);
 	GL_DepthMask(false);
@@ -2229,7 +2234,7 @@ init_done:
 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
 {
 	R_Mesh_ResetTextureState();
-	R_Mesh_SetMainRenderTargets();
+	R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
 	if (transparent)
 	{
 		r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
@@ -4479,7 +4484,7 @@ void R_Shadow_DrawPrepass(void)
 			if (r_refdef.scene.lights[lnum]->draw)
 				R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
 
-	R_Mesh_SetMainRenderTargets();
+	R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
 
 	R_Shadow_RenderMode_End();
 
@@ -4488,7 +4493,7 @@ void R_Shadow_DrawPrepass(void)
 }
 
 void R_Shadow_DrawLightSprites(void);
-void R_Shadow_PrepareLights(void)
+void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
 	int flag;
 	int lnum;
@@ -4506,6 +4511,10 @@ void R_Shadow_PrepareLights(void)
 		r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
 		R_Shadow_FreeShadowMaps();
 
+	r_shadow_fb_fbo = fbo;
+	r_shadow_fb_depthtexture = depthtexture;
+	r_shadow_fb_colortexture = colortexture;
+
 	r_shadow_usingshadowmaportho = false;
 
 	switch (vid.renderpath)
@@ -4759,7 +4768,7 @@ void R_Shadow_PrepareModelShadows(void)
 	}
 }
 
-void R_DrawModelShadowMaps(void)
+void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
 	int i;
 	float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
@@ -4771,7 +4780,7 @@ void R_DrawModelShadowMaps(void)
 	float m[12];
 	matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
 	r_viewport_t viewport;
-	GLuint fbo = 0;
+	GLuint fbo2d = 0;
 	float clearcolor[4];
 
 	if (!r_refdef.scene.numentities)
@@ -4785,7 +4794,11 @@ void R_DrawModelShadowMaps(void)
 		return;
 	}
 
-	R_ResetViewRendering3D();
+	r_shadow_fb_fbo = fbo;
+	r_shadow_fb_depthtexture = depthtexture;
+	r_shadow_fb_colortexture = colortexture;
+
+	R_ResetViewRendering3D(fbo, depthtexture, colortexture);
 	R_Shadow_RenderMode_Begin();
 	R_Shadow_RenderMode_ActiveLight(NULL);
 
@@ -4794,7 +4807,7 @@ void R_DrawModelShadowMaps(void)
 	case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
 		if (!r_shadow_shadowmap2dtexture)
 			R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
-		fbo = r_shadow_fbo2d;
+		fbo2d = r_shadow_fbo2d;
 		r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
 		r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
 		r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
@@ -4844,7 +4857,7 @@ void R_DrawModelShadowMaps(void)
 
 	VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
 
-	R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
+	R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
 	R_SetupShader_DepthOrShadow(true);
 	GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
 	GL_DepthMask(true);
@@ -4865,7 +4878,7 @@ void R_DrawModelShadowMaps(void)
 
 #if 0
 	// debugging
-	R_Mesh_SetMainRenderTargets();
+	R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
 	R_SetupShader_ShowDepth(true);
 	GL_ColorMask(1,1,1,1);
 	GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
@@ -4954,7 +4967,7 @@ void R_DrawModelShadowMaps(void)
 	}
 }
 
-void R_DrawModelShadows(void)
+void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
 	int i;
 	float relativethrowdistance;
@@ -4967,7 +4980,11 @@ void R_DrawModelShadows(void)
 	if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
 		return;
 
-	R_ResetViewRendering3D();
+	r_shadow_fb_fbo = fbo;
+	r_shadow_fb_depthtexture = depthtexture;
+	r_shadow_fb_colortexture = colortexture;
+
+	R_ResetViewRendering3D(fbo, depthtexture, colortexture);
 	//GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
 	//GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
 	R_Shadow_RenderMode_Begin();
@@ -5052,7 +5069,7 @@ void R_DrawModelShadows(void)
 	//GL_ScissorTest(true);
 	//R_EntityMatrix(&identitymatrix);
 	//R_Mesh_ResetTextureState();
-	R_ResetViewRendering2D();
+	R_ResetViewRendering2D(fbo, depthtexture, colortexture);
 
 	// set up a darkening blend on shadowed areas
 	GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
diff --git a/r_shadow.h b/r_shadow.h
index c595fbe9..97f073f7 100644
--- a/r_shadow.h
+++ b/r_shadow.h
@@ -78,7 +78,7 @@ void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec
 void R_RTLight_Compile(rtlight_t *rtlight);
 void R_RTLight_Uncompile(rtlight_t *rtlight);
 
-void R_Shadow_PrepareLights(void);
+void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
 void R_Shadow_DrawPrepass(void);
 void R_Shadow_DrawLights(void);
 void R_Shadow_DrawCoronas(void);
diff --git a/render.h b/render.h
index 439e7465..a3fc44cc 100644
--- a/render.h
+++ b/render.h
@@ -513,9 +513,9 @@ r_framebufferstate_t;
 
 extern r_framebufferstate_t r_fb;
 
-void R_ResetViewRendering2D(void);
-void R_ResetViewRendering3D(void);
-void R_SetupView(qboolean allowwaterclippingplane);
+void R_ResetViewRendering2D(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
+void R_ResetViewRendering3D(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
+void R_SetupView(qboolean allowwaterclippingplane, int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
 extern const float r_screenvertex3f[12];
 extern cvar_t r_shadows;
 extern cvar_t r_shadows_darken;