]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - vid_shared.c
more fullscreen cleanup
[xonotic/darkplaces.git] / vid_shared.c
index 38750d358950aac3a1cb62d20d5039a8449237fe..5edba6706b02e1faf57d244bc7ce4126eebae742 100644 (file)
@@ -1,5 +1,6 @@
 
 #include "quakedef.h"
+#include "cdaudio.h"
 
 // global video state
 viddef_t vid;
@@ -13,14 +14,19 @@ qboolean in_client_mouse = true;
 
 // AK where should it be placed ?
 float in_mouse_x, in_mouse_y;
+float in_windowmouse_x, in_windowmouse_y;
 
+// value of GL_MAX_TEXTURE_<various>_SIZE
+int gl_max_texture_size = 0;
+int gl_max_3d_texture_size = 0;
+int gl_max_cube_map_texture_size = 0;
 // GL_ARB_multitexture
 int gl_textureunits = 1;
 // GL_ARB_texture_env_combine or GL_EXT_texture_env_combine
 int gl_combine_extension = false;
 // GL_EXT_compiled_vertex_array
 int gl_supportslockarrays = false;
-// GLX_SGI_video_sync or WGL_EXT_swap_control
+// GLX_SGI_swap_control or WGL_EXT_swap_control
 int gl_videosyncavailable = false;
 // stencil available
 int gl_stencil = false;
@@ -28,6 +34,8 @@ int gl_stencil = false;
 int gl_texture3d = false;
 // GL_ARB_texture_cubemap
 int gl_texturecubemap = false;
+// GL_ARB_texture_non_power_of_two
+int gl_support_arb_texture_non_power_of_two = false;
 // GL_ARB_texture_env_dot3
 int gl_dot3arb = false;
 // GL_SGIS_texture_edge_clamp
@@ -35,10 +43,14 @@ int gl_support_clamptoedge = false;
 // GL_EXT_texture_filter_anisotropic
 int gl_support_anisotropy = false;
 int gl_max_anisotropy = 1;
-// GL_NV_texture_shader
-int gl_textureshader = false;
+// OpenGL2.0 core glStencilOpSeparate, or GL_ATI_separate_stencil
+int gl_support_separatestencil = false;
 // GL_EXT_stencil_two_side
 int gl_support_stenciltwoside = false;
+// GL_EXT_blend_minmax
+int gl_support_ext_blend_minmax = false;
+// GL_EXT_blend_subtract
+int gl_support_ext_blend_subtract = false;
 // GL_ARB_shader_objects
 int gl_support_shader_objects = false;
 // GL_ARB_shading_language_100
@@ -47,51 +59,63 @@ int gl_support_shading_language_100 = false;
 int gl_support_vertex_shader = false;
 // GL_ARB_fragment_shader
 int gl_support_fragment_shader = false;
+//GL_ARB_vertex_buffer_object
+int gl_support_arb_vertex_buffer_object = false;
+//GL_ARB_texture_compression
+int gl_support_texture_compression = false;
 
 // LordHavoc: if window is hidden, don't update screen
-int vid_hidden = true;
+qboolean vid_hidden = true;
 // LordHavoc: if window is not the active window, don't hog as much CPU time,
 // let go of the mouse, turn off sound, and restore system gamma ramps...
-int vid_activewindow = true;
+qboolean vid_activewindow = true;
 
 // we don't know until we try it!
-cvar_t vid_hardwaregammasupported = {CVAR_READONLY,"vid_hardwaregammasupported","1"};
+cvar_t vid_hardwaregammasupported = {CVAR_READONLY,"vid_hardwaregammasupported","1", "indicates whether hardware gamma is supported (updated by attempts to set hardware gamma ramps)"};
 // whether hardware gamma ramps are currently in effect
-int vid_usinghwgamma = false;
-
-unsigned short vid_gammaramps[768];
-unsigned short vid_systemgammaramps[768];
-
-cvar_t vid_fullscreen = {CVAR_SAVE, "vid_fullscreen", "1"};
-cvar_t vid_width = {CVAR_SAVE, "vid_width", "640"};
-cvar_t vid_height = {CVAR_SAVE, "vid_height", "480"};
-cvar_t vid_bitsperpixel = {CVAR_SAVE, "vid_bitsperpixel", "32"};
-
-cvar_t vid_vsync = {CVAR_SAVE, "vid_vsync", "1"};
-cvar_t vid_mouse = {CVAR_SAVE, "vid_mouse", "1"};
-cvar_t gl_combine = {CVAR_SAVE, "gl_combine", "1"};
-cvar_t gl_finish = {0, "gl_finish", "0"};
-
-cvar_t in_pitch_min = {0, "in_pitch_min", "-70"};
-cvar_t in_pitch_max = {0, "in_pitch_max", "80"};
-
-cvar_t m_filter = {CVAR_SAVE, "m_filter","0"};
-
-cvar_t v_gamma = {CVAR_SAVE, "v_gamma", "1"};
-cvar_t v_contrast = {CVAR_SAVE, "v_contrast", "1"};
-cvar_t v_brightness = {CVAR_SAVE, "v_brightness", "0"};
-cvar_t v_color_enable = {CVAR_SAVE, "v_color_enable", "0"};
-cvar_t v_color_black_r = {CVAR_SAVE, "v_color_black_r", "0"};
-cvar_t v_color_black_g = {CVAR_SAVE, "v_color_black_g", "0"};
-cvar_t v_color_black_b = {CVAR_SAVE, "v_color_black_b", "0"};
-cvar_t v_color_grey_r = {CVAR_SAVE, "v_color_grey_r", "0.5"};
-cvar_t v_color_grey_g = {CVAR_SAVE, "v_color_grey_g", "0.5"};
-cvar_t v_color_grey_b = {CVAR_SAVE, "v_color_grey_b", "0.5"};
-cvar_t v_color_white_r = {CVAR_SAVE, "v_color_white_r", "1"};
-cvar_t v_color_white_g = {CVAR_SAVE, "v_color_white_g", "1"};
-cvar_t v_color_white_b = {CVAR_SAVE, "v_color_white_b", "1"};
-cvar_t v_hwgamma = {CVAR_SAVE, "v_hwgamma", "1"};
-cvar_t v_psycho = {0, "v_psycho", "0"};
+qboolean vid_usinghwgamma = false;
+
+int vid_gammarampsize = 0;
+unsigned short *vid_gammaramps = NULL;
+unsigned short *vid_systemgammaramps = NULL;
+
+cvar_t vid_fullscreen = {CVAR_SAVE, "vid_fullscreen", "1", "use fullscreen (1) or windowed (0)"};
+cvar_t vid_width = {CVAR_SAVE, "vid_width", "640", "resolution"};
+cvar_t vid_height = {CVAR_SAVE, "vid_height", "480", "resolution"};
+cvar_t vid_bitsperpixel = {CVAR_SAVE, "vid_bitsperpixel", "32", "how many bits per pixel to render at (32 or 16, 32 is recommended)"};
+cvar_t vid_samples = {CVAR_SAVE, "vid_samples", "1", "how many anti-aliasing samples per pixel to request from the graphics driver (4 is recommended, 1 is faster)"};
+cvar_t vid_refreshrate = {CVAR_SAVE, "vid_refreshrate", "60", "refresh rate to use, in hz (higher values flicker less, if supported by your monitor)"};
+cvar_t vid_userefreshrate = {CVAR_SAVE, "vid_userefreshrate", "0", "set this to 1 to make vid_refreshrate used, or to 0 to let the engine choose a sane default"};
+cvar_t vid_stereobuffer = {CVAR_SAVE, "vid_stereobuffer", "0", "enables 'quad-buffered' stereo rendering for stereo shutterglasses, HMD (head mounted display) devices, or polarized stereo LCDs, if supported by your drivers"};
+
+cvar_t vid_vsync = {CVAR_SAVE, "vid_vsync", "0", "sync to vertical blank, prevents 'tearing' (seeing part of one frame and part of another on the screen at the same time), automatically disabled when doing timedemo benchmarks"};
+cvar_t vid_mouse = {CVAR_SAVE, "vid_mouse", "1", "whether to use the mouse in windowed mode (fullscreen always does)"};
+cvar_t vid_grabkeyboard = {CVAR_SAVE, "vid_grabkeyboard", "0", "whether to grab the keyboard when mouse is active (prevents use of volume control keys, music player keys, etc on some keyboards)"};
+cvar_t vid_minwidth = {0, "vid_minwidth", "0", "minimum vid_width that is acceptable (to be set in default.cfg in mods)"};
+cvar_t vid_minheight = {0, "vid_minheight", "0", "minimum vid_height that is acceptable (to be set in default.cfg in mods)"};
+cvar_t gl_combine = {0, "gl_combine", "1", "faster rendering by using GL_ARB_texture_env_combine extension (part of OpenGL 1.3 and above)"};
+cvar_t gl_finish = {0, "gl_finish", "0", "make the cpu wait for the graphics processor at the end of each rendered frame (can help with strange input or video lag problems on some machines)"};
+
+cvar_t vid_stick_mouse = {CVAR_SAVE, "vid_stick_mouse", "0", "have the mouse stuck in the center of the screen" };
+cvar_t vid_resizable = {CVAR_SAVE, "vid_resizable", "0", "0: window not resizable, 1: resizable, 2: window can be resized but the framebuffer isn't adjusted" };
+
+cvar_t v_gamma = {CVAR_SAVE, "v_gamma", "1", "inverse gamma correction value, a brightness effect that does not affect white or black, and tends to make the image grey and dull"};
+cvar_t v_contrast = {CVAR_SAVE, "v_contrast", "1", "brightness of white (values above 1 give a brighter image with increased color saturation, unlike v_gamma)"};
+cvar_t v_brightness = {CVAR_SAVE, "v_brightness", "0", "brightness of black, useful for monitors that are too dark"};
+cvar_t v_contrastboost = {CVAR_SAVE, "v_contrastboost", "1", "by how much to multiply the contrast in dark areas (1 is no change)"};
+cvar_t v_color_enable = {CVAR_SAVE, "v_color_enable", "0", "enables black-grey-white color correction curve controls"};
+cvar_t v_color_black_r = {CVAR_SAVE, "v_color_black_r", "0", "desired color of black"};
+cvar_t v_color_black_g = {CVAR_SAVE, "v_color_black_g", "0", "desired color of black"};
+cvar_t v_color_black_b = {CVAR_SAVE, "v_color_black_b", "0", "desired color of black"};
+cvar_t v_color_grey_r = {CVAR_SAVE, "v_color_grey_r", "0.5", "desired color of grey"};
+cvar_t v_color_grey_g = {CVAR_SAVE, "v_color_grey_g", "0.5", "desired color of grey"};
+cvar_t v_color_grey_b = {CVAR_SAVE, "v_color_grey_b", "0.5", "desired color of grey"};
+cvar_t v_color_white_r = {CVAR_SAVE, "v_color_white_r", "1", "desired color of white"};
+cvar_t v_color_white_g = {CVAR_SAVE, "v_color_white_g", "1", "desired color of white"};
+cvar_t v_color_white_b = {CVAR_SAVE, "v_color_white_b", "1", "desired color of white"};
+cvar_t v_hwgamma = {CVAR_SAVE, "v_hwgamma", "1", "enables use of hardware gamma correction ramps if available (note: does not work very well on Windows2000 and above), values are 0 = off, 1 = attempt to use hardware gamma, 2 = use hardware gamma whether it works or not"};
+cvar_t v_glslgamma = {CVAR_SAVE, "v_glslgamma", "0", "enables use of GLSL to apply gamma correction ramps if available (note: overrides v_hwgamma)"};
+cvar_t v_psycho = {0, "v_psycho", "0", "easter egg (does not work on Windows2000 or above)"};
 
 // brand of graphics chip
 const char *gl_vendor;
