cvar_t r_water_scissormode = {0, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
cvar_t r_water_lowquality = {0, "r_water_lowquality", "0", "special option to accelerate water rendering, 1 disables shadows and particles, 2 disables all dynamic lights"};
cvar_t r_water_hideplayer = {CVAR_SAVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
+cvar_t r_water_fbo = {CVAR_SAVE, "r_water_fbo", "1", "enables use of render to texture for water effects, otherwise copy to texture is used (slower)"};
cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
Con_Printf("failed to write to hlsl/default.hlsl\n");
}
-void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean usegamma, qboolean notrippy)
+void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
{
unsigned int permutation = 0;
if (r_trippy.integer && !notrippy)
permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
if (usegamma && v_glslgamma.integer && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
permutation |= SHADERPERMUTATION_GAMMARAMPS;
+ if (suppresstexalpha)
+ permutation |= SHADERPERMUTATION_REFLECTCUBE;
if (!second)
texturemode = GL_MODULATE;
if (vid.allowalphatocoverage)
}
}
+void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
+{
+ R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, usegamma, notrippy, false);
+}
+
void R_SetupShader_DepthOrShadow(qboolean notrippy)
{
unsigned int permutation = 0;
Cvar_RegisterVariable(&r_water_scissormode);
Cvar_RegisterVariable(&r_water_lowquality);
Cvar_RegisterVariable(&r_water_hideplayer);
+ Cvar_RegisterVariable(&r_water_fbo);
Cvar_RegisterVariable(&r_lerpsprites);
Cvar_RegisterVariable(&r_lerpmodels);
int i;
int waterwidth, waterheight, texturewidth, textureheight, camerawidth, cameraheight;
r_waterstate_waterplane_t *p;
+ qboolean usewaterfbo = (r_viewfbo.integer >= 1 || r_water_fbo.integer >= 1) && vid.support.ext_framebuffer_object && vid.samples < 2;
if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
return;
}
// allocate textures as needed
- if (r_fb.water.texturewidth != texturewidth || r_fb.water.textureheight != textureheight || r_fb.water.camerawidth != camerawidth || r_fb.water.cameraheight != cameraheight)
+ if (r_fb.water.texturewidth != texturewidth || r_fb.water.textureheight != textureheight || r_fb.water.camerawidth != camerawidth || r_fb.water.cameraheight != cameraheight || (r_fb.depthtexture && !usewaterfbo))
{
r_fb.water.maxwaterplanes = MAX_WATERPLANES;
for (i = 0, p = r_fb.water.waterplanes;i < r_fb.water.maxwaterplanes;i++, p++)
int planeindex, qualityreduction = 0, old_r_dynamic = 0, old_r_shadows = 0, old_r_worldrtlight = 0, old_r_dlight = 0, old_r_particles = 0, old_r_decals = 0;
r_waterstate_waterplane_t *p;
vec3_t visorigin;
+ qboolean usewaterfbo = (r_viewfbo.integer >= 1 || r_water_fbo.integer >= 1) && vid.support.ext_framebuffer_object && vid.samples < 2;
originalview = r_refdef.view;
p->texture_refraction = R_LoadTexture2D(r_main_texturepool, va("waterplane%i_refraction", planeindex), r_fb.water.texturewidth, r_fb.water.textureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
if (!p->texture_refraction)
goto error;
- if (r_viewfbo.integer >= 1 && vid.support.ext_framebuffer_object)
+ if (usewaterfbo)
{
if (r_fb.water.depthtexture == NULL)
r_fb.water.depthtexture = R_LoadTextureShadowMap2D(r_main_texturepool, "waterviewdepth", r_fb.water.texturewidth, r_fb.water.textureheight, 24, false);
p->texture_camera = R_LoadTexture2D(r_main_texturepool, va("waterplane%i_camera", planeindex), r_fb.water.camerawidth, r_fb.water.cameraheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR, -1, NULL);
if (!p->texture_camera)
goto error;
- if (r_viewfbo.integer >= 1 && vid.support.ext_framebuffer_object)
+ if (usewaterfbo)
{
if (r_fb.water.depthtexture == NULL)
r_fb.water.depthtexture = R_LoadTextureShadowMap2D(r_main_texturepool, "waterviewdepth", r_fb.water.texturewidth, r_fb.water.textureheight, 24, false);
p->texture_reflection = R_LoadTexture2D(r_main_texturepool, va("waterplane%i_reflection", planeindex), r_fb.water.texturewidth, r_fb.water.textureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
if (!p->texture_reflection)
goto error;
- if (r_viewfbo.integer >= 1 && vid.support.ext_framebuffer_object)
+ if (usewaterfbo)
{
if (r_fb.water.depthtexture == NULL)
r_fb.water.depthtexture = R_LoadTextureShadowMap2D(r_main_texturepool, "waterviewdepth", r_fb.water.texturewidth, r_fb.water.textureheight, 24, false);
int i;
int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
int viewwidth, viewheight;
+ qboolean useviewfbo = r_viewfbo.integer >= 1 && vid.support.ext_framebuffer_object && vid.samples < 2;
+ textype_t textype = TEXTYPE_COLORBUFFER;
- r_fb.textype = TEXTYPE_COLORBUFFER;
switch (vid.renderpath)
{
case RENDERPATH_GL20:
case RENDERPATH_GLES2:
if (vid.support.ext_framebuffer_object)
{
- if (r_viewfbo.integer == 2) r_fb.textype = TEXTYPE_COLORBUFFER16F;
- if (r_viewfbo.integer == 3) r_fb.textype = TEXTYPE_COLORBUFFER32F;
+ if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
+ if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
}
break;
case RENDERPATH_GL11:
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_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0)) && r_viewfbo.integer < 1 && r_viewscale.value == 1.0f && !r_viewscale_fpsscaling.integer)
+ if (!(r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial))
+ && !r_bloom.integer
+ && (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0))
+ && !useviewfbo
+ && r_viewscale.value == 1.0f
+ && !r_viewscale_fpsscaling.integer)
screentexturewidth = screentextureheight = 0;
if (!r_bloom.integer)
bloomtexturewidth = bloomtextureheight = 0;
|| r_fb.screentextureheight != screentextureheight
|| r_fb.bloomtexturewidth != bloomtexturewidth
|| r_fb.bloomtextureheight != bloomtextureheight
- || r_fb.viewfbo != r_viewfbo.integer)
+ || r_fb.textype != textype
+ || useviewfbo != (r_fb.fbo != 0))
{
for (i = 0;i < (int)(sizeof(r_fb.bloomtexture)/sizeof(r_fb.bloomtexture[i]));i++)
{
r_fb.screentextureheight = screentextureheight;
r_fb.bloomtexturewidth = bloomtexturewidth;
r_fb.bloomtextureheight = bloomtextureheight;
- r_fb.viewfbo = r_viewfbo.integer;
+ r_fb.textype = textype;
if (r_fb.screentexturewidth && r_fb.screentextureheight)
{
if (r_motionblur.value > 0 || r_damageblur.value > 0)
r_fb.ghosttexture = R_LoadTexture2D(r_main_texturepool, "framebuffermotionblur", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
+ r_fb.ghosttexture_valid = false;
r_fb.colortexture = R_LoadTexture2D(r_main_texturepool, "framebuffercolor", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
- if (r_viewfbo.integer >= 1 && vid.support.ext_framebuffer_object)
+ if (useviewfbo)
{
// FIXME: choose depth bits based on a cvar
r_fb.depthtexture = R_LoadTextureShadowMap2D(r_main_texturepool, "framebufferdepth", r_fb.screentexturewidth, r_fb.screentextureheight, 24, false);
for (i = 0;i < (int)(sizeof(r_fb.bloomtexture)/sizeof(r_fb.bloomtexture[i]));i++)
{
r_fb.bloomtexture[i] = R_LoadTexture2D(r_main_texturepool, "framebufferbloom", r_fb.bloomtexturewidth, r_fb.bloomtextureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
- if (r_viewfbo.integer >= 1 && vid.support.ext_framebuffer_object)
+ if (useviewfbo)
r_fb.bloomfbo[i] = R_Mesh_CreateFramebufferObject(NULL, r_fb.bloomtexture[i], NULL, NULL, NULL);
}
}
break;
}
// TODO: do boxfilter scale-down in shader?
- R_SetupShader_Generic(r_fb.colortexture, NULL, GL_MODULATE, 1, false, true);
+ R_SetupShader_Generic(r_fb.colortexture, NULL, GL_MODULATE, 1, false, true, true);
R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
r_refdef.stats.bloom_drawpixels += r_fb.bloomwidth * r_fb.bloomheight;
GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
GL_Color(r,r,r,1);
R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.bloomtexcoord2f);
- R_SetupShader_Generic(intex, NULL, GL_MODULATE, 1, false, true);
+ R_SetupShader_Generic(intex, NULL, GL_MODULATE, 1, false, true, false);
R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
r_refdef.stats.bloom_drawpixels += r_fb.bloomwidth * r_fb.bloomheight;
// TODO: do offset blends using GLSL
// TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
GL_BlendFunc(GL_ONE, GL_ZERO);
- R_SetupShader_Generic(intex, NULL, GL_MODULATE, 1, false, true);
+ R_SetupShader_Generic(intex, NULL, GL_MODULATE, 1, false, true, false);
for (x = -range;x <= range;x++)
{
if (!dir){xoffset = 0;yoffset = x;}
r_refdef.stats.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
}
- if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))
+ if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
{
// declare variables
float blur_factor, blur_mouseaccel, blur_velocity;
// apply the blur
R_ResetViewRendering2D(fbo, depthtexture, colortexture);
- if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture)
+ if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
{
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GL_Color(1, 1, 1, cl.motionbluralpha);
R_Mesh_PrepareVertices_Generic_Arrays(4, r_d3dscreenvertex3f, NULL, r_fb.screentexcoord2f);
break;
}
- R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true);
+ R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true, true);
R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
}
VectorCopy(cl.viewangles, blur_oldangles);
// copy view into the ghost texture
- if (!r_fb.ghosttexture)
- r_fb.ghosttexture = R_LoadTexture2D(r_main_texturepool, "motionblurtexture", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP, -1, NULL);
R_Mesh_CopyToTexture(r_fb.ghosttexture, 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;
+ r_fb.ghosttexture_valid = true;
}
}
else
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);
+ R_SetupShader_Generic_NoTexture(false, true);
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
}
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);
+ R_SetupShader_Generic_NoTexture(false, true);
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
}
}
R_Mesh_PrepareVertices_Generic_Arrays(8, vertex3f, color4f, NULL);
R_Mesh_ResetTextureState();
- R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
+ R_SetupShader_Generic_NoTexture(false, false);
R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
}
return;
GL_CullFace(GL_NONE);
- R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
+ R_SetupShader_Generic_NoTexture(false, false);
prog = 0;
SV_VM_Begin();
}
}
// R_Mesh_ResetTextureState();
- R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
+ R_SetupShader_Generic_NoTexture(false, false);
R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
}
// transparent sky would be ridiculous
if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
return;
- R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
+ R_SetupShader_Generic_NoTexture(false, false);
skyrenderlater = true;
RSurf_SetupDepthAndCulling();
GL_DepthMask(true);
}
else
{
- R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
+ R_SetupShader_Generic_NoTexture(false, false);
// fog sky
GL_BlendFunc(GL_ONE, GL_ZERO);
RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
float c[4];
// R_Mesh_ResetTextureState();
- R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
+ R_SetupShader_Generic_NoTexture(false, false);
if(rsurface.texture && rsurface.texture->currentskinframe)
{
RSurf_DrawBatch_GL11_ClampColor();
R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.passcolor4f, NULL);
- R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
+ R_SetupShader_Generic_NoTexture(false, false);
RSurf_DrawBatch();
}
else if (!r_refdef.view.showdebug)
vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
- R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
+ R_SetupShader_Generic_NoTexture(false, false);
R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
}
GL_DepthTest(true);
GL_CullFace(GL_NONE);
GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
- R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1, false, false);
+ R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1, false, false, false);
R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
}
}
{
float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
- R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
+ R_SetupShader_Generic_NoTexture(false, false);
GL_DepthTest(false);
GL_DepthMask(false);
GL_DepthRange(0, 1);
flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
// R_Mesh_ResetTextureState();
- R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
+ R_SetupShader_Generic_NoTexture(false, false);
GL_DepthRange(0, 1);
GL_DepthTest(!r_showdisabledepthtest.integer);
GL_DepthMask(false);