diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index e328e90e0..5f0c82784 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -670,6 +670,7 @@ void D_RegisterClientCommands(void)
 
 	// FIXME: not to be here.. but needs be done for config loading
 	CV_RegisterVar(&cv_usegamma);
+	CV_RegisterVar(&cv_usesaturation);
 
 	// m_menu.c
 	CV_RegisterVar(&cv_crosshair);
diff --git a/src/m_menu.c b/src/m_menu.c
index ba01ceaef..283b76b88 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -1166,36 +1166,38 @@ static menuitem_t OP_VideoOptionsMenu[] =
 {
 	{IT_STRING | IT_CALL,  NULL, "Set Resolution...", M_VideoModeMenu,        0},
 
-#ifdef HWRENDER
-	{IT_SUBMENU|IT_STRING, NULL, "3D Card Options...", &OP_OpenGLOptionsDef,  5},
+#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)
+	{IT_STRING|IT_CVAR,      NULL, "Fullscreen",       &cv_fullscreen,       5},
 #endif
 
-#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)
-	{IT_STRING|IT_CVAR,      NULL, "Fullscreen",       &cv_fullscreen,       10},
+#ifdef HWRENDER
+	{IT_SUBMENU|IT_STRING, NULL, "3D Card Options...", &OP_OpenGLOptionsDef,  10},
 #endif
 
 	{IT_STRING | IT_CVAR | IT_CV_SLIDER,
 	                         NULL, "Brightness",      &cv_usegamma,          15},
-
-	{IT_STRING | IT_CVAR, NULL, "Display HUD",        &cv_showhud,           25},
 	{IT_STRING | IT_CVAR | IT_CV_SLIDER,
-	                      NULL, "HUD Transparency",   &cv_translucenthud,    30},
-	{IT_STRING | IT_CVAR, NULL, "Time Display",       &cv_timetic,           35},
+	                         NULL, "Saturation",      &cv_usesaturation,     20},
+
+	{IT_STRING | IT_CVAR, NULL, "Display HUD",        &cv_showhud,           30},
+	{IT_STRING | IT_CVAR | IT_CV_SLIDER,
+	                      NULL, "HUD Transparency",   &cv_translucenthud,    35},
+	{IT_STRING | IT_CVAR, NULL, "Time Display",       &cv_timetic,           40},
 #ifdef SEENAMES
-	{IT_STRING | IT_CVAR, NULL, "Show HUD player names",  &cv_seenames,      40},
+	{IT_STRING | IT_CVAR, NULL, "Show HUD player names",  &cv_seenames,      45},
 #endif
 
-	{IT_STRING | IT_CVAR, NULL, "Console Background", &cons_backcolor,       50},
-	{IT_STRING | IT_CVAR, NULL, "Console Text Size",  &cv_constextsize,      55},
+	{IT_STRING | IT_CVAR, NULL, "Console Background", &cons_backcolor,       55},
+	{IT_STRING | IT_CVAR, NULL, "Console Text Size",  &cv_constextsize,      60},
 
-	{IT_STRING | IT_CVAR, NULL, "Draw Distance",      &cv_drawdist,          65},
-	{IT_STRING | IT_CVAR, NULL, "NiGHTS Draw Dist.",  &cv_drawdist_nights,   70},
-	{IT_STRING | IT_CVAR, NULL, "Weather Draw Dist.", &cv_drawdist_precip,   75},
-	{IT_STRING | IT_CVAR, NULL, "Weather Density",    &cv_precipdensity,     80},
+	{IT_STRING | IT_CVAR, NULL, "Draw Distance",      &cv_drawdist,          70},
+	{IT_STRING | IT_CVAR, NULL, "NiGHTS Draw Dist.",  &cv_drawdist_nights,   75},
+	{IT_STRING | IT_CVAR, NULL, "Weather Draw Dist.", &cv_drawdist_precip,   80},
+	{IT_STRING | IT_CVAR, NULL, "Weather Density",    &cv_precipdensity,     85},
 