@@ -110,8 +134,10 @@ const char *gl_platformextensions;
 char gl_driver[256];
 
 // GL_ARB_multitexture
+void (GLAPIENTRY *qglMultiTexCoord1f) (GLenum, GLfloat);
 void (GLAPIENTRY *qglMultiTexCoord2f) (GLenum, GLfloat, GLfloat);
 void (GLAPIENTRY *qglMultiTexCoord3f) (GLenum, GLfloat, GLfloat, GLfloat);
+void (GLAPIENTRY *qglMultiTexCoord4f) (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
 void (GLAPIENTRY *qglActiveTexture) (GLenum);
 void (GLAPIENTRY *qglClientActiveTexture) (GLenum);
 
@@ -119,12 +145,6 @@ void (GLAPIENTRY *qglClientActiveTexture) (GLenum);
 void (GLAPIENTRY *qglLockArraysEXT) (GLint first, GLint count);
 void (GLAPIENTRY *qglUnlockArraysEXT) (void);
 
-//GL_NV_vertex_array_range
-GLvoid *(GLAPIENTRY *qglAllocateMemoryNV)(GLsizei size, GLfloat readFrequency, GLfloat writeFrequency, GLfloat priority);
-GLvoid (GLAPIENTRY *qglFreeMemoryNV)(GLvoid *pointer);
-GLvoid (GLAPIENTRY *qglVertexArrayRangeNV)(GLsizei length, GLvoid *pointer);
-GLvoid (GLAPIENTRY *qglFlushVertexArrayRangeNV)(GLvoid);
-
 // general GL functions
 
 void (GLAPIENTRY *qglClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
@@ -169,9 +189,10 @@ void (GLAPIENTRY *qglTexCoordPointer)(GLint size, GLenum type, GLsizei stride, c
 void (GLAPIENTRY *qglArrayElement)(GLint i);
 
 void (GLAPIENTRY *qglColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
-void (GLAPIENTRY *qglTexCoord2f)(GLfloat s, GLfloat t);
+void (GLAPIENTRY *qglTexCoord1f)(GLfloat s);
 void (GLAPIENTRY *qglTexCoord2f)(GLfloat s, GLfloat t);
 void (GLAPIENTRY *qglTexCoord3f)(GLfloat s, GLfloat t, GLfloat r);
+void (GLAPIENTRY *qglTexCoord4f)(GLfloat s, GLfloat t, GLfloat r, GLfloat q);
 void (GLAPIENTRY *qglVertex2f)(GLfloat x, GLfloat y);
 void (GLAPIENTRY *qglVertex3f)(GLfloat x, GLfloat y, GLfloat z);
 void (GLAPIENTRY *qglBegin)(GLenum mode);
@@ -208,6 +229,7 @@ void (GLAPIENTRY *qglTexEnvi)(GLenum target, GLenum pname, GLint param);
 void (GLAPIENTRY *qglTexParameterf)(GLenum target, GLenum pname, GLfloat param);
 void (GLAPIENTRY *qglTexParameterfv)(GLenum target, GLenum pname, GLfloat *params);
 void (GLAPIENTRY *qglTexParameteri)(GLenum target, GLenum pname, GLint param);
+void (GLAPIENTRY *qglHint)(GLenum target, GLenum mode);
 
 void (GLAPIENTRY *qglGenTextures)(GLsizei n, GLuint *textures);
 void (GLAPIENTRY *qglDeleteTextures)(GLsizei n, const GLuint *textures);
@@ -239,7 +261,20 @@ void (GLAPIENTRY *qglCopyTexSubImage3D)(GLenum target, GLint level, GLint xoffse
 void (GLAPIENTRY *qglScissor)(GLint x, GLint y, GLsizei width, GLsizei height);
 
 void (GLAPIENTRY *qglPolygonOffset)(GLfloat factor, GLfloat units);
+void (GLAPIENTRY *qglPolygonMode)(GLenum face, GLenum mode);
+void (GLAPIENTRY *qglPolygonStipple)(const GLubyte *mask);
+
+void (GLAPIENTRY *qglClipPlane)(GLenum plane, const GLdouble *equation);
+void (GLAPIENTRY *qglGetClipPlane)(GLenum plane, GLdouble *equation);
+
+//[515]: added on 29.07.2005
+void (GLAPIENTRY *qglLineWidth)(GLfloat width);
+void (GLAPIENTRY *qglPointSize)(GLfloat size);
 
+void (GLAPIENTRY *qglBlendEquationEXT)(GLenum);
+
+void (GLAPIENTRY *qglStencilOpSeparate)(GLenum, GLenum, GLenum, GLenum);
+void (GLAPIENTRY *qglStencilFuncSeparate)(GLenum, GLenum, GLint, GLuint);
 void (GLAPIENTRY *qglActiveStencilFaceEXT)(GLenum);
 
 void (GLAPIENTRY *qglDeleteObjectARB)(GLhandleARB obj);
@@ -329,6 +364,24 @@ GLint (GLAPIENTRY *qglGetAttribLocationARB)(GLhandleARB programObj, const GLchar
 //void (GLAPIENTRY *qglGetVertexAttribivARB)(GLuint index, GLenum pname, GLint *params);
 //void (GLAPIENTRY *qglGetVertexAttribPointervARB)(GLuint index, GLenum pname, GLvoid **pointer);
 
+//GL_ARB_vertex_buffer_object
+void (GLAPIENTRY *qglBindBufferARB) (GLenum target, GLuint buffer);
+void (GLAPIENTRY *qglDeleteBuffersARB) (GLsizei n, const GLuint *buffers);
+void (GLAPIENTRY *qglGenBuffersARB) (GLsizei n, GLuint *buffers);
+GLboolean (GLAPIENTRY *qglIsBufferARB) (GLuint buffer);
+GLvoid* (GLAPIENTRY *qglMapBufferARB) (GLenum target, GLenum access);
+GLboolean (GLAPIENTRY *qglUnmapBufferARB) (GLenum target);
+void (GLAPIENTRY *qglBufferDataARB) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage);
+void (GLAPIENTRY *qglBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data);
+
+void (GLAPIENTRY *qglCompressedTexImage3DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+void (GLAPIENTRY *qglCompressedTexImage2DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border,  GLsizei imageSize, const void *data);
+void (GLAPIENTRY *qglCompressedTexImage1DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
+void (GLAPIENTRY *qglCompressedTexSubImage3DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+void (GLAPIENTRY *qglCompressedTexSubImage2DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+void (GLAPIENTRY *qglCompressedTexSubImage1DARB)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+void (GLAPIENTRY *qglGetCompressedTexImageARB)(GLenum target, GLint lod, void *img);
+
 int GL_CheckExtension(const char *name, const dllfunction_t *funcs, const char *disableparm, int silent)
 {
        int failed = false;
@@ -345,29 +398,27 @@ int GL_CheckExtension(const char *name, const dllfunction_t *funcs, const char *
                return false;
        }
 
-       if (strstr(gl_extensions, name) || strstr(gl_platformextensions, name) || (strncmp(name, "GL_", 3) && strncmp(name, "WGL_", 4) && strncmp(name, "GLX_", 4) && strncmp(name, "AGL_", 4)))
+       if ((name[2] == '_' || name[3] == '_') && !strstr(gl_extensions ? gl_extensions : "", name) && !strstr(gl_platformextensions ? gl_platformextensions : "", name))
+       {
+               Con_DPrint("not detected\n");
+               return false;
+       }
+
+       for (func = funcs;func && func->name != NULL;func++)
        {
-               for (func = funcs;func && func->name != NULL;func++)
+               // functions are cleared before all the extensions are evaluated
+               if (!(*func->funcvariable = (void *) GL_GetProcAddress(func->name)))
                {
-                       // functions are cleared before all the extensions are evaluated
-                       if (!(*func->funcvariable = (void *) GL_GetProcAddress(func->name)))
-                       {
-                               if (!silent)
-                                       Con_Printf("OpenGL extension \"%s\" is missing function \"%s\" - broken driver!\n", name, func->name);
-                               failed = true;
-                       }
+                       if (!silent)
+                               Con_DPrintf("OpenGL extension \"%s\" is missing function \"%s\" - broken driver!\n", name, func->name);
+                       failed = true;
                }
-               // delay the return so it prints all missing functions
-               if (failed)
-                       return false;
-               Con_DPrint("enabled\n");
-               return true;
        }
-       else
-       {
-               Con_DPrint("not detected\n");
+       // delay the return so it prints all missing functions
+       if (failed)
                return false;
-       }
+       Con_DPrint("enabled\n");
+       return true;
 }
 
 static dllfunction_t opengl110funcs[] =
@@ -404,12 +455,18 @@ static dllfunction_t opengl110funcs[] =
        {"glTexCoordPointer", (void **) &qglTexCoordPointer},
        {"glArrayElement", (void **) &qglArrayElement},
        {"glColor4f", (void **) &qglColor4f},
+       {"glTexCoord1f", (void **) &qglTexCoord1f},
        {"glTexCoord2f", (void **) &qglTexCoord2f},
        {"glTexCoord3f", (void **) &qglTexCoord3f},
+       {"glTexCoord4f", (void **) &qglTexCoord4f},
        {"glVertex2f", (void **) &qglVertex2f},
        {"glVertex3f", (void **) &qglVertex3f},
        {"glBegin", (void **) &qglBegin},
        {"glEnd", (void **) &qglEnd},
+//[515]: added on 29.07.2005
+       {"glLineWidth", (void**) &qglLineWidth},
+       {"glPointSize", (void**) &qglPointSize},
+//
        {"glMatrixMode", (void **) &qglMatrixMode},
        {"glOrtho", (void **) &qglOrtho},
        {"glFrustum", (void **) &qglFrustum},
@@ -438,6 +495,7 @@ static dllfunction_t opengl110funcs[] =
        {"glTexParameterf", (void **) &qglTexParameterf},
        {"glTexParameterfv", (void **) &qglTexParameterfv},
        {"glTexParameteri", (void **) &qglTexParameteri},
+       {"glHint", (void **) &qglHint},
        {"glPixelStoref", (void **) &qglPixelStoref},
        {"glPixelStorei", (void **) &qglPixelStorei},
        {"glGenTextures", (void **) &qglGenTextures},
@@ -456,6 +514,10 @@ static dllfunction_t opengl110funcs[] =
        {"glCopyTexSubImage2D", (void **) &qglCopyTexSubImage2D},
        {"glScissor", (void **) &qglScissor},
        {"glPolygonOffset", (void **) &qglPolygonOffset},
+       {"glPolygonMode", (void **) &qglPolygonMode},
+       {"glPolygonStipple", (void **) &qglPolygonStipple},
+       {"glClipPlane", (void **) &qglClipPlane},
+       {"glGetClipPlane", (void **) &qglGetClipPlane},
        {NULL, NULL}
 };
 
@@ -473,8 +535,10 @@ static dllfunction_t drawrangeelementsextfuncs[] =
 
 static dllfunction_t multitexturefuncs[] =
 {
+       {"glMultiTexCoord1fARB", (void **) &qglMultiTexCoord1f},
        {"glMultiTexCoord2fARB", (void **) &qglMultiTexCoord2f},
        {"glMultiTexCoord3fARB", (void **) &qglMultiTexCoord3f},
+       {"glMultiTexCoord4fARB", (void **) &qglMultiTexCoord4f},
        {"glActiveTextureARB", (void **) &qglActiveTexture},
        {"glClientActiveTextureARB", (void **) &qglClientActiveTexture},
        {NULL, NULL}
@@ -495,12 +559,32 @@ static dllfunction_t texture3dextfuncs[] =
        {NULL, NULL}
 };
 
+static dllfunction_t atiseparatestencilfuncs[] =
+{
+       {"glStencilOpSeparateATI", (void **) &qglStencilOpSeparate},
+       {"glStencilFuncSeparateATI", (void **) &qglStencilFuncSeparate},
+       {NULL, NULL}
+};
+
+static dllfunction_t gl2separatestencilfuncs[] =
+{
+       {"glStencilOpSeparate", (void **) &qglStencilOpSeparate},
+       {"glStencilFuncSeparate", (void **) &qglStencilFuncSeparate},
+       {NULL, NULL}
+};
+
 static dllfunction_t stenciltwosidefuncs[] =
 {
        {"glActiveStencilFaceEXT", (void **) &qglActiveStencilFaceEXT},
        {NULL, NULL}
 };
 
+static dllfunction_t blendequationfuncs[] =
+{
+       {"glBlendEquationEXT", (void **) &qglBlendEquationEXT},
+       {NULL, NULL}
+};
+
 static dllfunction_t shaderobjectsfuncs[] =
 {
        {"glDeleteObjectARB", (void **) &qglDeleteObjectARB},
@@ -596,6 +680,30 @@ static dllfunction_t vertexshaderfuncs[] =
        {NULL, NULL}
 };
 
+static dllfunction_t vbofuncs[] =
+{
+       {"glBindBufferARB"    , (void **) &qglBindBufferARB},
+       {"glDeleteBuffersARB" , (void **) &qglDeleteBuffersARB},
+       {"glGenBuffersARB"    , (void **) &qglGenBuffersARB},
+       {"glIsBufferARB"      , (void **) &qglIsBufferARB},
+       {"glMapBufferARB"     , (void **) &qglMapBufferARB},
+       {"glUnmapBufferARB"   , (void **) &qglUnmapBufferARB},
+       {"glBufferDataARB"    , (void **) &qglBufferDataARB},
+       {"glBufferSubDataARB" , (void **) &qglBufferSubDataARB},
+       {NULL, NULL}
+};
+
+static dllfunction_t texturecompressionfuncs[] =
+{
+       {"glCompressedTexImage3DARB",    (void **) &qglCompressedTexImage3DARB},
+       {"glCompressedTexImage2DARB",    (void **) &qglCompressedTexImage2DARB},
+       {"glCompressedTexImage1DARB",    (void **) &qglCompressedTexImage1DARB},
+       {"glCompressedTexSubImage3DARB", (void **) &qglCompressedTexSubImage3DARB},
+       {"glCompressedTexSubImage2DARB", (void **) &qglCompressedTexSubImage2DARB},
+       {"glCompressedTexSubImage1DARB", (void **) &qglCompressedTexSubImage1DARB},
+       {"glGetCompressedTexImageARB",   (void **) &qglGetCompressedTexImageARB},
+       {NULL, NULL}
+};
 
 void VID_CheckExtensions(void)
 {
@@ -603,111 +711,108 @@ void VID_CheckExtensions(void)
 
        // reset all the gl extension variables here
        // this should match the declarations
+       gl_max_texture_size = 0;
+       gl_max_3d_texture_size = 0;
+       gl_max_cube_map_texture_size = 0;
        gl_textureunits = 1;
        gl_combine_extension = false;
        gl_supportslockarrays = false;
        gl_texture3d = false;
        gl_texturecubemap = false;
+       gl_support_arb_texture_non_power_of_two = false;
        gl_dot3arb = false;
        gl_support_clamptoedge = false;
        gl_support_anisotropy = false;
        gl_max_anisotropy = 1;
-       gl_textureshader = false;
+       gl_support_separatestencil = false;
        gl_support_stenciltwoside = false;
+       gl_support_ext_blend_minmax = false;
+       gl_support_ext_blend_subtract = false;
        gl_support_shader_objects = false;
        gl_support_shading_language_100 = false;
        gl_support_vertex_shader = false;
        gl_support_fragment_shader = false;
+       gl_support_arb_vertex_buffer_object = false;
+       gl_support_texture_compression = false;
 
        if (!GL_CheckExtension("OpenGL 1.1.0", opengl110funcs, NULL, false))
-               Sys_Error("OpenGL 1.1.0 functions not found\n");
+               Sys_Error("OpenGL 1.1.0 functions not found");
 
-       Con_DPrintf("GL_VENDOR: %s\n", gl_vendor);
-       Con_DPrintf("GL_RENDERER: %s\n", gl_renderer);
-       Con_DPrintf("GL_VERSION: %s\n", gl_version);
-       Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions);
-       Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions);
+       CHECKGLERROR
+       qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl_max_texture_size);
 
        Con_DPrint("Checking OpenGL extensions...\n");
 
-// COMMANDLINEOPTION: -nodrawrangeelements disables GL_EXT_draw_range_elements (renders faster)
+// COMMANDLINEOPTION: GL: -nodrawrangeelements disables GL_EXT_draw_range_elements (renders faster)
        if (!GL_CheckExtension("glDrawRangeElements", drawrangeelementsfuncs, "-nodrawrangeelements", true))
                GL_CheckExtension("GL_EXT_draw_range_elements", drawrangeelementsextfuncs, "-nodrawrangeelements", false);
 
-// COMMANDLINEOPTION: -nomtex disables GL_ARB_multitexture (required for faster map rendering)
+// COMMANDLINEOPTION: GL: -nomtex disables GL_ARB_multitexture (required for faster map rendering)
        if (GL_CheckExtension("GL_ARB_multitexture", multitexturefuncs, "-nomtex", false))
        {
                qglGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &gl_textureunits);
-// COMMANDLINEOPTION: -nocombine disables GL_ARB_texture_env_combine or GL_EXT_texture_env_combine (required for bumpmapping and faster map rendering)
+// COMMANDLINEOPTION: GL: -nocombine disables GL_ARB_texture_env_combine or GL_EXT_texture_env_combine (required for bumpmapping and faster map rendering)
                gl_combine_extension = GL_CheckExtension("GL_ARB_texture_env_combine", NULL, "-nocombine", false) || GL_CheckExtension("GL_EXT_texture_env_combine", NULL, "-nocombine", false);
-// COMMANDLINEOPTION: -nodot3 disables GL_ARB_texture_env_dot3 (required for bumpmapping)
+// COMMANDLINEOPTION: GL: -nodot3 disables GL_ARB_texture_env_dot3 (required for bumpmapping)
                if (gl_combine_extension)
                        gl_dot3arb = GL_CheckExtension("GL_ARB_texture_env_dot3", NULL, "-nodot3", false);
        }
 
-// COMMANDLINEOPTION: -notexture3d disables GL_EXT_texture3D (required for spherical lights, otherwise they render as a column)
-       gl_texture3d = GL_CheckExtension("GL_EXT_texture3D", texture3dextfuncs, "-notexture3d", false);
-// COMMANDLINEOPTION: -nocubemap disables GL_ARB_texture_cube_map (required for bumpmapping)
-       gl_texturecubemap = GL_CheckExtension("GL_ARB_texture_cube_map", NULL, "-nocubemap", false);
-// COMMANDLINEOPTION: -nocva disables GL_EXT_compiled_vertex_array (renders faster)
+// COMMANDLINEOPTION: GL: -notexture3d disables GL_EXT_texture3D (required for spherical lights, otherwise they render as a column)
+       if ((gl_texture3d = GL_CheckExtension("GL_EXT_texture3D", texture3dextfuncs, "-notexture3d", false)))
+       {
+               qglGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &gl_max_3d_texture_size);
+               if (gl_max_3d_texture_size < 32)
+               {
+                       gl_texture3d = false;
+                       Con_Printf("GL_EXT_texture3D reported bogus GL_MAX_3D_TEXTURE_SIZE, disabled\n");
+               }
+       }
+// COMMANDLINEOPTION: GL: -nocubemap disables GL_ARB_texture_cube_map (required for bumpmapping)
+       if ((gl_texturecubemap = GL_CheckExtension("GL_ARB_texture_cube_map", NULL, "-nocubemap", false)))
+               qglGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &gl_max_cube_map_texture_size);
+#ifndef __APPLE__
+       // TODO: blacklist this extension on Radeon X1600-X1950 hardware (they support it only with certain filtering/repeat modes)
+       // LordHavoc: this is blocked on Mac OS X because the drivers claim support but often can't accelerate it or crash when used.
+// COMMANDLINEOPTION: GL: -notexturenonpoweroftwo disables GL_ARB_texture_non_power_of_two (which saves video memory if it is supported, but crashes on some buggy drivers)
+       gl_support_arb_texture_non_power_of_two = GL_CheckExtension("GL_ARB_texture_non_power_of_two", NULL, "-notexturenonpoweroftwo", false);
+#endif
+// COMMANDLINEOPTION: GL: -notexturecompression disables GL_ARB_texture_compression (which saves video memory if it is supported, but can also degrade image quality, see gl_texturecompression cvar documentation for more information)
+       gl_support_texture_compression = GL_CheckExtension("GL_ARB_texture_compression", texturecompressionfuncs, "-notexturecompression", false);
+// COMMANDLINEOPTION: GL: -nocva disables GL_EXT_compiled_vertex_array (renders faster)
        gl_supportslockarrays = GL_CheckExtension("GL_EXT_compiled_vertex_array", compiledvertexarrayfuncs, "-nocva", false);
-// COMMANDLINEOPTION: -noedgeclamp disables GL_EXT_texture_edge_clamp or GL_SGIS_texture_edge_clamp (recommended, some cards do not support the other texture clamp method)
+// COMMANDLINEOPTION: GL: -noedgeclamp disables GL_EXT_texture_edge_clamp or GL_SGIS_texture_edge_clamp (recommended, some cards do not support the other texture clamp method)
        gl_support_clamptoedge = GL_CheckExtension("GL_EXT_texture_edge_clamp", NULL, "-noedgeclamp", false) || GL_CheckExtension("GL_SGIS_texture_edge_clamp", NULL, "-noedgeclamp", false);
 
-// COMMANDLINEOPTION: -noanisotropy disables GL_EXT_texture_filter_anisotropic (allows higher quality texturing)
+// COMMANDLINEOPTION: GL: -noanisotropy disables GL_EXT_texture_filter_anisotropic (allows higher quality texturing)
        if ((gl_support_anisotropy = GL_CheckExtension("GL_EXT_texture_filter_anisotropic", NULL, "-noanisotropy", false)))
                qglGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_max_anisotropy);
 
-// COMMANDLINEOPTION: -notextureshader disables GL_NV_texture_shader (required for the Geforce3 water shader, NVIDIA only)
-       gl_textureshader = GL_CheckExtension("GL_NV_texture_shader", NULL, "-notextureshader", false);
+       gl_support_ext_blend_minmax = GL_CheckExtension("GL_EXT_blend_minmax", blendequationfuncs, "-noblendminmax", false);
+       gl_support_ext_blend_subtract = GL_CheckExtension("GL_EXT_blend_subtract", blendequationfuncs, "-noblendsubtract", false);
 
-// COMMANDLINEOPTION: -nostenciltwoside disables GL_EXT_stencil_two_side (accelerates shadow rendering)
+// COMMANDLINEOPTION: GL: -noseparatestencil disables use of OpenGL2.0 glStencilOpSeparate and GL_ATI_separate_stencil extensions (which accelerate shadow rendering)
+       if (!(gl_support_separatestencil = GL_CheckExtension("glStencilOpSeparate", gl2separatestencilfuncs, "-noseparatestencil", true)))
+               gl_support_separatestencil = GL_CheckExtension("GL_ATI_separate_stencil", atiseparatestencilfuncs, "-noseparatestencil", false);
+// COMMANDLINEOPTION: GL: -nostenciltwoside disables GL_EXT_stencil_two_side (which accelerate shadow rendering)
        gl_support_stenciltwoside = GL_CheckExtension("GL_EXT_stencil_two_side", stenciltwosidefuncs, "-nostenciltwoside", false);
 
+// COMMANDLINEOPTION: GL: -novbo disables GL_ARB_vertex_buffer_object (which accelerates rendering)
+       gl_support_arb_vertex_buffer_object = GL_CheckExtension("GL_ARB_vertex_buffer_object", vbofuncs, "-novbo", false);
+
        // we don't care if it's an extension or not, they are identical functions, so keep it simple in the rendering code
        if (qglDrawRangeElements == NULL)
                qglDrawRangeElements = qglDrawRangeElementsEXT;
 
-// COMMANDLINEOPTION: -noshaderobjects disables GL_ARB_shader_objects (required for vertex shader and fragment shader)
-// COMMANDLINEOPTION: -noshadinglanguage100 disables GL_ARB_shading_language_100 (required for vertex shader and fragment shader)
-// COMMANDLINEOPTION: -novertexshader disables GL_ARB_vertex_shader (currently unused, allows vertex shader effects)
-// COMMANDLINEOPTION: -nofragmentshader disables GL_ARB_fragment_shader (currently unused, allows pixel shader effects)
+// COMMANDLINEOPTION: GL: -noshaderobjects disables GL_ARB_shader_objects (required for vertex shader and fragment shader)
+// COMMANDLINEOPTION: GL: -noshadinglanguage100 disables GL_ARB_shading_language_100 (required for vertex shader and fragment shader)
+// COMMANDLINEOPTION: GL: -novertexshader disables GL_ARB_vertex_shader (allows vertex shader effects)
+// COMMANDLINEOPTION: GL: -nofragmentshader disables GL_ARB_fragment_shader (allows pixel shader effects, can improve per pixel lighting performance and capabilities)
        if ((gl_support_shader_objects = GL_CheckExtension("GL_ARB_shader_objects", shaderobjectsfuncs, "-noshaderobjects", false)))
                if ((gl_support_shading_language_100 = GL_CheckExtension("GL_ARB_shading_language_100", NULL, "-noshadinglanguage100", false)))
                        if ((gl_support_vertex_shader = GL_CheckExtension("GL_ARB_vertex_shader", vertexshaderfuncs, "-novertexshader", false)))
                                gl_support_fragment_shader = GL_CheckExtension("GL_ARB_fragment_shader", NULL, "-nofragmentshader", false);
-}
-
-int vid_vertexarrays_are_var = false;
-void *VID_AllocVertexArrays(mempool_t *pool, int size, int fast, float readfrequency, float writefrequency, float priority)
-{
-       void *m;
-       vid_vertexarrays_are_var = false;
-       if (fast && qglAllocateMemoryNV)
-       {
-               CHECKGLERROR
-               m = qglAllocateMemoryNV(size, readfrequency, writefrequency, priority);
-               CHECKGLERROR
-               if (m)
-               {
-                       vid_vertexarrays_are_var = true;
-                       return m;
-               }
-       }
-       return Mem_Alloc(pool, size);
-}
-
-void VID_FreeVertexArrays(void *pointer)
-{
-       if (vid_vertexarrays_are_var)
-       {
-               CHECKGLERROR
-               qglFreeMemoryNV(pointer);
-               CHECKGLERROR
-       }
-       else
-               Mem_Free(pointer);
-       vid_vertexarrays_are_var = false;
+       CHECKGLERROR
 }
 
 void Force_CenterView_f (void)
@@ -715,207 +820,191 @@ void Force_CenterView_f (void)
        cl.viewangles[PITCH] = 0;
 }
 
