diff --git a/src/g_game.c b/src/g_game.c
index a7ad1e68d73c4736a4e0a384883e875ef100572a..bf0557d02f0b4cd7ab4a7f423eefbd006ca3bdc6 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -1871,7 +1871,7 @@ boolean G_Responder(event_t *ev)
 
 	// allow spy mode changes even during the demo
 	if (gamestate == GS_LEVEL && ev->type == ev_keydown
-		&& (ev->data1 == KEY_F12 || ev->data1 == gamecontrol[gc_viewpoint][0] || ev->data1 == gamecontrol[gc_viewpoint][1]) && !demo.freecam)
+		&& (ev->data1 == KEY_F12 || ev->data1 == gamecontrol[gc_viewpoint][0] || ev->data1 == gamecontrol[gc_viewpoint][1]))
 	{
 		if (!demo.playback && (splitscreen || !netgame))
 			displayplayers[0] = consoleplayer;
diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h
index 129daa002dfad2ee94c732277b45b5f34aaa7afe..af545191a7382ba00da495d83673ad982ef1022f 100644
--- a/src/hardware/hw_defs.h
+++ b/src/hardware/hw_defs.h
@@ -223,6 +223,8 @@ typedef struct GLMipmap_s FTextureInfo;
 struct FLightInfo
 {
 	FUINT			light_level;
+	FUINT			fade_start;
+	FUINT			fade_end;
 };
 typedef struct FLightInfo FLightInfo;
 
@@ -241,9 +243,6 @@ enum hwdsetspecialstate
 {
 	HWD_SET_SHADERS,
 
-	HWD_SET_FOG_MODE,
-	HWD_SET_FOG_DENSITY,
-
 	HWD_SET_TEXTUREFILTERMODE,
 	HWD_SET_TEXTUREANISOTROPICMODE,
 
@@ -251,8 +250,8 @@ enum hwdsetspecialstate
 };
 typedef enum hwdsetspecialstate hwdspecialstate_t;
 
-#define GL_NORMALFOG 0x00000000
-#define GL_FADEFOG 0x19000000
+#define GL_DEFAULTMIX 0x00000000
+#define GL_DEFAULTFOG 0xFF000000
 
 enum hwdfiltermode
 {
diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h
index f19c1fae8b81801fef315e6e02f5b322f5453b24..bf8eb40f3632dca565c6ca50f4cb13ff7efd17de 100644
--- a/src/hardware/hw_drv.h
+++ b/src/hardware/hw_drv.h
@@ -74,11 +74,9 @@ EXPORT void HWRAPI(UnSetShader) (void);
 EXPORT void HWRAPI(LoadCustomShader) (int number, char *shader, size_t size, boolean fragment);
 EXPORT void HWRAPI(InitCustomShaders) (void);
 
-
 EXPORT void HWRAPI(StartBatching) (void);
 EXPORT void HWRAPI(RenderBatches) (int *sNumPolys, int *sNumVerts, int *sNumCalls, int *sNumShaders, int *sNumTextures, int *sNumPolyFlags, int *sNumColors);
 
-
 // ==========================================================================
 //                                      HWR DRIVER OBJECT, FOR CLIENT PROGRAM
 // ==========================================================================
diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h
index b3f058c4929a055ebfdd42dc432517031908be48..3d03e7fa1b0805fa008d39e1f22f24cf55c1e547 100644
--- a/src/hardware/hw_glob.h
+++ b/src/hardware/hw_glob.h
@@ -47,9 +47,6 @@ GLPatch_t *HWR_GetCachedGLPatchPwad(UINT16 wad, UINT16 lump);
 GLPatch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum);
 void HWR_GetFadeMask(lumpnum_t fademasklumpnum);
 
-// hardware driver
-extern INT32 gl_leveltime;
-
 // --------
 // hw_draw.c
 // --------
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index ee87be60eaa122372d97cebdf45ac0a80bc31262..20861b008c7f2a2079e4716526b1ea9cd82512f3 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -139,160 +139,126 @@ static INT32 drawcount = 0;
 // Lighting
 // ==========================================================================
 
-#define CALCLIGHT(x,y) ((float)(x)*((y)/255.0f))
-
-void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, UINT32 mixcolor, UINT32 fadecolor)
+void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap)
 {
-	if (!cv_grshaders.value || (cv_grshaders.value && !cv_grfog.value) || !gr_shadersavailable)
-	{
-		RGBA_t mix_color, fog_color, final_color;
-		INT32 mix;
-		float fog_alpha;
-	float red, green, blue;
+	RGBA_t poly_color, tint_color, fade_color;
 
-		mix_color.rgba = mixcolor;
-		fog_color.rgba = fadecolor;
+	poly_color.rgba = 0xFFFFFFFF;
+	tint_color.rgba = (colormap != NULL) ? (UINT32)colormap->rgba : GL_DEFAULTMIX;
+	fade_color.rgba = (colormap != NULL) ? (UINT32)colormap->fadergba : GL_DEFAULTFOG;
 
-		mix = mix_color.s.alpha*10/5;
-		if (mix > 25) mix = 25;
-		mix *= 255;
-		mix /= 25;
+	// Crappy backup coloring if you can't do shaders
+	if (!(cv_grshaders.value && gr_shadersavailable))
+	{
+		// be careful, this may get negative for high lightlevel values.
+		float tint_alpha, fade_alpha;
+		float red, green, blue;
 
-		// Modulate the colors by alpha.
-		mix_color.s.red = (UINT8)(CALCLIGHT(mix,mix_color.s.red));
-		mix_color.s.green = (UINT8)(CALCLIGHT(mix,mix_color.s.green));
-		mix_color.s.blue = (UINT8)(CALCLIGHT(mix,mix_color.s.blue));
+		red = (float)poly_color.s.red;
+		green = (float)poly_color.s.green;
+		blue = (float)poly_color.s.blue;
 
-		// Set the surface colors and further modulate the colors by light.
-		final_color.s.red = (UINT8)(CALCLIGHT((0xFF-mix),0xFF)+CALCLIGHT(mix_color.s.red,0xFF));
-		final_color.s.green = (UINT8)(CALCLIGHT((0xFF-mix),0xFF)+CALCLIGHT(mix_color.s.green,0xFF));
-		final_color.s.blue = (UINT8)(CALCLIGHT((0xFF-mix),0xFF)+CALCLIGHT(mix_color.s.blue,0xFF));
-		final_color.s.alpha = 0xFF;
+		// 48 is just an arbritrary value that looked relatively okay.
+		tint_alpha = (float)(sqrt(tint_color.s.alpha) * 48) / 255.0f;
 
-		// Fog.
-		fog_alpha = (0xFF - fog_color.s.alpha) / 255.0f;
+		// 8 is roughly the brightness of the "close" color in Software, and 16 the brightness of the "far" color.
+		// 8 is too bright for dark levels, and 16 is too dark for bright levels.
+		// 12 is the compromise value. It doesn't look especially good anywhere, but it's the most balanced.
+		// (Also, as far as I can tell, fade_color's alpha is actually not used in Software, so we only use light level.)
+		fade_alpha = (float)(sqrt(255-light_level) * 12) / 255.0f;
 
-		// Set the surface colors and further modulate the colors by light.
-		fog_color.s.red = (UINT8)(((float)fog_color.s.red) * fog_alpha);
-		fog_color.s.green = (UINT8)(((float)fog_color.s.green) * fog_alpha);
-		fog_color.s.blue = (UINT8)(((float)fog_color.s.blue) * fog_alpha);
+		// Clamp the alpha values
+		tint_alpha = min(max(tint_alpha, 0.0f), 1.0f);
+		fade_alpha = min(max(fade_alpha, 0.0f), 1.0f);
 
-		if (cv_grfog.value)
-		{
-			// be careful, this may get negative for high lightlevel values.
-			float fog = (fog_alpha - (light_level/255.0f))*3/2;
-			if (fog < 0)
-				fog = 0;
-
-			red = ((fog_color.s.red/255.0f) * fog) + ((final_color.s.red/255.0f) * (1.0f - fog));
-			green = ((fog_color.s.green/255.0f) * fog) + ((final_color.s.green/255.0f) * (1.0f - fog));
-			blue = ((fog_color.s.blue/255.0f) * fog) + ((final_color.s.blue/255.0f) * (1.0f - fog));
-			final_color.s.red = (UINT8)(red*255.0f);
-			final_color.s.green = (UINT8)(green*255.0f);
-			final_color.s.blue = (UINT8)(blue*255.0f);
-		}
+		red = (tint_color.s.red * tint_alpha) + (red * (1.0f - tint_alpha));
+		green = (tint_color.s.green * tint_alpha) + (green * (1.0f - tint_alpha));
+		blue = (tint_color.s.blue * tint_alpha) + (blue * (1.0f - tint_alpha));
 
-		Surface->PolyColor.rgba = final_color.rgba;
-		Surface->FadeColor.rgba = fog_color.rgba;
-		Surface->LightInfo.light_level = light_level;
-	}
-	else
-	{
-		Surface->PolyColor.rgba = 0xFFFFFFFF;
-		Surface->TintColor.rgba = mixcolor;
-		Surface->FadeColor.rgba = fadecolor;
-		Surface->LightInfo.light_level = light_level;
+		red = (fade_color.s.red * fade_alpha) + (red * (1.0f - fade_alpha));
+		green = (fade_color.s.green * fade_alpha) + (green * (1.0f - fade_alpha));
+		blue = (fade_color.s.blue * fade_alpha) + (blue * (1.0f - fade_alpha));
+
+		poly_color.s.red = (UINT8)red;
+		poly_color.s.green = (UINT8)green;
+		poly_color.s.blue = (UINT8)blue;
 	}
+
+	Surface->PolyColor.rgba = poly_color.rgba;
+	Surface->TintColor.rgba = tint_color.rgba;
+	Surface->FadeColor.rgba = fade_color.rgba;
+	Surface->LightInfo.light_level = light_level;
+	Surface->LightInfo.fade_start = (colormap != NULL) ? colormap->fadestart : 0;
+	Surface->LightInfo.fade_end = (colormap != NULL) ? colormap->fadeend : 31;
 }
 
-void HWR_NoColormapLighting(FSurfaceInfo *Surface, INT32 light_level, UINT32 mixcolor, UINT32 fadecolor)
+UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if this can work
 {
-	if (!cv_grshaders.value || (cv_grshaders.value && !cv_grfog.value) || !gr_shadersavailable)
-	{
-		RGBA_t mix_color, fog_color, final_color;
-		INT32 mix, fogmix, lightmix;
-		float fog_alpha;
+	RGBA_t realcolor, surfcolor;
+	INT32 alpha;
+
+	realcolor.rgba = (colormap != NULL) ? colormap->rgba : GL_DEFAULTMIX;
 
-		// You see the problem is that darker light isn't actually as dark as it SHOULD be.
-		lightmix = 255 - ((255 - light_level)*10/7);
+	if (!(cv_grshaders.value && gr_shadersavailable))
+	{
+		light = light - (255 - light);
 
 		// Don't go out of bounds
-		if (lightmix < 0)
-			lightmix = 0;
-		else if (lightmix > 255)
-			lightmix = 255;
-
-		mix_color.rgba = mixcolor;
-		fog_color.rgba = fadecolor;
-
-		mix = (mix_color.s.alpha*255)/25;
-		fogmix = (fog_color.s.alpha*255)/25;
-
-		// Modulate the colors by alpha.
-		mix_color.s.red = (UINT8)(CALCLIGHT(mix,mix_color.s.red));
-		mix_color.s.green = (UINT8)(CALCLIGHT(mix,mix_color.s.green));
-		mix_color.s.blue = (UINT8)(CALCLIGHT(mix,mix_color.s.blue));
-
-		// Set the surface colors and further modulate the colors by light.
-		final_color.s.red = (UINT8)(CALCLIGHT((0xFF-mix),lightmix)+CALCLIGHT(mix_color.s.red,lightmix));
-		final_color.s.green = (UINT8)(CALCLIGHT((0xFF-mix),lightmix)+CALCLIGHT(mix_color.s.green,lightmix));
-		final_color.s.blue = (UINT8)(CALCLIGHT((0xFF-mix),lightmix)+CALCLIGHT(mix_color.s.blue,lightmix));
-
-		// Modulate the colors by alpha.
-		fog_color.s.red = (UINT8)(CALCLIGHT(fogmix,fog_color.s.red));
-		fog_color.s.green = (UINT8)(CALCLIGHT(fogmix,fog_color.s.green));
-		fog_color.s.blue = (UINT8)(CALCLIGHT(fogmix,fog_color.s.blue));
-
-		// Set the surface colors and further modulate the colors by light.
-		final_color.s.red = final_color.s.red+((UINT8)(CALCLIGHT((0xFF-fogmix),(0xFF-lightmix))+CALCLIGHT(fog_color.s.red,(0xFF-lightmix))));
-		final_color.s.green = final_color.s.green+((UINT8)(CALCLIGHT((0xFF-fogmix),(0xFF-lightmix))+CALCLIGHT(fog_color.s.green,(0xFF-lightmix))));
-		final_color.s.blue = final_color.s.blue+((UINT8)(CALCLIGHT((0xFF-fogmix),(0xFF-lightmix))+CALCLIGHT(fog_color.s.blue,(0xFF-lightmix))));
-		final_color.s.alpha = 0xFF;
-
-		// Fog.
-		fog_color.rgba = fadecolor;
-		fog_alpha = (0xFF - fog_color.s.alpha*10/7) / 255.0f;
-
-		// Set the surface colors and further modulate the colors by light.
-		fog_color.s.red = (UINT8)(((float)fog_color.s.red) * fog_alpha);
-		fog_color.s.green = (UINT8)(((float)fog_color.s.green) * fog_alpha);
-		fog_color.s.blue = (UINT8)(((float)fog_color.s.blue) * fog_alpha);
-
-		Surface->PolyColor.rgba = final_color.rgba;
-		Surface->FadeColor.rgba = fog_color.rgba;
-		Surface->LightInfo.light_level = lightmix;
+		if (light < 0)
+			light = 0;
+		else if (light > 255)
+			light = 255;
+
+		alpha = (realcolor.s.alpha*255)/25;
+
+		// at 255 brightness, alpha is between 0 and 127, at 0 brightness alpha will always be 255
+		surfcolor.s.alpha = (alpha*light) / (2*256) + 255-light;
 	}
 	else
 	{
-		Surface->PolyColor.rgba = 0xFFFFFFFF;
-		Surface->TintColor.rgba = mixcolor;
-		Surface->FadeColor.rgba = fadecolor;
-		Surface->LightInfo.light_level = light_level;
+		surfcolor.s.alpha = (255 - light);
 	}
+
+	return surfcolor.s.alpha;
 }
 
-UINT8 HWR_FogBlockAlpha(INT32 light, UINT32 color) // Let's see if this can work
+static FUINT HWR_CalcWallLight(FUINT lightnum, fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y)
 {
-	RGBA_t realcolor, surfcolor;
-	INT32 alpha;
-
-	// You see the problem is that darker light isn't actually as dark as it SHOULD be.
-	light = light - ((255 - light)*24/22);
+	INT16 finallight = lightnum;
 
-	// Don't go out of bounds
-	if (light < 0)
-		light = 0;
-	else if (light > 255)
-		light = 255;
+	if (cv_grfakecontrast.value != 0)
+	{
+		const UINT8 contrast = 8;
+		fixed_t extralight = 0;
 
-	realcolor.rgba = color;
+		if (cv_grfakecontrast.value == 2) // Smooth setting
+		{
+			extralight = (-(contrast<<FRACBITS) +
+			FixedDiv(AngleFixed(R_PointToAngle2(0, 0,
+				abs(v1x - v2x),
+				abs(v1y - v2y))), 90<<FRACBITS)
+			* (contrast * 2)) >> FRACBITS;
+		}
+		else
+		{
+			if (v1y == v2y)
+				extralight = -contrast;
+			else if (v1x == v2x)
+				extralight = contrast;
+		}
 
-	alpha = (realcolor.s.alpha*255)/25;
+		if (extralight != 0)
+		{
+			finallight += extralight;
 
-	// at 255 brightness, alpha is between 0 and 127, at 0 brightness alpha will always be 255
-	surfcolor.s.alpha = (alpha*light)/(2*256)+255-light;
+			if (finallight < 0)
+				finallight = 0;
+			if (finallight > 255)
+				finallight = 255;
+		}
+	}
 
-	return surfcolor.s.alpha;
+	return (FUINT)finallight;
 }
 
 // ==========================================================================
@@ -492,10 +458,7 @@ void HWR_RenderPlane(extrasubsector_t *xsub, boolean isceiling, fixed_t fixedhei
 #endif
 	}
 
-	if (planecolormap)
-		HWR_Lighting(&Surf, lightlevel, planecolormap->rgba, planecolormap->fadergba);
-	else
-		HWR_NoColormapLighting(&Surf, lightlevel, GL_NORMALFOG, GL_FADEFOG);
+	HWR_Lighting(&Surf, lightlevel, planecolormap);
 
 	if (PolyFlags & (PF_Translucent|PF_Fog))
 	{
@@ -607,10 +570,7 @@ FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf)
 //
 void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blendmode, INT32 lightlevel, extracolormap_t *wallcolormap)
 {
-	if (wallcolormap)
-		HWR_Lighting(pSurf, lightlevel, wallcolormap->rgba, wallcolormap->fadergba);
-	else
-		HWR_NoColormapLighting(pSurf, lightlevel, GL_NORMALFOG, GL_FADEFOG);
+	HWR_Lighting(pSurf, lightlevel, wallcolormap);
 
 	HWD.pfnSetShader(2);	// wall shader
 	HWD.pfnDrawPolygon(pSurf, wallVerts, 4, blendmode|PF_Modulated|PF_Occlude);
@@ -651,7 +611,7 @@ void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfa
 	INT32   solid, i;
 	lightlist_t *  list = sector->lightlist;
 	const UINT8 alpha = Surf->PolyColor.s.alpha;
-	FUINT lightnum = sector->lightlevel;
+	FUINT lightnum = HWR_CalcWallLight(sector->lightlevel, v1x, v1y, v2x, v2y);
 	extracolormap_t *colormap = NULL;
 
 	realtop = top = wallVerts[3].y;
@@ -680,12 +640,12 @@ void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfa
 		{
 			if (pfloor && (pfloor->flags & FF_FOG))
 			{
-				lightnum = pfloor->master->frontsector->lightlevel;
+				lightnum = HWR_CalcWallLight(pfloor->master->frontsector->lightlevel, v1x, v1y, v2x, v2y);
 				colormap = pfloor->master->frontsector->extra_colormap;
 			}
 			else
 			{
-				lightnum = *list[i].lightlevel;
+				lightnum = HWR_CalcWallLight(*list[i].lightlevel, v1x, v1y, v2x, v2y);
 				colormap = list[i].extra_colormap;
 			}
 		}
@@ -966,7 +926,7 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 		cliphigh = (float)(texturehpeg + (gr_curline->flength*FRACUNIT));
 	}
 
-	lightnum = gr_frontsector->lightlevel;
+	lightnum = HWR_CalcWallLight(gr_frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
 	colormap = gr_frontsector->extra_colormap;
 
 	if (gr_frontsector)
@@ -1791,13 +1751,10 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 
 					blendmode = PF_Fog|PF_NoTexture;
 
-					lightnum = rover->master->frontsector->lightlevel;
+					lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
 					colormap = rover->master->frontsector->extra_colormap;
 
-					if (rover->master->frontsector->extra_colormap)
-						Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,rover->master->frontsector->extra_colormap->rgba);
-					else
-						Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,GL_NORMALFOG);
+					Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap);
 
 					if (gr_frontsector->numlights)
 						HWR_SplitWall(gr_frontsector, wallVerts, 0, &Surf, rover->flags, rover);