-	{IT_STRING | IT_CVAR, NULL, "Show FPS",           &cv_ticrate,           90},
-	{IT_STRING | IT_CVAR, NULL, "Clear Before Redraw",&cv_homremoval,        95},
-	{IT_STRING | IT_CVAR, NULL, "Vertical Sync",      &cv_vidwait,          100},
+	{IT_STRING | IT_CVAR, NULL, "Show FPS",           &cv_ticrate,           95},
+	{IT_STRING | IT_CVAR, NULL, "Clear Before Redraw",&cv_homremoval,       100},
+	{IT_STRING | IT_CVAR, NULL, "Vertical Sync",      &cv_vidwait,          105},
 };
 
 static menuitem_t OP_VideoModeMenu[] =
@@ -2784,7 +2786,7 @@ void M_Init(void)
 #ifdef HWRENDER
 	// Permanently hide some options based on render mode
 	if (rendermode == render_soft)
-		OP_VideoOptionsMenu[1].status = IT_DISABLED;
+		OP_VideoOptionsMenu[2].status = IT_DISABLED;
 #endif
 
 #ifndef NONET
@@ -2854,16 +2856,6 @@ static void M_DrawSlider(INT32 x, INT32 y, const consvar_t *cv)
 	INT32 range;
 	patch_t *p;
 
-	for (i = 0; cv->PossibleValue[i+1].strvalue; i++);
-
-	range = ((cv->value - cv->PossibleValue[0].value) * 100 /
-	 (cv->PossibleValue[i].value - cv->PossibleValue[0].value));
-
-	if (range < 0)
-		range = 0;
-	if (range > 100)
-		range = 100;
-
 	x = BASEVIDWIDTH - x - SLIDER_WIDTH;
 
 	V_DrawScaledPatch(x, y, 0, W_CachePatchName("M_SLIDEL", PU_CACHE));
@@ -2877,6 +2869,30 @@ static void M_DrawSlider(INT32 x, INT32 y, const consvar_t *cv)
 
 	// draw the slider cursor
 	p = W_CachePatchName("M_SLIDEC", PU_CACHE);
+
+	for (i = 0; cv->PossibleValue[i+1].strvalue; i++);
+
+	if ((range = atoi(cv->defaultvalue)) != cv->value)
+	{
+		range = ((range - cv->PossibleValue[0].value) * 100 /
+		 (cv->PossibleValue[i].value - cv->PossibleValue[0].value));
+
+		if (range < 0)
+			range = 0;
+		else if (range > 100)
+			range = 100;
+
+		V_DrawMappedPatch(x + 2 + (SLIDER_RANGE*8*range)/100, y, V_TRANSLUCENT, p, yellowmap);
+	}
+
+	range = ((cv->value - cv->PossibleValue[0].value) * 100 /
+	 (cv->PossibleValue[i].value - cv->PossibleValue[0].value));
+
+	if (range < 0)
+		range = 0;
+	else if (range > 100)
+		range = 100;
+
 	V_DrawMappedPatch(x + 2 + (SLIDER_RANGE*8*range)/100, y, 0, p, yellowmap);
 }
 
diff --git a/src/v_video.c b/src/v_video.c
index e4d079c73..931ec711f 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -38,12 +38,15 @@ UINT8 *screens[5];
 // screens[3] = fade screen start
 // screens[4] = fade screen end, postimage tempoarary buffer
 
