[iortcw] 38/152: All: Rend2: Merge recents updates Add r_shadowBlur Add r_glossType Speedup for SSAO & blur shaders, fix sunlight normals in lightall Create FBOs if target image exists, not cvar settings Fixes to depth blur and ssao More ssao/depth blur improvements

Simon McVittie smcv at debian.org
Fri Sep 8 10:39:55 UTC 2017


This is an automated email from the git hooks/post-receive script.

smcv pushed a commit to annotated tag 1.5a
in repository iortcw.

commit 9831dc25942ca81dddd289b4c29606dfd886de8b
Author: MAN-AT-ARMS <M4N4T4RMS at gmail.com>
Date:   Sat Mar 12 07:26:31 2016 -0500

    All: Rend2: Merge recents updates
    Add r_shadowBlur
    Add r_glossType
    Speedup for SSAO & blur shaders, fix sunlight normals in lightall
    Create FBOs if target image exists, not cvar settings
    Fixes to depth blur and ssao
    More ssao/depth blur improvements
---
 MP/code/rend2/glsl/depthblur_fp.glsl | 69 +++++++++++++++++-----------
 MP/code/rend2/glsl/depthblur_vp.glsl |  5 +-
 MP/code/rend2/glsl/lightall_fp.glsl  | 18 ++++++--
 MP/code/rend2/glsl/ssao_fp.glsl      | 54 +++++++++++-----------
 MP/code/rend2/tr_backend.c           | 88 +++++++++++++++++++-----------------
 MP/code/rend2/tr_fbo.c               | 44 +++++++++++++-----
 MP/code/rend2/tr_glsl.c              | 17 +++++++
 MP/code/rend2/tr_image.c             |  7 ++-
 MP/code/rend2/tr_init.c              |  6 ++-
 MP/code/rend2/tr_local.h             |  4 ++
 SP/code/rend2/glsl/depthblur_fp.glsl | 69 +++++++++++++++++-----------
 SP/code/rend2/glsl/depthblur_vp.glsl |  5 +-
 SP/code/rend2/glsl/lightall_fp.glsl  | 18 ++++++--
 SP/code/rend2/glsl/ssao_fp.glsl      | 54 +++++++++++-----------
 SP/code/rend2/tr_backend.c           | 88 +++++++++++++++++++-----------------
 SP/code/rend2/tr_fbo.c               | 44 +++++++++++++-----
 SP/code/rend2/tr_glsl.c              | 17 +++++++
 SP/code/rend2/tr_image.c             |  7 ++-
 SP/code/rend2/tr_init.c              |  6 ++-
 SP/code/rend2/tr_local.h             |  4 ++
 20 files changed, 400 insertions(+), 224 deletions(-)

diff --git a/MP/code/rend2/glsl/depthblur_fp.glsl b/MP/code/rend2/glsl/depthblur_fp.glsl
index 93895b4..9685f6d 100644
--- a/MP/code/rend2/glsl/depthblur_fp.glsl
+++ b/MP/code/rend2/glsl/depthblur_fp.glsl
@@ -1,58 +1,75 @@
 uniform sampler2D u_ScreenImageMap;
 uniform sampler2D u_ScreenDepthMap;
 
-uniform vec4   u_ViewInfo; // zfar / znear, zfar
+uniform vec4   u_ViewInfo; // zfar / znear, zfar, 1/width, 1/height
 varying vec2   var_ScreenTex;
 
+//float gauss[8] = float[8](0.17, 0.17, 0.16, 0.14, 0.12, 0.1, 0.08, 0.06);
 //float gauss[5] = float[5](0.30, 0.23, 0.097, 0.024, 0.0033);
 float gauss[4] = float[4](0.40, 0.24, 0.054, 0.0044);
 //float gauss[3] = float[3](0.60, 0.19, 0.0066);
-#define GAUSS_SIZE 4
+#define BLUR_SIZE 4
+//#define USE_GAUSS
 
 float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear)
 {
-		float sampleZDivW = texture2D(depthMap, tex).r;
-		return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW);
+	float sampleZDivW = texture2D(depthMap, tex).r;
+	return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW);
 }
 
-vec4 depthGaussian1D(sampler2D imageMap, sampler2D depthMap, vec2 tex, float zFarDivZNear, float zFar)
+vec4 depthGaussian1D(sampler2D imageMap, sampler2D depthMap, vec2 tex, float zFarDivZNear, float zFar, vec2 scale)
 {
-	float scale = 1.0 / 256.0;
+	float depthCenter = getLinearDepth(depthMap, tex, zFarDivZNear);
+
+	// enable for less blurring for farther objects
+	scale /= clamp(zFarDivZNear * depthCenter / 32.0, 1.0, 2.0);
 
 #if defined(USE_HORIZONTAL_BLUR)
-    vec2 direction = vec2(1.0, 0.0) * scale;
+	vec2 direction = vec2(scale.x * 2.0, 0.0);
+	vec2 nudge = vec2(0.0, scale.y * 0.5);
 #else // if defined(USE_VERTICAL_BLUR)
-	vec2 direction = vec2(0.0, 1.0) * scale;
+	vec2 direction = vec2(0.0, scale.y * 2.0);
+	vec2 nudge = vec2(scale.x * 0.5, 0.0);
 #endif
-	
-	float depthCenter = zFar * getLinearDepth(depthMap, tex, zFarDivZNear);
-	vec2 centerSlope = vec2(dFdx(depthCenter), dFdy(depthCenter)) / vec2(dFdx(tex.x), dFdy(tex.y));
-		
+
+	vec2 slope = vec2(dFdx(depthCenter), dFdy(depthCenter)) / vec2(dFdx(tex.x), dFdy(tex.y));
+
+#if defined(USE_GAUSS)
 	vec4 result = texture2D(imageMap, tex) * gauss[0];
 	float total = gauss[0];
+#else
+	vec4 result = texture2D(imageMap, tex);
+	float total = 1.0;
+#endif
 
+	float zLimit = 5.0 / zFar;
 	int i, j;
 	for (i = 0; i < 2; i++)
 	{
-		for (j = 1; j < GAUSS_SIZE; j++)
+		for (j = 1; j < BLUR_SIZE; j++)
 		{
-			vec2 offset = direction * j;
-			float depthSample = zFar * getLinearDepth(depthMap, tex + offset, zFarDivZNear);
-			float depthExpected = depthCenter + dot(centerSlope, offset);
-			if(abs(depthSample - depthExpected) < 5.0)
-			{
-				result += texture2D(imageMap, tex + offset) * gauss[j];
-				total += gauss[j];
-			}
+			vec2 offset = direction * (float(j) - 0.25) + nudge;
+			float depthSample = getLinearDepth(depthMap, tex + offset, zFarDivZNear);
+			float depthExpected = depthCenter + dot(slope, offset);
+			float useSample = float(abs(depthSample - depthExpected) < zLimit);
+#if defined(USE_GAUSS)
+			result += texture2D(imageMap, tex + offset) * (gauss[j] * useSample);
+			total += gauss[j] * useSample;
+#else
+			result += texture2D(imageMap, tex + offset) * useSample;
+			total += useSample;
+#endif
+			nudge = -nudge;
 		}
-		
+
 		direction = -direction;
-	}	
-		
+		nudge = -nudge;
+	}
+
 	return result / total;
 }
 
 void main()