@@ -1906,13 +1863,10 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 
 					blendmode = PF_Fog|PF_NoTexture;
 
-					lightnum = rover->master->frontsector->lightlevel;
+					lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
 					colormap = rover->master->frontsector->extra_colormap;
 
-					if (rover->master->frontsector->extra_colormap)
-						Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,rover->master->frontsector->extra_colormap->rgba);
-					else
-						Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,GL_NORMALFOG);
+					Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap);
 
 					if (gr_backsector->numlights)
 						HWR_SplitWall(gr_backsector, wallVerts, 0, &Surf, rover->flags, rover);
@@ -2339,10 +2293,7 @@ void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t
 		v3d->z = FIXED_TO_FLOAT(polysector->vertices[i]->y);
 	}
 
-	if (planecolormap)
-		HWR_Lighting(&Surf, lightlevel, planecolormap->rgba, planecolormap->fadergba);
-	else
-		HWR_NoColormapLighting(&Surf, lightlevel, GL_NORMALFOG, GL_FADEFOG);
+	HWR_Lighting(&Surf, lightlevel, planecolormap);
 
 	if (blendmode & PF_Translucent)
 	{
@@ -2607,10 +2558,7 @@ void HWR_Subsector(size_t num)
 
 					light = R_GetPlaneLight(gr_frontsector, centerHeight, viewz < cullHeight ? true : false);
 
-					if (rover->master->frontsector->extra_colormap)
-						alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap->rgba);
-					else
-						alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, GL_NORMALFOG);
+					alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap);
 
 					HWR_AddTransparentFloor(0,
 					                       &extrasubsectors[num],
@@ -2662,10 +2610,7 @@ void HWR_Subsector(size_t num)
 
 					light = R_GetPlaneLight(gr_frontsector, centerHeight, viewz < cullHeight ? true : false);
 
-					if (rover->master->frontsector->extra_colormap)
-						alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap->rgba);
-					else
-						alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, GL_NORMALFOG);
+					alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap);
 
 					HWR_AddTransparentFloor(0,
 					                       &extrasubsectors[num],
@@ -3381,10 +3326,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
 		}
 #endif
 