-void IN_PreMove(void)
-{
-}
-
-void CL_AdjustAngles(void);
-void IN_PostMove(void)
-{
-       // clamp after the move as well to prevent messed up rendering angles
-       CL_AdjustAngles();
-}
-
-/*
-===========
-IN_DoMove
-===========
-*/
-void IN_ProcessMove(usercmd_t *cmd)
-{
-       // get basic movement from keyboard
-       CL_BaseMove(cmd);
-
-       // OS independent code
-       IN_PreMove();
-
-       // allow mice or other external controllers to add to the move
-       IN_Move(cmd);
-
-       // OS independent code
-       IN_PostMove();
-}
-
+static int gamma_forcenextframe = false;
+static float cachegamma, cachebrightness, cachecontrast, cacheblack[3], cachegrey[3], cachewhite[3], cachecontrastboost;
+static int cachecolorenable, cachehwgamma;
 
-void IN_Mouse(usercmd_t *cmd, float mx, float my)
+unsigned int vid_gammatables_serial = 0; // so other subsystems can poll if gamma parameters have changed
+qboolean vid_gammatables_trivial = true;
+void VID_BuildGammaTables(unsigned short *ramps, int rampsize)
 {
-       int mouselook = (in_mlook.state & 1) || freelook.integer;
-       float mouse_x, mouse_y;
-       static float old_mouse_x = 0, old_mouse_y = 0;
-
-       if (m_filter.integer)
+       if (cachecolorenable)
        {
-               mouse_x = (mx + old_mouse_x) * 0.5;
-               mouse_y = (my + old_mouse_y) * 0.5;
+               BuildGammaTable16(1.0f, invpow(0.5, 1 - cachegrey[0]), cachewhite[0], cacheblack[0], cachecontrastboost, ramps, rampsize);
+               BuildGammaTable16(1.0f, invpow(0.5, 1 - cachegrey[1]), cachewhite[1], cacheblack[1], cachecontrastboost, ramps + rampsize, rampsize);
+               BuildGammaTable16(1.0f, invpow(0.5, 1 - cachegrey[2]), cachewhite[2], cacheblack[2], cachecontrastboost, ramps + rampsize*2, rampsize);
        }
        else
        {
-               mouse_x = mx;
-               mouse_y = my;
+               BuildGammaTable16(1.0f, cachegamma, cachecontrast, cachebrightness, cachecontrastboost, ramps, rampsize);
+               BuildGammaTable16(1.0f, cachegamma, cachecontrast, cachebrightness, cachecontrastboost, ramps + rampsize, rampsize);
+               BuildGammaTable16(1.0f, cachegamma, cachecontrast, cachebrightness, cachecontrastboost, ramps + rampsize*2, rampsize);
        }
 
-       old_mouse_x = mx;
-       old_mouse_y = my;
-
-       in_mouse_x = (float) mouse_x * vid.conwidth / vid.realwidth;
-       in_mouse_y = (float) mouse_y * vid.conheight / vid.realheight;
-
-       // AK: eveything else is client stuff
-       // BTW, this should be seperated somewhen
-       if(!in_client_mouse)
-               return;
-
-       // LordHavoc: viewzoom affects mouse sensitivity for sniping
-       mouse_x *= sensitivity.value * cl.viewzoom;
-       mouse_y *= sensitivity.value * cl.viewzoom;
-
-       // Add mouse X/Y movement to cmd
-       if ((in_strafe.state & 1) || (lookstrafe.integer && mouselook))
-               cmd->sidemove += m_side.value * mouse_x;
-       else
-               cl.viewangles[YAW] -= m_yaw.value * mouse_x;
+       // LordHavoc: this code came from Ben Winslow and Zinx Verituse, I have
+       // immensely butchered it to work with variable framerates and fit in with
+       // the rest of darkplaces.
+       if (v_psycho.integer)
+       {
+               int x, y;
+               float t;
+               static float n[3], nd[3], nt[3];
+               static int init = true;
+               unsigned short *ramp;
+               gamma_forcenextframe = true;
+               if (init)
+               {
+                       init = false;
+                       for (x = 0;x < 3;x++)
+                       {
+                               n[x] = lhrandom(0, 1);
+                               nd[x] = (rand()&1)?-0.25:0.25;
+                               nt[x] = lhrandom(1, 8.2);
+                       }
+               }
 
-       if (mouselook)
-               V_StopPitchDrift();
+               for (x = 0;x < 3;x++)
+               {
+                       nt[x] -= cl.realframetime;
+                       if (nt[x] < 0)
+                       {
+                               nd[x] = -nd[x];
+                               nt[x] += lhrandom(1, 8.2);
+                       }
+                       n[x] += nd[x] * cl.realframetime;
+                       n[x] -= floor(n[x]);
+               }
 
-       if (mouselook && !(in_strafe.state & 1))
-               cl.viewangles[PITCH] += m_pitch.value * mouse_y;
-       else
-       {
-               if ((in_strafe.state & 1) && noclip_anglehack)
-                       cmd->upmove -= m_forward.value * mouse_y;
-               else
-                       cmd->forwardmove -= m_forward.value * mouse_y;
+               for (x = 0, ramp = ramps;x < 3;x++)
+                       for (y = 0, t = n[x] - 0.75f;y < rampsize;y++, t += 0.75f * (2.0f / rampsize))
+                               *ramp++ = (unsigned short)(cos(t*(M_PI*2.0)) * 32767.0f + 32767.0f);
        }
 }
 
-static float cachegamma, cachebrightness, cachecontrast, cacheblack[3], cachegrey[3], cachewhite[3];
-static int cachecolorenable, cachehwgamma;
-#define BOUNDCVAR(cvar, m1, m2) c = &(cvar);f = bound(m1, c->value, m2);if (c->value != f) Cvar_SetValueQuick(c, f);
-void VID_UpdateGamma(qboolean force)
+void VID_UpdateGamma(qboolean force, int rampsize)
 {
        cvar_t *c;
        float f;
-       static int forcenextframe = false;
+       int wantgamma;
+       qboolean gamma_changed = false;
 
        // LordHavoc: don't mess with gamma tables if running dedicated
        if (cls.state == ca_dedicated)
                return;
 
-       if (!force
-        && !forcenextframe
-        && !v_psycho.integer
-        && vid_usinghwgamma == (vid_activewindow && v_hwgamma.integer)
-        && v_gamma.value == cachegamma
-        && v_contrast.value == cachecontrast
-        && v_brightness.value == cachebrightness
-        && cachecolorenable == v_color_enable.integer
-        && cacheblack[0] == v_color_black_r.value
-        && cacheblack[1] == v_color_black_g.value
-        && cacheblack[2] == v_color_black_b.value
-        && cachegrey[0] == v_color_grey_r.value
-        && cachegrey[1] == v_color_grey_g.value
-        && cachegrey[2] == v_color_grey_b.value
-        && cachewhite[0] == v_color_white_r.value
-        && cachewhite[1] == v_color_white_g.value
-        && cachewhite[2] == v_color_white_b.value)
-               return;
-               
-       forcenextframe = false;
-
-       if (vid_activewindow && v_hwgamma.integer)
+       wantgamma = v_hwgamma.integer;
+       if(r_glsl.integer && v_glslgamma.integer)
+               wantgamma = 0;
+       if(!vid_activewindow)
+               wantgamma = 0;
+#define BOUNDCVAR(cvar, m1, m2) c = &(cvar);f = bound(m1, c->value, m2);if (c->value != f) Cvar_SetValueQuick(c, f);
+       BOUNDCVAR(v_gamma, 0.1, 5);
+       BOUNDCVAR(v_contrast, 1, 5);
+       BOUNDCVAR(v_brightness, 0, 0.8);
+       BOUNDCVAR(v_contrastboost, 0.0625, 16);
+       BOUNDCVAR(v_color_black_r, 0, 0.8);
+       BOUNDCVAR(v_color_black_g, 0, 0.8);
+       BOUNDCVAR(v_color_black_b, 0, 0.8);
+       BOUNDCVAR(v_color_grey_r, 0, 0.95);
+       BOUNDCVAR(v_color_grey_g, 0, 0.95);
+       BOUNDCVAR(v_color_grey_b, 0, 0.95);
+       BOUNDCVAR(v_color_white_r, 1, 5);
+       BOUNDCVAR(v_color_white_g, 1, 5);
+       BOUNDCVAR(v_color_white_b, 1, 5);
+#undef BOUNDCVAR
+
+       // set vid_gammatables_trivial to true if the current settings would generate the identity gamma table
+       vid_gammatables_trivial = false;
+       if(v_psycho.integer == 0)
+       if(v_contrastboost.value == 1)
        {
-               if (!vid_usinghwgamma)
+               if(v_color_enable.integer)
                {
-                       vid_usinghwgamma = true;
-                       Cvar_SetValueQuick(&vid_hardwaregammasupported, VID_GetGamma(vid_systemgammaramps));
-               }
-
-               BOUNDCVAR(v_gamma, 0.1, 5);cachegamma = v_gamma.value;
-               BOUNDCVAR(v_contrast, 1, 5);cachecontrast = v_contrast.value;
-               BOUNDCVAR(v_brightness, 0, 0.8);cachebrightness = v_brightness.value;
-               BOUNDCVAR(v_color_black_r, 0, 0.8);cacheblack[0] = v_color_black_r.value;
-               BOUNDCVAR(v_color_black_g, 0, 0.8);cacheblack[1] = v_color_black_g.value;
-               BOUNDCVAR(v_color_black_b, 0, 0.8);cacheblack[2] = v_color_black_b.value;
-               BOUNDCVAR(v_color_grey_r, 0, 0.95);cachegrey[0] = v_color_grey_r.value;
-               BOUNDCVAR(v_color_grey_g, 0, 0.95);cachegrey[1] = v_color_grey_g.value;
-               BOUNDCVAR(v_color_grey_b, 0, 0.95);cachegrey[2] = v_color_grey_b.value;
-               BOUNDCVAR(v_color_white_r, 1, 5);cachewhite[0] = v_color_white_r.value;
-               BOUNDCVAR(v_color_white_g, 1, 5);cachewhite[1] = v_color_white_g.value;
-               BOUNDCVAR(v_color_white_b, 1, 5);cachewhite[2] = v_color_white_b.value;
-               cachecolorenable = v_color_enable.integer;
-               cachehwgamma = v_hwgamma.integer;
-
-               if (cachecolorenable)
-               {
-                       BuildGammaTable16(1.0f, invpow(0.5, 1 - cachegrey[0]), cachewhite[0], cacheblack[0], vid_gammaramps);
-                       BuildGammaTable16(1.0f, invpow(0.5, 1 - cachegrey[1]), cachewhite[1], cacheblack[1], vid_gammaramps + 256);
-                       BuildGammaTable16(1.0f, invpow(0.5, 1 - cachegrey[2]), cachewhite[2], cacheblack[2], vid_gammaramps + 512);
+                       if(v_color_black_r.value == 0)
+                       if(v_color_black_g.value == 0)
+                       if(v_color_black_b.value == 0)
+                       if(fabs(v_color_grey_r.value - 0.5) < 1e-6)
+                       if(fabs(v_color_grey_g.value - 0.5) < 1e-6)
+                       if(fabs(v_color_grey_b.value - 0.5) < 1e-6)
+                       if(v_color_white_r.value == 1)
+                       if(v_color_white_g.value == 1)
+                       if(v_color_white_b.value == 1)
+                               vid_gammatables_trivial = true;
                }
                else
                {
-                       BuildGammaTable16(1.0f, cachegamma, cachecontrast, cachebrightness, vid_gammaramps);
-                       BuildGammaTable16(1.0f, cachegamma, cachecontrast, cachebrightness, vid_gammaramps + 256);
-                       BuildGammaTable16(1.0f, cachegamma, cachecontrast, cachebrightness, vid_gammaramps + 512);
+                       if(v_gamma.value == 1)
+                       if(v_contrast.value == 1)
+                       if(v_brightness.value == 0)
+                               vid_gammatables_trivial = true;
                }
+       }
+
+#define GAMMACHECK(cache, value) if (cache != (value)) gamma_changed = true;cache = (value)
+       if(v_psycho.integer)
+               gamma_changed = true;
+       GAMMACHECK(cachegamma      , v_gamma.value);
+       GAMMACHECK(cachecontrast   , v_contrast.value);
+       GAMMACHECK(cachebrightness , v_brightness.value);
+       GAMMACHECK(cachecontrastboost, v_contrastboost.value);
+       GAMMACHECK(cachecolorenable, v_color_enable.integer);
+       GAMMACHECK(cacheblack[0]   , v_color_black_r.value);
+       GAMMACHECK(cacheblack[1]   , v_color_black_g.value);
+       GAMMACHECK(cacheblack[2]   , v_color_black_b.value);
+       GAMMACHECK(cachegrey[0]    , v_color_grey_r.value);
+       GAMMACHECK(cachegrey[1]    , v_color_grey_g.value);
+       GAMMACHECK(cachegrey[2]    , v_color_grey_b.value);
+       GAMMACHECK(cachewhite[0]   , v_color_white_r.value);
+       GAMMACHECK(cachewhite[1]   , v_color_white_g.value);
+       GAMMACHECK(cachewhite[2]   , v_color_white_b.value);
+
+       if(gamma_changed)
+               ++vid_gammatables_serial;
+
+       GAMMACHECK(cachehwgamma    , wantgamma);
+#undef GAMMACHECK
+
+       if (!force && !gamma_forcenextframe && !gamma_changed)
+               return;
+
+       gamma_forcenextframe = false;
 
-               // LordHavoc: this code came from Ben Winslow and Zinx Verituse, I have
-               // immensely butchered it to work with variable framerates and fit in with
-               // the rest of darkplaces.
-               if (v_psycho.integer)
+       if (cachehwgamma)
+       {
+               if (!vid_usinghwgamma)
                {
-                       int x, y;
-                       float t;
-                       static float n[3], nd[3], nt[3];
-                       static int init = true;
-                       unsigned short *ramp;
-                       forcenextframe = true;
-                       if (init)
+                       vid_usinghwgamma = true;
+                       if (vid_gammarampsize != rampsize || !vid_gammaramps)
                        {
-                               init = false;
-                               for (x = 0;x < 3;x++)
-                               {
-                                       n[x] = lhrandom(0, 1);
-                                       nd[x] = (rand()&1)?-0.25:0.25;
-                                       nt[x] = lhrandom(1, 8.2);
-                               }
+                               vid_gammarampsize = rampsize;
+                               if (vid_gammaramps)
+                                       Z_Free(vid_gammaramps);
+                               vid_gammaramps = (unsigned short *)Z_Malloc(6 * vid_gammarampsize * sizeof(unsigned short));
+                               vid_systemgammaramps = vid_gammaramps + 3 * vid_gammarampsize;
                        }
-                       
-                       for (x = 0;x < 3;x++)
+                       VID_GetGamma(vid_systemgammaramps, vid_gammarampsize);
+               }
+
+               VID_BuildGammaTables(vid_gammaramps, vid_gammarampsize);
+
+               // set vid_hardwaregammasupported to true if VID_SetGamma succeeds, OR if vid_hwgamma is >= 2 (forced gamma - ignores driver return value)
+               Cvar_SetValueQuick(&vid_hardwaregammasupported, VID_SetGamma(vid_gammaramps, vid_gammarampsize) || cachehwgamma >= 2);
+               // if custom gamma ramps failed (Windows stupidity), restore to system gamma
+               if(!vid_hardwaregammasupported.integer)
+               {
+                       if (vid_usinghwgamma)
                        {
-                               nt[x] -= host_realframetime;
-                               if (nt[x] < 0)
-                               {
-                                       nd[x] = -nd[x];
-                                       nt[x] += lhrandom(1, 8.2);
-                               }
-                               n[x] += nd[x] * host_realframetime;
-                               n[x] -= floor(n[x]);
+                               vid_usinghwgamma = false;
+                               VID_SetGamma(vid_systemgammaramps, vid_gammarampsize);
                        }
-               
-                       for (x = 0, ramp = vid_gammaramps;x < 3;x++)
-                               for (y = 0, t = n[x] - 0.75f;y < 256;y++, t += 0.75f * (2.0f / 256.0f))
-                                       *ramp++ = cos(t*(M_PI*2.0)) * 32767.0f + 32767.0f;
                }
-
-               Cvar_SetValueQuick(&vid_hardwaregammasupported, VID_SetGamma(vid_gammaramps));
        }
        else
        {
                if (vid_usinghwgamma)
                {
                        vid_usinghwgamma = false;
-                       Cvar_SetValueQuick(&vid_hardwaregammasupported, VID_SetGamma(vid_systemgammaramps));
+                       VID_SetGamma(vid_systemgammaramps, vid_gammarampsize);
                }
        }
 }
@@ -925,7 +1014,9 @@ void VID_RestoreSystemGamma(void)
        if (vid_usinghwgamma)
        {
                vid_usinghwgamma = false;
-               VID_SetGamma(vid_systemgammaramps);
+               Cvar_SetValueQuick(&vid_hardwaregammasupported, VID_SetGamma(vid_systemgammaramps, vid_gammarampsize));
+               // force gamma situation to be reexamined next frame
+               gamma_forcenextframe = true;
        }
 }
 
