]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - vid_shared.c
fix missing .string message fielddef
[xonotic/darkplaces.git] / vid_shared.c
index ac44a78e086c21a7cfa60b50861c3364c3c47403..aad8446ee4d76714ff714ff6bc0db196dbb66cdf 100644 (file)
@@ -2,10 +2,6 @@
 #include "quakedef.h"
 #include "cdaudio.h"
 
-#ifdef SUPPORTCG
-#include <Cg/cgGL.h>
-#endif
-
 #ifdef SUPPORTD3D
 #include <d3d9.h>
 #ifdef _MSC_VER
@@ -35,6 +31,11 @@ qboolean vid_hidden = true;
 // let go of the mouse, turn off sound, and restore system gamma ramps...
 qboolean vid_activewindow = true;
 
+// cvars for DPSOFTRAST
+cvar_t vid_soft = {CVAR_SAVE, "vid_soft", "0", "enables use of the DarkPlaces Software Rasterizer rather than OpenGL or Direct3D"};
+cvar_t vid_soft_threads = {CVAR_SAVE, "vid_soft_threads", "2", "the number of threads the DarkPlaces Software Rasterizer should use"}; 
+cvar_t vid_soft_interlace = {CVAR_SAVE, "vid_soft_interlace", "1", "whether the DarkPlaces Software Rasterizer should interlace the screen bands occupied by each thread"};
+
 // we don't know until we try it!
 cvar_t vid_hardwaregammasupported = {CVAR_READONLY,"vid_hardwaregammasupported","1", "indicates whether hardware gamma is supported (updated by attempts to set hardware gamma ramps)"};
 
@@ -58,6 +59,7 @@ 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_multisampling = {CVAR_SAVE, "vid_multisampling", "0", "Make use of GL_AGB_MULTISAMPLING for advaced anti-aliasing techniques such as Alpha-To-Coverage, not yet finished"};
 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"};