-		if (colormap)
-			HWR_Lighting(&Surf, lightlevel, colormap->rgba, colormap->fadergba);
-		else
-			HWR_NoColormapLighting(&Surf, lightlevel, GL_NORMALFOG, GL_FADEFOG);
+		HWR_Lighting(&Surf, lightlevel, colormap);
 
 		Surf.PolyColor.s.alpha = alpha;
 
@@ -3424,10 +3366,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
 	wallVerts[0].y = wallVerts[1].y = bot;
 #endif
 
-	if (colormap)
-		HWR_Lighting(&Surf, lightlevel, colormap->rgba, colormap->fadergba);
-	else
-		HWR_NoColormapLighting(&Surf, lightlevel, GL_NORMALFOG, GL_FADEFOG);
+	HWR_Lighting(&Surf, lightlevel, colormap);
 
 	Surf.PolyColor.s.alpha = alpha;
 
@@ -3559,10 +3498,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
 		if (!(spr->mobj->frame & FF_FULLBRIGHT))
 			lightlevel = sector->lightlevel;
 
-		if (colormap)
-			HWR_Lighting(&Surf, lightlevel, colormap->rgba, colormap->fadergba);
-		else
-			HWR_NoColormapLighting(&Surf, lightlevel, GL_NORMALFOG, GL_FADEFOG);
+		HWR_Lighting(&Surf, lightlevel, colormap);
 	}
 
 	{
@@ -3668,10 +3604,7 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
 				colormap = sector->extra_colormap;
 		}
 
-		if (colormap)
-			HWR_Lighting(&Surf, lightlevel, colormap->rgba, colormap->fadergba);
-		else
-			HWR_NoColormapLighting(&Surf, lightlevel, GL_NORMALFOG, GL_FADEFOG);
+		HWR_Lighting(&Surf, lightlevel, colormap);
 	}
 
 	if (spr->mobj->flags2 & MF2_SHADOW)
@@ -4540,11 +4473,11 @@ static boolean drewsky = false;
 
 void HWR_DrawSkyBackground(float fpov)
 {
+	FTransform dometransform;
+
 	if (drewsky)
 		return;
 
-	FTransform dometransform;
-
 	memset(&dometransform, 0x00, sizeof(FTransform));
 
 	//04/01/2000: Hurdler: added for T&L
@@ -4647,7 +4580,6 @@ void HWR_RenderFrame(INT32 viewnumber, player_t *player, boolean skybox)
 		gr_windowcenterx += gr_viewwidth;
 	}
 
-
 	// check for new console commands.
 	NetUpdate();
 
@@ -4726,12 +4658,6 @@ void HWR_RenderFrame(INT32 viewnumber, player_t *player, boolean skybox)
 	HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_grshaders.value);
 	HWD.pfnSetShader(0);
 
-	// Check if fog is enabled.
-	if (cv_grfog.value)
-		HWR_FoggingOn(); // First of all, turn it on, set the default user settings too
-	else
-		HWD.pfnSetSpecialState(HWD_SET_FOG_MODE, 0); // Turn it off
-
 	if (cv_grbatching.value)
 		HWD.pfnStartBatching();
 
@@ -4763,10 +4689,6 @@ void HWR_RenderFrame(INT32 viewnumber, player_t *player, boolean skybox)
 	HWD.pfnSetTransform(NULL);
 	HWD.pfnUnSetShader();
 
-	// Disable fog
-	if (cv_grfog.value)
-		HWD.pfnSetSpecialState(HWD_SET_FOG_MODE, 0);
-
 	// Run post processor effects
 	if (!skybox)
 		HWR_DoPostProcessor(player);
@@ -4785,14 +4707,17 @@ void HWR_RenderFrame(INT32 viewnumber, player_t *player, boolean skybox)
 void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
 {
 	const boolean skybox = (skyboxmo[0] && cv_skybox.value); // True if there's a skybox object and skyboxes are on
+
 	// Clear the color buffer, stops HOMs. Also seems to fix the skybox issue on Intel GPUs.
 	if (viewnumber == 0) // Only do it if it's the first screen being rendered
 	{
 		FRGBAFloat ClearColor;
+
 		ClearColor.red = 0.0f;
 		ClearColor.green = 0.0f;
 		ClearColor.blue = 0.0f;
 		ClearColor.alpha = 1.0f;
+
 		HWD.pfnClearBuffer(true, false, &ClearColor);
 	}
 
@@ -4811,16 +4736,6 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
 	HWR_RenderFrame(viewnumber, player, false);
 }
 
-// ==========================================================================
-//                                                                        FOG
-// ==========================================================================
-
-void HWR_FoggingOn(void)
-{
-	HWD.pfnSetSpecialState(HWD_SET_FOG_MODE, 1);
-	HWD.pfnSetSpecialState(HWD_SET_FOG_DENSITY, cv_grfogdensity.value);
-}
-
 // ==========================================================================
 //                                                         3D ENGINE COMMANDS
 // ==========================================================================
@@ -4918,10 +4833,7 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend,
 	UINT8 alpha = pSurf->PolyColor.s.alpha; // retain the alpha
 
 	// Lighting is done here instead so that fog isn't drawn incorrectly on transparent walls after sorting