-static CV_PossibleValue_t gamma_cons_t[] = {{0, "MIN"}, {4, "MAX"}, {0, NULL}};
+static CV_PossibleValue_t gamma_cons_t[] = {{-5, "MIN"}, {5, "MAX"}, {0, NULL}};
 static void CV_usegamma_OnChange(void);
 
 consvar_t cv_ticrate = {"showfps", "No", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_usegamma = {"gamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_usegamma_OnChange, 0, NULL, NULL, 0, 0, NULL};
 
+static CV_PossibleValue_t saturation_cons_t[] = {{0, "MIN"}, {10, "MAX"}, {0, NULL}};
+consvar_t cv_usesaturation = {"saturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_usegamma_OnChange, 0, NULL, NULL, 0, 0, NULL};
+
 static CV_PossibleValue_t constextsize_cons_t[] = {
 	{V_NOSCALEPATCH, "Small"}, {V_SMALLSCALEPATCH, "Medium"}, {V_MEDSCALEPATCH, "Large"}, {0, "Huge"},
 	{0, NULL}};
@@ -81,97 +84,123 @@ static CV_PossibleValue_t CV_MD2[] = {{0, "Off"}, {1, "On"}, {2, "Old"}, {0, NUL
 consvar_t cv_grmd2 = {"gr_md2", "Off", CV_SAVE, CV_MD2, NULL, 0, NULL, NULL, 0, 0, NULL};
 #endif
 
-const UINT8 gammatable[5][256] =
-{
-	{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
-	17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
-	33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
-	49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,
-	65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
-	81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,
-	97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,
-	113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
-	128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
-	144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
-	160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
-	176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
-	192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
-	208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
-	224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
-	240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255},
-
-	{2,4,5,7,8,10,11,12,14,15,16,18,19,20,21,23,24,25,26,27,29,30,31,
-	32,33,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,54,55,
-	56,57,58,59,60,61,62,63,64,65,66,67,69,70,71,72,73,74,75,76,77,
-	78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,
-	99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,
-	115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,129,
-	130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,
-	146,147,148,148,149,150,151,152,153,154,155,156,157,158,159,160,
-	161,162,163,163,164,165,166,167,168,169,170,171,172,173,174,175,
-	175,176,177,178,179,180,181,182,183,184,185,186,186,187,188,189,
-	190,191,192,193,194,195,196,196,197,198,199,200,201,202,203,204,
-	205,205,206,207,208,209,210,211,212,213,214,214,215,216,217,218,
-	219,220,221,222,222,223,224,225,226,227,228,229,230,230,231,232,
-	233,234,235,236,237,237,238,239,240,241,242,243,244,245,245,246,
-	247,248,249,250,251,252,252,253,254,255},
-
-	{4,7,9,11,13,15,17,19,21,22,24,26,27,29,30,32,33,35,36,38,39,40,42,
-	43,45,46,47,48,50,51,52,54,55,56,57,59,60,61,62,63,65,66,67,68,69,
-	70,72,73,74,75,76,77,78,79,80,82,83,84,85,86,87,88,89,90,91,92,93,
-	94,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,
-	113,114,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
-	129,130,131,132,133,133,134,135,136,137,138,139,140,141,142,143,144,
-	144,145,146,147,148,149,150,151,152,153,153,154,155,156,157,158,159,
-	160,160,161,162,163,164,165,166,166,167,168,169,170,171,172,172,173,
-	174,175,176,177,178,178,179,180,181,182,183,183,184,185,186,187,188,
-	188,189,190,191,192,193,193,194,195,196,197,197,198,199,200,201,201,
-	202,203,204,205,206,206,207,208,209,210,210,211,212,213,213,214,215,
-	216,217,217,218,219,220,221,221,222,223,224,224,225,226,227,228,228,
-	229,230,231,231,232,233,234,235,235,236,237,238,238,239,240,241,241,
-	242,243,244,244,245,246,247,247,248,249,250,251,251,252,253,254,254,
-	255},
-
-	{8,12,16,19,22,24,27,29,31,34,36,38,40,41,43,45,47,49,50,52,53,55,
-	57,58,60,61,63,64,65,67,68,70,71,72,74,75,76,77,79,80,81,82,84,85,
-	86,87,88,90,91,92,93,94,95,96,98,99,100,101,102,103,104,105,106,107,
-	108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,
-	125,126,127,128,129,130,131,132,133,134,135,135,136,137,138,139,140,
-	141,142,143,143,144,145,146,147,148,149,150,150,151,152,153,154,155,
-	155,156,157,158,159,160,160,161,162,163,164,165,165,166,167,168,169,
-	169,170,171,172,173,173,174,175,176,176,177,178,179,180,180,181,182,
-	183,183,184,185,186,186,187,188,189,189,190,191,192,192,193,194,195,
-	195,196,197,197,198,199,200,200,201,202,202,203,204,205,205,206,207,
-	207,208,209,210,210,211,212,212,213,214,214,215,216,216,217,218,219,
-	219,220,221,221,222,223,223,224,225,225,226,227,227,228,229,229,230,
-	231,231,232,233,233,234,235,235,236,237,237,238,238,239,240,240,241,
-	242,242,243,244,244,245,246,246,247,247,248,249,249,250,251,251,252,
-	253,253,254,254,255},
-
-	{16,23,28,32,36,39,42,45,48,50,53,55,57,60,62,64,66,68,69,71,73,75,76,
-	78,80,81,83,84,86,87,89,90,92,93,94,96,97,98,100,101,102,103,105,106,
-	107,108,109,110,112,113,114,115,116,117,118,119,120,121,122,123,124,
-	125,126,128,128,129,130,131,132,133,134,135,136,137,138,139,140,141,
-	142,143,143,144,145,146,147,148,149,150,150,151,152,153,154,155,155,
-	156,157,158,159,159,160,161,162,163,163,164,165,166,166,167,168,169,
-	169,170,171,172,172,173,174,175,175,176,177,177,178,179,180,180,181,
-	182,182,183,184,184,185,186,187,187,188,189,189,190,191,191,192,193,
-	193,194,195,195,196,196,197,198,198,199,200,200,201,202,202,203,203,
-	204,205,205,206,207,207,208,208,209,210,210,211,211,212,213,213,214,
-	214,215,216,216,217,217,218,219,219,220,220,221,221,222,223,223,224,
-	224,225,225,226,227,227,228,228,229,229,230,230,231,232,232,233,233,
-	234,234,235,235,236,236,237,237,238,239,239,240,240,241,241,242,242,
-	243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,
-	251,252,252,253,254,254,255,255}
-};
-
 // local copy of the palette for V_GetColor()
 RGBA_t *pLocalPalette = NULL;
 
+/*
+The following was an extremely helpful resource when developing my Colour Cube LUT.
+http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter24.html
+Please check it out if you're trying to maintain this.
+toast 18/04/17
+*/
+
+float Cubepal[2][2][2][3];
+
+// returns whether to apply cube, selectively avoiding expensive operations
+static boolean InitCube(void)
+{
+	boolean apply = false;
+	UINT8 q;
+	float working[2][2][2][3] = // the initial positions of the corners of the colour cube!
+	{
+		{
+			{
+				{0.0, 0.0, 0.0}, // black corner
+				{1.0, 0.0, 0.0}  // red corner
+			},
+			{
+				{0.0, 1.0, 0.0}, // green corner
+				{1.0, 1.0, 0.0}  // yellow corner
+			}
+		},
+		{
+			{
+				{0.0, 0.0, 1.0}, // blue corner
+				{1.0, 0.0, 1.0}  // magenta corner
+			},
+			{
+				{0.0, 1.0, 1.0}, // cyan corner
+				{1.0, 1.0, 1.0}  // white corner
+			}
+		}
+	};
+
+	if (cv_usegamma.value)
+	{
+#define gammascale 8
+		float gammamul = (255 - (gammascale*abs(cv_usegamma.value)))/255.0;
+		float gammaoffs = ((cv_usegamma.value > 0) ? ((gammascale*cv_usegamma.value)/255.0) : 0.0);
+#undef gammascale
+
+		apply = true;
+
+		#define dogamma(i, j, k, l) \
+			working[i][j][k][l]*= gammamul;\
+			working[i][j][k][l] += gammaoffs
+		for (q = 0; q < 3; q++)
+		{
+			dogamma(0, 0, 0, q);
+			dogamma(1, 0, 0, q);
+			dogamma(0, 1, 0, q);
+			dogamma(1, 1, 0, q);
+			dogamma(0, 0, 1, q);
+			dogamma(1, 0, 1, q);
+			dogamma(0, 1, 1, q);
+			dogamma(1, 1, 1, q);
+		}
+#undef dogamma
+	}
+
+	if (cv_usesaturation.value != 10)
+	{
+		float desatur[3] = {0.33, 0.33, 0.33}; // grey
+		float work = (cv_usesaturation.value/10.0);
+
+		apply = true;
+
+#define dosaturation(a, e) a = ((1 - work)*e + work*a)
+		for (q = 0; q < 3; q++)
+		{
+			dosaturation(working[0][0][1][q], desatur[q]);
+			dosaturation(working[0][1][0][q], desatur[q]);
+			dosaturation(working[1][0][0][q], desatur[q]);
+
+			dosaturation(working[1][1][0][q], 2*desatur[q]);
+			dosaturation(working[1][0][1][q], 2*desatur[q]);
+			dosaturation(working[0][1][1][q], 2*desatur[q]);
+		}
+#undef dosaturation
+	}
+
+	if (!apply)
+		return false;
+
+#define dowork(i, j, k, l) \
+	if (working[i][j][k][l] > 1.0)\
+		working[i][j][k][l] = 1.0;\
+	else if (working[i][j][k][l] < 0.0)\
+		working[i][j][k][l] = 0.0;\
+	Cubepal[i][j][k][l] = working[i][j][k][l]
+	for (q = 0; q < 3; q++)
+	{
+		dowork(0, 0, 0, q);
+		dowork(1, 0, 0, q);
+		dowork(0, 1, 0, q);
+		dowork(1, 1, 0, q);
+		dowork(0, 0, 1, q);
+		dowork(1, 0, 1, q);
+		dowork(0, 1, 1, q);
+		dowork(1, 1, 1, q);
+	}
+#undef dowork
+
+	return true;
+}
+
 // keep a copy of the palette so that we can get the RGB value for a color index at any time.
 static void LoadPalette(const char *lumpname)
 {
-	const UINT8 *usegamma = gammatable[cv_usegamma.value];
+	boolean cube = InitCube();
 	lumpnum_t lumpnum = W_GetNumForName(lumpname);
 	size_t i, palsize = W_LumpLength(lumpnum)/3;
 	UINT8 *pal;
@@ -183,10 +212,54 @@ static void LoadPalette(const char *lumpname)
 	pal = W_CacheLumpNum(lumpnum, PU_CACHE);
 	for (i = 0; i < palsize; i++)
 	{
-		pLocalPalette[i].s.red = usegamma[*pal++];
-		pLocalPalette[i].s.green = usegamma[*pal++];
-		pLocalPalette[i].s.blue = usegamma[*pal++];
+		pLocalPalette[i].s.red = *pal++;
+		pLocalPalette[i].s.green = *pal++;
+		pLocalPalette[i].s.blue = *pal++;
 		pLocalPalette[i].s.alpha = 0xFF;
+
+		// lerp of colour cubing!
+		if (cube)
+		{
+			float working[4][3];
+			float linear;
+			UINT8 q;
+
+			linear = (pLocalPalette[i].s.red/255.0);
+#define dolerp(e1, e2) ((1 - linear)*e1 + linear*e2)
+			for (q = 0; q < 3; q++)
+			{
+				working[0][q] = dolerp(Cubepal[0][0][0][q], Cubepal[1][0][0][q]);
+				working[1][q] = dolerp(Cubepal[0][1][0][q], Cubepal[1][1][0][q]);
+				working[2][q] = dolerp(Cubepal[0][0][1][q], Cubepal[1][0][1][q]);
+				working[3][q] = dolerp(Cubepal[0][1][1][q], Cubepal[1][1][1][q]);
+			}
+			linear = (pLocalPalette[i].s.green/255.0);
+			for (q = 0; q < 3; q++)
+			{
+				working[0][q] = dolerp(working[0][q], working[1][q]);
+				working[1][q] = dolerp(working[2][q], working[3][q]);
+			}
+			linear = (pLocalPalette[i].s.blue/255.0);
+			for (q = 0; q < 3; q++)
+			{
+				working[0][q] = 255*dolerp(working[0][q], working[1][q]);
+				if (working[0][q] > 255.0)
+					working[0][q] = 255.0;
+				else if (working[0][q]  < 0.0)
+					working[0][q] = 0.0;
+			}
+#undef dowork
+
+			/*
+			I don't know what I messed up such that red takes index 2 and blue takes index 0.
+			It should be the other way around, but I've just got this working after spending
+			hours on it and I'm not going to look a gift ho(rse/t)fix in the mouth.
+			toast 18/04/17
+			*/
+			pLocalPalette[i].s.red = (UINT8)(working[0][2]);
+			pLocalPalette[i].s.green = (UINT8)(working[0][1]);
+			pLocalPalette[i].s.blue = (UINT8)(working[0][0]);
+		}
 	}
 }
 
diff --git a/src/v_video.h b/src/v_video.h
index 0c9e289d0..f1761162f 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -27,8 +27,7 @@
 
 extern UINT8 *screens[5];
 
-extern const UINT8 gammatable[5][256];
-extern consvar_t cv_ticrate, cv_usegamma, cv_constextsize;
+extern consvar_t cv_ticrate, cv_usegamma, cv_usesaturation, cv_constextsize;
 
 // Allocates buffer screens, call before R_Init.
 void V_Init(void);