@@ -69,11 +71,10 @@ cvar_t vid_minwidth = {0, "vid_minwidth", "0", "minimum vid_width that is accept
 cvar_t vid_minheight = {0, "vid_minheight", "0", "minimum vid_height that is acceptable (to be set in default.cfg in mods)"};
 cvar_t vid_gl13 = {0, "vid_gl13", "1", "enables faster rendering using OpenGL 1.3 features (such as GL_ARB_texture_env_combine extension)"};
 cvar_t vid_gl20 = {0, "vid_gl20", "1", "enables faster rendering using OpenGL 2.0 features (such as GL_ARB_fragment_shader extension)"};
-#ifdef SUPPORTCG
-cvar_t vid_cggl = {0, "vid_glcg", "1", "enables faster rendering using the Cg shader library"};
-#endif
 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_sRGB = {CVAR_SAVE, "vid_sRGB", "0", "if hardware is capable, modify rendering to be gamma corrected for the sRGB color standard (computer monitors, TVs), recommended"};
 
+cvar_t vid_touchscreen = {0, "vid_touchscreen", "0", "Use touchscreen-style input (no mouse grab, track mouse motion only while button is down, screen areas for mimicing joystick axes and buttons"};
 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" };
 
@@ -91,9 +92,9 @@ cvar_t v_color_grey_b = {CVAR_SAVE, "v_color_grey_b", "0.5", "desired color of g
 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)"};
+cvar_t v_hwgamma = {CVAR_SAVE, "v_hwgamma", "0", "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", "1", "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"};
 
 // brand of graphics chip
 const char *gl_vendor;
@@ -261,7 +262,7 @@ void (GLAPIENTRY *qglActiveStencilFaceEXT)(GLenum);
 
 void (GLAPIENTRY *qglDeleteShader)(GLuint obj);
 void (GLAPIENTRY *qglDeleteProgram)(GLuint obj);
-GLuint (GLAPIENTRY *qglGetHandle)(GLenum pname);
+//GLuint (GLAPIENTRY *qglGetHandle)(GLenum pname);
 void (GLAPIENTRY *qglDetachShader)(GLuint containerObj, GLuint attachedObj);
 GLuint (GLAPIENTRY *qglCreateShader)(GLenum shaderType);
 void (GLAPIENTRY *qglShaderSource)(GLuint shaderObj, GLsizei count, const GLchar **string, const GLint *length);
@@ -341,6 +342,7 @@ void (GLAPIENTRY *qglVertexAttribPointer)(GLuint index, GLint size, GLenum type,
 void (GLAPIENTRY *qglEnableVertexAttribArray)(GLuint index);
 void (GLAPIENTRY *qglDisableVertexAttribArray)(GLuint index);
 void (GLAPIENTRY *qglBindAttribLocation)(GLuint programObj, GLuint index, const GLchar *name);
+void (GLAPIENTRY *qglBindFragDataLocation)(GLuint programObj, GLuint index, const GLchar *name);
 void (GLAPIENTRY *qglGetActiveAttrib)(GLuint programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
 GLint (GLAPIENTRY *qglGetAttribLocation)(GLuint programObj, const GLchar *name);
 void (GLAPIENTRY *qglGetVertexAttribdv)(GLuint index, GLenum pname, GLdouble *params);
@@ -396,11 +398,12 @@ void (GLAPIENTRY *qglGetQueryivARB)(GLenum target, GLenum pname, GLint *params);
 void (GLAPIENTRY *qglGetQueryObjectivARB)(GLuint qid, GLenum pname, GLint *params);
 void (GLAPIENTRY *qglGetQueryObjectuivARB)(GLuint qid, GLenum pname, GLuint *params);
 
+void (GLAPIENTRY *qglSampleCoverageARB)(GLclampf value, GLboolean invert);
+
 #if _MSC_VER >= 1400
 #define sscanf sscanf_s
 #endif
 
-#ifndef __IPHONEOS__
 qboolean GL_CheckExtension(const char *minglver_or_ext, const dllfunction_t *funcs, const char *disableparm, int silent)
 {
        int failed = false;
@@ -645,7 +648,7 @@ static dllfunction_t gl20shaderfuncs[] =
 {
        {"glDeleteShader", (void **) &qglDeleteShader},
        {"glDeleteProgram", (void **) &qglDeleteProgram},
-       {"glGetHandle", (void **) &qglGetHandle},
+//     {"glGetHandle", (void **) &qglGetHandle},
        {"glDetachShader", (void **) &qglDetachShader},
        {"glCreateShader", (void **) &qglCreateShader},
        {"glShaderSource", (void **) &qglShaderSource},
@@ -733,6 +736,12 @@ static dllfunction_t gl20shaderfuncs[] =
        {NULL, NULL}
 };
 
+static dllfunction_t glsl130funcs[] =
+{
+       {"glBindFragDataLocation", (void **) &qglBindFragDataLocation},
+       {NULL, NULL}
+};
+
 static dllfunction_t vbofuncs[] =
 {
        {"glBindBufferARB"    , (void **) &qglBindBufferARB},
@@ -799,6 +808,12 @@ static dllfunction_t drawbuffersfuncs[] =
        {NULL, NULL}
 };
 
+static dllfunction_t multisamplefuncs[] =
+{
+       {"glSampleCoverageARB",          (void **) &qglSampleCoverageARB},
+       {NULL, NULL}
+};
+
 void VID_ClearExtensions(void)
 {
        // VorteX: reset extensions info cvar, it got filled by GL_CheckExtension
@@ -807,6 +822,8 @@ void VID_ClearExtensions(void)
        // clear the extension flags
        memset(&vid.support, 0, sizeof(vid.support));
        vid.renderpath = RENDERPATH_GL11;
+       vid.sRGBcapable2D = false;
+       vid.sRGBcapable3D = false;
        vid.useinterleavedarrays = false;
        vid.forcevbo = false;
        vid.maxtexturesize_2d = 0;
@@ -831,14 +848,33 @@ void VID_ClearExtensions(void)
 
 void VID_CheckExtensions(void)
 {
-       if (!GL_CheckExtension("1.1", opengl110funcs, NULL, false))
+       if (!GL_CheckExtension("glbase", opengl110funcs, NULL, false))
                Sys_Error("OpenGL 1.1.0 functions not found");
-       vid.support.gl20shaders = GL_CheckExtension("2.0", gl20shaderfuncs, "-noshaders", false);
+       vid.support.gl20shaders = GL_CheckExtension("GL_ARB_fragment_shader", gl20shaderfuncs, "-noshaders", true);
 
        CHECKGLERROR
 
        Con_DPrint("Checking OpenGL extensions...\n");
 
+       if (vid.support.gl20shaders)
+       {
+               // this one is purely optional, needed for GLSL 1.3 support (#version 130), so we don't even check the return value of GL_CheckExtension
+               vid.support.gl20shaders130 = GL_CheckExtension("glshaders130", glsl130funcs, "-noglsl130", true);
+               if(vid.support.gl20shaders130)
+               {
+                       char *s = (char *) qglGetString(GL_SHADING_LANGUAGE_VERSION);
+                       if(!s || atof(s) < 1.30 - 0.00001)
+                               vid.support.gl20shaders130 = 0;
+               }
+               if(vid.support.gl20shaders130)
+                       Con_DPrintf("Using GLSL 1.30\n");
+               else
+                       Con_DPrintf("Using GLSL 1.00\n");
+       }
+
+       // GL drivers generally prefer GL_BGRA
+       vid.forcetextype = GL_BGRA;
+
        vid.support.amd_texture_texture4 = GL_CheckExtension("GL_AMD_texture_texture4", NULL, "-notexture4", false);
        vid.support.arb_depth_texture = GL_CheckExtension("GL_ARB_depth_texture", NULL, "-nodepthtexture", false);
        vid.support.arb_draw_buffers = GL_CheckExtension("GL_ARB_draw_buffers", drawbuffersfuncs, "-nodrawbuffers", false);
@@ -849,18 +885,24 @@ void VID_CheckExtensions(void)
        vid.support.arb_texture_cube_map = GL_CheckExtension("GL_ARB_texture_cube_map", NULL, "-nocubemap", false);
        vid.support.arb_texture_env_combine = GL_CheckExtension("GL_ARB_texture_env_combine", NULL, "-nocombine", false) || GL_CheckExtension("GL_EXT_texture_env_combine", NULL, "-nocombine", false);
        vid.support.arb_texture_gather = GL_CheckExtension("GL_ARB_texture_gather", NULL, "-notexturegather", false);
+#ifndef __APPLE__
+       // LordHavoc: too many bugs on OSX!
        vid.support.arb_texture_non_power_of_two = GL_CheckExtension("GL_ARB_texture_non_power_of_two", NULL, "-notexturenonpoweroftwo", false);
+#endif
        vid.support.arb_vertex_buffer_object = GL_CheckExtension("GL_ARB_vertex_buffer_object", vbofuncs, "-novbo", false);
-       vid.support.ati_separate_stencil = GL_CheckExtension("2.0", gl2separatestencilfuncs, "-noseparatestencil", true) || GL_CheckExtension("GL_ATI_separate_stencil", atiseparatestencilfuncs, "-noseparatestencil", false);
+       vid.support.ati_separate_stencil = GL_CheckExtension("separatestencil", gl2separatestencilfuncs, "-noseparatestencil", true) || GL_CheckExtension("GL_ATI_separate_stencil", atiseparatestencilfuncs, "-noseparatestencil", false);
        vid.support.ext_blend_minmax = GL_CheckExtension("GL_EXT_blend_minmax", blendequationfuncs, "-noblendminmax", false);
        vid.support.ext_blend_subtract = GL_CheckExtension("GL_EXT_blend_subtract", blendequationfuncs, "-noblendsubtract", false);
-       vid.support.ext_draw_range_elements = GL_CheckExtension("1.2", drawrangeelementsfuncs, "-nodrawrangeelements", true) || GL_CheckExtension("GL_EXT_draw_range_elements", drawrangeelementsextfuncs, "-nodrawrangeelements", false);
+       vid.support.ext_draw_range_elements = GL_CheckExtension("drawrangeelements", drawrangeelementsfuncs, "-nodrawrangeelements", true) || GL_CheckExtension("GL_EXT_draw_range_elements", drawrangeelementsextfuncs, "-nodrawrangeelements", false);
        vid.support.ext_framebuffer_object = GL_CheckExtension("GL_EXT_framebuffer_object", fbofuncs, "-nofbo", false);
        vid.support.ext_stencil_two_side = GL_CheckExtension("GL_EXT_stencil_two_side", stenciltwosidefuncs, "-nostenciltwoside", false);
        vid.support.ext_texture_3d = GL_CheckExtension("GL_EXT_texture3D", texture3dextfuncs, "-notexture3d", false);
        vid.support.ext_texture_compression_s3tc = GL_CheckExtension("GL_EXT_texture_compression_s3tc", NULL, "-nos3tc", false);
        vid.support.ext_texture_edge_clamp = GL_CheckExtension("GL_EXT_texture_edge_clamp", NULL, "-noedgeclamp", false) || GL_CheckExtension("GL_SGIS_texture_edge_clamp", NULL, "-noedgeclamp", false);
        vid.support.ext_texture_filter_anisotropic = GL_CheckExtension("GL_EXT_texture_filter_anisotropic", NULL, "-noanisotropy", false);
+       vid.support.ext_texture_srgb = GL_CheckExtension("GL_EXT_texture_sRGB", NULL, "-nosrgb", false);
+       vid.support.arb_multisample = GL_CheckExtension("GL_ARB_multisample", multisamplefuncs, "-nomultisample", false);
+
 // COMMANDLINEOPTION: GL: -noshaders disables use of OpenGL 2.0 shaders (which allow pixel shader effects, can improve per pixel lighting performance and capabilities)
 // COMMANDLINEOPTION: GL: -noanisotropy disables GL_EXT_texture_filter_anisotropic (allows higher quality texturing)
 // COMMANDLINEOPTION: GL: -noblendminmax disables GL_EXT_blend_minmax
@@ -884,6 +926,8 @@ void VID_CheckExtensions(void)
 // COMMANDLINEOPTION: GL: -notexturegather disables GL_ARB_texture_gather (which provides fetch4 sampling)
 // 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)
 // COMMANDLINEOPTION: GL: -novbo disables GL_ARB_vertex_buffer_object (which accelerates rendering)
+// COMMANDLINEOPTION: GL: -nosrgb disables GL_EXT_texture_sRGB (which is used for higher quality non-linear texture gamma)
+// COMMANDLINEOPTION: GL: -nomultisample disables GL_ARB_multisample
 
        if (vid.support.arb_draw_buffers)
                qglGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, (GLint*)&vid.maxdrawbuffers);
@@ -930,19 +974,10 @@ void VID_CheckExtensions(void)
                vid.texarrayunits = bound(8, vid.texarrayunits, MAX_TEXTUREUNITS);
                Con_DPrintf("Using GL2.0 rendering path - %i texture matrix, %i texture images, %i texcoords%s\n", vid.texunits, vid.teximageunits, vid.texarrayunits, vid.support.ext_framebuffer_object ? ", shadowmapping supported" : "");
                vid.renderpath = RENDERPATH_GL20;
+               vid.sRGBcapable2D = false;
+               vid.sRGBcapable3D = true;
                vid.useinterleavedarrays = false;
        }
-#ifdef SUPPORTCG
-       else if (vid_cggl.integer && (vid.cgcontext = cgCreateContext()))
-       {
-               vid.texunits = 4;
-               vid.teximageunits = 16;
-               vid.texarrayunits = 8;
-               Con_DPrintf("Using NVIDIA Cg rendering path - %i texture matrix, %i texture images, %i texcoords%s\n", vid.texunits, vid.teximageunits, vid.texarrayunits, vid.support.ext_framebuffer_object ? ", shadowmapping supported" : "");
-               vid.renderpath = RENDERPATH_CGGL;
-               vid.useinterleavedarrays = false;
-       }
-#endif
        else if (vid.support.arb_texture_env_combine && vid.texunits >= 2 && vid_gl13.integer)
        {
                qglGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&vid.texunits);
@@ -951,6 +986,8 @@ void VID_CheckExtensions(void)
                vid.texarrayunits = vid.texunits;
                Con_DPrintf("Using GL1.3 rendering path - %i texture units, single pass rendering\n", vid.texunits);
                vid.renderpath = RENDERPATH_GL13;
+               vid.sRGBcapable2D = false;
+               vid.sRGBcapable3D = false;
                vid.useinterleavedarrays = false;
        }
        else
@@ -960,6 +997,8 @@ void VID_CheckExtensions(void)
                vid.texarrayunits = vid.texunits;
                Con_DPrintf("Using GL1.1 rendering path - %i texture units, two pass rendering\n", vid.texunits);
                vid.renderpath = RENDERPATH_GL11;
+               vid.sRGBcapable2D = false;
+               vid.sRGBcapable3D = false;
                vid.useinterleavedarrays = false;
        }
 
@@ -970,7 +1009,6 @@ void VID_CheckExtensions(void)
        Cvar_SetQuick(&gl_info_platform, gl_platform ? gl_platform : "");
        Cvar_SetQuick(&gl_info_driver, gl_driver);
 }
-#endif // __IPHONEOS__
 
 void Force_CenterView_f (void)
 {
@@ -985,17 +1023,18 @@ unsigned int vid_gammatables_serial = 0; // so other subsystems can poll if gamm
 qboolean vid_gammatables_trivial = true;
 void VID_BuildGammaTables(unsigned short *ramps, int rampsize)
 {
+       float srgbmul = (vid.sRGB2D || vid.sRGB3D) ? 2.2f : 1.0f;
        if (cachecolorenable)
        {
-               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);
+               BuildGammaTable16(1.0f, invpow(0.5, 1 - cachegrey[0]) * srgbmul, cachewhite[0], cacheblack[0], cachecontrastboost, ramps, rampsize);
+               BuildGammaTable16(1.0f, invpow(0.5, 1 - cachegrey[1]) * srgbmul, cachewhite[1], cacheblack[1], cachecontrastboost, ramps + rampsize, rampsize);
+               BuildGammaTable16(1.0f, invpow(0.5, 1 - cachegrey[2]) * srgbmul, cachewhite[2], cacheblack[2], cachecontrastboost, ramps + rampsize*2, rampsize);
        }
        else
        {
-               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);
+               BuildGammaTable16(1.0f, cachegamma * srgbmul, cachecontrast, cachebrightness, cachecontrastboost, ramps, rampsize);
+               BuildGammaTable16(1.0f, cachegamma * srgbmul, cachecontrast, cachebrightness, cachecontrastboost, ramps + rampsize, rampsize);
+               BuildGammaTable16(1.0f, cachegamma * srgbmul, cachecontrast, cachebrightness, cachecontrastboost, ramps + rampsize*2, rampsize);
        }
 
        // LordHavoc: this code came from Ben Winslow and Zinx Verituse, I have
@@ -1053,16 +1092,17 @@ void VID_UpdateGamma(qboolean force, int rampsize)
        switch(vid.renderpath)
        {
        case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
        case RENDERPATH_D3D9:
        case RENDERPATH_D3D10:
        case RENDERPATH_D3D11:
        case RENDERPATH_SOFT:
+       case RENDERPATH_GLES2:
                if (v_glslgamma.integer)
                        wantgamma = 0;
                break;
-       case RENDERPATH_GL13:
        case RENDERPATH_GL11:
+       case RENDERPATH_GL13:
+       case RENDERPATH_GLES1:
                break;
        }
        if(!vid_activewindow)
@@ -1087,6 +1127,8 @@ void VID_UpdateGamma(qboolean force, int rampsize)
        vid_gammatables_trivial = false;
        if(v_psycho.integer == 0)
        if(v_contrastboost.value == 1)
+       if(!vid.sRGB2D)
+       if(!vid.sRGB3D)
        {
                if(v_color_enable.integer)
                {
@@ -1192,6 +1234,20 @@ void VID_RestoreSystemGamma(void)
 
 void VID_Shared_Init(void)
 {
+#ifdef SSE_POSSIBLE
+       if (Sys_HaveSSE2())
+       {
+               Con_Printf("DPSOFTRAST available (SSE2 instructions detected)\n");
+               Cvar_RegisterVariable(&vid_soft);
+               Cvar_RegisterVariable(&vid_soft_threads);
+               Cvar_RegisterVariable(&vid_soft_interlace);
+       }
+       else
+               Con_Printf("DPSOFTRAST not available (SSE2 disabled or not detected)\n");
+#else
+       Con_Printf("DPSOFTRAST not available (SSE2 not compiled in)\n");
+#endif
+
        Cvar_RegisterVariable(&vid_hardwaregammasupported);
        Cvar_RegisterVariable(&gl_info_vendor);
        Cvar_RegisterVariable(&gl_info_renderer);
@@ -1225,22 +1281,22 @@ void VID_Shared_Init(void)
        Cvar_RegisterVariable(&vid_height);
        Cvar_RegisterVariable(&vid_bitsperpixel);
        Cvar_RegisterVariable(&vid_samples);
+       Cvar_RegisterVariable(&vid_multisampling);
        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_touchscreen);
        Cvar_RegisterVariable(&vid_stick_mouse);
        Cvar_RegisterVariable(&vid_resizable);
        Cvar_RegisterVariable(&vid_minwidth);
        Cvar_RegisterVariable(&vid_minheight);
        Cvar_RegisterVariable(&vid_gl13);
        Cvar_RegisterVariable(&vid_gl20);
-#ifdef SUPPORTCG
-       Cvar_RegisterVariable(&vid_cggl);
-#endif
        Cvar_RegisterVariable(&gl_finish);
+       Cvar_RegisterVariable(&vid_sRGB);
        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)");
 }
@@ -1272,6 +1328,9 @@ int VID_Mode(int fullscreen, int width, int height, int bpp, float refreshrate,
                vid.stereobuffer   = vid.mode.stereobuffer;
                vid.samples        = vid.mode.samples;
                vid.stencil        = vid.mode.bitsperpixel > 16;
+               vid.sRGB2D         = vid_sRGB.integer >= 1 && vid.sRGBcapable2D;
+               vid.sRGB3D         = vid_sRGB.integer >= 1 && vid.sRGBcapable3D;
+
                Con_Printf("Video Mode: %s %dx%dx%dx%.2fhz%s%s\n", mode.fullscreen ? "fullscreen" : "window", mode.width, mode.height, mode.bitsperpixel, mode.refreshrate, mode.stereobuffer ? " stereo" : "", mode.samples > 1 ? va(" (%ix AA)", mode.samples) : "");
 
                Cvar_SetValueQuick(&vid_fullscreen, vid.mode.fullscreen);
@@ -1302,6 +1361,7 @@ static void VID_CloseSystems(void)
 }
 
 qboolean vid_commandlinecheck = true;
+extern qboolean vid_opened;
 
 void VID_Restart_f(void)
 {
@@ -1309,6 +1369,12 @@ void VID_Restart_f(void)
        if (vid_commandlinecheck)
                return;
 
+       if (!vid_opened)
+       {
+               SCR_BeginLoadingPlaque();
+               return;
+       }
+
        Con_Printf("VID_Restart: changing from %s %dx%dx%dbpp%s%s, to %s %dx%dx%dbpp%s%s.\n",
                vid.mode.fullscreen ? "fullscreen" : "window", vid.mode.width, vid.mode.height, vid.mode.bitsperpixel, vid.mode.fullscreen && vid.mode.userefreshrate ? va("x%.2fhz", vid.mode.refreshrate) : "", vid.mode.samples > 1 ? va(" (%ix AA)", vid.mode.samples) : "",
                vid_fullscreen.integer ? "fullscreen" : "window", vid_width.integer, vid_height.integer, vid_bitsperpixel.integer, vid_fullscreen.integer && vid_userefreshrate.integer ? va("x%.2fhz", vid_refreshrate.value) : "", vid_samples.integer > 1 ? va(" (%ix AA)", vid_samples.integer) : "");
@@ -1334,7 +1400,7 @@ const char *vidfallbacks[][2] =
        {NULL, NULL}
 };
 
-// this is only called once by Host_StartVideo
+// this is only called once by Host_StartVideo and again on each FS_GameDir_f
 void VID_Start(void)
 {
        int i, width, height, success;
@@ -1384,6 +1450,12 @@ void VID_Start(void)
        VID_OpenSystems();
 }
 
+void VID_Stop(void)
+{
+       VID_CloseSystems();
+       VID_Shutdown();
+}
+
 int VID_SortModes_Compare(const void *a_, const void *b_)
 {
        vid_mode_t *a = (vid_mode_t *) a_;
@@ -1446,3 +1518,69 @@ size_t VID_SortModes(vid_mode_t *modes, size_t count, qboolean usebpp, qboolean
        }
        return count;
 }
+
+void VID_Soft_SharedSetup(void)
+{
+       gl_platform = "DPSOFTRAST";
+       gl_platformextensions = "";
+
+       gl_renderer = "DarkPlaces-Soft";
+       gl_vendor = "Forest Hale";
+       gl_version = "0.0";
+       gl_extensions = "";
+
+       // clear the extension flags
+       memset(&vid.support, 0, sizeof(vid.support));
+       Cvar_SetQuick(&gl_info_extensions, "");
+
+       // DPSOFTRAST requires BGRA
+       vid.forcetextype = TEXTYPE_BGRA;
+
+       vid.forcevbo = false;
+       vid.support.arb_depth_texture = true;
+       vid.support.arb_draw_buffers = true;
+       vid.support.arb_occlusion_query = true;
+       vid.support.arb_shadow = true;
+       //vid.support.arb_texture_compression = true;
+       vid.support.arb_texture_cube_map = true;
+       vid.support.arb_texture_non_power_of_two = false;
+       vid.support.arb_vertex_buffer_object = true;
+       vid.support.ext_blend_subtract = true;
+       vid.support.ext_draw_range_elements = true;
+       vid.support.ext_framebuffer_object = true;
+       vid.support.ext_texture_3d = true;
+       //vid.support.ext_texture_compression_s3tc = true;
+       vid.support.ext_texture_filter_anisotropic = true;
+       vid.support.ati_separate_stencil = true;
+       vid.support.ext_texture_srgb = false;
+
+       vid.maxtexturesize_2d = 16384;
+       vid.maxtexturesize_3d = 512;
+       vid.maxtexturesize_cubemap = 16384;
+       vid.texunits = 4;
+       vid.teximageunits = 32;
+       vid.texarrayunits = 8;
+       vid.max_anisotropy = 1;
+       vid.maxdrawbuffers = 4;
+
+       vid.texunits = bound(4, vid.texunits, MAX_TEXTUREUNITS);
+       vid.teximageunits = bound(16, vid.teximageunits, MAX_TEXTUREUNITS);
+       vid.texarrayunits = bound(8, vid.texarrayunits, MAX_TEXTUREUNITS);
+       Con_DPrintf("Using DarkPlaces Software Rasterizer rendering path\n");
+       vid.renderpath = RENDERPATH_SOFT;
+       vid.sRGBcapable2D = false;
+       vid.sRGBcapable3D = false;
+       vid.useinterleavedarrays = false;
+
+       Cvar_SetQuick(&gl_info_vendor, gl_vendor);
+       Cvar_SetQuick(&gl_info_renderer, gl_renderer);
+       Cvar_SetQuick(&gl_info_version, gl_version);
+       Cvar_SetQuick(&gl_info_platform, gl_platform ? gl_platform : "");
+       Cvar_SetQuick(&gl_info_driver, gl_driver);
+
+       // LordHavoc: report supported extensions
+       Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
+
+       // clear to black (loading plaque will be seen over this)
+       GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
+}