@@ -934,6 +1025,7 @@ void VID_Shared_Init(void)
        Cvar_RegisterVariable(&vid_hardwaregammasupported);
        Cvar_RegisterVariable(&v_gamma);
        Cvar_RegisterVariable(&v_brightness);
+       Cvar_RegisterVariable(&v_contrastboost);
        Cvar_RegisterVariable(&v_contrast);
 
        Cvar_RegisterVariable(&v_color_enable);
@@ -948,43 +1040,61 @@ void VID_Shared_Init(void)
        Cvar_RegisterVariable(&v_color_white_b);
 
        Cvar_RegisterVariable(&v_hwgamma);
-       
+       Cvar_RegisterVariable(&v_glslgamma);
+
        Cvar_RegisterVariable(&v_psycho);
 
        Cvar_RegisterVariable(&vid_fullscreen);
        Cvar_RegisterVariable(&vid_width);
        Cvar_RegisterVariable(&vid_height);
        Cvar_RegisterVariable(&vid_bitsperpixel);
+       Cvar_RegisterVariable(&vid_samples);
+       Cvar_RegisterVariable(&vid_refreshrate);
+       Cvar_RegisterVariable(&vid_userefreshrate);
+       Cvar_RegisterVariable(&vid_stereobuffer);
        Cvar_RegisterVariable(&vid_vsync);
        Cvar_RegisterVariable(&vid_mouse);