-{		
-	gl_FragColor = depthGaussian1D(u_ScreenImageMap, u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y);
+{
+	gl_FragColor = depthGaussian1D(u_ScreenImageMap, u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y, u_ViewInfo.zw);
 }
diff --git a/MP/code/rend2/glsl/depthblur_vp.glsl b/MP/code/rend2/glsl/depthblur_vp.glsl
index 9c46a79..ba0b6c5 100644
--- a/MP/code/rend2/glsl/depthblur_vp.glsl
+++ b/MP/code/rend2/glsl/depthblur_vp.glsl
@@ -1,12 +1,15 @@
 attribute vec4 attr_Position;
 attribute vec4 attr_TexCoord0;
 
+uniform vec4   u_ViewInfo; // zfar / znear, zfar, 1/width, 1/height
+
 varying vec2   var_ScreenTex;
 
 void main()
 {
 	gl_Position = attr_Position;
-	var_ScreenTex = attr_TexCoord0.xy;
+	var_ScreenTex = (floor(attr_TexCoord0.xy * (1.0 / u_ViewInfo.zw - vec2(1.0))) + vec2(0.5)) * u_ViewInfo.zw;
+
 	//vec2 screenCoords = gl_Position.xy / gl_Position.w;
 	//var_ScreenTex = screenCoords * 0.5 + 0.5;
 }
diff --git a/MP/code/rend2/glsl/lightall_fp.glsl b/MP/code/rend2/glsl/lightall_fp.glsl
index 6a0a515..f16298a 100644
--- a/MP/code/rend2/glsl/lightall_fp.glsl
+++ b/MP/code/rend2/glsl/lightall_fp.glsl
@@ -292,7 +292,7 @@ void main()
 	float shadowValue = texture2D(u_ShadowMap, shadowTex).r;
 
 	// surfaces not facing the light are always shadowed
-	shadowValue *= clamp(dot(var_Normal.xyz, var_PrimaryLightDir.xyz), 0.0, 1.0);
+	shadowValue *= clamp(dot(N, var_PrimaryLightDir.xyz), 0.0, 1.0);
 
     #if defined(SHADOWMAP_MODULATE)
 	lightColor *= shadowValue * (1.0 - u_PrimaryLightAmbient.r) + u_PrimaryLightAmbient.r;
@@ -330,21 +330,31 @@ void main()
 
   #if defined(USE_PBR)
 	// diffuse rgb is base color
-	// specular red is smoothness
+	// specular red is gloss
 	// specular green is metallicness
-	float roughness = 1.0 - specular.r;
+	float gloss = specular.r;
 	specular.rgb = specular.g * diffuse.rgb + vec3(0.04 - 0.04 * specular.g);
 	diffuse.rgb *= 1.0 - specular.g;
   #else
 	// diffuse rgb is diffuse
 	// specular rgb is specular reflectance at normal incidence
 	// specular alpha is gloss
-	float roughness = exp2(-3.0 * specular.a);
+	float gloss = specular.a;
 
 	// adjust diffuse by specular reflectance, to maintain energy conservation
 	diffuse.rgb *= vec3(1.0) - specular.rgb;
   #endif
 
+  #if defined(GLOSS_IS_GLOSS)
+	float roughness = exp2(-3.0 * gloss);
+  #elif defined(GLOSS_IS_SMOOTHNESS)
+	float roughness = 1.0 - gloss;
+  #elif defined(GLOSS_IS_ROUGHNESS)
+	float roughness = gloss;
+  #elif defined(GLOSS_IS_SHININESS)
+	float roughness = pow(2.0 / (8190.0 * gloss + 2.0), 0.25);
+  #endif
+
 	reflectance  = CalcDiffuse(diffuse.rgb, NH, EH, roughness);
 
 	gl_FragColor.rgb  = lightColor   * reflectance * (attenuation * NL);
diff --git a/MP/code/rend2/glsl/ssao_fp.glsl b/MP/code/rend2/glsl/ssao_fp.glsl
index 6263284..93f6185 100644
--- a/MP/code/rend2/glsl/ssao_fp.glsl
+++ b/MP/code/rend2/glsl/ssao_fp.glsl
@@ -1,6 +1,6 @@
 uniform sampler2D u_ScreenDepthMap;
 
-uniform vec4   u_ViewInfo; // zfar / znear, zfar
+uniform vec4   u_ViewInfo; // zfar / znear, zfar, 1/width, 1/height
 
 varying vec2   var_ScreenTex;
 
@@ -11,6 +11,7 @@ vec2(0.5784913, -0.002528916), vec2(0.192888, 0.4064181),
 vec2(-0.6335801, -0.5247476),  vec2(-0.5579782, 0.7491854),
 vec2(0.7320465, 0.6317794)
 );
+#define NUM_SAMPLES 3
 
 // Input: It uses texture coords as the random number seed.
 // Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive.
@@ -39,48 +40,47 @@ mat2 randomRotation( const vec2 p )
 
 float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear)
 {
-		float sampleZDivW = texture2D(depthMap, tex).r;
-		return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW);
+	float sampleZDivW = texture2D(depthMap, tex).r;
+	return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW);
 }
 
-float ambientOcclusion(sampler2D depthMap, const vec2 tex, const float zFarDivZNear, const float zFar)
+float ambientOcclusion(sampler2D depthMap, const vec2 tex, const float zFarDivZNear, const float zFar, const vec2 scale)
 {
 	float result = 0;
 
-	float sampleZ = zFar * getLinearDepth(depthMap, tex, zFarDivZNear);
+	float sampleZ = getLinearDepth(depthMap, tex, zFarDivZNear);
+	float scaleZ = zFarDivZNear * sampleZ;
 
-	vec2 expectedSlope = vec2(dFdx(sampleZ), dFdy(sampleZ)) / vec2(dFdx(tex.x), dFdy(tex.y));
-	
-	if (length(expectedSlope) > 5000.0)
+	vec2 slope = vec2(dFdx(sampleZ), dFdy(sampleZ)) / vec2(dFdx(tex.x), dFdy(tex.y));
+
+	if (length(slope) * zFar > 5000.0)
 		return 1.0;
-	
-	vec2 offsetScale = vec2(3.0 / sampleZ);
-	
+
+	vec2 offsetScale = vec2(scale * 1024.0 / scaleZ);
+
 	mat2 rmat = randomRotation(tex);
-		
+
+	float invZFar = 1.0 / zFar;
+	float zLimit = 20.0 * invZFar;
 	int i;
-	for (i = 0; i < 3; i++)
+	for (i = 0; i < NUM_SAMPLES; i++)
 	{
 		vec2 offset = rmat * poissonDisc[i] * offsetScale;
-		float sampleZ2 = zFar * getLinearDepth(depthMap, tex + offset, zFarDivZNear);
-
-		if (abs(sampleZ - sampleZ2) > 20.0)
-			result += 1.0;
-		else
-		{
-			float expectedZ = sampleZ + dot(expectedSlope, offset);
-			result += step(expectedZ - 1.0, sampleZ2);
-		}
+		float sampleDiff = getLinearDepth(depthMap, tex + offset, zFarDivZNear) - sampleZ;
+
+		bool s1 = abs(sampleDiff) > zLimit;
+		bool s2 = sampleDiff + invZFar > dot(slope, offset);
+		result += float(s1 || s2);
 	}
-	
-	result *= 0.33333;
-	
+
+	result *= 1.0 / float(NUM_SAMPLES);
+
 	return result;
 }
 
 void main()
 {
-	float result = ambientOcclusion(u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y);
-			
+	float result = ambientOcclusion(u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y, u_ViewInfo.wz);
+
 	gl_FragColor = vec4(vec3(result), 1.0);
 }
diff --git a/MP/code/rend2/tr_backend.c b/MP/code/rend2/tr_backend.c
index 7ac01f6..f793694 100644
--- a/MP/code/rend2/tr_backend.c
+++ b/MP/code/rend2/tr_backend.c
@@ -1223,6 +1223,9 @@ const void  *RB_DrawSurfs( const void *data ) {
 	if (glRefConfig.framebufferObject && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && (r_depthPrepass->integer || (backEnd.viewParms.flags & VPF_DEPTHSHADOW)))
 	{
 		FBO_t *oldFbo = glState.currentFBO;
+		vec4_t viewInfo;
+
+		VectorSet4(viewInfo, backEnd.viewParms.zFar / r_znear->value, backEnd.viewParms.zFar, 0.0, 0.0);
 
 		backEnd.depthFill = qtrue;
 		qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
@@ -1241,10 +1244,14 @@ const void  *RB_DrawSurfs( const void *data ) {
 			qglCopyTextureImage2D(tr.renderDepthImage->texnum, GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0);
 		}
 
-		if (r_ssao->integer)
+		if (tr.hdrDepthFbo)
 		{
 			// need the depth in a texture we can do GL_LINEAR sampling on, so copy it to an HDR image
-			FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, tr.hdrDepthFbo, NULL, NULL, NULL, 0);
+			ivec4_t srcBox;
+
+			VectorSet4(srcBox, 0, tr.renderDepthImage->height, tr.renderDepthImage->width, -tr.renderDepthImage->height);
+
+			FBO_BlitFromTexture(tr.renderDepthImage, srcBox, NULL, tr.hdrDepthFbo, NULL, NULL, NULL, 0);
 		}
 
 		if (r_sunlightMode->integer && backEnd.viewParms.flags & VPF_USESUNLIGHT)
@@ -1309,15 +1316,12 @@ const void  *RB_DrawSurfs( const void *data ) {
 			
 			GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWORIGIN,  backEnd.refdef.vieworg);
 			{
-				vec4_t viewInfo;
 				vec3_t viewVector;
 
 				float zmax = backEnd.viewParms.zFar;
 				float ymax = zmax * tan(backEnd.viewParms.fovY * M_PI / 360.0f);
 				float xmax = zmax * tan(backEnd.viewParms.fovX * M_PI / 360.0f);
 
-				float zmin = r_znear->value;
-
 				VectorScale(backEnd.refdef.viewaxis[0], zmax, viewVector);
 				GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWFORWARD, viewVector);
 				VectorScale(backEnd.refdef.viewaxis[1], xmax, viewVector);
@@ -1325,13 +1329,39 @@ const void  *RB_DrawSurfs( const void *data ) {
 				VectorScale(backEnd.refdef.viewaxis[2], ymax, viewVector);
 				GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWUP,      viewVector);
 
-				VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0);
-
 				GLSL_SetUniformVec4(&tr.shadowmaskShader, UNIFORM_VIEWINFO, viewInfo);
 			}
 
 
 			RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
