[PATCH] Use XF86 "Vidmode" gamma extension

This patch sets things up to make use of the XFree86 gamma manipulation
functions.

One issue is that the OpenGL blending substitute we set up is not really the
same as gamma correction because it only brightens pixels according to their
current values. This means black areas are not brightened using this method
(which I think is a good thing), but gamma correction adds "white" to every
area of the screen.

At the moment I've set up the "manual" OpenGL version as a fallback in case
the system gamma functions are not working or not available. I've also set
things up such that the system gamma is not used unless we are in fullscreen
mode since it affects the whole display.

The cvar _gl_allowgammafallback controls whether the fallback is used or not,
but I don't currently have a way to force it to use the "fallback" even if the
other gamma settings work. Most likely I'll separate out the two functions
into gamma and "intensity" similar to Quake 2 and later games.

diff -urN b/NQ/gl_rmain.c head/NQ/gl_rmain.c
--- b/NQ/gl_rmain.c	2005-12-29 13:08:31.000000000 +1030
+++ head/NQ/gl_rmain.c	2005-12-30 21:50:44.000000000 +1030
@@ -25,6 +25,7 @@
 #include "quakedef.h"
 #include "sound.h"
 #include "sys.h"
+#include "vid.h"
 #include "view.h"
 
 entity_t r_worldentity;
@@ -113,6 +114,7 @@
 
 cvar_t _gl_lightmap_sort = { "_gl_lightmap_sort", "0" };
 cvar_t _gl_sky_mtex = { "_gl_sky_mtex", "1" };
