diff -urNp quake2~/Makefile quake2/Makefile
--- quake2~/Makefile	2005-09-07 15:57:40.000000000 +0300
+++ quake2/Makefile	2005-12-12 18:33:29.000000000 +0200
@@ -30,6 +30,7 @@ BUILD_AA=NO		# build the ascii soft rend
 BUILD_QMAX=NO		# build the fancier GL graphics
 BUILD_RETEXTURE=YES	# build a version supporting retextured graphics
 BUILD_REDBLUE=NO	# build a red-blue 3d glasses renderer...
+USE_3DFXGAMMA=NO	# adds hardware gamma support for old Voodoo1/2 boards. linux only
 STATICSDL=NO
 SDLDIR=/usr/local/lib
 
@@ -254,6 +255,8 @@ ifeq ($(strip $(BUILD_ROGUE)),YES)
  TARGETS += $(BUILDDIR)/rogue/game$(ARCH).$(SHLIBEXT)
 endif
 
+OBJ_3DFXGAMMA:=
+
 ifeq ($(ARCH),axp)
  ifeq ($(strip $(BUILD_SDLQUAKE2)),YES)
   $(warning Warning: SDLQuake2 not supported for $(ARCH))
@@ -402,6 +405,14 @@ ifeq ($(ARCH),i386)
  ifeq ($(strip $(BUILD_SDLGL)),YES)
   TARGETS += $(BUILDDIR)/ref_sdlgl.$(SHLIBEXT)
  endif
+
+ ifeq ($(OSTYPE),Linux)
+ ifeq ($(strip $(USE_3DFXGAMMA)),YES)
+  OBJ_3DFXGAMMA:=$(BUILDDIR)/ref_gl/fx_gamma.o 
+  GLXCFLAGS:=$(GLXCFLAGS) -DUSE_3DFXGAMMA
+ endif
+ endif
+
 endif # ARCH i386
 
 ifeq ($(strip $(BUILD_AA)),YES)
@@ -1795,6 +1806,7 @@ REF_GL_OBJS = \
 
 REF_GLX_OBJS = \
 	$(BUILDDIR)/ref_gl/gl_glx.o \
+	$(OBJ_3DFXGAMMA)\
 	$(BUILDDIR)/ref_gl/rw_linux.o \
 	$(BUILDDIR)/ref_gl/joystick.o
 #	$(BUILDDIR)/ref_gl/rw_x11.o