+       Cvar_RegisterVariable(&vid_grabkeyboard);
+       Cvar_RegisterVariable(&vid_stick_mouse);
+       Cvar_RegisterVariable(&vid_resizable);
+       Cvar_RegisterVariable(&vid_minwidth);
+       Cvar_RegisterVariable(&vid_minheight);
        Cvar_RegisterVariable(&gl_combine);
        Cvar_RegisterVariable(&gl_finish);
-       Cvar_RegisterVariable(&in_pitch_min);
-       Cvar_RegisterVariable(&in_pitch_max);
-       Cvar_RegisterVariable(&m_filter);
-       Cmd_AddCommand("force_centerview", Force_CenterView_f);
-       Cmd_AddCommand("vid_restart", VID_Restart_f);
+       Cmd_AddCommand("force_centerview", Force_CenterView_f, "recenters view (stops looking up/down)");
+       Cmd_AddCommand("vid_restart", VID_Restart_f, "restarts video system (closes and reopens the window, restarts renderer)");
        if (gamemode == GAME_GOODVSBAD2)
                Cvar_Set("gl_combine", "0");
 }
 
-int current_vid_fullscreen;
-int current_vid_width;
-int current_vid_height;
-int current_vid_bitsperpixel;
-int VID_Mode(int fullscreen, int width, int height, int bpp)
+int VID_Mode(int fullscreen, int width, int height, int bpp, int refreshrate, int stereobuffer, int samples)
 {
-       Con_Printf("Video: %s %dx%dx%d\n", fullscreen ? "fullscreen" : "window", width, height, bpp);
-       if (VID_InitMode(fullscreen, width, height, bpp))
+       int requestedWidth = width;
+       int requestedHeight = height;
+       cl_ignoremousemoves = 2;
+       Con_Printf("Initializing Video Mode: %s %dx%dx%dx%dhz%s%s\n", fullscreen ? "fullscreen" : "window", width, height, bpp, refreshrate, stereobuffer ? " stereo" : "", samples > 1 ? va(" (%ix AA)", samples) : "");
+       if (VID_InitMode(fullscreen, &width, &height, bpp, vid_userefreshrate.integer ? max(1, refreshrate) : 0, stereobuffer, samples))
        {
-               current_vid_fullscreen = fullscreen;
-               current_vid_width = width;
-               current_vid_height = height;
-               current_vid_bitsperpixel = bpp;
+               vid.fullscreen = fullscreen;
+               vid.width = width;
+               vid.height = height;
+               vid.bitsperpixel = bpp;
+               vid.samples = samples;
+               vid.refreshrate = refreshrate;
+               vid.stereobuffer = stereobuffer;
+               vid.userefreshrate = vid_userefreshrate.integer;
                Cvar_SetValueQuick(&vid_fullscreen, fullscreen);
                Cvar_SetValueQuick(&vid_width, width);
                Cvar_SetValueQuick(&vid_height, height);
                Cvar_SetValueQuick(&vid_bitsperpixel, bpp);
+               Cvar_SetValueQuick(&vid_samples, samples);
+               if(vid_userefreshrate.integer)
+                       Cvar_SetValueQuick(&vid_refreshrate, refreshrate);
+               Cvar_SetValueQuick(&vid_stereobuffer, stereobuffer);
+
+               if(width != requestedWidth || height != requestedHeight)
+                       Con_Printf("Chose a similar video mode %dx%d instead of the requested mode %dx%d\n", width, height, requestedWidth, requestedHeight);
+
                return true;
        }
        else
@@ -995,17 +1105,15 @@ static void VID_OpenSystems(void)
 {
        R_Modules_Start();
        S_Startup();
-       CDAudio_Startup();
 }
 
 static void VID_CloseSystems(void)
 {
-       CDAudio_Shutdown();
        S_Shutdown();
        R_Modules_Shutdown();
 }
 
-int vid_commandlinecheck = true;
+qboolean vid_commandlinecheck = true;
 
 void VID_Restart_f(void)
 {
@@ -1013,38 +1121,51 @@ void VID_Restart_f(void)
        if (vid_commandlinecheck)
                return;
 
-       Con_Printf("VID_Restart: changing from %s %dx%dx%dbpp, to %s %dx%dx%dbpp.\n",
-               current_vid_fullscreen ? "fullscreen" : "window", current_vid_width, current_vid_height, current_vid_bitsperpixel,
-               vid_fullscreen.integer ? "fullscreen" : "window", vid_width.integer, vid_height.integer, vid_bitsperpixel.integer);
-       VID_Close();
-       if (!VID_Mode(vid_fullscreen.integer, vid_width.integer, vid_height.integer, vid_bitsperpixel.integer))
+       Con_Printf("VID_Restart: changing from %s %dx%dx%dbpp%s%s, to %s %dx%dx%dbpp%s%s.\n",
+               vid.fullscreen ? "fullscreen" : "window", vid.width, vid.height, vid.bitsperpixel, vid.fullscreen && vid_userefreshrate.integer ? va("x%ihz", vid.refreshrate) : "", vid.samples > 1 ? va(" (%ix AA)", vid.samples) : "",
+               vid_fullscreen.integer ? "fullscreen" : "window", vid_width.integer, vid_height.integer, vid_bitsperpixel.integer, vid_fullscreen.integer && vid_userefreshrate.integer ? va("x%ihz", vid_refreshrate.integer) : "", vid_samples.integer > 1 ? va(" (%ix AA)", vid_samples.integer) : "");
+       VID_CloseSystems();
+       VID_Shutdown();
+       if (!VID_Mode(vid_fullscreen.integer, vid_width.integer, vid_height.integer, vid_bitsperpixel.integer, vid_refreshrate.integer, vid_stereobuffer.integer, vid_samples.integer))
        {
                Con_Print("Video mode change failed\n");
-               if (!VID_Mode(current_vid_fullscreen, current_vid_width, current_vid_height, current_vid_bitsperpixel))
-                       Sys_Error("Unable to restore to last working video mode\n");
+               if (!VID_Mode(vid.fullscreen, vid.width, vid.height, vid.bitsperpixel, vid.refreshrate, vid.stereobuffer, vid.samples))
+                       Sys_Error("Unable to restore to last working video mode");
        }
        VID_OpenSystems();
 }
 
-void VID_Open(void)
+const char *vidfallbacks[][2] =
+{
+       {"vid_stereobuffer", "0"},
+       {"vid_samples", "1"},
+       {"vid_userefreshrate", "0"},
+       {"vid_width", "640"},
+       {"vid_height", "480"},
+       {"vid_bitsperpixel", "16"},
+       {NULL, NULL}
+};
+
+// this is only called once by Host_StartVideo
+void VID_Start(void)
 {
        int i, width, height, success;
        if (vid_commandlinecheck)
        {
                // interpret command-line parameters
                vid_commandlinecheck = false;
-// COMMANDLINEOPTION: -window performs +vid_fullscreen 0
+// COMMANDLINEOPTION: Video: -window performs +vid_fullscreen 0
                if (COM_CheckParm("-window") || COM_CheckParm("-safe"))
                        Cvar_SetValueQuick(&vid_fullscreen, false);
-// COMMANDLINEOPTION: -fullscreen performs +vid_fullscreen 1
+// COMMANDLINEOPTION: Video: -fullscreen performs +vid_fullscreen 1
                if (COM_CheckParm("-fullscreen"))
                        Cvar_SetValueQuick(&vid_fullscreen, true);
                width = 0;
                height = 0;
-// COMMANDLINEOPTION: -width <pixels> performs +vid_width <pixels> and also +vid_height <pixels*3/4> if only -width is specified (example: -width 1024 sets 1024x768 mode)
+// COMMANDLINEOPTION: Video: -width <pixels> performs +vid_width <pixels> and also +vid_height <pixels*3/4> if only -width is specified (example: -width 1024 sets 1024x768 mode)
                if ((i = COM_CheckParm("-width")) != 0)
                        width = atoi(com_argv[i+1]);
-// COMMANDLINEOPTION: -height <pixels> performs +vid_height <pixels> and also +vid_width <pixels*4/3> if only -height is specified (example: -height 768 sets 1024x768 mode)
+// COMMANDLINEOPTION: Video: -height <pixels> performs +vid_height <pixels> and also +vid_width <pixels*4/3> if only -height is specified (example: -height 768 sets 1024x768 mode)
                if ((i = COM_CheckParm("-height")) != 0)
                        height = atoi(com_argv[i+1]);
                if (width == 0)
@@ -1055,31 +1176,23 @@ void VID_Open(void)
                        Cvar_SetValueQuick(&vid_width, width);
                if (height)
                        Cvar_SetValueQuick(&vid_height, height);
-// COMMANDLINEOPTION: -bpp <bits> performs +vid_bitsperpixel <bits> (example -bpp 32 or -bpp 16)
+// COMMANDLINEOPTION: Video: -bpp <bits> performs +vid_bitsperpixel <bits> (example -bpp 32 or -bpp 16)
                if ((i = COM_CheckParm("-bpp")) != 0)
                        Cvar_SetQuick(&vid_bitsperpixel, com_argv[i+1]);
        }
 
-       Con_DPrint("Starting video system\n");
-       success = VID_Mode(vid_fullscreen.integer, vid_width.integer, vid_height.integer, vid_bitsperpixel.integer);
+       success = VID_Mode(vid_fullscreen.integer, vid_width.integer, vid_height.integer, vid_bitsperpixel.integer, vid_refreshrate.integer, vid_stereobuffer.integer, vid_samples.integer);
        if (!success)
        {
                Con_Print("Desired video mode fail, trying fallbacks...\n");
-               if (!success && vid_bitsperpixel.integer > 16)
-                       success = VID_Mode(vid_fullscreen.integer, vid_width.integer, vid_height.integer, 16);
-               if (!success && (vid_width.integer > 640 || vid_height.integer > 480))
-                       success = VID_Mode(vid_fullscreen.integer, 640, 480, 16);
-               if (!success && vid_fullscreen.integer)
-                       success = VID_Mode(false, 640, 480, 16);
+               for (i = 0;!success && vidfallbacks[i][0] != NULL;i++)
+               {
+                       Cvar_Set(vidfallbacks[i][0], vidfallbacks[i][1]);
+                       success = VID_Mode(vid_fullscreen.integer, vid_width.integer, vid_height.integer, vid_bitsperpixel.integer, vid_refreshrate.integer, vid_stereobuffer.integer, vid_samples.integer);
+               }
                if (!success)
-                       Sys_Error("Video modes failed\n");
+                       Sys_Error("Video modes failed");
        }
        VID_OpenSystems();
 }
 
-void VID_Close(void)
-{
-       VID_CloseSystems();
-       VID_Shutdown();
-}
-