+
+			if (r_shadowBlur->integer)
+			{
+				viewInfo[2] = 1.0f / (float)(tr.screenScratchFbo->width);
+				viewInfo[3] = 1.0f / (float)(tr.screenScratchFbo->height);
+
+				FBO_Bind(tr.screenScratchFbo);
+
+				GLSL_BindProgram(&tr.depthBlurShader[0]);
+
+				GL_BindToTMU(tr.screenShadowImage, TB_COLORMAP);
+				GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP);
+
+				GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo);
+
+				RB_InstantQuad2(quadVerts, texCoords);
+
+				FBO_Bind(tr.screenShadowFbo);
+
+				GLSL_BindProgram(&tr.depthBlurShader[1]);
+
+				GL_BindToTMU(tr.screenScratchImage, TB_COLORMAP);
+				GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP);
+
+				GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo);
+
+				RB_InstantQuad2(quadVerts, texCoords);
+			}
 		}
 
 		if (r_ssao->integer)
@@ -1339,6 +1369,10 @@ const void  *RB_DrawSurfs( const void *data ) {
 			vec4_t quadVerts[4];
 			vec2_t texCoords[4];
 
+			viewInfo[2] = 1.0f / ((float)(tr.quarterImage[0]->width)  * tan(backEnd.viewParms.fovX * M_PI / 360.0f) * 2.0f);
+			viewInfo[3] = 1.0f / ((float)(tr.quarterImage[0]->height) * tan(backEnd.viewParms.fovY * M_PI / 360.0f) * 2.0f);
+			viewInfo[3] *= (float)backEnd.viewParms.viewportHeight / (float)backEnd.viewParms.viewportWidth;
+
 			FBO_Bind(tr.quarterFbo[0]);
 
 			qglViewport(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height);
@@ -1360,20 +1394,14 @@ const void  *RB_DrawSurfs( const void *data ) {
 
 			GL_BindToTMU(tr.hdrDepthImage, TB_COLORMAP);
 
-			{
-				vec4_t viewInfo;
-
-				float zmax = backEnd.viewParms.zFar;
-				float zmin = r_znear->value;
-
-				VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0);
-
-				GLSL_SetUniformVec4(&tr.ssaoShader, UNIFORM_VIEWINFO, viewInfo);
-			}
+			GLSL_SetUniformVec4(&tr.ssaoShader, UNIFORM_VIEWINFO, viewInfo);
 
 			RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
 
 
+			viewInfo[2] = 1.0f / (float)(tr.quarterImage[0]->width);
+			viewInfo[3] = 1.0f / (float)(tr.quarterImage[0]->height);
+
 			FBO_Bind(tr.quarterFbo[1]);
 
 			qglViewport(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height);
@@ -1384,16 +1412,7 @@ const void  *RB_DrawSurfs( const void *data ) {
 			GL_BindToTMU(tr.quarterImage[0],  TB_COLORMAP);
 			GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP);
 
-			{
-				vec4_t viewInfo;
-
-				float zmax = backEnd.viewParms.zFar;
-				float zmin = r_znear->value;
-
-				VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0);
-
-				GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo);
-			}
+			GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo);
 
 			RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
 
@@ -1408,16 +1427,7 @@ const void  *RB_DrawSurfs( const void *data ) {
 			GL_BindToTMU(tr.quarterImage[1],  TB_COLORMAP);
 			GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP);
 
-			{
-				vec4_t viewInfo;
-
-				float zmax = backEnd.viewParms.zFar;
-				float zmin = r_znear->value;
-
-				VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0);
-
-				GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo);
-			}
+			GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo);
 
 
 			RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
@@ -1803,10 +1813,6 @@ const void *RB_PostProcess(const void *data)
 		srcBox[2] = backEnd.viewParms.viewportWidth  * tr.screenSsaoImage->width  / (float)glConfig.vidWidth;
 		srcBox[3] = backEnd.viewParms.viewportHeight * tr.screenSsaoImage->height / (float)glConfig.vidHeight;
 
-		//FBO_BlitFromTexture(tr.screenSsaoImage, srcBox, NULL, srcFbo, dstBox, NULL, NULL, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO);
-		srcBox[1] = tr.screenSsaoImage->height - srcBox[1];
-		srcBox[3] = -srcBox[3];
-
 		FBO_Blit(tr.screenSsaoFbo, srcBox, NULL, srcFbo, dstBox, NULL, NULL, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO);
 	}
 
diff --git a/MP/code/rend2/tr_fbo.c b/MP/code/rend2/tr_fbo.c
index 1229376..d013748 100644
--- a/MP/code/rend2/tr_fbo.c
+++ b/MP/code/rend2/tr_fbo.c
@@ -310,7 +310,15 @@ void FBO_Init(void)
 		qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
 	}
 
-	if (r_drawSunRays->integer)
+	if (tr.screenScratchImage)
+	{
+		tr.screenScratchFbo = FBO_Create("screenScratch", tr.screenScratchImage->width, tr.screenScratchImage->height);
+		FBO_AttachImage(tr.screenScratchFbo, tr.screenScratchImage, GL_COLOR_ATTACHMENT0_EXT, 0);
+		FBO_AttachImage(tr.screenScratchFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT_EXT, 0);
+		R_CheckFBO(tr.screenScratchFbo);
+	}
+
+	if (tr.sunRaysImage)
 	{
 		tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height);
 		FBO_AttachImage(tr.sunRaysFbo, tr.sunRaysImage, GL_COLOR_ATTACHMENT0_EXT, 0);
@@ -332,7 +340,7 @@ void FBO_Init(void)
 
 	if (tr.sunShadowDepthImage[0])
 	{
-		for ( i = 0; i < 4; i++)
+		for (i = 0; i < 4; i++)
 		{
 			tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height);
 			// FIXME: this next line wastes 16mb with 4x1024x1024 sun shadow maps, skip if OpenGL 4.3+ or ARB_framebuffer_no_attachments
@@ -341,44 +349,58 @@ void FBO_Init(void)
 			FBO_AttachImage(tr.sunShadowFbo[i], tr.sunShadowDepthImage[i], GL_DEPTH_ATTACHMENT_EXT, 0);
 			R_CheckFBO(tr.sunShadowFbo[i]);
 		}
+	}
 
+	if (tr.screenShadowImage)
+	{
 		tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height);
 		FBO_AttachImage(tr.screenShadowFbo, tr.screenShadowImage, GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.screenShadowFbo);
 	}
 
-	for (i = 0; i < 2; i++)
+	if (tr.textureScratchImage[0])
 	{
-		tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height);
-		FBO_AttachImage(tr.textureScratchFbo[i], tr.textureScratchImage[i], GL_COLOR_ATTACHMENT0_EXT, 0);
-		R_CheckFBO(tr.textureScratchFbo[i]);
+		for (i = 0; i < 2; i++)
+		{
+			tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height);
+			FBO_AttachImage(tr.textureScratchFbo[i], tr.textureScratchImage[i], GL_COLOR_ATTACHMENT0_EXT, 0);
+			R_CheckFBO(tr.textureScratchFbo[i]);
+		}
 	}
 