-	if (wallcolormap)
-		HWR_Lighting(pSurf, lightlevel, wallcolormap->rgba, wallcolormap->fadergba);
-	else
-		HWR_NoColormapLighting(pSurf, lightlevel, GL_NORMALFOG, GL_FADEFOG);
+	HWR_Lighting(pSurf, lightlevel, wallcolormap);
 
 	pSurf->PolyColor.s.alpha = alpha; // put the alpha back after lighting
 
diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h
index b0985fbb9cbf924874e0f8b3f4d398e94f0798ca..bc4a74e5f6a852f873cf5e259123c3a5e4dfc3c4 100644
--- a/src/hardware/hw_main.h
+++ b/src/hardware/hw_main.h
@@ -69,11 +69,8 @@ void HWR_AddCommands(void);
 // into files like hw_bsp.c, hw_sprites.c...
 
 // hw_main.c: Lighting and fog
-void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, UINT32 mixcolor, UINT32 fadecolor);
-void HWR_NoColormapLighting(FSurfaceInfo *Surface, INT32 light_level, UINT32 mixcolor, UINT32 fadecolor);
-UINT8 HWR_FogBlockAlpha(INT32 light, UINT32 color); // Let's see if this can work
-
-void HWR_FoggingOn(void);
+void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap);
+UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap); // Let's see if this can work
 
 FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf);
 
@@ -149,6 +146,7 @@ extern consvar_t cv_grcorrecttricks;
 extern consvar_t cv_grfovchange;
 extern consvar_t cv_grsolvetjoin;
 extern consvar_t cv_grspritebillboarding;
+extern consvar_t cv_grfakecontrast;
 extern consvar_t cv_grfallbackplayermodel;
 
 extern CV_PossibleValue_t granisotropicmode_cons_t[];
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 6144e1a846851db00667740cf4c82fd861b2b687..9e77d22bcfb6b420d6d71679cde2a7fbb8eaf4e0 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -659,18 +659,24 @@ spritemd2found:
 // 0.0722 to blue
 // (See this same define in k_kart.c!)
 #define SETBRIGHTNESS(brightness,r,g,b) \
-	brightness = (UINT8)(((1063*((UINT16)r)/5000) + (3576*((UINT16)g)/5000) + (361*((UINT16)b)/5000)) / 3)
+	brightness = (UINT8)(((1063*(UINT16)(r))/5000) + ((3576*(UINT16)(g))/5000) + ((361*(UINT16)(b))/5000))
 
 static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, INT32 skinnum, skincolors_t color)
 {
-	UINT8 i;
 	UINT16 w = gpatch->width, h = gpatch->height;
 	UINT32 size = w*h;
 	RGBA_t *image, *blendimage, *cur, blendcolor;
+	UINT8 translation[16]; // First the color index
+	UINT8 cutoff[16]; // Brightness cutoff before using the next color
+	UINT8 translen = 0;
+	UINT8 i;
+
+	blendcolor = V_GetColor(0); // initialize
+	memset(translation, 0, sizeof(translation));
+	memset(cutoff, 0, sizeof(cutoff));
 
 	if (grmip->width == 0)
 	{
-
 		grmip->width = gpatch->width;
 		grmip->height = gpatch->height;
 
@@ -680,8 +686,11 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
 		grmip->grInfo.format = GR_RGBA;
 	}
 
-	Z_Free(grmip->grInfo.data);
-	grmip->grInfo.data = NULL;
+	if (grmip->grInfo.data)
+	{
+		Z_Free(grmip->grInfo.data);
+		grmip->grInfo.data = NULL;
+	}
 
 	cur = Z_Malloc(size*4, PU_HWRCACHE, &grmip->grInfo.data);
 	memset(cur, 0x00, size*4);
@@ -689,101 +698,285 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
 	image = gpatch->mipmap->grInfo.data;
 	blendimage = blendgpatch->mipmap->grInfo.data;
 
-	// Average all of the translation's colors
+	// TC_METALSONIC includes an actual skincolor translation, on top of its flashing.
+	if (skinnum == TC_METALSONIC)
+		color = SKINCOLOR_BLUEBERRY;
+
+	if (color != SKINCOLOR_NONE)
 	{
-		const UINT8 div = 6;
-		const UINT8 start = 4;
-		UINT32 r, g, b;
+		UINT8 numdupes = 1;
+		UINT8 prevdupes = numdupes;
 
-		blendcolor = V_GetColor(colortranslations[color][start]);
-		r = (UINT32)(blendcolor.s.red*blendcolor.s.red);
-		g = (UINT32)(blendcolor.s.green*blendcolor.s.green);
-		b = (UINT32)(blendcolor.s.blue*blendcolor.s.blue);
+		translation[translen] = colortranslations[color][0];
+		cutoff[translen] = 255;
 
-		for (i = 1; i < div; i++)
+		for (i = 1; i < 16; i++)
 		{
-			RGBA_t nextcolor = V_GetColor(colortranslations[color][start+i]);
-			r += (UINT32)(nextcolor.s.red*nextcolor.s.red);
-			g += (UINT32)(nextcolor.s.green*nextcolor.s.green);
-			b += (UINT32)(nextcolor.s.blue*nextcolor.s.blue);
+			if (translation[translen] == colortranslations[color][i])
+			{
+				numdupes++;
+				continue;
+			}
+
+			if (translen > 0)
+			{
+				INT16 newcutoff = cutoff[translen-1] - (255 / (16 / prevdupes));
+
+				if (newcutoff < 0)
+					newcutoff = 0;
+
+				cutoff[translen] = (UINT8)newcutoff;
+			}
+
+			prevdupes = numdupes;
+			numdupes = 1;
+			translen++;
+
+			translation[translen] = (UINT8)colortranslations[color][i];
 		}
 
-		blendcolor.s.red = (UINT8)(FixedSqrt((r/div)<<FRACBITS)>>FRACBITS);
-		blendcolor.s.green = (UINT8)(FixedSqrt((g/div)<<FRACBITS)>>FRACBITS);
-		blendcolor.s.blue = (UINT8)(FixedSqrt((b/div)<<FRACBITS)>>FRACBITS);
+		translen++;
 	}
 
-	// rainbow support, could theoretically support boss ones too
-	if (skinnum == TC_RAINBOW)
+	while (size--)
 	{
-		while (size--)
+		if (skinnum == TC_BOSS)
+		{
+			// Turn everything below a certain threshold white
+			if ((image->s.red == image->s.green) && (image->s.green == image->s.blue) && image->s.blue < 127)
+			{
+				// Lactozilla: Invert the colors
+				cur->s.red = cur->s.green = cur->s.blue = (255 - image->s.blue);
+			}
+			else
+			{
+				cur->s.red = image->s.red;
+				cur->s.green = image->s.green;
+				cur->s.blue = image->s.blue;
+			}
+
+			cur->s.alpha = image->s.alpha;
+		}
+		else if (skinnum == TC_ALLWHITE)
 		{
-			if (image->s.alpha == 0 && blendimage->s.alpha == 0)
+			// Turn everything white
+			cur->s.red = cur->s.green = cur->s.blue = 255;
+			cur->s.alpha = image->s.alpha;
+		}
+		else
+		{
+			// All settings that use skincolors!
+			UINT16 brightness;
+
+			// Everything below requires a blend image
+			if (blendimage == NULL)
 			{
-				// Don't bother with blending the pixel if the alpha of the blend pixel is 0
 				cur->rgba = image->rgba;
+				goto skippixel;
+			}
+
+			if (translen <= 0)
+			{
+				cur->rgba = image->rgba;
+				goto skippixel;
+			}
+
+			// Don't bother with blending the pixel if the alpha of the blend pixel is 0
+			if (skinnum == TC_RAINBOW)
+			{
+				if (image->s.alpha == 0 && blendimage->s.alpha == 0)
+				{
+					cur->rgba = image->rgba;
+					goto skippixel;
+				}
+				else
+				{
+					UINT16 imagebright, blendbright;
+					SETBRIGHTNESS(imagebright,image->s.red,image->s.green,image->s.blue);
+					SETBRIGHTNESS(blendbright,blendimage->s.red,blendimage->s.green,blendimage->s.blue);
+					// slightly dumb average between the blend image color and base image colour, usually one or the other will be fully opaque anyway
+					brightness = (imagebright*(255-blendimage->s.alpha))/255 + (blendbright*blendimage->s.alpha)/255;
+				}
 			}
 			else
+			{
+				if (blendimage->s.alpha == 0)
+				{
+					cur->rgba = image->rgba;
+					goto skippixel; // for metal sonic blend
+				}
+				else
+				{
+					SETBRIGHTNESS(brightness,blendimage->s.red,blendimage->s.green,blendimage->s.blue);
+				}
+			}
+
+			// Calculate a sort of "gradient" for the skincolor
+			// (Me splitting this into a function didn't work, so I had to ruin this entire function's groove...)
+			{
+				RGBA_t nextcolor;
+				UINT8 firsti, secondi, mul, mulmax;
+				INT32 r, g, b;
+
+				// Rainbow needs to find the closest match to the textures themselves, instead of matching brightnesses to other colors.
+				// Ensue horrible mess.
+				if (skinnum == TC_RAINBOW)
+				{
+					UINT16 brightdif = 256;
+					UINT8 colorbrightnesses[16];
+					INT32 compare, m, d;
+
+					// Ignore pure white & pitch black
+					if (brightness > 253 || brightness < 2)
+					{
+						cur->rgba = image->rgba;
+						cur++; image++; blendimage++;
+						continue;
+					}
+
+					firsti = 0;
+					mul = 0;
+					mulmax = 1;
+
+					for (i = 0; i < translen; i++)
+					{
+						RGBA_t tempc = V_GetColor(translation[i]);
+						SETBRIGHTNESS(colorbrightnesses[i], tempc.s.red, tempc.s.green, tempc.s.blue); // store brightnesses for comparison
+					}
+
+					for (i = 0; i < translen; i++)
+					{
+						if (brightness > colorbrightnesses[i]) // don't allow greater matches (because calculating a makeshift gradient for this is already a huge mess as is)
+							continue;
+
+						compare = abs((INT16)(colorbrightnesses[i]) - (INT16)(brightness));
+
+						if (compare < brightdif)
+						{
+							brightdif = (UINT16)compare;
+							firsti = i; // best matching color that's equal brightness or darker
+						}
+					}
+
+					secondi = firsti+1; // next color in line
+
+					m = (INT16)brightness - (INT16)colorbrightnesses[secondi];
+					d = (INT16)colorbrightnesses[firsti] - (INT16)colorbrightnesses[secondi];
+
+					if (m >= d)
+						m = d-1;
+
+					mulmax = 16;
+
+					// calculate the "gradient" multiplier based on how close this color is to the one next in line
+					if (m <= 0 || d <= 0)
+						mul = 0;
+					else
+						mul = (mulmax-1) - ((m * mulmax) / d);
+				}
+				else
+				{
+					// Just convert brightness to a skincolor value, use distance to next position to find the gradient multipler
+					firsti = 0;
+
+					for (i = 1; i < translen; i++)
+					{
+						if (brightness >= cutoff[i])
+							break;
+						firsti = i;
+					}
+
+					secondi = firsti+1;
+
+					mulmax = cutoff[firsti] - cutoff[secondi];
+					mul = cutoff[firsti] - brightness;
+				}
+
+				blendcolor = V_GetColor(translation[firsti]);
+
+				if (mul > 0) // If it's 0, then we only need the first color.
+				{
+					nextcolor = V_GetColor(translation[secondi]);
+
+					// Find difference between points
+					r = (INT32)(nextcolor.s.red - blendcolor.s.red);
+					g = (INT32)(nextcolor.s.green - blendcolor.s.green);
+					b = (INT32)(nextcolor.s.blue - blendcolor.s.blue);
+
+					// Find the gradient of the two points
+					r = ((mul * r) / mulmax);
+					g = ((mul * g) / mulmax);
+					b = ((mul * b) / mulmax);
+
+					// Add gradient value to color
+					blendcolor.s.red += r;
+					blendcolor.s.green += g;
+					blendcolor.s.blue += b;
+				}
+			}
+
+			if (skinnum == TC_RAINBOW)
 			{
 				UINT32 tempcolor;
-				UINT16 imagebright, blendbright, finalbright, colorbright;
-				SETBRIGHTNESS(imagebright,image->s.red,image->s.green,image->s.blue);
-				SETBRIGHTNESS(blendbright,blendimage->s.red,blendimage->s.green,blendimage->s.blue);
-				// slightly dumb average between the blend image color and base image colour, usually one or the other will be fully opaque anyway
-				finalbright = (imagebright*(255-blendimage->s.alpha))/255 + (blendbright*blendimage->s.alpha)/255;
+				UINT16 colorbright;
+
 				SETBRIGHTNESS(colorbright,blendcolor.s.red,blendcolor.s.green,blendcolor.s.blue);
+				if (colorbright == 0)
+					colorbright = 1; // no dividing by 0 please
 
-				tempcolor = (finalbright*blendcolor.s.red)/colorbright;
+				tempcolor = (brightness * blendcolor.s.red) / colorbright;
 				tempcolor = min(255, tempcolor);
 				cur->s.red = (UINT8)tempcolor;
-				tempcolor = (finalbright*blendcolor.s.green)/colorbright;
+
+				tempcolor = (brightness * blendcolor.s.green) / colorbright;
 				tempcolor = min(255, tempcolor);
 				cur->s.green = (UINT8)tempcolor;
-				tempcolor = (finalbright*blendcolor.s.blue)/colorbright;
+
+				tempcolor = (brightness * blendcolor.s.blue) / colorbright;
 				tempcolor = min(255, tempcolor);
 				cur->s.blue = (UINT8)tempcolor;
 				cur->s.alpha = image->s.alpha;
 			}
-
-			cur++; image++; blendimage++;
-		}
-	}
-	else
-	{
-		while (size--)
-		{
-			if (blendimage->s.alpha == 0)
-			{
-				// Don't bother with blending the pixel if the alpha of the blend pixel is 0
-				cur->rgba = image->rgba;
-			}
 			else
 			{
+				// Color strength depends on image alpha
 				INT32 tempcolor;
-				INT16 tempmult, tempalpha;
-				tempalpha = -(abs(blendimage->s.red-127)-127)*2;
-				if (tempalpha > 255)
-					tempalpha = 255;
-				else if (tempalpha < 0)
-					tempalpha = 0;
-
-				tempmult = (blendimage->s.red-127)*2;
-				if (tempmult > 255)
-					tempmult = 255;
-				else if (tempmult < 0)
-					tempmult = 0;
-
-				tempcolor = (image->s.red*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.red)/255)) * blendimage->s.alpha)/255;
+
+				tempcolor = ((image->s.red * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.red * blendimage->s.alpha) / 255);
+				tempcolor = min(255, tempcolor);
 				cur->s.red = (UINT8)tempcolor;
-				tempcolor = (image->s.green*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.green)/255)) * blendimage->s.alpha)/255;
+
+				tempcolor = ((image->s.green * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.green * blendimage->s.alpha) / 255);
+				tempcolor = min(255, tempcolor);
 				cur->s.green = (UINT8)tempcolor;