@@ -1869,6 +1881,9 @@ $(BUILDDIR)/ref_gl/glob.o :           $(
 $(BUILDDIR)/ref_gl/gl_glx.o :         $(LINUX_DIR)/gl_glx.c
 	$(DO_GL_SHLIB_CC) $(GLXCFLAGS)
 
+$(BUILDDIR)/ref_gl/fx_gamma.o :       $(LINUX_DIR)/fx_gamma.c
+	$(DO_GL_SHLIB_CC) $(GLXCFLAGS)
+
 $(BUILDDIR)/ref_gl/rw_linux.o :     $(LINUX_DIR)/rw_linux.c
 	$(DO_GL_SHLIB_CC) $(XCFLAGS)
 
diff -urNp quake2~/src/linux/fx_gamma.c quake2/src/linux/fx_gamma.c
--- quake2~/src/linux/fx_gamma.c	1970-01-01 02:00:00.000000000 +0200
+++ quake2/src/linux/fx_gamma.c	2005-12-12 18:33:29.000000000 +0200
@@ -0,0 +1,193 @@
+/*
+ * Small library providing gamma control functions for 3Dfx Voodoo1/2
+ * cards by abusing the exposed glide symbols when using fxMesa.
+ * Author: O. Sezer <sezero@users.sourceforge.net>	License: GPL
+ *
+ * This version is for compiling into an application
+ *
+ * How to use:
+ * If you are linking to the opengl library at compile time (-lGL),
+ * not much is necessary. If you dlopen() the opengl library, then
+ * RTLD_GLOBAL flag is necessary so that the library's symbols would be
+ * available to you: SDL_GL_LoadLibrary() is just fine in this regard.
+ * In either case, if the gllib is an fxMesa library, then you will have
+ * the necessary glide symbols exposed on you. Decide whether you have
+ * a Voodoo1/2 and then use the functions here.
+ *
+ * Issues:
+ * glSetDeviceGammaRamp3DFX works nicely with Voodoo2, but it crashes
+ * Voodoo1. The ramp functions are added for completeness sake anyway.
+ * do3dfxGammaCtrl works just fine for both Voodoo1 and Voodoo2.
+ *
+ * Revision history:
+ * v0.0.1, 2005-06-04:	Initial version, do3dfxGammaCtrl works fine,
+ *			glGetDeviceGammaRamp3DFX & co need more care
+ * v0.0.2, 2005-06-13:	tried following the exact win32 versions for
+ *			glGetDeviceGammaRamp3DFX/glSetDeviceGammaRamp3DFX
+ * v0.0.3, 2005-12-05:	Updated documentation about the RTLD_GLOBAL flag.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+
+/**********************************************************************/
+
+// 3dfx glide2 func for gamma correction
+static void (*FX_GammaControl2)(float) = NULL;
+// 3dfx glide3 func for gamma correction
+static void (*FX_GammaControl3)(float,float,float) = NULL;
+
+#define USE_GAMMA_RAMPS		0
+
+#if USE_GAMMA_RAMPS
+// 3dfx glide3 funcs to make a replacement wglSetDeviceGammaRamp3DFX
+#define GR_GAMMA_TABLE_ENTRIES	0x05
+static unsigned int (*FX_Get)(unsigned int, unsigned int, unsigned int *) = NULL;
+static void (*FX_LoadGammaTable)(unsigned int, unsigned int*, unsigned int*, unsigned int*) = NULL;
+#endif
+
+/**********************************************************************/
+
+/*
+ * Init_3dfxGammaCtrl
+ * Sends 0 for failure, 2 for glide2 or 3 for glide3 api.
+ */
+int Init_3dfxGammaCtrl (void)
+{
+	void *prjobj;
+	int ret = 0;
+
+	if (FX_GammaControl2 != NULL)
+		return 2;
+	if (FX_GammaControl3 != NULL)
+		return 3;
+
+	prjobj = dlopen(NULL, RTLD_LAZY);
+	if (prjobj != NULL)
+	{
+		if ((FX_GammaControl2 = dlsym(prjobj, "grGammaCorrectionValue")) != NULL)
+			ret = 2;
+		else if ((FX_GammaControl3 = dlsym(prjobj, "guGammaCorrectionRGB")) != NULL)
+			ret = 3;
+
+		dlclose(prjobj);
+	}
+	else
+	{	// shouldn't happen.
+		ret = -1;
+	}
+
+	return ret;
+}
+
+void Shutdown_3dfxGamma (void)
+{
+	FX_GammaControl2 = NULL;
+	FX_GammaControl3 = NULL;
+#if USE_GAMMA_RAMPS
+	FX_Get = NULL;
+	FX_LoadGammaTable = NULL;
+#endif
+}
+
+/*
+ * do3dfxGammaCtrl
+ */
+int do3dfxGammaCtrl(float value)
+{
+	if (FX_GammaControl2)
+		FX_GammaControl2 (value);
+	else if (FX_GammaControl3)
+		FX_GammaControl3 (value,value,value);
+
+	return 0;
+}
+
+/**********************************************************************/
+#if USE_GAMMA_RAMPS
+static int Check_3DfxGammaRamp (void)
+{
+	void *prjobj;
+
+	if (FX_LoadGammaTable != NULL)
+		return 1;
+
+	prjobj = dlopen(NULL, RTLD_LAZY);
+	if (prjobj != NULL)
+	{
+		FX_Get = dlsym(prjobj, "grGet");
+		FX_LoadGammaTable = dlsym(prjobj, "grLoadGammaTable");
+		if ((FX_LoadGammaTable != NULL) && (FX_Get != NULL))
+			return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * glSetDeviceGammaRamp3DFX is adapted from Mesa-6.x
+ *
+ * glSetDeviceGammaRamp3DFX crashes Voodoo1, at least
+ * currently, so it is not recommended yet.
+ */
+int glSetDeviceGammaRamp3DFX (void *arrays)
+{
+	int tableSize = 0;
+	int i, inc, idx;
+	unsigned short *red, *green, *blue;
+	unsigned int gammaTableR[256], gammaTableG[256], gammaTableB[256];
+
+	if ((FX_LoadGammaTable == NULL) || (FX_Get == NULL))
+		return 0;
+
+	FX_Get (GR_GAMMA_TABLE_ENTRIES, 4, &tableSize);
+	if (!tableSize)
+		return 0;
+
+	inc = 256 / tableSize;
+
+	red = (unsigned short *)arrays;
+	green = (unsigned short *)arrays + 256;
+	blue = (unsigned short *)arrays + 512;
+
+	for (i = 0, idx = 0; i < tableSize; i++, idx += inc)
+	{
+		gammaTableR[i] = red[idx] >> 8;
+		gammaTableG[i] = green[idx] >> 8;
+		gammaTableB[i] = blue[idx] >> 8;
+	}
+
+	FX_LoadGammaTable(tableSize, gammaTableR, gammaTableG, gammaTableB);
+
+	return 1;
+}
+
+/*
+ * glGetDeviceGammaRamp3DFX
+ * Sends a 1.0 gamma table. Also to be used for querying the lib.
+ */
+int glGetDeviceGammaRamp3DFX (void *arrays)
+{
+	int	i;
+	unsigned short	gammaTable[3][256];
+
+	if ((FX_LoadGammaTable == NULL) || (FX_Get == NULL))
+	{
+		if (Check_3DfxGammaRamp() == 0)
+			return 0;
+	}
+
+	for (i=0 ; i<256 ; i++)
+	{
+		 gammaTable[0][i] = i << 8;
+		 gammaTable[1][i] = i << 8;
+		 gammaTable[2][i] = i << 8;
+	}
+
+	memcpy(arrays, gammaTable, 3*256*sizeof(unsigned short));
+
+	return 1;
+}
+#endif
+
diff -urNp quake2~/src/linux/gl_glx.c quake2/src/linux/gl_glx.c
--- quake2~/src/linux/gl_glx.c	2005-01-28 00:35:20.000000000 +0200
+++ quake2/src/linux/gl_glx.c	2005-12-12 18:33:29.000000000 +0200
@@ -112,6 +112,12 @@ static XF86VidModeModeInfo **vidmodes;
 static int num_vidmodes;
 static qboolean vidmode_active = false;
 static XF86VidModeGamma oldgamma;
+#ifdef USE_3DFXGAMMA
+// evil glide gamma hack
+extern int  Init_3dfxGammaCtrl(void);
+extern void Shutdown_3dfxGamma(void);
+extern int  do3dfxGammaCtrl(float g);
+#endif
 
 static qboolean mouse_active = false;
 static qboolean dgamouse = false;
@@ -699,6 +705,7 @@ int GLimp_SetMode( int *pwidth, int *phe
 		}
 	}
 
+	gl_state.fxgamma = false;
 	gl_state.hwgamma = false;
 
 	/* do some pantsness */
@@ -766,14 +773,8 @@ int GLimp_SetMode( int *pwidth, int *phe
 				XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
 				vidmode_active = true;
 
-				if (XF86VidModeGetGamma(dpy, scrnum, &oldgamma)) {
+				if (XF86VidModeGetGamma(dpy, scrnum, &oldgamma))
 					gl_state.hwgamma = true;
-					/* We can not reliably detect hardware gamma
-					   changes across software gamma calls, which
-					   can reset the flag, so change it anyway */
-					vid_gamma->modified = true;
-					ri.Con_Printf( PRINT_ALL, "Using hardware gamma\n");
-				}
 
 				// Move the viewport to top left
 				XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
@@ -869,6 +870,27 @@ int GLimp_SetMode( int *pwidth, int *phe
 
 	qglXMakeCurrent(dpy, win, ctx);
 
+#ifdef USE_3DFXGAMMA
+	if (!Q_strncasecmp ((char *)qglGetString(GL_RENDERER), "Mesa Glide", 10))
+	{ // attempt to use glide symbols for gamma
+		gl_state.hwgamma = false;
+		gl_state.fxgamma = Init_3dfxGammaCtrl();
+		if (gl_state.fxgamma) {
+			ri.Con_Printf(PRINT_ALL, "Using 3dfx glide gamma controls\n");
+		}
+	}
+#endif
+	if (gl_state.hwgamma)
+		ri.Con_Printf(PRINT_ALL, "Using hardware gamma\n");
+
+	if (gl_state.hwgamma || gl_state.fxgamma)
+	{
+		/* We can not reliably detect hardware gamma
+		   changes across software gamma calls, which
+		   can reset the flag, so change it anyway */
+		vid_gamma->modified = true;
+	}
+
 	return rserr_ok;
 }
 
@@ -887,6 +909,11 @@ void GLimp_Shutdown( void )
 	mouse_active = false;
 	dgamouse = false;
 
+#ifdef USE_3DFXGAMMA
+	if (gl_state.fxgamma)
+		Shutdown_3dfxGamma();
+#endif
+
 	if (dpy) {
 		if (ctx)
 			qglXDestroyContext(dpy, ctx);
@@ -980,6 +1007,14 @@ void UpdateHardwareGamma()
 
 	g = (1.3 - vid_gamma->value + 1);
 	g = (g>1 ? g : 1);
+
+#ifdef USE_3DFXGAMMA
+	if (gl_state.fxgamma)
+	{
+		do3dfxGammaCtrl (g);
+		return;
+	}
+#endif
 	gamma.red = oldgamma.red * g;
 	gamma.green = oldgamma.green * g;
 	gamma.blue = oldgamma.blue * g;
diff -urNp quake2~/src/ref_candygl/gl_local.h quake2/src/ref_candygl/gl_local.h
--- quake2~/src/ref_candygl/gl_local.h	2003-07-12 04:59:52.000000000 +0300
+++ quake2/src/ref_candygl/gl_local.h	2005-12-12 18:33:29.000000000 +0200
@@ -525,12 +525,13 @@ typedef struct
 	qboolean	texture_compression; // Heffo - ARB Texture Compression
 
 
-
 	unsigned char originalRedGammaTable[256];
 	unsigned char originalGreenGammaTable[256];
 	unsigned char originalBlueGammaTable[256];
-  qboolean hwgamma;
-  
+
+	qboolean hwgamma;
+	qboolean fxgamma;
+
 } glstate_t;
 
 extern glconfig_t  gl_config;
diff -urNp quake2~/src/ref_gl/gl_image.c quake2/src/ref_gl/gl_image.c
--- quake2~/src/ref_gl/gl_image.c	2004-09-25 01:06:52.000000000 +0300
+++ quake2/src/ref_gl/gl_image.c	2005-12-12 18:33:29.000000000 +0200
@@ -1568,14 +1568,15 @@ void	GL_InitImages (void)
 			ri.Sys_Error( ERR_FATAL, "Couldn't load pics/16to8.pcx");
 	}
 
-	if ( gl_config.renderer & ( GL_RENDERER_VOODOO | GL_RENDERER_VOODOO2 ) )
+	if ( ( gl_config.renderer & ( GL_RENDERER_VOODOO | GL_RENDERER_VOODOO2 ) )
+	    && !gl_state.fxgamma)
 	{
 		g = 1.0F;
 	}
 
 	for ( i = 0; i < 256; i++ )
 	{
-		if ( g == 1 || gl_state.hwgamma )
+		if ( g == 1 || gl_state.hwgamma || gl_state.fxgamma)
 		{
 			gammatable[i] = i;
 		}
diff -urNp quake2~/src/ref_gl/gl_local.h quake2/src/ref_gl/gl_local.h
--- quake2~/src/ref_gl/gl_local.h	2005-09-06 16:02:26.000000000 +0300
+++ quake2/src/ref_gl/gl_local.h	2005-12-12 18:33:29.000000000 +0200
@@ -432,6 +432,7 @@ typedef struct
 	qboolean stereo_enabled;
 
 	qboolean hwgamma;
+	qboolean fxgamma;	// hack to use glide symbols exposed upon us
 
 	unsigned char originalRedGammaTable[256];
 	unsigned char originalGreenGammaTable[256];
diff -urNp quake2~/src/ref_gl/gl_rmain.c quake2/src/ref_gl/gl_rmain.c
--- quake2~/src/ref_gl/gl_rmain.c	2005-09-07 01:46:08.000000000 +0300
+++ quake2/src/ref_gl/gl_rmain.c	2005-12-12 18:33:29.000000000 +0200
@@ -1484,7 +1484,7 @@ void R_BeginFrame( float camera_separati
 	{
 		vid_gamma->modified = false;
 
-		if ( gl_state.hwgamma ) {
+		if ( gl_state.hwgamma || gl_state.fxgamma) {
 			UpdateHardwareGamma();
 		} else if ( gl_config.renderer & ( GL_RENDERER_VOODOO ) )
 		{
