diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 708b3cdf4459941b5f48425d712d592e96378ae7..b2ea919f5fc4589131a046bcbe705b604ac109dc 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -5747,6 +5747,7 @@ static void CV_glmodellighting_OnChange(void);
 static void CV_glpaletterendering_OnChange(void);
 static void CV_glpalettedepth_OnChange(void);
 static void CV_glshaders_OnChange(void);
+static void CV_gllightdithering_OnChange(void);
 
 static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"},
 	{HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"},
@@ -5790,6 +5791,8 @@ static CV_PossibleValue_t glpalettedepth_cons_t[] = {{16, "16 bits"}, {24, "24 b
 consvar_t cv_glpaletterendering = CVAR_INIT ("gr_paletterendering", "On", "Emulate Software's coloring graphics (requires shaders)", CV_SAVE|CV_CALL, CV_OnOff, CV_glpaletterendering_OnChange);
 consvar_t cv_glpalettedepth = CVAR_INIT ("gr_palettedepth", "16 bits", NULL, CV_SAVE|CV_CALL, glpalettedepth_cons_t, CV_glpalettedepth_OnChange);
 
+consvar_t cv_gllightdither = CVAR_INIT ("gr_lightdithering", "Off", "Adds a dither effect to lighting (requires shaders)", CV_SAVE|CV_CALL, CV_OnOff, CV_gllightdithering_OnChange);
+
 #define ONLY_IF_GL_LOADED if (vid.glstate != VID_GL_LIBRARY_LOADED) return;
 consvar_t cv_glwireframe = CVAR_INIT ("gr_wireframe", "Off", "When combined with devmode, will render the world with lines instead, revealing how polygons are split and rendered", 0, CV_OnOff, NULL);
 
@@ -5842,6 +5845,15 @@ static void CV_glshaders_OnChange(void)
 	}
 }
 
+static void CV_gllightdithering_OnChange(void)
+{
+	ONLY_IF_GL_LOADED
+	if (gl_shadersavailable)
+	{
+		HWR_CompileShaders();
+	}
+}
+
 //added by Hurdler: console varibale that are saved
 void HWR_AddCommands(void)
 {
@@ -5872,6 +5884,7 @@ void HWR_AddCommands(void)
 
 	CV_RegisterVar(&cv_glpaletterendering);
 	CV_RegisterVar(&cv_glpalettedepth);
+	CV_RegisterVar(&cv_gllightdither);
 	CV_RegisterVar(&cv_glwireframe);
 }
 
diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h
index 22ea3f24c73fb37b514a4e3ae07c13510c0b73f0..78996f6a693b5d8035a659fe3cdc3c6f78c19b57 100644
--- a/src/hardware/hw_main.h
+++ b/src/hardware/hw_main.h
@@ -96,6 +96,7 @@ extern consvar_t cv_glslopecontrast;
 extern consvar_t cv_glbatching;
 extern consvar_t cv_glpaletterendering;
 extern consvar_t cv_glpalettedepth;
+extern consvar_t cv_gllightdither;
 
 extern consvar_t cv_glwireframe;
 
diff --git a/src/hardware/hw_shaders.c b/src/hardware/hw_shaders.c
index fde67375f016e8132004ee14231cc31e575f5a30..7b0c8f66f33c0bcc579ce7335d800717f43cf33b 100644
--- a/src/hardware/hw_shaders.c
+++ b/src/hardware/hw_shaders.c
@@ -81,6 +81,7 @@ static shadertarget_t gl_shadertargets[NUMSHADERTARGETS];
 
 #define MODEL_LIGHTING_DEFINE "#define SRB2_MODEL_LIGHTING"
 #define PALETTE_RENDERING_DEFINE "#define SRB2_PALETTE_RENDERING"
+#define LIGHT_DITHERING_DEFINE "#define SRB2_LIGHT_DITHER"
 
 // Initialize shader variables and the backend's shader system. Load the base shaders.
 // Returns false if shaders cannot be used.
@@ -281,6 +282,8 @@ static char *HWR_PreprocessShader(char *original)
 		ADD_TO_LEN(MODEL_LIGHTING_DEFINE)
 	if (cv_glpaletterendering.value)
 		ADD_TO_LEN(PALETTE_RENDERING_DEFINE)
+	if (cv_gllightdither.value)
+		ADD_TO_LEN(LIGHT_DITHERING_DEFINE)
 
 #undef ADD_TO_LEN
 
@@ -324,6 +327,8 @@ static char *HWR_PreprocessShader(char *original)
 		WRITE_DEFINE(MODEL_LIGHTING_DEFINE)
 	if (cv_glpaletterendering.value)
 		WRITE_DEFINE(PALETTE_RENDERING_DEFINE)
+	if (cv_gllightdither.value)
+		WRITE_DEFINE(LIGHT_DITHERING_DEFINE)
 
 #undef WRITE_DEFINE
 
diff --git a/src/hardware/hw_shaders.h b/src/hardware/hw_shaders.h
index 38a2d991191dc7531fb2e72e70b3b5946e98b245..0dd7effc7182b008e070453c0833b27b5cb1d0e2 100644
--- a/src/hardware/hw_shaders.h
+++ b/src/hardware/hw_shaders.h
@@ -69,15 +69,49 @@
 //
 
 // Include GLSL_FLOOR_FUDGES or GLSL_WALL_FUDGES or define the fudges in shaders that use this macro.
+#define GLSL_DOOM_COLORMAP_DITHER \
+	"float baseValue = max(startmap * STARTMAP_FUDGE - scale * 0.5 * SCALE_FUDGE, cap);\n" \
+	"float halfResolutionx = scr_resolution.x;\n" \
+	"float halfResolutiony = scr_resolution.y;\n" \
+	"if (scr_resolution.x > 1280.0) {\n" \
+	"    halfResolutionx = scr_resolution.x * 0.5;\n" \
+	"}\n" \
+	"if (scr_resolution.y > 720.0) {\n" \
+	"    halfResolutiony = scr_resolution.y * 0.5;\n" \
+	"}\n" \
+	"vec2 normalizedPosition = position * vec2(halfResolutionx / scr_resolution.x, halfResolutiony / scr_resolution.y);\n" \
+	"int x = int(mod(normalizedPosition.x, 8.0));\n" \
+	"int y = int(mod(normalizedPosition.y, 8.0));\n" \
+	"float bayerMatrix[8*8] = float[8*8](\n" \
+	"0.0, 32.0, 8.0, 40.0, 2.0, 34.0, 10.0, 42.0,\n" \
+	"48.0, 16.0, 56.0, 24.0, 50.0, 18.0, 58.0, 26.0,\n" \
+	"12.0, 44.0, 4.0, 36.0, 14.0, 46.0, 6.0, 38.0,\n" \
+	"60.0, 28.0, 52.0, 20.0, 62.0, 30.0, 54.0, 22.0,\n" \
+	"3.0, 35.0, 11.0, 43.0, 1.0, 33.0, 9.0, 41.0,\n" \
+	"51.0, 19.0, 59.0, 27.0, 49.0, 17.0, 57.0, 25.0,\n" \
+	"15.0, 47.0, 7.0, 39.0, 13.0, 45.0, 5.0, 37.0,\n" \
+	"63.0, 31.0, 55.0, 23.0, 61.0, 29.0, 53.0, 21.0\n" \
+	");\n" \
+	"float threshold = bayerMatrix[y*8 + x] / 64.0;\n" \
+	"return baseValue + threshold - 0.5 / 64.0;\n" \
+
+#define GLSL_DOOM_COLORMAP_NODITHER \
+	"return max(startmap * STARTMAP_FUDGE - scale * 0.5 * SCALE_FUDGE, cap);\n" \
+
 #define GLSL_DOOM_COLORMAP \
-	"float R_DoomColormap(float light, float z)\n" \
+"uniform vec2 scr_resolution;\n" \
+"float R_DoomColormap(float light, float z, vec2 position)\n" \
 	"{\n" \
 		"float lightnum = clamp(light / 17.0, 0.0, 15.0);\n" \
 		"float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \
 		"float startmap = (15.0 - lightnum) * 4.0;\n" \
 		"float scale = 160.0 / (lightz + 1.0);\n" \
 		"float cap = (155.0 - light) * 0.26;\n" \
-		"return max(startmap * STARTMAP_FUDGE - scale * 0.5 * SCALE_FUDGE, cap);\n" \
+		"#ifdef SRB2_LIGHT_DITHER\n" \
+		GLSL_DOOM_COLORMAP_DITHER \
+		"#else\n" \
+		GLSL_DOOM_COLORMAP_NODITHER \
+		"#endif\n" \
 	"}\n"
 // lighting cap adjustment:
 // first num (155.0), increase to make it start to go dark sooner
@@ -87,7 +121,7 @@
 	"float R_DoomLightingEquation(float light)\n" \
 	"{\n" \
 		"float z = gl_FragCoord.z / gl_FragCoord.w;\n" \
-		"float colormap = floor(R_DoomColormap(light, z)) + 0.5;\n" \
+		"float colormap = floor(R_DoomColormap(light, z, gl_FragCoord.xy)) + 0.5;\n" \
 		"return clamp(colormap, 0.0, 31.0) / 32.0;\n" \
 	"}\n"
 
@@ -113,7 +147,7 @@
 #define GLSL_PALETTE_RENDERING \
 	"float tex_pal_idx = texture3D(palette_lookup_tex, vec3((texel * 63.0 + 0.5) / 64.0))[0] * 255.0;\n" \
 	"float z = gl_FragCoord.z / gl_FragCoord.w;\n" \
-	"float light_y = clamp(floor(R_DoomColormap(lighting, z)), 0.0, 31.0);\n" \
+	"float light_y = clamp(floor(R_DoomColormap(lighting, z, gl_FragCoord.xy)), 0.0, 31.0);\n" \
 	"vec2 lighttable_coord = vec2((tex_pal_idx + 0.5) / 256.0, (light_y + 0.5) / 32.0);\n" \
 	"vec4 final_color = texture2D(lighttable_tex, lighttable_coord);\n" \
 	"final_color.a = texel.a * poly_color.a;\n" \
@@ -154,10 +188,12 @@
 
 // hand tuned adjustments for light level calculation
 #define GLSL_FLOOR_FUDGES \
+	"#version 120\n" \
 	"#define STARTMAP_FUDGE 1.06\n" \
 	"#define SCALE_FUDGE 1.15\n"
 
 #define GLSL_WALL_FUDGES \
+	"#version 120\n" \
 	"#define STARTMAP_FUDGE 1.05\n" \
 	"#define SCALE_FUDGE 2.2\n"
 
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index db9fa17884e00779d8df9c37c3469707f798fbe7..f2267dfacd839d7f89491504b24bdb9531a87937 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -628,6 +628,8 @@ typedef enum
 	// misc.
 	gluniform_leveltime,
 
+	gluniform_scr_resolution,
+
 	gluniform_max,
 } gluniform_t;
 