+cvar_t _gl_allowgammafallback = { "_gl_allowgammafallback", "1" };
 
 /*
 =================
@@ -760,12 +762,16 @@
 static void
 R_PolyBlend(void)
 {
-    float gamma = v_gamma.value * v_gamma.value;
+    float gamma = 1.0;
 
-    if (gamma < 0.25)
-	gamma = 0.25;
-    else if (gamma > 1.0)
-	gamma = 1.0;
+    if (!VID_IsFullScreen() || (!VID_SetGammaRamp &&
+				_gl_allowgammafallback.value)) {
+	gamma = v_gamma.value * v_gamma.value;
+	if (gamma < 0.25)
+	    gamma = 0.25;
+	else if (gamma > 1.0)
+	    gamma = 1.0;
+    }
 
     if ((gl_polyblend.value && v_blend[3]) || gamma < 1.0) {
 	GL_DisableMultitexture();
diff -urN b/NQ/gl_rmisc.c head/NQ/gl_rmisc.c
--- b/NQ/gl_rmisc.c	2005-02-04 18:16:08.000000000 +1030
+++ head/NQ/gl_rmisc.c	2005-12-30 11:40:07.000000000 +1030
@@ -212,6 +212,7 @@
 
     Cvar_RegisterVariable(&_gl_lightmap_sort);
     Cvar_RegisterVariable(&_gl_sky_mtex);
+    Cvar_RegisterVariable(&_gl_allowgammafallback);
     Cvar_RegisterVariable(&_gl_drawhull);
 
     Cvar_RegisterVariable(&gl_cull);
diff -urN b/NQ/view.c head/NQ/view.c
--- b/NQ/view.c	2005-12-29 22:52:12.000000000 +1030
+++ head/NQ/view.c	2005-12-30 21:43:08.000000000 +1030
@@ -518,7 +518,7 @@
 void
 V_UpdatePalette(void)
 {
-    int i, j;
+    int i;
     qboolean force;
 
     V_CalcPowerupCshift();
@@ -541,7 +541,9 @@
 	    ramps[1][i] = gammatable[i] << 8;
 	    ramps[2][i] = gammatable[i] << 8;
 	}
-	VID_ShiftPalette(NULL);
+	if (VID_IsFullScreen() && VID_SetGammaRamp)
+	    VID_SetGammaRamp(ramps);
+	//VID_ShiftPalette(NULL);
     }
 }
 #else // !GLQUAKE
diff -urN b/QW/client/gl_rmain.c head/QW/client/gl_rmain.c
--- b/QW/client/gl_rmain.c	2005-12-29 13:08:31.000000000 +1030
+++ head/QW/client/gl_rmain.c	2005-12-30 22:02:15.000000000 +1030
@@ -26,6 +26,7 @@
 #include "render.h"
 #include "screen.h"
 #include "sys.h"
+#include "vid.h"
 #include "view.h"
 
 entity_t r_worldentity;
@@ -117,6 +118,7 @@
 
 cvar_t _gl_lightmap_sort = { "_gl_lightmap_sort", "0" };
 cvar_t _gl_sky_mtex = { "_gl_sky_mtex", "1" };
+cvar_t _gl_allowgammafallback = { "_gl_allowgammafallback", "1" };
 
 /*
 =================
@@ -773,12 +775,16 @@
 static void
 R_PolyBlend(void)
 {
-    float gamma = v_gamma.value * v_gamma.value;
+    float gamma = 1.0;
 
-    if (gamma < 0.25)
-	gamma = 0.25;
-    else if (gamma > 1.0)
-	gamma = 1.0;
+    if (!VID_IsFullScreen() || (!VID_SetGammaRamp &&
+				_gl_allowgammafallback.value)) {
+	gamma = v_gamma.value * v_gamma.value;
+	if (gamma < 0.25)
+	    gamma = 0.25;
+	else if (gamma > 1.0)
+	    gamma = 1.0;
+    }
 
     if ((gl_polyblend.value && v_blend[3]) || gamma < 1.0) {
 	GL_DisableMultitexture();
diff -urN b/QW/client/gl_rmisc.c head/QW/client/gl_rmisc.c
--- b/QW/client/gl_rmisc.c	2005-02-04 18:16:08.000000000 +1030
+++ head/QW/client/gl_rmisc.c	2005-12-30 11:40:17.000000000 +1030
@@ -212,6 +212,7 @@
 
     Cvar_RegisterVariable(&_gl_lightmap_sort);
     Cvar_RegisterVariable(&_gl_sky_mtex);
+    Cvar_RegisterVariable(&_gl_allowgammafallback);
     Cvar_RegisterVariable(&_gl_drawhull);
 
     Cvar_RegisterVariable(&gl_cull);
diff -urN b/QW/client/view.c head/QW/client/view.c
--- b/QW/client/view.c	2005-12-29 22:52:12.000000000 +1030
+++ head/QW/client/view.c	2005-12-30 21:43:27.000000000 +1030
@@ -530,7 +530,7 @@
 void
 V_UpdatePalette(void)
 {
-    int i, j;
+    int i;
     qboolean force;
 
     V_CalcPowerupCshift();
@@ -553,7 +553,9 @@
 	    ramps[1][i] = gammatable[i] << 8;
 	    ramps[2][i] = gammatable[i] << 8;
 	}
-	VID_ShiftPalette(NULL);
+	if (VID_IsFullScreen() && VID_SetGammaRamp)
+	    VID_SetGammaRamp(ramps);
+	//VID_ShiftPalette(NULL);
     }
 }
 #else // !GLQUAKE
diff -urN b/common/gl_vidlinuxglx.c head/common/gl_vidlinuxglx.c
--- b/common/gl_vidlinuxglx.c	2005-12-28 12:41:21.000000000 +1030
+++ head/common/gl_vidlinuxglx.c	2005-12-30 14:03:14.000000000 +1030
@@ -429,11 +429,16 @@
 	IN_CenterMouse();
 }
 
+void (*VID_SetGammaRamp)(unsigned short ramp[3][256]);
+static unsigned short saved_gamma_ramp[3][256];
+
 void
 signal_handler(int sig)
 {
     printf("Received signal %d, exiting...\n", sig);
     XAutoRepeatOn(x_disp);
+    if (VID_SetGammaRamp)
+	VID_SetGammaRamp(saved_gamma_ramp);
     XCloseDisplay(x_disp);
     Sys_Quit();
     exit(0);
@@ -547,6 +552,33 @@
     }
 }
 
+static void
+VID_SetXF86GammaRamp(unsigned short ramp[3][256])
+{
+    if (!x_disp)
+	Sys_Error("%s: x_disp == NULL!", __func__);
+
+    XF86VidModeSetGammaRamp(x_disp, scrnum, 256, ramp[0], ramp[1], ramp[2]);
+}
+
+/*
+ * Gamma_Init
+ * - Checks to see if gamma settings are available
+ * - Saves the current gamma settings
+ * - Sets the default gamma ramp function
+ */
+static void
+Gamma_Init()
+{
+    if (XF86VidModeGetGammaRamp(x_disp, scrnum, 256,
+				saved_gamma_ramp[0],
+				saved_gamma_ramp[1],
+				saved_gamma_ramp[2]))
+	VID_SetGammaRamp = VID_SetXF86GammaRamp;
+    else
+	VID_SetGammaRamp = NULL;
+}
+
 /*
 ===============
 GL_Init
@@ -858,6 +890,8 @@
     if (vidmode_ext && fullscreen)
 	fullscreen = VID_set_vidmode(width, height);
 
+    Gamma_Init();
+
     /* window attributes */
     mask = CWBackPixel | CWColormap | CWEventMask;
     attr.background_pixel = 0;
@@ -931,6 +965,9 @@
 void
 VID_Shutdown(void)
 {
+    if (VID_SetGammaRamp)
+	VID_SetGammaRamp(saved_gamma_ramp);
+
     if (x_disp != NULL) {
 	if (ctx != NULL)
 	    glXDestroyContext(x_disp, ctx);
diff -urN b/include/glquake.h head/include/glquake.h
--- b/include/glquake.h	2005-12-28 13:25:28.000000000 +1030
+++ head/include/glquake.h	2005-12-30 11:39:37.000000000 +1030
@@ -217,6 +217,7 @@
 
 extern cvar_t _gl_lightmap_sort;
 extern cvar_t _gl_sky_mtex;
+extern cvar_t _gl_allowgammafallback;
 extern cvar_t _gl_drawhull;
 
 #ifdef NQ_HACK
diff -urN b/include/vid.h head/include/vid.h
--- b/include/vid.h	2004-11-03 18:05:26.000000000 +1030
+++ head/include/vid.h	2005-12-30 00:40:58.000000000 +1030
@@ -70,6 +70,10 @@
 
 // called for bonus and pain flashes, and for underwater color changes
 
+extern void (*VID_SetGammaRamp)(unsigned short ramp[3][256]);
+
+// called to set hardware gamma (if available - primarily for OpenGL renderer)
+
 void VID_Init(unsigned char *palette);
 
 // Called at startup to set up translation tables, takes 256 8 bit RGB values