+	if (tr.calcLevelsImage)
 	{
 		tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height);
 		FBO_AttachImage(tr.calcLevelsFbo, tr.calcLevelsImage, GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.calcLevelsFbo);
 	}
 
+	if (tr.targetLevelsImage)
 	{
 		tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height);
 		FBO_AttachImage(tr.targetLevelsFbo, tr.targetLevelsImage, GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.targetLevelsFbo);
 	}
 
-	for (i = 0; i < 2; i++)
+	if (tr.quarterImage[0])
 	{
-		tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height);
-		FBO_AttachImage(tr.quarterFbo[i], tr.quarterImage[i], GL_COLOR_ATTACHMENT0_EXT, 0);
-		R_CheckFBO(tr.quarterFbo[i]);
+		for (i = 0; i < 2; i++)
+		{
+			tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height);
+			FBO_AttachImage(tr.quarterFbo[i], tr.quarterImage[i], GL_COLOR_ATTACHMENT0_EXT, 0);
+			R_CheckFBO(tr.quarterFbo[i]);
+		}
 	}
 
-	if (r_ssao->integer)
+	if (tr.hdrDepthImage)
 	{
 		tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height);
 		FBO_AttachImage(tr.hdrDepthFbo, tr.hdrDepthImage, GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.hdrDepthFbo);
+	}
 
+	if (tr.screenSsaoImage)
+	{
 		tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height);
 		FBO_AttachImage(tr.screenSsaoFbo, tr.screenSsaoImage, GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.screenSsaoFbo);
diff --git a/MP/code/rend2/tr_glsl.c b/MP/code/rend2/tr_glsl.c
index 9cfa025..b9b73e2 100644
--- a/MP/code/rend2/tr_glsl.c
+++ b/MP/code/rend2/tr_glsl.c
@@ -1075,6 +1075,23 @@ void GLSL_InitGPUShaders(void)
 
 			if (r_cubeMapping->integer)
 				Q_strcat(extradefines, 1024, "#define USE_CUBEMAP\n");
+
+			switch (r_glossType->integer)
+			{
+				case 0:
+				default:
+					Q_strcat(extradefines, 1024, "#define GLOSS_IS_GLOSS\n");
+					break;
+				case 1:
+					Q_strcat(extradefines, 1024, "#define GLOSS_IS_SMOOTHNESS\n");
+					break;
+				case 2:
+					Q_strcat(extradefines, 1024, "#define GLOSS_IS_ROUGHNESS\n");
+					break;
+				case 3:
+					Q_strcat(extradefines, 1024, "#define GLOSS_IS_SHININESS\n");
+					break;
+			}
 		}
 
 		if (i & LIGHTDEF_USE_SHADOWMAP)