-				tempcolor = (image->s.blue*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.blue)/255)) * blendimage->s.alpha)/255;
+
+				tempcolor = ((image->s.blue * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.blue * blendimage->s.alpha) / 255);
+				tempcolor = min(255, tempcolor);
 				cur->s.blue = (UINT8)tempcolor;
 				cur->s.alpha = image->s.alpha;
 			}
 
-			cur++; image++; blendimage++;
+skippixel:
+
+			// *Now* we can do Metal Sonic's flashing
+			if (skinnum == TC_METALSONIC)
+			{
+				// Blend dark blue into white
+				if (cur->s.alpha > 0 && cur->s.red == 0 && cur->s.green == 0 && cur->s.blue < 255 && cur->s.blue > 31)
+				{
+					// Sal: Invert non-blue
+					cur->s.red = cur->s.green = (255 - cur->s.blue);
+					cur->s.blue = 255;
+				}
+
+				cur->s.alpha = image->s.alpha;
+			}
 		}
+
+		cur++; image++;
+
+		if (blendimage != NULL)
+			blendimage++;
 	}
 
 	return;
@@ -890,10 +1083,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 				colormap = sector->extra_colormap;
 		}
 
-		if (colormap)
-			HWR_Lighting(&Surf, lightlevel, colormap->rgba, colormap->fadergba);
-		else
-			HWR_NoColormapLighting(&Surf, lightlevel, GL_NORMALFOG, GL_FADEFOG);
+		HWR_Lighting(&Surf, lightlevel, colormap);
 	}
 	else
 	{
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index 783a09ba7a224c25e5723da62f4df23b9628dd54..f06020634f84f8591f10f351081a4224691e22f6 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -26,6 +26,8 @@
 #include "r_opengl.h"
 #include "r_vbo.h"
 
+#include "../../p_tick.h" // for leveltime (NOTE: THIS IS BAD, FIGURE OUT HOW TO PROPERLY IMPLEMENT gl_leveltime)
+
 #if defined (HWRENDER) && !defined (NOROPENGL)
 
 struct GLRGBAFloat
@@ -482,11 +484,6 @@ boolean SetupGLfunc(void)
 	return true;
 }
 
-static INT32 glstate_fog_mode = 0;
-static float glstate_fog_density = 0;
-
-INT32 gl_leveltime = 0;
-
 #ifdef GL_SHADERS
 typedef GLuint 	(APIENTRY *PFNglCreateShader)		(GLenum);
 typedef void 	(APIENTRY *PFNglShaderSource)		(GLuint, GLsizei, const GLchar**, GLint*);
@@ -552,10 +549,8 @@ typedef enum
 	gluniform_tint_color,
 	gluniform_fade_color,
 	gluniform_lighting,
-
-	// fog
-	gluniform_fog_mode,
-	gluniform_fog_density,
+	gluniform_fade_start,
+	gluniform_fade_end,
 
 	// misc. (custom shaders)
 	gluniform_leveltime,
@@ -579,9 +574,6 @@ static gl_shaderprogram_t gl_shaderprograms[MAXSHADERPROGRAMS];
 // GLSL Software fragment shader
 //
 
-// (new shader stuff taken from srb2 shader branch)
-// this is missing support for fade_start and fade_end
-
 #define GLSL_DOOM_COLORMAP \
 	"float R_DoomColormap(float light, float z)\n" \
 	"{\n" \
