static cvar_t gl_combine = {CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
static cvar_t r_glsl = {CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
+cvar_t r_viewfbo = {CVAR_SAVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
+cvar_t r_viewscale = {CVAR_SAVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
+
cvar_t r_glsl_deluxemapping = {CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
cvar_t r_glsl_offsetmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
int bloomwidth, bloomheight;
+ textype_t texturetype;
+ int viewfbo; // used to check if r_viewfbo cvar has changed
+
+ int fbo_framebuffer; // non-zero if r_viewfbo is enabled and working
+ rtexture_t *texture_framebuffercolor; // non-NULL if fbo_screen is non-zero
+ rtexture_t *texture_framebufferdepth; // non-NULL if fbo_screen is non-zero
+
int screentexturewidth, screentextureheight;
rtexture_t *texture_screen; /// \note also used for motion blur if enabled!
Cvar_RegisterVariable(&r_texture_convertsRGB_particles);
Cvar_RegisterVariable(&r_textureunits);
Cvar_RegisterVariable(&gl_combine);
+ Cvar_RegisterVariable(&r_viewfbo);
+ Cvar_RegisterVariable(&r_viewscale);
Cvar_RegisterVariable(&r_glsl);
Cvar_RegisterVariable(&r_glsl_deluxemapping);
Cvar_RegisterVariable(&r_glsl_offsetmapping);
R_View_UpdateEntityLighting();
}
+void R_Mesh_SetMainRenderTargets(void)
+{
+ if (r_bloomstate.fbo_framebuffer)
+ R_Mesh_SetRenderTargets(r_bloomstate.fbo_framebuffer, r_bloomstate.texture_framebufferdepth, r_bloomstate.texture_framebuffercolor, NULL, NULL, NULL);
+ else
+ R_Mesh_ResetRenderTargets();
+}
+
void R_SetupView(qboolean allowwaterclippingplane)
{
const float *customclipplane = NULL;
R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, 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 - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
+ R_Mesh_SetMainRenderTargets();
R_SetViewport(&r_refdef.view.viewport);
}
// 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_SetViewport(&viewport);
GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
GL_Color(1, 1, 1, 1);
void R_Bloom_StartFrame(void)
{
int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
+ textype_t textype;
switch(vid.renderpath)
{
Cvar_SetValueQuick(&r_damageblur, 0);
}
- if (!(r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial)) && !r_bloom.integer && !r_hdr.integer && (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0)))
+ if (!(r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial)) && !r_bloom.integer && !r_hdr.integer && (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0)) && r_viewfbo.integer < 1 && r_viewscale.value == 1.0f)
screentexturewidth = screentextureheight = 0;
if (!r_hdr.integer && !r_bloom.integer)
bloomtexturewidth = bloomtextureheight = 0;
+ textype = TEXTYPE_COLORBUFFER;
+ switch (vid.renderpath)
+ {
+ case RENDERPATH_GL20:
+ case RENDERPATH_GLES2:
+ if (vid.support.ext_framebuffer_object)
+ {
+ if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
+ if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
+ }
+ break;
+ case RENDERPATH_D3D9:
+ case RENDERPATH_D3D10:
+ case RENDERPATH_D3D11:
+ case RENDERPATH_SOFT:
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL11:
+ break;
+ }
+
// allocate textures as needed
- if (r_bloomstate.screentexturewidth != screentexturewidth || r_bloomstate.screentextureheight != screentextureheight)
+ if (r_bloomstate.screentexturewidth != screentexturewidth
+ || r_bloomstate.screentextureheight != screentextureheight
+ || r_bloomstate.bloomtexturewidth != bloomtexturewidth
+ || r_bloomstate.bloomtextureheight != bloomtextureheight
+ || r_bloomstate.texturetype != textype
+ || r_bloomstate.viewfbo != r_viewfbo.integer)
{
+ if (r_bloomstate.texture_bloom)
+ R_FreeTexture(r_bloomstate.texture_bloom);
+ r_bloomstate.texture_bloom = NULL;
if (r_bloomstate.texture_screen)
R_FreeTexture(r_bloomstate.texture_screen);
r_bloomstate.texture_screen = NULL;
+ if (r_bloomstate.fbo_framebuffer)
+ R_Mesh_DestroyFramebufferObject(r_bloomstate.fbo_framebuffer);
+ r_bloomstate.fbo_framebuffer = 0;
+ if (r_bloomstate.texture_framebuffercolor)
+ R_FreeTexture(r_bloomstate.texture_framebuffercolor);
+ r_bloomstate.texture_framebuffercolor = NULL;
+ if (r_bloomstate.texture_framebufferdepth)
+ R_FreeTexture(r_bloomstate.texture_framebufferdepth);
+ r_bloomstate.texture_framebufferdepth = NULL;
r_bloomstate.screentexturewidth = screentexturewidth;
r_bloomstate.screentextureheight = screentextureheight;
if (r_bloomstate.screentexturewidth && r_bloomstate.screentextureheight)
- r_bloomstate.texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP, -1, NULL);
- }
- if (r_bloomstate.bloomtexturewidth != bloomtexturewidth || r_bloomstate.bloomtextureheight != bloomtextureheight)
- {
- if (r_bloomstate.texture_bloom)
- R_FreeTexture(r_bloomstate.texture_bloom);
- r_bloomstate.texture_bloom = NULL;
+ r_bloomstate.texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, NULL, textype, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP, -1, NULL);
+ if (r_viewfbo.integer >= 1 && vid.support.ext_framebuffer_object)
+ {
+ // FIXME: choose depth bits based on a cvar
+ r_bloomstate.texture_framebufferdepth = R_LoadTextureShadowMap2D(r_main_texturepool, "framebufferdepth", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, 24, false);
+ r_bloomstate.texture_framebuffercolor = R_LoadTexture2D(r_main_texturepool, "framebuffercolor", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, NULL, textype, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP, -1, NULL);
+ r_bloomstate.fbo_framebuffer = R_Mesh_CreateFramebufferObject(r_bloomstate.texture_framebufferdepth, r_bloomstate.texture_framebuffercolor, NULL, NULL, NULL);
+ R_Mesh_SetRenderTargets(r_bloomstate.fbo_framebuffer, r_bloomstate.texture_framebufferdepth, r_bloomstate.texture_framebuffercolor, NULL, NULL, NULL);
+ // render depth into one texture and normalmap into the other
+ if (qglDrawBuffer)
+ {
+ int status;
+ qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
+ qglReadBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
+ status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+ Con_Printf("R_Bloom_StartFrame: glCheckFramebufferStatusEXT returned %i\n", status);
+ }
+ }
r_bloomstate.bloomtexturewidth = bloomtexturewidth;
r_bloomstate.bloomtextureheight = bloomtextureheight;
if (r_bloomstate.bloomtexturewidth && r_bloomstate.bloomtextureheight)
- r_bloomstate.texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", r_bloomstate.bloomtexturewidth, r_bloomstate.bloomtextureheight, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
+ r_bloomstate.texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", r_bloomstate.bloomtexturewidth, r_bloomstate.bloomtextureheight, NULL, textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
+ r_bloomstate.viewfbo = r_viewfbo.integer;
+ r_bloomstate.texturetype = textype;
}
// when doing a reduced render (HDR) we want to use a smaller area
}
R_Viewport_InitOrtho(&r_bloomstate.viewport, &identitymatrix, r_refdef.view.x, vid.height - r_bloomstate.bloomheight - r_refdef.view.y, r_bloomstate.bloomwidth, r_bloomstate.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
+
+ if (r_bloomstate.fbo_framebuffer)
+ r_refdef.view.clear = true;
}
void R_Bloom_CopyBloomTexture(float colorscale)
// scale down screen texture to the bloom texture size
CHECKGLERROR
+ R_Mesh_SetMainRenderTargets();
R_SetViewport(&r_bloomstate.viewport);
GL_BlendFunc(GL_ONE, GL_ZERO);
GL_Color(colorscale, colorscale, colorscale, 1);
if (r_bloom_blur.value < 1) { Cvar_SetValueQuick(&r_bloom_blur, 1); }
R_ResetViewRendering2D();
+ R_Mesh_SetMainRenderTargets();
if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))
{
static textypeinfo_t textype_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0 , 0 };
static textypeinfo_t textype_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0 , 0 };
static textypeinfo_t textype_colorbuffer = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_colorbuffer16f = {TEXTYPE_COLORBUFFER16F,8,8,8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_FLOAT };
+static textypeinfo_t textype_colorbuffer32f = {TEXTYPE_COLORBUFFER32F,16,16,16.0f,GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT };
typedef enum gltexturetype_e
return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
case TEXTYPE_COLORBUFFER:
return &textype_colorbuffer;
+ case TEXTYPE_COLORBUFFER16F:
+ return &textype_colorbuffer16f;
+ case TEXTYPE_COLORBUFFER32F:
+ return &textype_colorbuffer32f;
default:
Host_Error("R_GetTexTypeInfo: unknown texture format");
break;
flags |= TEXF_ALPHA;
break;
case TEXTYPE_COLORBUFFER:
+ case TEXTYPE_COLORBUFFER16F:
+ case TEXTYPE_COLORBUFFER32F:
flags |= TEXF_ALPHA;
break;
default:
case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break;
case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
- case TEXTYPE_COLORBUFFER: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break;
+ case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
+ case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
+ case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break;
default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break;
case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break;
case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break;
+ case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break;
+ case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break;
case TEXTYPE_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break;
case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break;
default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype);
void R_Shadow_RenderMode_Reset(void)
{
- R_Mesh_ResetRenderTargets();
+ R_Mesh_SetMainRenderTargets();
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();
r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
R_Mesh_ResetTextureState();
- R_Mesh_ResetRenderTargets();
R_Shadow_RenderMode_Reset();
- if (fbo)
- {
- R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
- R_SetupShader_DepthOrShadow();
- }
- else
- R_SetupShader_ShowDepth();
+ R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
+ R_SetupShader_DepthOrShadow();
GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
GL_DepthMask(true);
GL_DepthTest(true);
void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
{
R_Mesh_ResetTextureState();
- R_Mesh_ResetRenderTargets();
+ R_Mesh_SetMainRenderTargets();
if (transparent)
{
r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
if (r_refdef.scene.lights[lnum]->draw)
R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
- R_Mesh_ResetRenderTargets();
+ R_Mesh_SetMainRenderTargets();
R_Shadow_RenderMode_End();
#if 0
// debugging
- R_Mesh_ResetRenderTargets();
+ R_Mesh_SetMainRenderTargets();
R_SetupShader_ShowDepth();
GL_ColorMask(1,1,1,1);
GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);