diff --git a/MP/code/rend2/tr_image.c b/MP/code/rend2/tr_image.c
index d6c1b80..644fe00 100644
--- a/MP/code/rend2/tr_image.c
+++ b/MP/code/rend2/tr_image.c
@@ -2927,6 +2927,12 @@ void R_CreateBuiltinImages( void ) {
 
 		tr.renderImage = R_CreateImage("_render", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat);
 
+		if (r_shadowBlur->integer)
+			tr.screenScratchImage = R_CreateImage("screenScratch", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat);
+
+		if (r_shadowBlur->integer || r_ssao->integer)
+			tr.hdrDepthImage = R_CreateImage("*hdrDepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_INTENSITY32F_ARB);
+
 		if (r_drawSunRays->integer)
 			tr.sunRaysImage = R_CreateImage("*sunRays", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat);
 
@@ -2974,7 +2980,6 @@ void R_CreateBuiltinImages( void ) {
 		if (r_ssao->integer)
 		{
 			tr.screenSsaoImage = R_CreateImage("*screenSsao", NULL, width / 2, height / 2, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8);
-			tr.hdrDepthImage = R_CreateImage("*hdrDepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_INTENSITY32F_ARB);
 		}
 
 		if (r_shadows->integer == 4)
diff --git a/MP/code/rend2/tr_init.c b/MP/code/rend2/tr_init.c
index 1787326..7d7675f 100644
--- a/MP/code/rend2/tr_init.c
+++ b/MP/code/rend2/tr_init.c
@@ -166,6 +166,7 @@ cvar_t  *r_baseNormalY;
 cvar_t  *r_baseParallax;
 cvar_t  *r_baseSpecular;
 cvar_t  *r_baseGloss;
+cvar_t  *r_glossType;
 cvar_t  *r_mergeLightmaps;
 cvar_t  *r_dlightMode;
 cvar_t  *r_pshadowDist;
@@ -181,6 +182,7 @@ cvar_t  *r_sunlightMode;
 cvar_t  *r_drawSunRays;
 cvar_t  *r_sunShadows;
 cvar_t  *r_shadowFilter;
+cvar_t  *r_shadowBlur;
 cvar_t  *r_shadowMapSize;
 cvar_t  *r_shadowCascadeZNear;
 cvar_t  *r_shadowCascadeZFar;
@@ -1345,6 +1347,7 @@ void R_Register( void ) {
 	r_baseParallax = ri.Cvar_Get( "r_baseParallax", "0.05", CVAR_ARCHIVE | CVAR_LATCH );
 	r_baseSpecular = ri.Cvar_Get( "r_baseSpecular", "0.04", CVAR_ARCHIVE | CVAR_LATCH );
 	r_baseGloss = ri.Cvar_Get( "r_baseGloss", "0.1", CVAR_ARCHIVE | CVAR_LATCH );
+	r_glossType = ri.Cvar_Get("r_glossType", "1", CVAR_ARCHIVE | CVAR_LATCH);
 	r_dlightMode = ri.Cvar_Get( "r_dlightMode", "0", CVAR_ARCHIVE | CVAR_LATCH );
 	r_pshadowDist = ri.Cvar_Get( "r_pshadowDist", "128", CVAR_ARCHIVE );
 	r_mergeLightmaps = ri.Cvar_Get( "r_mergeLightmaps", "1", CVAR_ARCHIVE | CVAR_LATCH );
@@ -1362,7 +1365,8 @@ void R_Register( void ) {
 
 	r_sunShadows = ri.Cvar_Get( "r_sunShadows", "1", CVAR_ARCHIVE | CVAR_LATCH );
 	r_shadowFilter = ri.Cvar_Get( "r_shadowFilter", "1", CVAR_ARCHIVE | CVAR_LATCH );
-	r_shadowMapSize = ri.Cvar_Get( "r_shadowMapSize", "1024", CVAR_ARCHIVE | CVAR_LATCH );
+	r_shadowBlur = ri.Cvar_Get("r_shadowBlur", "0", CVAR_ARCHIVE | CVAR_LATCH);
+	r_shadowMapSize = ri.Cvar_Get("r_shadowMapSize", "1024", CVAR_ARCHIVE | CVAR_LATCH);
 	r_shadowCascadeZNear = ri.Cvar_Get( "r_shadowCascadeZNear", "8", CVAR_ARCHIVE | CVAR_LATCH );
 	r_shadowCascadeZFar = ri.Cvar_Get( "r_shadowCascadeZFar", "1024", CVAR_ARCHIVE | CVAR_LATCH );
 	r_shadowCascadeZBias = ri.Cvar_Get( "r_shadowCascadeZBias", "0", CVAR_ARCHIVE | CVAR_LATCH );
diff --git a/MP/code/rend2/tr_local.h b/MP/code/rend2/tr_local.h
index b2a7f7e..5778ecf 100644
--- a/MP/code/rend2/tr_local.h
+++ b/MP/code/rend2/tr_local.h
@@ -1651,6 +1651,7 @@ typedef struct {
 	image_t					*sunRaysImage;
 	image_t					*renderDepthImage;
 	image_t					*pshadowMaps[MAX_DRAWN_PSHADOWS];
+	image_t					*screenScratchImage;
 	image_t					*textureScratchImage[2];
 	image_t                 *quarterImage[2];
 	image_t					*calcLevelsImage;
@@ -1669,6 +1670,7 @@ typedef struct {
 	FBO_t					*sunRaysFbo;
 	FBO_t					*depthFbo;
 	FBO_t					*pshadowFbos[MAX_DRAWN_PSHADOWS];
+	FBO_t					*screenScratchFbo;
 	FBO_t					*textureScratchFbo[2];
 	FBO_t                   *quarterFbo[2];
 	FBO_t					*calcLevelsFbo;
@@ -1990,6 +1992,7 @@ extern  cvar_t  *r_baseNormalY;
 extern  cvar_t  *r_baseParallax;
 extern  cvar_t  *r_baseSpecular;
 extern  cvar_t  *r_baseGloss;
+extern  cvar_t  *r_glossType;
 extern  cvar_t  *r_dlightMode;
 extern  cvar_t  *r_pshadowDist;
 extern  cvar_t  *r_mergeLightmaps;
@@ -2005,6 +2008,7 @@ extern  cvar_t  *r_sunlightMode;
 extern  cvar_t  *r_drawSunRays;
 extern  cvar_t  *r_sunShadows;
 extern  cvar_t  *r_shadowFilter;
+extern  cvar_t  *r_shadowBlur;
 extern  cvar_t  *r_shadowMapSize;
 extern  cvar_t  *r_shadowCascadeZNear;
 extern  cvar_t  *r_shadowCascadeZFar;
diff --git a/SP/code/rend2/glsl/depthblur_fp.glsl b/SP/code/rend2/glsl/depthblur_fp.glsl
index 93895b4..9685f6d 100644
--- a/SP/code/rend2/glsl/depthblur_fp.glsl
+++ b/SP/code/rend2/glsl/depthblur_fp.glsl
@@ -1,58 +1,75 @@
 uniform sampler2D u_ScreenImageMap;
 uniform sampler2D u_ScreenDepthMap;
 
-uniform vec4   u_ViewInfo; // zfar / znear, zfar
+uniform vec4   u_ViewInfo; // zfar / znear, zfar, 1/width, 1/height
 varying vec2   var_ScreenTex;
 
+//float gauss[8] = float[8](0.17, 0.17, 0.16, 0.14, 0.12, 0.1, 0.08, 0.06);
 //float gauss[5] = float[5](0.30, 0.23, 0.097, 0.024, 0.0033);
 float gauss[4] = float[4](0.40, 0.24, 0.054, 0.0044);
 //float gauss[3] = float[3](0.60, 0.19, 0.0066);
-#define GAUSS_SIZE 4
+#define BLUR_SIZE 4
+//#define USE_GAUSS
 
 float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear)
 {
-		float sampleZDivW = texture2D(depthMap, tex).r;
-		return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW);
+	float sampleZDivW = texture2D(depthMap, tex).r;
+	return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW);
 }
 
-vec4 depthGaussian1D(sampler2D imageMap, sampler2D depthMap, vec2 tex, float zFarDivZNear, float zFar)
+vec4 depthGaussian1D(sampler2D imageMap, sampler2D depthMap, vec2 tex, float zFarDivZNear, float zFar, vec2 scale)
 {
-	float scale = 1.0 / 256.0;
+	float depthCenter = getLinearDepth(depthMap, tex, zFarDivZNear);
+
+	// enable for less blurring for farther objects
+	scale /= clamp(zFarDivZNear * depthCenter / 32.0, 1.0, 2.0);
 
 #if defined(USE_HORIZONTAL_BLUR)
-    vec2 direction = vec2(1.0, 0.0) * scale;
+	vec2 direction = vec2(scale.x * 2.0, 0.0);
+	vec2 nudge = vec2(0.0, scale.y * 0.5);
 #else // if defined(USE_VERTICAL_BLUR)
-	vec2 direction = vec2(0.0, 1.0) * scale;
+	vec2 direction = vec2(0.0, scale.y * 2.0);
+	vec2 nudge = vec2(scale.x * 0.5, 0.0);
 #endif
-	
-	float depthCenter = zFar * getLinearDepth(depthMap, tex, zFarDivZNear);
-	vec2 centerSlope = vec2(dFdx(depthCenter), dFdy(depthCenter)) / vec2(dFdx(tex.x), dFdy(tex.y));
-		
+
+	vec2 slope = vec2(dFdx(depthCenter), dFdy(depthCenter)) / vec2(dFdx(tex.x), dFdy(tex.y));
+
+#if defined(USE_GAUSS)
 	vec4 result = texture2D(imageMap, tex) * gauss[0];
 	float total = gauss[0];
+#else
+	vec4 result = texture2D(imageMap, tex);
+	float total = 1.0;
+#endif
 
+	float zLimit = 5.0 / zFar;
 	int i, j;
 	for (i = 0; i < 2; i++)
 	{
-		for (j = 1; j < GAUSS_SIZE; j++)
+		for (j = 1; j < BLUR_SIZE; j++)
 		{
-			vec2 offset = direction * j;
-			float depthSample = zFar * getLinearDepth(depthMap, tex + offset, zFarDivZNear);
-			float depthExpected = depthCenter + dot(centerSlope, offset);
-			if(abs(depthSample - depthExpected) < 5.0)
-			{
-				result += texture2D(imageMap, tex + offset) * gauss[j];
-				total += gauss[j];
-			}
+			vec2 offset = direction * (float(j) - 0.25) + nudge;
+			float depthSample = getLinearDepth(depthMap, tex + offset, zFarDivZNear);
+			float depthExpected = depthCenter + dot(slope, offset);
+			float useSample = float(abs(depthSample - depthExpected) < zLimit);
+#if defined(USE_GAUSS)
+			result += texture2D(imageMap, tex + offset) * (gauss[j] * useSample);
+			total += gauss[j] * useSample;
+#else
+			result += texture2D(imageMap, tex + offset) * useSample;
+			total += useSample;
+#endif
+			nudge = -nudge;
 		}
-		
+
 		direction = -direction;
-	}	
-		
+		nudge = -nudge;
+	}
+
 	return result / total;
 }
 
 void main()
-{		
-	gl_FragColor = depthGaussian1D(u_ScreenImageMap, u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y);
+{
+	gl_FragColor = depthGaussian1D(u_ScreenImageMap, u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y, u_ViewInfo.zw);
 }
diff --git a/SP/code/rend2/glsl/depthblur_vp.glsl b/SP/code/rend2/glsl/depthblur_vp.glsl
index 9c46a79..ba0b6c5 100644
--- a/SP/code/rend2/glsl/depthblur_vp.glsl
+++ b/SP/code/rend2/glsl/depthblur_vp.glsl
@@ -1,12 +1,15 @@
 attribute vec4 attr_Position;
 attribute vec4 attr_TexCoord0;
 
+uniform vec4   u_ViewInfo; // zfar / znear, zfar, 1/width, 1/height
+
 varying vec2   var_ScreenTex;
 
 void main()
 {
 	gl_Position = attr_Position;
-	var_ScreenTex = attr_TexCoord0.xy;
+	var_ScreenTex = (floor(attr_TexCoord0.xy * (1.0 / u_ViewInfo.zw - vec2(1.0))) + vec2(0.5)) * u_ViewInfo.zw;
+
 	//vec2 screenCoords = gl_Position.xy / gl_Position.w;
 	//var_ScreenTex = screenCoords * 0.5 + 0.5;
 }
diff --git a/SP/code/rend2/glsl/lightall_fp.glsl b/SP/code/rend2/glsl/lightall_fp.glsl
index 6a0a515..f16298a 100644
--- a/SP/code/rend2/glsl/lightall_fp.glsl
+++ b/SP/code/rend2/glsl/lightall_fp.glsl
@@ -292,7 +292,7 @@ void main()
 	float shadowValue = texture2D(u_ShadowMap, shadowTex).r;
 
 	// surfaces not facing the light are always shadowed
-	shadowValue *= clamp(dot(var_Normal.xyz, var_PrimaryLightDir.xyz), 0.0, 1.0);
+	shadowValue *= clamp(dot(N, var_PrimaryLightDir.xyz), 0.0, 1.0);
 
     #if defined(SHADOWMAP_MODULATE)
 	lightColor *= shadowValue * (1.0 - u_PrimaryLightAmbient.r) + u_PrimaryLightAmbient.r;
@@ -330,21 +330,31 @@ void main()
 
   #if defined(USE_PBR)
 	// diffuse rgb is base color
-	// specular red is smoothness
+	// specular red is gloss
 	// specular green is metallicness
-	float roughness = 1.0 - specular.r;
+	float gloss = specular.r;
 	specular.rgb = specular.g * diffuse.rgb + vec3(0.04 - 0.04 * specular.g);
 	diffuse.rgb *= 1.0 - specular.g;
   #else
 	// diffuse rgb is diffuse
 	// specular rgb is specular reflectance at normal incidence
 	// specular alpha is gloss
-	float roughness = exp2(-3.0 * specular.a);
+	float gloss = specular.a;
 
 	// adjust diffuse by specular reflectance, to maintain energy conservation
 	diffuse.rgb *= vec3(1.0) - specular.rgb;
   #endif
 
+  #if defined(GLOSS_IS_GLOSS)
+	float roughness = exp2(-3.0 * gloss);
+  #elif defined(GLOSS_IS_SMOOTHNESS)
+	float roughness = 1.0 - gloss;
+  #elif defined(GLOSS_IS_ROUGHNESS)
+	float roughness = gloss;
+  #elif defined(GLOSS_IS_SHININESS)
+	float roughness = pow(2.0 / (8190.0 * gloss + 2.0), 0.25);
+  #endif
+
 	reflectance  = CalcDiffuse(diffuse.rgb, NH, EH, roughness);
 
 	gl_FragColor.rgb  = lightColor   * reflectance * (attenuation * NL);
diff --git a/SP/code/rend2/glsl/ssao_fp.glsl b/SP/code/rend2/glsl/ssao_fp.glsl
index 6263284..93f6185 100644
--- a/SP/code/rend2/glsl/ssao_fp.glsl
+++ b/SP/code/rend2/glsl/ssao_fp.glsl
@@ -1,6 +1,6 @@
 uniform sampler2D u_ScreenDepthMap;
 
-uniform vec4   u_ViewInfo; // zfar / znear, zfar
+uniform vec4   u_ViewInfo; // zfar / znear, zfar, 1/width, 1/height
 
 varying vec2   var_ScreenTex;
 
@@ -11,6 +11,7 @@ vec2(0.5784913, -0.002528916), vec2(0.192888, 0.4064181),
 vec2(-0.6335801, -0.5247476),  vec2(-0.5579782, 0.7491854),
 vec2(0.7320465, 0.6317794)
 );
+#define NUM_SAMPLES 3
 
 // Input: It uses texture coords as the random number seed.
 // Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive.
@@ -39,48 +40,47 @@ mat2 randomRotation( const vec2 p )
 
 float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear)
 {
-		float sampleZDivW = texture2D(depthMap, tex).r;
-		return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW);
+	float sampleZDivW = texture2D(depthMap, tex).r;
+	return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW);
 }
 
-float ambientOcclusion(sampler2D depthMap, const vec2 tex, const float zFarDivZNear, const float zFar)
+float ambientOcclusion(sampler2D depthMap, const vec2 tex, const float zFarDivZNear, const float zFar, const vec2 scale)
 {
 	float result = 0;
 
-	float sampleZ = zFar * getLinearDepth(depthMap, tex, zFarDivZNear);
+	float sampleZ = getLinearDepth(depthMap, tex, zFarDivZNear);
+	float scaleZ = zFarDivZNear * sampleZ;
 
-	vec2 expectedSlope = vec2(dFdx(sampleZ), dFdy(sampleZ)) / vec2(dFdx(tex.x), dFdy(tex.y));
-	
-	if (length(expectedSlope) > 5000.0)
+	vec2 slope = vec2(dFdx(sampleZ), dFdy(sampleZ)) / vec2(dFdx(tex.x), dFdy(tex.y));
+
+	if (length(slope) * zFar > 5000.0)
 		return 1.0;
-	
-	vec2 offsetScale = vec2(3.0 / sampleZ);
-	
+
+	vec2 offsetScale = vec2(scale * 1024.0 / scaleZ);
+
 	mat2 rmat = randomRotation(tex);
-		
+
+	float invZFar = 1.0 / zFar;
+	float zLimit = 20.0 * invZFar;
 	int i;
-	for (i = 0; i < 3; i++)
+	for (i = 0; i < NUM_SAMPLES; i++)
 	{
 		vec2 offset = rmat * poissonDisc[i] * offsetScale;
-		float sampleZ2 = zFar * getLinearDepth(depthMap, tex + offset, zFarDivZNear);
-
-		if (abs(sampleZ - sampleZ2) > 20.0)
-			result += 1.0;
-		else
-		{
-			float expectedZ = sampleZ + dot(expectedSlope, offset);
-			result += step(expectedZ - 1.0, sampleZ2);
-		}
+		float sampleDiff = getLinearDepth(depthMap, tex + offset, zFarDivZNear) - sampleZ;
+
+		bool s1 = abs(sampleDiff) > zLimit;
+		bool s2 = sampleDiff + invZFar > dot(slope, offset);
+		result += float(s1 || s2);
 	}
-	
-	result *= 0.33333;
-	
+
+	result *= 1.0 / float(NUM_SAMPLES);
+
 	return result;
 }
 
 void main()
 {
-	float result = ambientOcclusion(u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y);
-			
+	float result = ambientOcclusion(u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y, u_ViewInfo.wz);
+
 	gl_FragColor = vec4(vec3(result), 1.0);
 }
diff --git a/SP/code/rend2/tr_backend.c b/SP/code/rend2/tr_backend.c
index ed156fd..5380004 100644
--- a/SP/code/rend2/tr_backend.c
+++ b/SP/code/rend2/tr_backend.c
@@ -1475,6 +1475,9 @@ const void  *RB_DrawSurfs( const void *data ) {
 	if (glRefConfig.framebufferObject && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && (r_depthPrepass->integer || (backEnd.viewParms.flags & VPF_DEPTHSHADOW)))
 	{
 		FBO_t *oldFbo = glState.currentFBO;
+		vec4_t viewInfo;
+
+		VectorSet4(viewInfo, backEnd.viewParms.zFar / r_znear->value, backEnd.viewParms.zFar, 0.0, 0.0);
 
 		backEnd.depthFill = qtrue;
 		qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
@@ -1493,10 +1496,14 @@ const void  *RB_DrawSurfs( const void *data ) {
 			qglCopyTextureImage2D(tr.renderDepthImage->texnum, GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0);
 		}
 
-		if (r_ssao->integer)
+		if (tr.hdrDepthFbo)
 		{
 			// need the depth in a texture we can do GL_LINEAR sampling on, so copy it to an HDR image
-			FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, tr.hdrDepthFbo, NULL, NULL, NULL, 0);
+			ivec4_t srcBox;
+
+			VectorSet4(srcBox, 0, tr.renderDepthImage->height, tr.renderDepthImage->width, -tr.renderDepthImage->height);
+
+			FBO_BlitFromTexture(tr.renderDepthImage, srcBox, NULL, tr.hdrDepthFbo, NULL, NULL, NULL, 0);
 		}
 
 		if (r_sunlightMode->integer && backEnd.viewParms.flags & VPF_USESUNLIGHT)
@@ -1561,15 +1568,12 @@ const void  *RB_DrawSurfs( const void *data ) {
 			
 			GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWORIGIN,  backEnd.refdef.vieworg);
 			{
-				vec4_t viewInfo;
 				vec3_t viewVector;
 
 				float zmax = backEnd.viewParms.zFar;
 				float ymax = zmax * tan(backEnd.viewParms.fovY * M_PI / 360.0f);
 				float xmax = zmax * tan(backEnd.viewParms.fovX * M_PI / 360.0f);
 
-				float zmin = r_znear->value;
-
 				VectorScale(backEnd.refdef.viewaxis[0], zmax, viewVector);
 				GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWFORWARD, viewVector);
 				VectorScale(backEnd.refdef.viewaxis[1], xmax, viewVector);
@@ -1577,13 +1581,39 @@ const void  *RB_DrawSurfs( const void *data ) {
 				VectorScale(backEnd.refdef.viewaxis[2], ymax, viewVector);
 				GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWUP,      viewVector);
 
-				VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0);
-
 				GLSL_SetUniformVec4(&tr.shadowmaskShader, UNIFORM_VIEWINFO, viewInfo);
 			}
 
 
 			RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