@@ -611,6 +603,12 @@ static gl_shaderprogram_t gl_shaderprograms[MAXSHADERPROGRAMS];
 
 #define GLSL_SOFTWARE_FADE_EQUATION \
 	"float darkness = R_DoomLightingEquation(lighting);\n" \
+	"if (fade_start != 0.0 || fade_end != 31.0) {\n" \
+		"float fs = fade_start / 31.0;\n" \
+		"float fe = fade_end / 31.0;\n" \
+		"float fd = fe - fs;\n" \
+		"darkness = clamp((darkness - fs) * (1.0 / fd), 0.0, 1.0);\n" \
+	"}\n" \
 	"final_color = mix(final_color, fade_color, darkness);\n"
 
 #define GLSL_SOFTWARE_FRAGMENT_SHADER \
@@ -619,6 +617,8 @@ static gl_shaderprogram_t gl_shaderprograms[MAXSHADERPROGRAMS];
 	"uniform vec4 tint_color;\n" \
 	"uniform vec4 fade_color;\n" \
 	"uniform float lighting;\n" \
+	"uniform float fade_start;\n" \
+	"uniform float fade_end;\n" \
 	GLSL_DOOM_COLORMAP \
 	GLSL_DOOM_LIGHT_EQUATION \
 	"void main(void) {\n" \
@@ -631,9 +631,44 @@ static gl_shaderprogram_t gl_shaderprograms[MAXSHADERPROGRAMS];
 		"gl_FragColor = final_color;\n" \
 	"}\0"
 
+//
+// Water surface shader
+//
+// Mostly guesstimated, rather than the rest being built off Software science.
+// Still needs to distort things underneath/around the water...
+//
+
+#define GLSL_WATER_FRAGMENT_SHADER \
+	"uniform sampler2D tex;\n" \
+	"uniform vec4 poly_color;\n" \
+	"uniform vec4 tint_color;\n" \
+	"uniform vec4 fade_color;\n" \
+	"uniform float lighting;\n" \
+	"uniform float fade_start;\n" \
+	"uniform float fade_end;\n" \
+	"uniform float leveltime;\n" \
+	"const float freq = 0.025;\n" \
+	"const float amp = 0.025;\n" \
+	"const float speed = 2.0;\n" \
+	"const float pi = 3.14159;\n" \
+	GLSL_DOOM_COLORMAP \
+	GLSL_DOOM_LIGHT_EQUATION \
+	"void main(void) {\n" \
+		"float z = (gl_FragCoord.z / gl_FragCoord.w) / 2.0;\n" \
+		"float a = -pi * (z * freq) + (leveltime * speed);\n" \
+		"float sdistort = sin(a) * amp;\n" \
+		"float cdistort = cos(a) * amp;\n" \
+		"vec4 texel = texture2D(tex, vec2(gl_TexCoord[0].s - sdistort, gl_TexCoord[0].t - cdistort));\n" \
+		"vec4 base_color = texel * poly_color;\n" \
+		"vec4 final_color = base_color;\n" \
+		GLSL_SOFTWARE_TINT_EQUATION \
+		GLSL_SOFTWARE_FADE_EQUATION \
+		"final_color.a = texel.a * poly_color.a;\n" \
+		"gl_FragColor = final_color;\n" \
+	"}\0"
 
 //
-// Fog block shader (Taken from srb2 shader branch)
+// Fog block shader
 //
 // Alpha of the planes themselves are still slightly off -- see HWR_FogBlockAlpha
 //
@@ -642,6 +677,8 @@ static gl_shaderprogram_t gl_shaderprograms[MAXSHADERPROGRAMS];
 	"uniform vec4 tint_color;\n" \
 	"uniform vec4 fade_color;\n" \
 	"uniform float lighting;\n" \
+	"uniform float fade_start;\n" \
+	"uniform float fade_end;\n" \
 	GLSL_DOOM_COLORMAP \
 	GLSL_DOOM_LIGHT_EQUATION \
 	"void main(void) {\n" \
@@ -652,16 +689,15 @@ static gl_shaderprogram_t gl_shaderprograms[MAXSHADERPROGRAMS];
 		"gl_FragColor = final_color;\n" \
 	"}\0"
 
-
 //
 // GLSL generic fragment shader
 //
 
 #define GLSL_DEFAULT_FRAGMENT_SHADER \
 	"uniform sampler2D tex;\n" \
-	"uniform vec4 mix_color;\n" \
+	"uniform vec4 poly_color;\n" \
 	"void main(void) {\n" \
