]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_backend.c
vid_usingvsync now set to false after a vid_restart (so that vsync will be set again...
[xonotic/darkplaces.git] / gl_backend.c
index 3d3567373bec8e0a663524ee940d3a5da9e96345..0fa1f802c4cb6f6e6e3fc56de47947a18b4d0ca6 100644 (file)
@@ -75,8 +75,6 @@ void GL_PrintError(int errornumber, char *filename, int linenumber)
 
 #define BACKENDACTIVECHECK if (!backendactive) Sys_Error("GL backend function called when backend is not active\n");
 
-int c_meshs, c_meshelements;
-
 void SCR_ScreenShot_f (void);
 
 static matrix4x4_t backend_viewmatrix;
@@ -85,7 +83,7 @@ static matrix4x4_t backend_modelviewmatrix;
 static matrix4x4_t backend_glmodelviewmatrix;
 static matrix4x4_t backend_projectmatrix;
 
-static int backendunits, backendactive;
+static int backendunits, backendimageunits, backendarrayunits, backendactive;
 static mempool_t *gl_backend_mempool;
 
 /*
@@ -161,7 +159,9 @@ void GL_Backend_FreeArrays(void)
 
 static void gl_backend_start(void)
 {
-       Con_DPrint("OpenGL Backend started\n");
+       Con_Print("OpenGL Backend starting...\n");
+       CHECKGLERROR
+
        if (qglDrawRangeElements != NULL)
        {
                CHECKGLERROR
@@ -169,22 +169,43 @@ static void gl_backend_start(void)
                CHECKGLERROR
                qglGetIntegerv(GL_MAX_ELEMENTS_INDICES, &gl_maxdrawrangeelementsindices);
                CHECKGLERROR
-               Con_DPrintf("glDrawRangeElements detected (max vertices %i, max indices %i)\n", gl_maxdrawrangeelementsvertices, gl_maxdrawrangeelementsindices);
+               Con_Printf("glDrawRangeElements detected (max vertices %i, max indices %i)\n", gl_maxdrawrangeelementsvertices, gl_maxdrawrangeelementsindices);
        }
 
        backendunits = min(MAX_TEXTUREUNITS, gl_textureunits);
+       backendimageunits = backendunits;
+       backendarrayunits = backendunits;
+       if (gl_support_fragment_shader)
+       {
+               CHECKGLERROR
+               qglGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &backendimageunits);
+               CHECKGLERROR
+               qglGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB, &backendarrayunits);
+               CHECKGLERROR
+               Con_Printf("GLSL shader support detected: texture units = %i texenv, %i image, %i array\n", backendunits, backendimageunits, backendarrayunits);
+       }
+       else if (backendunits > 1)
+               Con_Printf("multitexture detected: texture units = %i\n", backendunits);
+       else
+               Con_Printf("singletexture\n");
 
        GL_Backend_AllocArrays();
 
+       Con_Printf("OpenGL backend started.\n");
+
+       CHECKGLERROR
+
        backendactive = true;
 }
 
 static void gl_backend_shutdown(void)
 {
        backendunits = 0;
+       backendimageunits = 0;
+       backendarrayunits = 0;
        backendactive = false;
 
-       Con_DPrint("OpenGL Backend shutting down\n");
+       Con_Print("OpenGL Backend shutting down\n");
 
        GL_Backend_FreeArrays();
 }
@@ -417,10 +438,8 @@ void GL_SetupTextureState(void)
        CHECKGLERROR
        gl_state.unit = -1;
        gl_state.clientunit = -1;
-       for (i = 0;i < backendunits;i++)
+       for (i = 0;i < MAX_TEXTUREUNITS;i++)
        {
-               GL_ActiveTexture(i);
-               GL_ClientActiveTexture(i);
                unit = gl_state.units + i;
                unit->t1d = 0;
                unit->t2d = 0;
@@ -435,13 +454,33 @@ void GL_SetupTextureState(void)
                unit->combinealpha = GL_MODULATE;
                unit->texmatrixenabled = false;
                unit->matrix = r_identitymatrix;
-               qglMatrixMode(GL_TEXTURE);
-               qglLoadIdentity();
-               qglMatrixMode(GL_MODELVIEW);
+       }
 
+       for (i = 0;i < backendimageunits;i++)
+       {
+               GL_ActiveTexture(i);
+               qglBindTexture(GL_TEXTURE_1D, 0);CHECKGLERROR
+               qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
+               if (gl_texture3d)
+               {
+                       qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
+               }
+               if (gl_texturecubemap)
+               {
+                       qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
+               }
+       }
+
+       for (i = 0;i < backendarrayunits;i++)
+       {
+               GL_ClientActiveTexture(i);
                qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), NULL);CHECKGLERROR
                qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
+       }
 
+       for (i = 0;i < backendunits;i++)
+       {
+               GL_ActiveTexture(i);
                qglDisable(GL_TEXTURE_1D);CHECKGLERROR
                qglDisable(GL_TEXTURE_2D);CHECKGLERROR
                if (gl_texture3d)
@@ -452,6 +491,9 @@ void GL_SetupTextureState(void)
                {
                        qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
                }
+               qglMatrixMode(GL_TEXTURE);
+               qglLoadIdentity();
+               qglMatrixMode(GL_MODELVIEW);
                if (gl_combine.integer)
                {
                        qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
@@ -715,6 +757,109 @@ void R_Mesh_Start(void)
        GL_Backend_ResetState();
 }
 
+unsigned int GL_Backend_CompileProgram(int vertexstrings_count, const char **vertexstrings_list, int fragmentstrings_count, const char **fragmentstrings_list)
+{
+       GLint vertexshadercompiled, fragmentshadercompiled, programlinked;
+       GLuint vertexshaderobject, fragmentshaderobject, programobject = 0;
+       char compilelog[4096];
+       CHECKGLERROR
+
+       programobject = qglCreateProgramObjectARB();
+       CHECKGLERROR
+       if (!programobject)
+               return 0;
+
+       if (vertexstrings_count)
+       {
+               CHECKGLERROR
+               vertexshaderobject = qglCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
+               if (!vertexshaderobject)
+               {
+                       qglDeleteObjectARB(programobject);
+                       CHECKGLERROR
+                       return 0;
+               }
+               qglShaderSourceARB(vertexshaderobject, vertexstrings_count, vertexstrings_list, NULL);
+               qglCompileShaderARB(vertexshaderobject);
+               CHECKGLERROR
+               qglGetObjectParameterivARB(vertexshaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &vertexshadercompiled);
+               qglGetInfoLogARB(vertexshaderobject, sizeof(compilelog), NULL, compilelog);
+               if (compilelog[0])
+                       Con_Printf("vertex shader compile log:\n%s\n", compilelog);
+               if (!vertexshadercompiled)
+               {
+                       qglDeleteObjectARB(programobject);
+                       qglDeleteObjectARB(vertexshaderobject);
+                       CHECKGLERROR
+                       return 0;
+               }
+               qglAttachObjectARB(programobject, vertexshaderobject);
+               qglDeleteObjectARB(vertexshaderobject);
+               CHECKGLERROR
+       }
+
+       if (fragmentstrings_count)
+       {
+               CHECKGLERROR
+               fragmentshaderobject = qglCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
+               if (!fragmentshaderobject)
+               {
+                       qglDeleteObjectARB(programobject);
+                       CHECKGLERROR
+                       return 0;
+               }
+               qglShaderSourceARB(fragmentshaderobject, fragmentstrings_count, fragmentstrings_list, NULL);
+               qglCompileShaderARB(fragmentshaderobject);
+               CHECKGLERROR
+               qglGetObjectParameterivARB(fragmentshaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &fragmentshadercompiled);
+               qglGetInfoLogARB(fragmentshaderobject, sizeof(compilelog), NULL, compilelog);
+               if (compilelog[0])
+                       Con_Printf("fragment shader compile log:\n%s\n", compilelog);
+               if (!fragmentshadercompiled)
+               {
+                       qglDeleteObjectARB(programobject);
+                       qglDeleteObjectARB(fragmentshaderobject);
+                       CHECKGLERROR
+                       return 0;
+               }
+               qglAttachObjectARB(programobject, fragmentshaderobject);
+               qglDeleteObjectARB(fragmentshaderobject);
+               CHECKGLERROR
+       }
+
+       qglLinkProgramARB(programobject);
+       CHECKGLERROR
+       qglGetObjectParameterivARB(programobject, GL_OBJECT_LINK_STATUS_ARB, &programlinked);
+       qglGetInfoLogARB(programobject, sizeof(compilelog), NULL, compilelog);
+       if (compilelog[0])
+       {
+               Con_Printf("program link log:\n%s\n", compilelog);
+               // software vertex shader is ok but software fragment shader is WAY
+               // too slow, fail program if so.
+               // NOTE: this string might be ATI specific, but that's ok because the
+               // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a
+               // software fragment shader due to low instruction and dependent
+               // texture limits.
+               if (strstr(compilelog, "fragment shader will run in software"))
+                       programlinked = false;
+       }
+       CHECKGLERROR
+       if (!programlinked)
+       {
+               qglDeleteObjectARB(programobject);
+               return 0;
+       }
+       CHECKGLERROR
+       return programobject;
+}
+
+void GL_Backend_FreeProgram(unsigned int prog)
+{
+       CHECKGLERROR
+       qglDeleteObjectARB(prog);
+       CHECKGLERROR
+}
+
 int gl_backend_rebindtextures;
 
 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
@@ -762,12 +907,10 @@ void R_Mesh_Draw(int numverts, int numtriangles, const int *elements)
                        for (j = 0, size = numverts * (int)sizeof(float[4]), p = gl_state.pointer_color;j < size;j += sizeof(int), p++)
                                paranoidblah += *p;
                }
-               for (i = 0;i < backendunits;i++)
+               for (i = 0;i < backendarrayunits;i++)
                {
-                       if (gl_state.units[i].t1d || gl_state.units[i].t2d || gl_state.units[i].t3d || gl_state.units[i].tcubemap || gl_state.units[i].arrayenabled)
+                       if (gl_state.units[i].arrayenabled)
                        {
-                               if (gl_state.units[i].arrayenabled && !(gl_state.units[i].t1d || gl_state.units[i].t2d || gl_state.units[i].t3d || gl_state.units[i].tcubemap))
-                                       Con_Print("R_Mesh_Draw: array enabled but no texture bound\n");
                                GL_ClientActiveTexture(i);
                                if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
                                        Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
@@ -795,13 +938,13 @@ void R_Mesh_Draw(int numverts, int numtriangles, const int *elements)
                        qglBegin(GL_TRIANGLES);
                        for (i = 0;i < numtriangles * 3;i++)
                        {
-                               for (j = 0;j < backendunits;j++)
+                               for (j = 0;j < backendarrayunits;j++)
                                {
                                        if (gl_state.units[j].pointer_texcoord)
                                        {
-                                               if (backendunits > 1)
+                                               if (backendarrayunits > 1)
                                                {
-                                                       if (gl_state.units[j].t3d || gl_state.units[j].tcubemap)
+                                                       if (gl_state.units[j].arrayis3d)
                                                        {
                                                                p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
                                                                qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
@@ -814,7 +957,7 @@ void R_Mesh_Draw(int numverts, int numtriangles, const int *elements)
                                                }
                                                else
                                                {
-                                                       if (gl_state.units[j].t3d || gl_state.units[j].tcubemap)
+                                                       if (gl_state.units[j].arrayis3d)
                                                        {
                                                                p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
                                                                qglTexCoord3f(p[0], p[1], p[2]);
@@ -870,13 +1013,28 @@ void R_Mesh_Finish(void)
        GL_LockArrays(0, 0);
        CHECKGLERROR
 
-       for (i = backendunits - 1;i >= 0;i--)
+       for (i = 0;i < backendimageunits;i++)
        {
-               if (qglActiveTexture)
-                       qglActiveTexture(GL_TEXTURE0_ARB + i);CHECKGLERROR
-               if (qglClientActiveTexture)
-                       qglClientActiveTexture(GL_TEXTURE0_ARB + i);CHECKGLERROR
+               GL_ActiveTexture(i);
+               qglBindTexture(GL_TEXTURE_1D, 0);CHECKGLERROR
+               qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
+               if (gl_texture3d)
+               {
+                       qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
+               }
+               if (gl_texturecubemap)
+               {
+                       qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
+               }
+       }
+       for (i = backendarrayunits - 1;i >= 0;i--)
+       {
+               GL_ActiveTexture(i);
                qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
+       }
+       for (i = backendunits - 1;i >= 0;i--)
+       {
+               GL_ActiveTexture(i);
                qglDisable(GL_TEXTURE_1D);CHECKGLERROR
                qglDisable(GL_TEXTURE_2D);CHECKGLERROR
                if (gl_texture3d)
@@ -960,219 +1118,215 @@ void R_Mesh_State(const rmeshstate_t *m)
                GL_SetupTextureState();
        }
 
-       for (i = 0, unit = gl_state.units;i < backendunits;i++, unit++)
+       for (i = 0, unit = gl_state.units;i < backendimageunits;i++, unit++)
        {
                // update 1d texture binding
                if (unit->t1d != m->tex1d[i])
                {
-                       if (m->tex1d[i])
+                       GL_ActiveTexture(i);
+                       if (i < backendunits)
                        {
-                               if (unit->t1d == 0)
+                               if (m->tex1d[i])
                                {
-                                       GL_ActiveTexture(i);
-                                       qglEnable(GL_TEXTURE_1D);CHECKGLERROR
+                                       if (unit->t1d == 0)
+                                               qglEnable(GL_TEXTURE_1D);
                                }
-                               unit->t1d = m->tex1d[i];
-                               GL_ActiveTexture(i);
-                               qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
-                       }
-                       else
-                       {
-                               if (unit->t1d)
+                               else
                                {
-                                       unit->t1d = 0;
-                                       GL_ActiveTexture(i);
-                                       qglDisable(GL_TEXTURE_1D);CHECKGLERROR
+                                       if (unit->t1d)
+                                               qglDisable(GL_TEXTURE_1D);
                                }
                        }
+                       unit->t1d = m->tex1d[i];
+                       qglBindTexture(GL_TEXTURE_1D, unit->t1d);
+                       CHECKGLERROR
                }
                // update 2d texture binding
                if (unit->t2d != m->tex[i])
                {
-                       if (m->tex[i])
+                       GL_ActiveTexture(i);
+                       if (i < backendunits)
                        {
-                               if (unit->t2d == 0)
+                               if (m->tex[i])
                                {
-                                       GL_ActiveTexture(i);
-                                       qglEnable(GL_TEXTURE_2D);CHECKGLERROR
+                                       if (unit->t2d == 0)
+                                               qglEnable(GL_TEXTURE_2D);
                                }
-                               unit->t2d = m->tex[i];
-                               GL_ActiveTexture(i);
-                               qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
-                       }
-                       else
-                       {
-                               if (unit->t2d)
+                               else
                                {
-                                       unit->t2d = 0;
-                                       GL_ActiveTexture(i);
-                                       qglDisable(GL_TEXTURE_2D);CHECKGLERROR
+                                       if (unit->t2d)
+                                               qglDisable(GL_TEXTURE_2D);
                                }
                        }
+                       unit->t2d = m->tex[i];
+                       qglBindTexture(GL_TEXTURE_2D, unit->t2d);
+                       CHECKGLERROR
                }
                // update 3d texture binding
                if (unit->t3d != m->tex3d[i])
                {
-                       if (m->tex3d[i])
+                       GL_ActiveTexture(i);
+                       if (i < backendunits)
                        {
-                               if (unit->t3d == 0)
+                               if (m->tex3d[i])
                                {
-                                       GL_ActiveTexture(i);
-                                       qglEnable(GL_TEXTURE_3D);CHECKGLERROR
+                                       if (unit->t3d == 0)
+                                               qglEnable(GL_TEXTURE_3D);
                                }
-                               unit->t3d = m->tex3d[i];
-                               GL_ActiveTexture(i);
-                               qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
-                       }
-                       else
-                       {
-                               if (unit->t3d)
+                               else
                                {
-                                       unit->t3d = 0;
-                                       GL_ActiveTexture(i);
-                                       qglDisable(GL_TEXTURE_3D);CHECKGLERROR
+                                       if (unit->t3d)
+                                               qglDisable(GL_TEXTURE_3D);
                                }
                        }
+                       unit->t3d = m->tex3d[i];
+                       qglBindTexture(GL_TEXTURE_3D, unit->t3d);
+                       CHECKGLERROR
                }
                // update cubemap texture binding
                if (unit->tcubemap != m->texcubemap[i])
                {
-                       if (m->texcubemap[i])
+                       GL_ActiveTexture(i);
+                       if (i < backendunits)
                        {
-                               if (unit->tcubemap == 0)
+                               if (m->texcubemap[i])
                                {
-                                       GL_ActiveTexture(i);
-                                       qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
+                                       if (unit->tcubemap == 0)
+                                               qglEnable(GL_TEXTURE_CUBE_MAP_ARB);
                                }
-                               unit->tcubemap = m->texcubemap[i];
-                               GL_ActiveTexture(i);
-                               qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
-                       }
-                       else
-                       {
-                               if (unit->tcubemap)
+                               else
                                {
-                                       unit->tcubemap = 0;
-                                       GL_ActiveTexture(i);
-                                       qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
+                                       if (unit->tcubemap)
+                                               qglDisable(GL_TEXTURE_CUBE_MAP_ARB);
                                }
                        }
+                       unit->tcubemap = m->texcubemap[i];
+                       qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);
+                       CHECKGLERROR
                }
-               // update texture unit settings if the unit is enabled
-               if (unit->t1d || unit->t2d || unit->t3d || unit->tcubemap)
+       }
+       for (i = 0, unit = gl_state.units;i < backendarrayunits;i++, unit++)
+       {
+               // update array settings
+               if (m->pointer_texcoord3f[i])
                {
-                       // texture unit is enabled, enable the array
+                       // 3d texcoord array
+                       if (unit->pointer_texcoord != m->pointer_texcoord3f[i] || !unit->arrayis3d)
+                       {
+                               unit->pointer_texcoord = m->pointer_texcoord3f[i];
+                               unit->arrayis3d = true;
+                               GL_ClientActiveTexture(i);
+                               qglTexCoordPointer(3, GL_FLOAT, sizeof(float[3]), unit->pointer_texcoord);
+                               CHECKGLERROR
+                       }
+                       // texture array unit is enabled, enable the array
                        if (!unit->arrayenabled)
                        {
                                unit->arrayenabled = true;
                                GL_ClientActiveTexture(i);
                                qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
                        }
-                       // update combine settings
-                       if (gl_combine.integer)
+               }
+               else if (m->pointer_texcoord[i])
+               {
+                       // 2d texcoord array
+                       if (unit->pointer_texcoord != m->pointer_texcoord[i] || unit->arrayis3d)
                        {
-                               // GL_ARB_texture_env_combine
-                               combinergb = m->texcombinergb[i] ? m->texcombinergb[i] : GL_MODULATE;
-                               if (unit->combinergb != combinergb)
-                               {
-                                       unit->combinergb = combinergb;
-                                       GL_ActiveTexture(i);
-                                       qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
-                               }
-                               combinealpha = m->texcombinealpha[i] ? m->texcombinealpha[i] : GL_MODULATE;
-                               if (unit->combinealpha != combinealpha)
-                               {
-                                       unit->combinealpha = combinealpha;
-                                       GL_ActiveTexture(i);
-                                       qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
-                               }
-                               scale = max(m->texrgbscale[i], 1);
-                               if (unit->rgbscale != scale)
-                               {
-                                       GL_ActiveTexture(i);
-                                       qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = scale));CHECKGLERROR
-                               }
-                               scale = max(m->texalphascale[i], 1);
-                               if (unit->alphascale != scale)
-                               {
-                                       GL_ActiveTexture(i);
-                                       qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = scale));CHECKGLERROR
-                               }
+                               unit->pointer_texcoord = m->pointer_texcoord[i];
+                               unit->arrayis3d = false;
+                               GL_ClientActiveTexture(i);
+                               qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), unit->pointer_texcoord);
+                               CHECKGLERROR
                        }
-                       else
+                       // texture array unit is enabled, enable the array
+                       if (!unit->arrayenabled)
                        {
-                               // normal GL texenv
-                               combinergb = m->texcombinergb[i] ? m->texcombinergb[i] : GL_MODULATE;
-                               if (unit->combinergb != combinergb)
-                               {
-                                       unit->combinergb = combinergb;
-                                       GL_ActiveTexture(i);
-                                       qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
-                               }
+                               unit->arrayenabled = true;
+                               GL_ClientActiveTexture(i);
+                               qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
                        }
-                       // update array settings
-                       if (m->pointer_texcoord3f[i])
+               }
+               else
+               {
+                       // texture array unit is disabled, disable the array
+                       if (unit->arrayenabled)
                        {
-                               // 3d texcoord array
-                               if (unit->pointer_texcoord != m->pointer_texcoord3f[i] || !unit->arrayis3d)
-                               {
-                                       unit->pointer_texcoord = m->pointer_texcoord3f[i];
-                                       unit->arrayis3d = true;
-                                       GL_ClientActiveTexture(i);
-                                       qglTexCoordPointer(3, GL_FLOAT, sizeof(float[3]), unit->pointer_texcoord);
-                                       CHECKGLERROR
-                               }
+                               unit->arrayenabled = false;
+                               GL_ClientActiveTexture(i);
+                               qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
                        }
-                       else
+               }
+       }
+       for (i = 0, unit = gl_state.units;i < backendunits;i++, unit++)
+       {
+               // update texmatrix
+               if (m->texmatrix[i].m[3][3])
+               {
+                       // texmatrix specified, check if it is different
+                       if (!unit->texmatrixenabled || memcmp(&unit->matrix, &m->texmatrix[i], sizeof(matrix4x4_t)))
                        {
-                               // 2d texcoord array
-                               if (unit->pointer_texcoord != m->pointer_texcoord[i] || unit->arrayis3d)
-                               {
-                                       unit->pointer_texcoord = m->pointer_texcoord[i];
-                                       unit->arrayis3d = false;
-                                       GL_ClientActiveTexture(i);
-                                       qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), unit->pointer_texcoord);
-                                       CHECKGLERROR
-                               }
+                               unit->texmatrixenabled = true;
+                               unit->matrix = m->texmatrix[i];
+                               Matrix4x4_Transpose(&tempmatrix, &unit->matrix);
+                               qglMatrixMode(GL_TEXTURE);
+                               GL_ActiveTexture(i);
+                               qglLoadMatrixf(&tempmatrix.m[0][0]);
+                               qglMatrixMode(GL_MODELVIEW);
                        }
-                       // update texmatrix
-                       if (m->texmatrix[i].m[3][3])
+               }
+               else
+               {
+                       // no texmatrix specified, revert to identity
+                       if (unit->texmatrixenabled)
                        {
-                               // texmatrix specified, check if it is different
-                               if (!unit->texmatrixenabled || memcmp(&unit->matrix, &m->texmatrix[i], sizeof(matrix4x4_t)))
-                               {
-                                       unit->texmatrixenabled = true;
-                                       unit->matrix = m->texmatrix[i];
-                                       Matrix4x4_Transpose(&tempmatrix, &unit->matrix);
-                                       qglMatrixMode(GL_TEXTURE);
-                                       GL_ActiveTexture(i);
-                                       qglLoadMatrixf(&tempmatrix.m[0][0]);
-                                       qglMatrixMode(GL_MODELVIEW);
-                               }
+                               unit->texmatrixenabled = false;
+                               qglMatrixMode(GL_TEXTURE);
+                               GL_ActiveTexture(i);
+                               qglLoadIdentity();
+                               qglMatrixMode(GL_MODELVIEW);
                        }
-                       else
+               }
+               // update combine settings
+               if (gl_combine.integer)
+               {
+                       // GL_ARB_texture_env_combine
+                       combinergb = m->texcombinergb[i] ? m->texcombinergb[i] : GL_MODULATE;
+                       if (unit->combinergb != combinergb)
                        {
-                               // no texmatrix specified, revert to identity
-                               if (unit->texmatrixenabled)
-                               {
-                                       unit->texmatrixenabled = false;
-                                       qglMatrixMode(GL_TEXTURE);
-                                       GL_ActiveTexture(i);
-                                       qglLoadIdentity();
-                                       qglMatrixMode(GL_MODELVIEW);
-                               }
+                               unit->combinergb = combinergb;
+                               GL_ActiveTexture(i);
+                               qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
+                       }
+                       combinealpha = m->texcombinealpha[i] ? m->texcombinealpha[i] : GL_MODULATE;
+                       if (unit->combinealpha != combinealpha)
+                       {
+                               unit->combinealpha = combinealpha;
+                               GL_ActiveTexture(i);
+                               qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
+                       }
+                       scale = max(m->texrgbscale[i], 1);
+                       if (unit->rgbscale != scale)
+                       {
+                               GL_ActiveTexture(i);
+                               qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = scale));CHECKGLERROR
+                       }
+                       scale = max(m->texalphascale[i], 1);
+                       if (unit->alphascale != scale)
+                       {
+                               GL_ActiveTexture(i);
+                               qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = scale));CHECKGLERROR
                        }
                }
                else
                {
-                       // texture unit is disabled, disable the array
-                       if (unit->arrayenabled)
+                       // normal GL texenv
+                       combinergb = m->texcombinergb[i] ? m->texcombinergb[i] : GL_MODULATE;
+                       if (unit->combinergb != combinergb)
                        {
-                               unit->arrayenabled = false;
-                               GL_ClientActiveTexture(i);
-                               qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
+                               unit->combinergb = combinergb;
+                               GL_ActiveTexture(i);
+                               qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
                        }
-                       // no need to update most settings on a disabled texture unit
                }
        }
 }
@@ -1209,6 +1363,17 @@ qboolean SCR_ScreenShot(char *filename, qbyte *buffer1, qbyte *buffer2, qbyte *b
        qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer1);
        CHECKGLERROR
 
+       if (scr_screenshot_gamma.value != 1)
+       {
+               int i;
+               double igamma = 1.0 / scr_screenshot_gamma.value;
+               unsigned char ramp[256];
+               for (i = 0;i < 256;i++)
+                       ramp[i] = (unsigned char) (pow(i * (1.0 / 255.0), igamma) * 255.0);
+               for (i = 0;i < width*height*3;i++)
+                       buffer1[i] = ramp[buffer1[i]];
+       }
+
        Image_CopyMux (buffer2, buffer1, width, height, flipx, flipy, flipdiagonal, 3, 3, indices);
 
        if (jpeg)
@@ -1257,7 +1422,7 @@ CalcFov
 float CalcFov (float fov_x, float width, float height)
 {
        // calculate vision size and alter by aspect, then convert back to angle
-       return atan (((height/width)/vid_pixelaspect.value)*tan(fov_x/360.0*M_PI))*360.0/M_PI; 
+       return atan (((height/width)/vid_pixelaspect.value)*tan(fov_x/360.0*M_PI))*360.0/M_PI;
 }
 
 int r_stereo_side;
@@ -1283,7 +1448,7 @@ void SCR_DrawScreen (void)
                        r_showtrispass = 1;
                }
 
-               if (scr_conlines < vid.conheight && cls.signon == SIGNONS)
+               if (cls.signon == SIGNONS)
                {
                        float size;
 
@@ -1308,8 +1473,8 @@ void SCR_DrawScreen (void)
                        }
 
                        // LordHavoc: viewzoom (zoom in for sniper rifles, etc)
-                       r_refdef.fov_x = scr_fov.value * cl.viewzoom * r_refdef.fovscale_x;
-                       r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.width, r_refdef.height) * r_refdef.fovscale_y;
+                       r_refdef.fov_x = scr_fov.value * r_refdef.fovscale_x;
+                       r_refdef.fov_y = CalcFov (scr_fov.value, r_refdef.width, r_refdef.height) * r_refdef.fovscale_y;
 
                        R_RenderView();
 
@@ -1322,7 +1487,7 @@ void SCR_DrawScreen (void)
                                r_refdef.x = (vid.realwidth - r_refdef.width)/2;
                                r_refdef.y = 0;
                                r_refdef.fov_x = scr_zoomwindow_fov.value * r_refdef.fovscale_x;
-                               r_refdef.fov_y = CalcFov(r_refdef.fov_x, r_refdef.width, r_refdef.height) * r_refdef.fovscale_y;
+                               r_refdef.fov_y = CalcFov(scr_zoomwindow_fov.value, r_refdef.width, r_refdef.height) * r_refdef.fovscale_y;
 
                                R_RenderView();
                        }
@@ -1419,56 +1584,6 @@ void SCR_UpdateScreen (void)
        if (gl_combine.integer && (!gl_combine_extension || r_textureunits.integer < 2))
                Cvar_SetValueQuick(&gl_combine, 0);
 
-       // don't allow cheats in multiplayer
-       if (!cl.islocalgame && cl.worldmodel)
-       {
-               if (r_fullbright.integer != 0)
-                       Cvar_Set ("r_fullbright", "0");
-               if (r_ambient.value != 0)
-                       Cvar_Set ("r_ambient", "0");
-       }
-
-       // bound viewsize
-       if (scr_viewsize.value < 30)
-               Cvar_Set ("viewsize","30");
-       if (scr_viewsize.value > 120)
-               Cvar_Set ("viewsize","120");
-
-       // bound field of view
-       if (scr_fov.value < 1)
-               Cvar_Set ("fov","1");
-       if (scr_fov.value > 170)
-               Cvar_Set ("fov","170");
-
-       // intermission is always full screen
-       if (cl.intermission)
-               sb_lines = 0;
-       else
-       {
-               if (scr_viewsize.value >= 120)
-                       sb_lines = 0;           // no status bar at all
-               else if (scr_viewsize.value >= 110)
-                       sb_lines = 24;          // no inventory
-               else
-                       sb_lines = 24+16+8;
-       }
-
-       r_refdef.fovscale_x = 1;
-       r_refdef.fovscale_y = 1;
-       if (r_waterwarp.value > 0 && cl.worldmodel)
-       {
-               Mod_CheckLoaded(cl.worldmodel);
-               if (CL_PointSuperContents(r_vieworigin) & SUPERCONTENTS_LIQUIDSMASK)
-               {
-                       r_refdef.fovscale_x = 1 - (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value);
-                       r_refdef.fovscale_y = 1 - (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value);
-               }
-       }
-
-       r_refdef.colormask[0] = 1;
-       r_refdef.colormask[1] = 1;
-       r_refdef.colormask[2] = 1;
-
        CHECKGLERROR
        qglViewport(0, 0, vid.realwidth, vid.realheight);
        qglDisable(GL_SCISSOR_TEST);
@@ -1521,7 +1636,7 @@ void SCR_UpdateScreen (void)
        {
                r_showtrispass = false;
                SCR_DrawScreen();
-       
+
                if (r_showtris.value > 0)
                {
                        rmeshstate_t m;