+
+			if (r_shadowBlur->integer)
+			{
+				viewInfo[2] = 1.0f / (float)(tr.screenScratchFbo->width);
+				viewInfo[3] = 1.0f / (float)(tr.screenScratchFbo->height);
+
+				FBO_Bind(tr.screenScratchFbo);
+
+				GLSL_BindProgram(&tr.depthBlurShader[0]);
+
+				GL_BindToTMU(tr.screenShadowImage, TB_COLORMAP);
+				GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP);
+
+				GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo);
+
+				RB_InstantQuad2(quadVerts, texCoords);
+
+				FBO_Bind(tr.screenShadowFbo);
+
+				GLSL_BindProgram(&tr.depthBlurShader[1]);
+
+				GL_BindToTMU(tr.screenScratchImage, TB_COLORMAP);
+				GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP);
+
+				GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo);
+
+				RB_InstantQuad2(quadVerts, texCoords);
+			}
 		}
 
 		if (r_ssao->integer)
@@ -1591,6 +1621,10 @@ const void  *RB_DrawSurfs( const void *data ) {
 			vec4_t quadVerts[4];
 			vec2_t texCoords[4];
 
+			viewInfo[2] = 1.0f / ((float)(tr.quarterImage[0]->width)  * tan(backEnd.viewParms.fovX * M_PI / 360.0f) * 2.0f);
+			viewInfo[3] = 1.0f / ((float)(tr.quarterImage[0]->height) * tan(backEnd.viewParms.fovY * M_PI / 360.0f) * 2.0f);
+			viewInfo[3] *= (float)backEnd.viewParms.viewportHeight / (float)backEnd.viewParms.viewportWidth;
+
 			FBO_Bind(tr.quarterFbo[0]);
 
 			qglViewport(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height);
@@ -1612,20 +1646,14 @@ const void  *RB_DrawSurfs( const void *data ) {
 
 			GL_BindToTMU(tr.hdrDepthImage, TB_COLORMAP);
 
-			{
-				vec4_t viewInfo;
-
-				float zmax = backEnd.viewParms.zFar;
-				float zmin = r_znear->value;
-
-				VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0);
-
-				GLSL_SetUniformVec4(&tr.ssaoShader, UNIFORM_VIEWINFO, viewInfo);
-			}
+			GLSL_SetUniformVec4(&tr.ssaoShader, UNIFORM_VIEWINFO, viewInfo);
 
 			RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
 
 
+			viewInfo[2] = 1.0f / (float)(tr.quarterImage[0]->width);
+			viewInfo[3] = 1.0f / (float)(tr.quarterImage[0]->height);
+
 			FBO_Bind(tr.quarterFbo[1]);
 
 			qglViewport(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height);
@@ -1636,16 +1664,7 @@ const void  *RB_DrawSurfs( const void *data ) {
 			GL_BindToTMU(tr.quarterImage[0],  TB_COLORMAP);
 			GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP);
 
-			{
-				vec4_t viewInfo;
-
-				float zmax = backEnd.viewParms.zFar;
-				float zmin = r_znear->value;
-
-				VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0);
-
-				GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo);
-			}
+			GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo);
 
 			RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
 