-		"gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * mix_color;\n" \
+		"gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \
 	"}\0"
 
 static const char *fragment_shaders[] = {
@@ -681,7 +717,7 @@ static const char *fragment_shaders[] = {
 	GLSL_SOFTWARE_FRAGMENT_SHADER,
 
 	// Water fragment shader
-	GLSL_SOFTWARE_FRAGMENT_SHADER,
+	GLSL_WATER_FRAGMENT_SHADER,
 
 	// Fog fragment shader
 	GLSL_FOG_FRAGMENT_SHADER,
@@ -689,7 +725,7 @@ static const char *fragment_shaders[] = {
 	// Sky fragment shader
 	"uniform sampler2D tex;\n"
 	"void main(void) {\n"
-		"gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n" \
+		"gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
 	"}\0",
 
 	NULL,
@@ -709,7 +745,7 @@ static const char *fragment_shaders[] = {
 		"gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \
 		"gl_FrontColor = gl_Color;\n" \
 		"gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \
-		"gl_ClipVertex = gl_ModelViewMatrix*gl_Vertex;\n" \
+		"gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \
 	"}\0"
 
 static const char *vertex_shaders[] = {
@@ -885,10 +921,8 @@ EXPORT boolean HWRAPI(LoadShaders) (void)
 		shader->uniforms[gluniform_tint_color] = GETUNI("tint_color");
 		shader->uniforms[gluniform_fade_color] = GETUNI("fade_color");
 		shader->uniforms[gluniform_lighting] = GETUNI("lighting");
-
-		// fog
-		shader->uniforms[gluniform_fog_mode] = GETUNI("fog_mode");
-		shader->uniforms[gluniform_fog_density] = GETUNI("fog_density");
+		shader->uniforms[gluniform_fade_start] = GETUNI("fade_start");
+		shader->uniforms[gluniform_fade_end] = GETUNI("fade_end");
 
 		// misc. (custom shaders)
 		shader->uniforms[gluniform_leveltime] = GETUNI("leveltime");
@@ -899,6 +933,9 @@ EXPORT boolean HWRAPI(LoadShaders) (void)
 	return true;
 }
 
+//
+// Custom shader loading
+//
 EXPORT void HWRAPI(LoadCustomShader) (int number, char *shader, size_t size, boolean fragment)
 {
 #ifdef GL_SHADERS
@@ -1689,19 +1726,10 @@ static void load_shaders(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *
 			{
 				if (!custom)
 				{
-					if (glstate_fog_mode == 0)	// disabled
-					{
-						// Nevermind!
-						pglUseProgram(0);
-						return;
-					}
-					else	// enabled
+					if (gl_shaderprogramchanged)
 					{
-						if (gl_shaderprogramchanged)
-						{
-							pglUseProgram(gl_shaderprograms[gl_currentshaderprogram].program);
-							gl_shaderprogramchanged = false;
-						}
+						pglUseProgram(gl_shaderprograms[gl_currentshaderprogram].program);
+						gl_shaderprogramchanged = false;
 					}
 				}
 				else	// always load custom shaders
@@ -1735,26 +1763,11 @@ static void load_shaders(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *
 				// polygon
 				UNIFORM_4(shader->uniforms[gluniform_poly_color], poly->red, poly->green, poly->blue, poly->alpha, pglUniform4f);
 				UNIFORM_4(shader->uniforms[gluniform_tint_color], tint->red, tint->green, tint->blue, tint->alpha, pglUniform4f);
-
-
-				// 13062019
-				// Check for fog
-				if (glstate_fog_mode == 1)
-				{
-					// glstate
-					UNIFORM_1(shader->uniforms[gluniform_fog_density], glstate_fog_density, pglUniform1f);
-
-					// polygon
-					UNIFORM_4(shader->uniforms[gluniform_fade_color], fade->red, fade->green, fade->blue, fade->alpha, pglUniform4f);
-					UNIFORM_1(shader->uniforms[gluniform_lighting], Surface->LightInfo.light_level, pglUniform1f);
-
-					// Custom shader uniforms
-					if (custom)
-					{
-						UNIFORM_1(shader->uniforms[gluniform_fog_mode], glstate_fog_mode, pglUniform1i);
-						UNIFORM_1(shader->uniforms[gluniform_leveltime], (float)gl_leveltime, pglUniform1f);
-					}
-				}
+				UNIFORM_4(shader->uniforms[gluniform_fade_color], fade->red, fade->green, fade->blue, fade->alpha, pglUniform4f);
+				UNIFORM_1(shader->uniforms[gluniform_lighting], Surface->LightInfo.light_level, pglUniform1f);
+				UNIFORM_1(shader->uniforms[gluniform_fade_start], Surface->LightInfo.fade_start, pglUniform1f);
+				UNIFORM_1(shader->uniforms[gluniform_fade_end], Surface->LightInfo.fade_end, pglUniform1f);
+				UNIFORM_1(shader->uniforms[gluniform_leveltime], ((float)leveltime) / TICRATE, pglUniform1f);
 
 				#undef UNIFORM_1
 				#undef UNIFORM_2
@@ -2592,14 +2605,6 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
 			}
 			break;
 
-		case HWD_SET_FOG_MODE:
-			glstate_fog_mode = Value;
-			break;
-
-		case HWD_SET_FOG_DENSITY:
-			glstate_fog_density = FIXED_TO_FLOAT(Value);
-			break;
-
 		case HWD_SET_TEXTUREFILTERMODE:
 			switch (Value)
 			{
diff --git a/src/k_kart.c b/src/k_kart.c
index f9af5a24f63b699a03a0b2a5c7c816e1ca81dc75..cc5504bb436617b777ef0a7674af8c2213af5845 100644
--- a/src/k_kart.c
+++ b/src/k_kart.c
@@ -409,7 +409,7 @@ UINT8 colortranslations[MAXTRANSLATIONS][16] = {
 // 0.0722 to blue
 // (See this same define in hw_md2.c!)
 #define SETBRIGHTNESS(brightness,r,g,b) \
-	brightness = (UINT8)(((1063*((UINT16)r)/5000) + (3576*((UINT16)g)/5000) + (361*((UINT16)b)/5000)) / 3)
+	brightness = (UINT8)(((1063*(UINT16)(r))/5000) + ((3576*(UINT16)(g))/5000) + ((361*(UINT16)(b))/5000))
 
 /** \brief	Generates the rainbow colourmaps that are used when a player has the invincibility power
 
@@ -8781,8 +8781,11 @@ void K_drawKartHUD(void)
 	if (!demo.title && (!battlefullscreen || splitscreen))
 	{
 		// Draw the CHECK indicator before the other items, so it's overlapped by everything else
-		if (cv_kartcheck.value && !splitscreen && !players[displayplayers[0]].exiting && !freecam)
-			K_drawKartPlayerCheck();
+#ifdef HAVE_BLUA
+		if (LUA_HudEnabled(hud_check))	// delete lua when?
+#endif
+			if (cv_kartcheck.value && !splitscreen && !players[displayplayers[0]].exiting && !freecam)
+				K_drawKartPlayerCheck();
 
 		// Draw WANTED status
 		if (G_BattleGametype())
diff --git a/src/lua_hud.h b/src/lua_hud.h
index 88d7fd6bc96f2ab895652503fc78db9c1c25219d..960195cdaa1246e9af5d05b017b41e1830d66e97 100644
--- a/src/lua_hud.h
+++ b/src/lua_hud.h
@@ -19,6 +19,7 @@ enum hud {
 	hud_minimap,
 	hud_item,
 	hud_position,
+	hud_check,			// "CHECK" f-zero indicator
 	hud_minirankings,	// Rankings to the left
 	hud_battlebumpers,	// mini rankings battle bumpers.
 	hud_battlefullscreen,	// battle huge text (WAIT, WIN, LOSE ...) + karma comeback time
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index 22c89a234fe9ab1318ef3f28e317f869d478a15a..22e98315fb52c343771212a27a7e6d9d031f8e36 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -46,6 +46,7 @@ static const char *const hud_disable_options[] = {
 	"minimap",
 	"item",
 	"position",
+	"check",		// "CHECK" f-zero indicator
 	"minirankings",	// Gametype rankings to the left
 	"battlerankingsbumpers",	// bumper drawer for battle. Useful if you want to make a custom battle gamemode without bumpers being involved.
 	"battlefullscreen",			// battlefullscreen func (WAIT, ATTACK OR PROTECT ...)
diff --git a/src/m_menu.c b/src/m_menu.c
index 7032de4d72eccc38e83f3b633c38e3731f37a6ea..ed8df01d4e8c7dd0ff6cfcce49c86da64c712120 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -279,7 +279,7 @@ static void M_ResetControls(INT32 choice);
 // Video & Sound
 menu_t OP_VideoOptionsDef, OP_VideoModeDef;
 #ifdef HWRENDER
-menu_t OP_OpenGLOptionsDef, OP_OpenGLFogDef, OP_OpenGLColorDef;
+menu_t OP_OpenGLOptionsDef, OP_OpenGLColorDef;
 #endif
 menu_t OP_SoundOptionsDef;
 //static void M_RestartAudio(void);
@@ -346,7 +346,6 @@ static void M_DrawHUDOptions(void);
 static void M_DrawVideoMode(void);
 static void M_DrawMonitorToggles(void);
 #ifdef HWRENDER
-static void M_OGL_DrawFogMenu(void);
 static void M_OGL_DrawColorMenu(void);
 #endif
 static void M_DrawMPMainMenu(void);
@@ -1241,15 +1240,13 @@ static menuitem_t OP_VideoOptionsMenu[] =
 	{IT_STRING | IT_CVAR,	NULL,	"Weather Draw Distance",&cv_drawdist_precip,	 55},
 	//{IT_STRING | IT_CVAR,	NULL,	"Weather Density",		&cv_precipdensity,		 65},
 	{IT_STRING | IT_CVAR,	NULL,	"Skyboxes",				&cv_skybox,				 65},
-	{IT_STRING | IT_CVAR,	NULL,	"Field of View",		&cv_fov,					75},
+	{IT_STRING | IT_CVAR,	NULL,	"Field of View",		&cv_fov,				 75},
 
 	{IT_STRING | IT_CVAR,	NULL,	"Show FPS",				&cv_ticrate,			 90},
 	{IT_STRING | IT_CVAR,	NULL,	"Vertical Sync",		&cv_vidwait,			100},
 
 #ifdef HWRENDER
-	{IT_STRING | IT_CVAR,	NULL,	"3D models",            &cv_grmdls,              115},
-	{IT_STRING | IT_CVAR,	NULL,	"Fallback Player 3D Model",	&cv_grfallbackplayermodel,	125},
-	{IT_SUBMENU|IT_STRING,	NULL,	"OpenGL Options...",	&OP_OpenGLOptionsDef,   135},
+	{IT_SUBMENU|IT_STRING,	NULL,	"OpenGL Options...",	&OP_OpenGLOptionsDef,	120},
 #endif
 };
 
@@ -1268,8 +1265,6 @@ enum
 	op_video_fps,
 	op_video_vsync,
 #ifdef HWRENDER
-	op_video_md2,
-	op_video_kartman,
 	op_video_ogl,
 #endif
 };
@@ -1282,24 +1277,19 @@ static menuitem_t OP_VideoModeMenu[] =
 #ifdef HWRENDER
 static menuitem_t OP_OpenGLOptionsMenu[] =
 {
-	{IT_STRING|IT_CVAR,         NULL, "Shaders",                    &cv_grshaders,         10},
-	{IT_STRING|IT_CVAR,         NULL, "Software Perspective",       &cv_grshearing,        20},
-	{IT_STRING|IT_CVAR,         NULL, "Sprite Billboarding",      	&cv_grspritebillboarding,30},
+	{IT_STRING | IT_CVAR,	NULL, "3D Models",					&cv_grmdls,					 10},
+	{IT_STRING | IT_CVAR,	NULL, "Fallback Player 3D Model",	&cv_grfallbackplayermodel,	 20},
+	{IT_STRING|IT_CVAR,		NULL, "Shaders",					&cv_grshaders,				 30},
 
-	{IT_STRING|IT_CVAR,         NULL, "Quality",                    &cv_scr_depth,         50},
-	{IT_STRING|IT_CVAR,         NULL, "Texture Filter",             &cv_grfiltermode,      60},
-	{IT_STRING|IT_CVAR,         NULL, "Anisotropic",                &cv_granisotropicmode, 70},
-#ifdef _WINDOWS
-	{IT_STRING|IT_CVAR,         NULL, "Fullscreen",                 &cv_fullscreen,        80},
-#endif
-	{IT_SUBMENU|IT_STRING,      NULL, "Fog...",                     &OP_OpenGLFogDef,      100},
-	{IT_SUBMENU|IT_STRING,      NULL, "Gamma...",                   &OP_OpenGLColorDef,    110},
-};
+	{IT_STRING|IT_CVAR,		NULL, "Texture Quality",			&cv_scr_depth,				 50},
+	{IT_STRING|IT_CVAR,		NULL, "Texture Filter",				&cv_grfiltermode,			 60},
+	{IT_STRING|IT_CVAR,		NULL, "Anisotropic",				&cv_granisotropicmode,		 70},
 
-static menuitem_t OP_OpenGLFogMenu[] =
-{
-	{IT_STRING|IT_CVAR,       NULL, "Fog",         &cv_grfog,        10},
-	{IT_STRING|IT_CVAR,       NULL, "Fog density", &cv_grfogdensity, 20},
+	{IT_STRING|IT_CVAR,		NULL, "Wall Contrast Style",		&cv_grfakecontrast,			 90},
+	{IT_STRING|IT_CVAR,		NULL, "Sprite Billboarding",		&cv_grspritebillboarding,	100},
+	{IT_STRING|IT_CVAR,		NULL, "Software Perspective",		&cv_grshearing,				110},
+
+	{IT_SUBMENU|IT_STRING,	NULL, "Gamma...",					&OP_OpenGLColorDef,			130},
 };
 
 static menuitem_t OP_OpenGLColorMenu[] =
@@ -2063,17 +2053,6 @@ menu_t OP_MonitorToggleDef =
 
 #ifdef HWRENDER
 menu_t OP_OpenGLOptionsDef = DEFAULTMENUSTYLE("M_VIDEO", OP_OpenGLOptionsMenu, &OP_VideoOptionsDef, 30, 30);
-menu_t OP_OpenGLFogDef =
-{
-	"M_VIDEO",
-	sizeof (OP_OpenGLFogMenu)/sizeof (menuitem_t),
-	&OP_OpenGLOptionsDef,
-	OP_OpenGLFogMenu,
-	M_OGL_DrawFogMenu,
-	60, 40,
-	0,
-	NULL
-};
 menu_t OP_OpenGLColorDef =
 {
 	"M_VIDEO",
@@ -3449,9 +3428,7 @@ void M_Init(void)
 #ifdef HWRENDER
 	// Permanently hide some options based on render mode
 	if (rendermode == render_soft)
-		OP_VideoOptionsMenu[op_video_ogl].status =
-			OP_VideoOptionsMenu[op_video_kartman].status =
-			OP_VideoOptionsMenu[op_video_md2]    .status = IT_DISABLED;
+		OP_VideoOptionsMenu[op_video_ogl].status = IT_DISABLED;
 #endif
 
 #ifndef NONET
@@ -11098,21 +11075,6 @@ static void M_QuitSRB2(INT32 choice)
 // OpenGL specific options
 // =====================================================================
 
-#define FOG_DENSITY_ITEM  1
-// ===================
-// M_OGL_DrawFogMenu()
-// ===================
-static void M_OGL_DrawFogMenu(void)
-{
-	INT32 mx, my;
-
-	mx = currentMenu->x;
-	my = currentMenu->y;
-	M_DrawGenericMenu(); // use generic drawer for cursor, items and title
-	V_DrawString(BASEVIDWIDTH - mx - V_StringWidth(cv_grfogdensity.string, 0),
-		my + currentMenu->menuitems[FOG_DENSITY_ITEM].alphaKey, V_YELLOWMAP, cv_grfogdensity.string);
-}
-
 // =====================
 // M_OGL_DrawColorMenu()
 // =====================
diff --git a/src/p_user.c b/src/p_user.c
index e0fb6fb47d201df56a1160012c0c30b4a83481fd..03f8f0fbe33bcfcc53d930243019b19d2de03e9f 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -7314,6 +7314,10 @@ static ticcmd_t *P_CameraCmd(camera_t *cam)
 	if (InputDown(gc_aimbackward, 1) || (usejoystick && axis > 0))
 		forward -= forwardmove[1];
 
+	// fire with any button/key
+	axis = JoyAxis(AXISFIRE, 1);
+	if (InputDown(gc_fire, 1) || (usejoystick && axis > 0))
+		cmd->buttons |= BT_ATTACK;
 
 	// spectator aiming shit, ahhhh...
 	player_invert = invertmouse ? -1 : 1;
@@ -7380,6 +7384,7 @@ void P_DemoCameraMovement(camera_t *cam)
 	ticcmd_t *cmd;
 	angle_t thrustangle;
 	mobj_t *awayviewmobj_hack;
+	player_t *lastp;
 
 	// update democam stuff with what we got here:
 	democam.cam = cam;
@@ -7399,6 +7404,14 @@ void P_DemoCameraMovement(camera_t *cam)
 	else if (cmd->buttons & BT_BRAKE)
 		cam->z -= 32*mapobjectscale;
 
+	// if you hold item, you will lock on to displayplayer. (The last player you were ""f12-ing"")
+	if (cmd->buttons & BT_ATTACK)
+	{
+		lastp = &players[displayplayers[0]];	// Fun fact, I was trying displayplayers[0]->mo as if it was Lua like an absolute idiot.
+		cam->angle = R_PointToAngle2(cam->x, cam->y, lastp->mo->x, lastp->mo->y);
+		cam->aiming = R_PointToAngle2(0, cam->z, R_PointToDist2(cam->x, cam->y, lastp->mo->x, lastp->mo->y), lastp->mo->z + lastp->mo->scale*128*P_MobjFlip(lastp->mo));	// This is still unholy. Aim a bit above their heads.
+	}
+
 
 	cam->momx = cam->momy = cam->momz = 0;
 	if (cmd->forwardmove != 0)
diff --git a/src/r_main.c b/src/r_main.c
index 5ef401795c6936ad25336826caf7b21451b59867..2ec064975947d5be3a303180f4b84b45c4e39a2f 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -1550,8 +1550,6 @@ void R_RegisterEngineStuff(void)
 	CV_RegisterVar(&cv_grgammagreen);
 	CV_RegisterVar(&cv_grgammared);
 	CV_RegisterVar(&cv_grfovchange);
-	CV_RegisterVar(&cv_grfog);
-	//CV_RegisterVar(&cv_grfogcolor);
 #ifdef ALAM_LIGHTING
 	CV_RegisterVar(&cv_grstaticlighting);
 	CV_RegisterVar(&cv_grdynamiclighting);
@@ -1560,8 +1558,8 @@ void R_RegisterEngineStuff(void)
 #endif
 	CV_RegisterVar(&cv_grmdls);
 	CV_RegisterVar(&cv_grfallbackplayermodel);
-	CV_RegisterVar(&cv_grfogdensity);
 	CV_RegisterVar(&cv_grspritebillboarding);
+	CV_RegisterVar(&cv_grfakecontrast);
 	CV_RegisterVar(&cv_grshearing);
 	CV_RegisterVar(&cv_grshaders);
 #endif
diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c
index 37d6dd797498af1827fc2ae65ad808db82f13d6b..ef769564c0de87bde39024ef8ec33e6988a7a24d 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -692,7 +692,7 @@ static inline void I_ShutdownConsole(void){}
 //
 // StartupKeyboard
 //
-void I_RegisterSignals (void)
+static void I_RegisterSignals (void)
 {
 #ifdef SIGINT
 	signal(SIGINT , quit_handler);
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index 9acff2b2d1ec706a3682fbb793d46f10f1ef577d..a740ef84d83c41da56759be60b7aaac470e162c5 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -1870,7 +1870,7 @@ void I_StartupGraphics(void)
 		HWD.pfnMakeScreenTexture= hwSym("MakeScreenTexture",NULL);
 		HWD.pfnMakeScreenFinalTexture=hwSym("MakeScreenFinalTexture",NULL);
 		HWD.pfnDrawScreenFinalTexture=hwSym("DrawScreenFinalTexture",NULL);
-		
+
 		HWD.pfnRenderSkyDome = hwSym("RenderSkyDome",NULL);
 
 		HWD.pfnLoadShaders = hwSym("LoadShaders",NULL);
@@ -1880,7 +1880,7 @@ void I_StartupGraphics(void)
 
 		HWD.pfnLoadCustomShader = hwSym("LoadCustomShader",NULL);
 		HWD.pfnInitCustomShaders = hwSym("InitCustomShaders",NULL);
-		
+
 		HWD.pfnStartBatching = hwSym("StartBatching",NULL);
 		HWD.pfnRenderBatches = hwSym("RenderBatches",NULL);
 
diff --git a/src/v_video.c b/src/v_video.c
index 1ea8d5475ef329d948028eac580243718fea7f39..47fe4c8e2d37b6039af93b988b70af7b19c6eb49 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -58,11 +58,9 @@ static void CV_Gammaxxx_ONChange(void);
 // - You can change them in software,
 // but they won't do anything.
 static CV_PossibleValue_t grgamma_cons_t[] = {{1, "MIN"}, {255, "MAX"}, {0, NULL}};
-static CV_PossibleValue_t grfogdensity_cons_t[] = {{FRACUNIT/8, "MIN"}, {FRACUNIT*2, "MAX"}, {0, NULL}};
+static CV_PossibleValue_t grfakecontrast_cons_t[] = {{0, "Off"}, {1, "Standard"}, {2, "Smooth"}, {0, NULL}};
 
 consvar_t cv_grshaders = {"gr_shaders", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_grfog = {"gr_fog", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_grfogdensity = {"gr_fogdensity", "0.30", CV_SAVE|CV_FLOAT, grfogdensity_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grfovchange = {"gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grgammared = {"gr_gammared", "127", CV_SAVE|CV_CALL, grgamma_cons_t,
                            CV_Gammaxxx_ONChange, 0, NULL, NULL, 0, 0, NULL};
@@ -78,6 +76,7 @@ consvar_t cv_grfallbackplayermodel = {"gr_fallbackplayermodel", "Off", CV_SAVE,
 
 consvar_t cv_grshearing = {"gr_shearing", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grspritebillboarding = {"gr_spritebillboarding", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grfakecontrast = {"gr_fakecontrast", "Standard", CV_SAVE, grfakecontrast_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 #endif
 
 const UINT8 gammatable[5][256] =