@@ -1805,6 +1807,8 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF
 
 		UNIFORM_1(shader->uniforms[gluniform_leveltime], shader_leveltime, pglUniform1f);
 
+		UNIFORM_2(shader->uniforms[gluniform_scr_resolution], vid.width, vid.height, pglUniform2f);
+
 		#undef UNIFORM_1
 		#undef UNIFORM_2
 		#undef UNIFORM_3
@@ -1928,6 +1932,8 @@ static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i)
 	shader->uniforms[gluniform_palette_lookup_tex] = GETUNI("palette_lookup_tex");
 	shader->uniforms[gluniform_lighttable_tex] = GETUNI("lighttable_tex");
 
+	shader->uniforms[gluniform_scr_resolution] = GETUNI("scr_resolution");
+
 	// misc.
 	shader->uniforms[gluniform_leveltime] = GETUNI("leveltime");
 #undef GETUNI
diff --git a/src/m_menu.c b/src/m_menu.c
index 60a52052983a866ee28c9cee687f7796c86116c5..525783c82b2afb943742d0da75801c81533883fd 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -1401,25 +1401,26 @@ static menuitem_t OP_ColorOptionsMenu[] =
 static menuitem_t OP_OpenGLOptionsMenu[] =
 {
 	{IT_HEADER, NULL, "3D Models", NULL, NULL, 0},
-	{IT_STRING|IT_CVAR,         NULL, "Models",              NULL, &cv_glmodels,             12},
-	{IT_STRING|IT_CVAR,         NULL, "Frame interpolation", NULL, &cv_glmodelinterpolation, 22},
-	{IT_STRING|IT_CVAR,         NULL, "Ambient lighting",    NULL, &cv_glmodellighting,      32},
-
-	{IT_HEADER, NULL, "General", NULL, NULL, 51},
-	{IT_STRING|IT_CVAR,         NULL, "Shaders",             NULL, &cv_glshaders,            63},
-	{IT_STRING|IT_CVAR,         NULL, "Palette rendering",   NULL, &cv_glpaletterendering,   73},
-	{IT_STRING|IT_CVAR,         NULL, "Lack of perspective", NULL, &cv_glshearing,           83},
-	{IT_STRING | IT_CVAR, 	NULL, "Min Shader Brightness",   NULL, &cv_glsecbright,	   93},
-
-	{IT_HEADER, NULL, "Miscellaneous", NULL, NULL, 112},
-	{IT_STRING|IT_CVAR,         NULL, "Bit depth",           NULL, &cv_scr_depth,           124},
-	{IT_STRING|IT_CVAR,         NULL, "Texture filter",      NULL, &cv_glfiltermode,        134},
-	{IT_STRING|IT_CVAR,         NULL, "Anisotropic",         NULL, &cv_glanisotropicmode,   144},
+	{IT_STRING|IT_CVAR,         NULL, "Models",              NULL, &cv_glmodels,             6},
+	{IT_STRING|IT_CVAR,         NULL, "Frame interpolation", NULL, &cv_glmodelinterpolation, 11},
+	{IT_STRING|IT_CVAR,         NULL, "Ambient lighting",    NULL, &cv_glmodellighting,      16},
+
+	{IT_HEADER, NULL, "General", NULL, NULL, 25},
+	{IT_STRING|IT_CVAR,         NULL, "Shaders",             NULL, &cv_glshaders,            31},
+	{IT_STRING|IT_CVAR,         NULL, "Palette rendering",   NULL, &cv_glpaletterendering,   36},
+	{IT_STRING|IT_CVAR,         NULL, "Lack of perspective", NULL, &cv_glshearing,           41},
+	{IT_STRING | IT_CVAR, 	   NULL, "Min Shader Brightness",   NULL, &cv_glsecbright,	     46},
+	{IT_STRING | IT_CVAR, 	   NULL, "Light Dithering",         NULL, &cv_gllightdither,	 51},
+
+	{IT_HEADER, NULL, "Miscellaneous", NULL, NULL, 58},
+	{IT_STRING|IT_CVAR,         NULL, "Bit depth",           NULL, &cv_scr_depth,           64},
+	{IT_STRING|IT_CVAR,         NULL, "Texture filter",      NULL, &cv_glfiltermode,        69},
+	{IT_STRING|IT_CVAR,         NULL, "Anisotropic",         NULL, &cv_glanisotropicmode,   74},
 #ifdef ALAM_LIGHTING
-	{IT_SUBMENU|IT_STRING,      NULL, "Lighting...",         NULL, &OP_OpenGLLightingDef,   154},
+	{IT_SUBMENU|IT_STRING,      NULL, "Lighting...",         NULL, &OP_OpenGLLightingDef,   79},
 #endif
 #if defined (_WINDOWS) && (!(defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL)))
-	{IT_STRING|IT_CVAR,         NULL, "Fullscreen",          NULL, &cv_fullscreen,          164},
+	{IT_STRING|IT_CVAR,         NULL, "Fullscreen",          NULL, &cv_fullscreen,          84},
 #endif
 };
 
@@ -2191,7 +2192,7 @@ static void M_OpenGLOptionsMenu(void)
 		M_StartMessage(M_GetText("You must be in OpenGL mode\nto access this menu.\n\n(Press a key)\n"), NULL, MM_NOTHING);
 }
 
-menu_t OP_OpenGLOptionsDef = DEFAULTMENUSTYLE(
+menu_t OP_OpenGLOptionsDef = DEFAULTSCROLLMENUSTYLE(
 	MTREE3(MN_OP_MAIN, MN_OP_VIDEO, MN_OP_OPENGL),
 	"M_VIDEO", OP_OpenGLOptionsMenu, &OP_VideoOptionsDef, 30, 30);
 #ifdef ALAM_LIGHTING