@@ -1660,16 +1679,7 @@ const void  *RB_DrawSurfs( const void *data ) {
 			GL_BindToTMU(tr.quarterImage[1],  TB_COLORMAP);
 			GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP);
 
-			{
-				vec4_t viewInfo;
-
-				float zmax = backEnd.viewParms.zFar;
-				float zmin = r_znear->value;
-
-				VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0);
-
-				GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo);
-			}
+			GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo);
 
 
 			RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
@@ -2055,10 +2065,6 @@ const void *RB_PostProcess(const void *data)
 		srcBox[2] = backEnd.viewParms.viewportWidth  * tr.screenSsaoImage->width  / (float)glConfig.vidWidth;
 		srcBox[3] = backEnd.viewParms.viewportHeight * tr.screenSsaoImage->height / (float)glConfig.vidHeight;
 
-		//FBO_BlitFromTexture(tr.screenSsaoImage, srcBox, NULL, srcFbo, dstBox, NULL, NULL, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO);
-		srcBox[1] = tr.screenSsaoImage->height - srcBox[1];
-		srcBox[3] = -srcBox[3];
-
 		FBO_Blit(tr.screenSsaoFbo, srcBox, NULL, srcFbo, dstBox, NULL, NULL, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO);
 	}
 
diff --git a/SP/code/rend2/tr_fbo.c b/SP/code/rend2/tr_fbo.c
index 1229376..d013748 100644
--- a/SP/code/rend2/tr_fbo.c
+++ b/SP/code/rend2/tr_fbo.c
@@ -310,7 +310,15 @@ void FBO_Init(void)
 		qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
 	}
 
-	if (r_drawSunRays->integer)
+	if (tr.screenScratchImage)
+	{
+		tr.screenScratchFbo = FBO_Create("screenScratch", tr.screenScratchImage->width, tr.screenScratchImage->height);
+		FBO_AttachImage(tr.screenScratchFbo, tr.screenScratchImage, GL_COLOR_ATTACHMENT0_EXT, 0);
+		FBO_AttachImage(tr.screenScratchFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT_EXT, 0);
+		R_CheckFBO(tr.screenScratchFbo);
+	}
+
+	if (tr.sunRaysImage)
 	{
 		tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height);
 		FBO_AttachImage(tr.sunRaysFbo, tr.sunRaysImage, GL_COLOR_ATTACHMENT0_EXT, 0);
@@ -332,7 +340,7 @@ void FBO_Init(void)
 
 	if (tr.sunShadowDepthImage[0])
 	{
-		for ( i = 0; i < 4; i++)
+		for (i = 0; i < 4; i++)
 		{
 			tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height);
 			// FIXME: this next line wastes 16mb with 4x1024x1024 sun shadow maps, skip if OpenGL 4.3+ or ARB_framebuffer_no_attachments
@@ -341,44 +349,58 @@ void FBO_Init(void)
 			FBO_AttachImage(tr.sunShadowFbo[i], tr.sunShadowDepthImage[i], GL_DEPTH_ATTACHMENT_EXT, 0);
 			R_CheckFBO(tr.sunShadowFbo[i]);
 		}
+	}
 
+	if (tr.screenShadowImage)
+	{
 		tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height);
 		FBO_AttachImage(tr.screenShadowFbo, tr.screenShadowImage, GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.screenShadowFbo);
 	}
 
-	for (i = 0; i < 2; i++)
+	if (tr.textureScratchImage[0])
 	{
-		tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height);
-		FBO_AttachImage(tr.textureScratchFbo[i], tr.textureScratchImage[i], GL_COLOR_ATTACHMENT0_EXT, 0);
-		R_CheckFBO(tr.textureScratchFbo[i]);
+		for (i = 0; i < 2; i++)
+		{
+			tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height);
+			FBO_AttachImage(tr.textureScratchFbo[i], tr.textureScratchImage[i], GL_COLOR_ATTACHMENT0_EXT, 0);
+			R_CheckFBO(tr.textureScratchFbo[i]);
+		}
 	}
 
+	if (tr.calcLevelsImage)
 	{
 		tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height);
 		FBO_AttachImage(tr.calcLevelsFbo, tr.calcLevelsImage, GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.calcLevelsFbo);
 	}
 
+	if (tr.targetLevelsImage)
 	{
 		tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height);
 		FBO_AttachImage(tr.targetLevelsFbo, tr.targetLevelsImage, GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.targetLevelsFbo);
 	}
 
-	for (i = 0; i < 2; i++)
+	if (tr.quarterImage[0])
 	{
-		tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height);
-		FBO_AttachImage(tr.quarterFbo[i], tr.quarterImage[i], GL_COLOR_ATTACHMENT0_EXT, 0);
-		R_CheckFBO(tr.quarterFbo[i]);
+		for (i = 0; i < 2; i++)
+		{
+			tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height);
+			FBO_AttachImage(tr.quarterFbo[i], tr.quarterImage[i], GL_COLOR_ATTACHMENT0_EXT, 0);
+			R_CheckFBO(tr.quarterFbo[i]);
+		}
 	}
 
-	if (r_ssao->integer)
+	if (tr.hdrDepthImage)
 	{
 		tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height);
 		FBO_AttachImage(tr.hdrDepthFbo, tr.hdrDepthImage, GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.hdrDepthFbo);
+	}
 
+	if (tr.screenSsaoImage)
+	{
 		tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height);
 		FBO_AttachImage(tr.screenSsaoFbo, tr.screenSsaoImage, GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.screenSsaoFbo);
diff --git a/SP/code/rend2/tr_glsl.c b/SP/code/rend2/tr_glsl.c
index 9cfa025..b9b73e2 100644
--- a/SP/code/rend2/tr_glsl.c
+++ b/SP/code/rend2/tr_glsl.c
@@ -1075,6 +1075,23 @@ void GLSL_InitGPUShaders(void)
 
 			if (r_cubeMapping->integer)
 				Q_strcat(extradefines, 1024, "#define USE_CUBEMAP\n");
+
+			switch (r_glossType->integer)
+			{
+				case 0:
+				default:
+					Q_strcat(extradefines, 1024, "#define GLOSS_IS_GLOSS\n");
+					break;
+				case 1:
+					Q_strcat(extradefines, 1024, "#define GLOSS_IS_SMOOTHNESS\n");
+					break;
+				case 2:
+					Q_strcat(extradefines, 1024, "#define GLOSS_IS_ROUGHNESS\n");
+					break;
+				case 3:
+					Q_strcat(extradefines, 1024, "#define GLOSS_IS_SHININESS\n");
+					break;
+			}
 		}
 
 		if (i & LIGHTDEF_USE_SHADOWMAP)
diff --git a/SP/code/rend2/tr_image.c b/SP/code/rend2/tr_image.c
index f2eaaab..65a4f92 100644
--- a/SP/code/rend2/tr_image.c
+++ b/SP/code/rend2/tr_image.c
@@ -2936,6 +2936,12 @@ void R_CreateBuiltinImages( void ) {
 
 		tr.renderImage = R_CreateImage("_render", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat);
 
+		if (r_shadowBlur->integer)
+			tr.screenScratchImage = R_CreateImage("screenScratch", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat);
+
+		if (r_shadowBlur->integer || r_ssao->integer)
+			tr.hdrDepthImage = R_CreateImage("*hdrDepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_INTENSITY32F_ARB);
+
 		if (r_drawSunRays->integer)
 			tr.sunRaysImage = R_CreateImage("*sunRays", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat);
 
@@ -2983,7 +2989,6 @@ void R_CreateBuiltinImages( void ) {
 		if (r_ssao->integer)
 		{
 			tr.screenSsaoImage = R_CreateImage("*screenSsao", NULL, width / 2, height / 2, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8);
-			tr.hdrDepthImage = R_CreateImage("*hdrDepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_INTENSITY32F_ARB);
 		}
 
 		if (r_shadows->integer == 4)
diff --git a/SP/code/rend2/tr_init.c b/SP/code/rend2/tr_init.c
index b485415..d338fd1 100644
--- a/SP/code/rend2/tr_init.c
+++ b/SP/code/rend2/tr_init.c
@@ -171,6 +171,7 @@ cvar_t  *r_baseNormalY;
 cvar_t  *r_baseParallax;
 cvar_t  *r_baseSpecular;
 cvar_t  *r_baseGloss;
+cvar_t  *r_glossType;
 cvar_t  *r_mergeLightmaps;
 cvar_t  *r_dlightMode;
 cvar_t  *r_pshadowDist;
@@ -186,6 +187,7 @@ cvar_t  *r_sunlightMode;
 cvar_t  *r_drawSunRays;
 cvar_t  *r_sunShadows;
 cvar_t  *r_shadowFilter;
+cvar_t  *r_shadowBlur;
 cvar_t  *r_shadowMapSize;
 cvar_t  *r_shadowCascadeZNear;
 cvar_t  *r_shadowCascadeZFar;
@@ -1368,6 +1370,7 @@ void R_Register( void ) {
 	r_baseParallax = ri.Cvar_Get( "r_baseParallax", "0.05", CVAR_ARCHIVE | CVAR_LATCH );
 	r_baseSpecular = ri.Cvar_Get( "r_baseSpecular", "0.04", CVAR_ARCHIVE | CVAR_LATCH );
 	r_baseGloss = ri.Cvar_Get( "r_baseGloss", "0.1", CVAR_ARCHIVE | CVAR_LATCH );
+	r_glossType = ri.Cvar_Get("r_glossType", "1", CVAR_ARCHIVE | CVAR_LATCH);
 	r_dlightMode = ri.Cvar_Get( "r_dlightMode", "0", CVAR_ARCHIVE | CVAR_LATCH );
 	r_pshadowDist = ri.Cvar_Get( "r_pshadowDist", "128", CVAR_ARCHIVE );
 	r_mergeLightmaps = ri.Cvar_Get( "r_mergeLightmaps", "1", CVAR_ARCHIVE | CVAR_LATCH );
@@ -1385,7 +1388,8 @@ void R_Register( void ) {
 
 	r_sunShadows = ri.Cvar_Get( "r_sunShadows", "1", CVAR_ARCHIVE | CVAR_LATCH );
 	r_shadowFilter = ri.Cvar_Get( "r_shadowFilter", "1", CVAR_ARCHIVE | CVAR_LATCH );
-	r_shadowMapSize = ri.Cvar_Get( "r_shadowMapSize", "1024", CVAR_ARCHIVE | CVAR_LATCH );
+	r_shadowBlur = ri.Cvar_Get("r_shadowBlur", "0", CVAR_ARCHIVE | CVAR_LATCH);
+	r_shadowMapSize = ri.Cvar_Get("r_shadowMapSize", "1024", CVAR_ARCHIVE | CVAR_LATCH);
 	r_shadowCascadeZNear = ri.Cvar_Get( "r_shadowCascadeZNear", "8", CVAR_ARCHIVE | CVAR_LATCH );
 	r_shadowCascadeZFar = ri.Cvar_Get( "r_shadowCascadeZFar", "1024", CVAR_ARCHIVE | CVAR_LATCH );
 	r_shadowCascadeZBias = ri.Cvar_Get( "r_shadowCascadeZBias", "0", CVAR_ARCHIVE | CVAR_LATCH );
diff --git a/SP/code/rend2/tr_local.h b/SP/code/rend2/tr_local.h
index 554427c..759df11 100644
--- a/SP/code/rend2/tr_local.h
+++ b/SP/code/rend2/tr_local.h
@@ -1664,6 +1664,7 @@ typedef struct {
 	image_t					*sunRaysImage;
 	image_t					*renderDepthImage;
 	image_t					*pshadowMaps[MAX_DRAWN_PSHADOWS];
+	image_t					*screenScratchImage;
 	image_t					*textureScratchImage[2];
 	image_t                 *quarterImage[2];
 	image_t					*calcLevelsImage;
@@ -1682,6 +1683,7 @@ typedef struct {
 	FBO_t					*sunRaysFbo;
 	FBO_t					*depthFbo;
 	FBO_t					*pshadowFbos[MAX_DRAWN_PSHADOWS];
+	FBO_t					*screenScratchFbo;
 	FBO_t					*textureScratchFbo[2];
 	FBO_t                   *quarterFbo[2];
 	FBO_t					*calcLevelsFbo;
@@ -2010,6 +2012,7 @@ extern  cvar_t  *r_baseNormalY;
 extern  cvar_t  *r_baseParallax;
 extern  cvar_t  *r_baseSpecular;
 extern  cvar_t  *r_baseGloss;
+extern  cvar_t  *r_glossType;
 extern  cvar_t  *r_dlightMode;
 extern  cvar_t  *r_pshadowDist;
 extern  cvar_t  *r_mergeLightmaps;
@@ -2025,6 +2028,7 @@ extern  cvar_t  *r_sunlightMode;
 extern  cvar_t  *r_drawSunRays;
 extern  cvar_t  *r_sunShadows;
 extern  cvar_t  *r_shadowFilter;
+extern  cvar_t  *r_shadowBlur;
 extern  cvar_t  *r_shadowMapSize;
 extern  cvar_t  *r_shadowCascadeZNear;
 extern  cvar_t  *r_shadowCascadeZFar;

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/iortcw.git



More information about the Pkg-games-commits mailing list