]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
eliminated model->meshlist, replaced with an embedded model->surfmesh to cut down...
[xonotic/darkplaces.git] / gl_rmain.c
index 57f17f315fdb96a34aaeb4ed59c2c77dad025961..1a566d4e38f35feda5e4cd1e485435a99f3c6f89 100644 (file)
@@ -48,9 +48,6 @@ qboolean r_rtdlight;
 qboolean r_rtdlightshadows;
 
 
-// forces all rendering to draw triangle outlines
-int r_showtrispass;
-
 // view origin
 vec3_t r_vieworigin;
 vec3_t r_viewforward;
@@ -64,15 +61,18 @@ int r_view_width;
 int r_view_height;
 int r_view_depth;
 matrix4x4_t r_view_matrix;
-
+float r_polygonfactor;
+float r_polygonoffset;
+float r_shadowpolygonfactor;
+float r_shadowpolygonoffset;
 //
 // screen size info
 //
 refdef_t r_refdef;
 
 cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" };
+cvar_t r_showsurfaces = {0, "r_showsurfaces", "0", "shows surfaces as different colors"};
 cvar_t r_showtris = {0, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
-cvar_t r_showtris_polygonoffset = {0, "r_showtris_polygonoffset", "-10", "nudges triangle outlines in hardware depth units, used to make outlines appear infront of walls"};
 cvar_t r_shownormals = {0, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
 cvar_t r_showlighting = {0, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
 cvar_t r_showshadowvolumes = {0, "r_showshadowvolumes", "0", "shows areas shadowed by lights, useful for finding out why some areas of a map render slowly (bright blue = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
@@ -99,11 +99,12 @@ cvar_t gl_fogend = {0, "gl_fogend","0", "nehahra fog end distance (for Nehahra c
 cvar_t r_textureunits = {0, "r_textureunits", "32", "number of hardware texture units reported by driver (note: setting this to 1 turns off gl_combine)"};
 
 cvar_t r_glsl = {0, "r_glsl", "1", "enables use of OpenGL 2.0 pixel shaders for lighting"};
-cvar_t r_glsl_offsetmapping = {0, "r_glsl_offsetmapping", "0", "enables offset mapping effect (also known as parallax mapping or sometimes as virtual displacement mapping, not as good as relief mapping or silohuette mapping but much faster), can cause strange artifacts on many textures, requires bumpmaps for depth information (normalmaps can have depth information as alpha channel, but most do not)"};
-cvar_t r_glsl_offsetmapping_scale = {0, "r_glsl_offsetmapping_scale", "-0.04", "how deep the offset mapping effect is, and whether it is inward or outward"};
-cvar_t r_glsl_offsetmapping_bias = {0, "r_glsl_offsetmapping_bias", "0.04", "pushes the effect closer/further"};
+cvar_t r_glsl_offsetmapping = {0, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
+cvar_t r_glsl_offsetmapping_reliefmapping = {0, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
+cvar_t r_glsl_offsetmapping_scale = {0, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
 cvar_t r_glsl_usehalffloat = {0, "r_glsl_usehalffloat", "0", "use half and hvec variables in GLSL shader for a speed gain (NVIDIA only)"};
 cvar_t r_glsl_surfacenormalize = {0, "r_glsl_surfacenormalize", "1", "normalize bumpmap texels in GLSL shader, produces a more rounded look on small bumps and dents"};
+cvar_t r_glsl_deluxemapping = {0, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
 
 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1", "enables animation smoothing on sprites (requires r_lerpmodels 1)"};
 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
@@ -444,6 +445,12 @@ static const char *builtinshaderstring =
 "varying vec3 EyeVector;\n"
 "#endif\n"
 "\n"
+"#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
+"varying myhvec3 VectorS; // direction of S texcoord (sometimes crudely called tangent)\n"
+"varying myhvec3 VectorT; // direction of T texcoord (sometimes crudely called binormal)\n"
+"varying myhvec3 VectorR; // direction of R texcoord (surface normal)\n"
+"#endif\n"
+"\n"
 "\n"
 "\n"
 "\n"
@@ -501,6 +508,12 @@ static const char *builtinshaderstring =
 "      EyeVector.z = dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
 "#endif\n"
 "\n"
+"#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
+"      VectorS = gl_MultiTexCoord1.xyz;\n"
+"      VectorT = gl_MultiTexCoord2.xyz;\n"
+"      VectorR = gl_MultiTexCoord3.xyz;\n"
+"#endif\n"
+"\n"
 "      // transform vertex to camera space, using ftransform to match non-VS\n"
 "      // rendering\n"
 "      gl_Position = ftransform();\n"
@@ -520,7 +533,7 @@ static const char *builtinshaderstring =
 "uniform myhalf OffsetMapping_Bias;\n"
 "#endif\n"
 "\n"
-"#if defined(MODE_LIGHTSOURCE) || defined(MODE_LIGHTDIRECTIONMAP) || defined(MODE_LIGHTDIRECTION) || defined(USEOFFSETMAPPING)\n"
+"#if defined(MODE_LIGHTSOURCE) || defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE) || defined(MODE_LIGHTDIRECTION) || defined(USEOFFSETMAPPING)\n"
 "uniform sampler2D Texture_Normal;\n"
 "#endif\n"
 "\n"
@@ -535,7 +548,7 @@ static const char *builtinshaderstring =
 "#if !defined(MODE_LIGHTSOURCE) && !defined(MODE_LIGHTDIRECTION)\n"
 "uniform sampler2D Texture_Lightmap;\n"
 "#endif\n"
-"#ifdef MODE_LIGHTDIRECTIONMAP\n"
+"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
 "uniform sampler2D Texture_Deluxemap;\n"
 "#endif\n"
 "\n"
@@ -595,12 +608,39 @@ static const char *builtinshaderstring =
 "{\n"
 "      // apply offsetmapping\n"
 "#ifdef USEOFFSETMAPPING\n"
-"      // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
-"      myhvec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
-"      myhvec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
-"      TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
-"      TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
+"      myhvec2 TexCoordOffset = TexCoord;\n"
 "#define TexCoord TexCoordOffset\n"
+"\n"
+"      myhvec3 eyedir = myhvec3(normalize(EyeVector));\n"
+"      myhalf depthbias = 1.0 - eyedir.z; // should this be a -?\n"
+"      depthbias = 1.0 - depthbias * depthbias;\n"
+"\n"
+"#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n"
+"      // 14 sample relief mapping: linear search and then binary search\n"
+"      myhvec3 OffsetVector = myhvec3(EyeVector.xy * (1.0 / EyeVector.z) * depthbias * OffsetMapping_Scale * myhvec2(-0.1, 0.1), -0.1);\n"
+"      vec3 RT = vec3(TexCoord - OffsetVector.xy * 10.0, 1.0) + OffsetVector;\n"
+"      if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
+"      if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
+"      if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
+"      if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
+"      if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
+"      if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
+"      if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
+"      if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
+"      if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;\n"
+"      if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;\n"
+"      if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;\n"
+"      if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;\n"
+"      if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;\n"
+"      if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;\n"
+"      TexCoord = RT.xy;\n"
+"#else\n"
+"      // 3 sample offset mapping (only 3 samples because of ATI Radeon 9500-9800/X300 limits)\n"
+"      myhvec2 OffsetVector = myhvec2((EyeVector.xy * (1.0 / EyeVector.z) * depthbias) * OffsetMapping_Scale * myhvec2(-0.333, 0.333));\n"
+"      TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
+"      TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
+"      TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
+"#endif\n"
 "#endif\n"
 "\n"
 "      // combine the diffuse textures (base, pants, shirt)\n"
@@ -665,7 +705,6 @@ static const char *builtinshaderstring =
 "\n"
 "      // calculate directional shading\n"
 "      color.rgb *= AmbientColor + DiffuseColor * max(dot(surfacenormal, diffusenormal), 0.0);\n"
-"      //color.rgb *= AmbientColor + DiffuseColor * max(dot(surfacenormal, diffusenormal), 0.0);\n"
 "#ifdef USESPECULAR\n"
 "      myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
 "      color.rgb += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower);\n"
@@ -674,20 +713,45 @@ static const char *builtinshaderstring =
 "\n"
 "\n"
 "\n"
-"#elif defined(MODE_LIGHTDIRECTIONMAP)\n"
-"      // deluxemap lightmapping\n"
+"#elif defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE)\n"
+"      // deluxemap lightmapping using light vectors in modelspace (evil q3map2)\n"
+"\n"
+"      // get the surface normal and light normal\n"
+"#ifdef SURFACENORMALIZE\n"
+"      myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - 0.5);\n"
+"#else\n"
+"      myhvec3 surfacenormal = -1.0 + 2.0 * myhvec3(texture2D(Texture_Normal, TexCoord));\n"
+"#endif\n"
+"      myhvec3 diffusenormal_modelspace = myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - 0.5;\n"
+"      myhvec3 diffusenormal = normalize(myhvec3(dot(diffusenormal_modelspace, VectorS), dot(diffusenormal_modelspace, VectorT), dot(diffusenormal_modelspace, VectorR)));\n"
+"\n"
+"      // calculate directional shading\n"
+"      myhvec3 tempcolor = color.rgb * (DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
+"#ifdef USESPECULAR\n"
+"      myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
+"      tempcolor += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower);\n"
+"#endif\n"
+"\n"
+"      // apply lightmap color\n"
+"      color.rgb = tempcolor * myhvec3(texture2D(Texture_Lightmap, TexCoordLightmap)) + color.rgb * myhvec3(AmbientScale);\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#elif defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
+"      // deluxemap lightmapping using light vectors in tangentspace\n"
 "\n"
 "      // get the surface normal and light normal\n"
 "#ifdef SURFACENORMALIZE\n"
 "      myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - 0.5);\n"
-"      myhvec3 diffusenormal = normalize(myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)));\n"
+"      myhvec3 diffusenormal = normalize(myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - 0.5);\n"
 "#else\n"
 "      myhvec3 surfacenormal = -1.0 + 2.0 * myhvec3(texture2D(Texture_Normal, TexCoord));\n"
-"      myhvec3 diffusenormal = myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap));\n"
+"      myhvec3 diffusenormal = -1.0 + 2.0 * myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap));\n"
 "#endif\n"
 "\n"
 "      // calculate directional shading\n"
-"      myhvec3 tempcolor = color.rgb * (DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0)));\n"
+"      myhvec3 tempcolor = color.rgb * (DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
 "#ifdef USESPECULAR\n"
 "      myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
 "      tempcolor += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower);\n"
@@ -721,14 +785,12 @@ static const char *builtinshaderstring =
 "#endif\n"
 ;
 
-// the loaded GLSL shader file for compiling shader permutations as needed
-static char *shaderstring = NULL;
-
 void R_GLSL_CompilePermutation(int permutation)
 {
        r_glsl_permutation_t *p = r_glsl_permutations + permutation;
        int vertstrings_count;
        int fragstrings_count;
+       char *shaderstring;
        const char *vertstrings_list[SHADERPERMUTATION_COUNT+1];
        const char *fragstrings_list[SHADERPERMUTATION_COUNT+1];
        char permutationname[256];
@@ -746,11 +808,17 @@ void R_GLSL_CompilePermutation(int permutation)
                fragstrings_list[fragstrings_count++] = "#define MODE_LIGHTSOURCE\n";
                strlcat(permutationname, " lightsource", sizeof(permutationname));
        }
-       if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP)
+       if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE)
        {
-               vertstrings_list[vertstrings_count++] = "#define MODE_LIGHTDIRECTIONMAP\n";
-               fragstrings_list[fragstrings_count++] = "#define MODE_LIGHTDIRECTIONMAP\n";
-               strlcat(permutationname, " lightdirectionmap", sizeof(permutationname));
+               vertstrings_list[vertstrings_count++] = "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n";
+               fragstrings_list[fragstrings_count++] = "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n";
+               strlcat(permutationname, " lightdirectionmap_modelspace", sizeof(permutationname));
+       }
+       if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)
+       {
+               vertstrings_list[vertstrings_count++] = "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n";
+               fragstrings_list[fragstrings_count++] = "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n";
+               strlcat(permutationname, " lightdirectionmap_tangentspace", sizeof(permutationname));
        }
        if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTION)
        {
@@ -794,6 +862,12 @@ void R_GLSL_CompilePermutation(int permutation)
                fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
                strlcat(permutationname, " offsetmapping", sizeof(permutationname));
        }
+       if (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING)
+       {
+               vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING_RELIEFMAPPING\n";
+               fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING_RELIEFMAPPING\n";
+               strlcat(permutationname, " OFFSETMAPPING_RELIEFMAPPING", sizeof(permutationname));
+       }
        if (permutation & SHADERPERMUTATION_SURFACENORMALIZE)
        {
                vertstrings_list[vertstrings_count++] = "#define SURFACENORMALIZE\n";
@@ -806,8 +880,10 @@ void R_GLSL_CompilePermutation(int permutation)
                fragstrings_list[fragstrings_count++] = "#define GEFORCEFX\n";
                strlcat(permutationname, " halffloat", sizeof(permutationname));
        }
+       shaderstring = (char *)FS_LoadFile("glsl/default.glsl", r_main_mempool, false, NULL);
        if (shaderstring)
        {
+               Con_DPrintf("GLSL shader text loaded from disk\n");
                vertstrings_list[vertstrings_count++] = shaderstring;
                fragstrings_list[fragstrings_count++] = shaderstring;
        }
@@ -843,7 +919,6 @@ void R_GLSL_CompilePermutation(int permutation)
                p->loc_SpecularPower       = qglGetUniformLocationARB(p->program, "SpecularPower");
                p->loc_SpecularScale       = qglGetUniformLocationARB(p->program, "SpecularScale");
                p->loc_OffsetMapping_Scale = qglGetUniformLocationARB(p->program, "OffsetMapping_Scale");
-               p->loc_OffsetMapping_Bias  = qglGetUniformLocationARB(p->program, "OffsetMapping_Bias");
                p->loc_AmbientColor        = qglGetUniformLocationARB(p->program, "AmbientColor");
                p->loc_DiffuseColor        = qglGetUniformLocationARB(p->program, "DiffuseColor");
                p->loc_SpecularColor       = qglGetUniformLocationARB(p->program, "SpecularColor");
@@ -863,6 +938,17 @@ void R_GLSL_CompilePermutation(int permutation)
        }
        else
                Con_Printf("permutation%s failed for shader %s, some features may not work properly!\n", permutationname, "glsl/default.glsl");
+       if (shaderstring)
+               Mem_Free(shaderstring);
+}
+
+void R_GLSL_Restart_f(void)
+{
+       int i;
+       for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
+               if (r_glsl_permutations[i].program)
+                       GL_Backend_FreeProgram(r_glsl_permutations[i].program);
+       memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
 }
 
 void R_SetupSurfaceShader(const entity_render_t *ent, const texture_t *texture, const vec3_t modelorg, const vec3_t lightcolorbase, qboolean modellighting)
@@ -881,20 +967,19 @@ void R_SetupSurfaceShader(const entity_render_t *ent, const texture_t *texture,
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                        permutation |= SHADERPERMUTATION_CUBEFILTER;
        }
-       else if (modellighting)
-       {
-               permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTION;
-               if (texture->skin.glow)
-                       permutation |= SHADERPERMUTATION_GLOW;
-       }
-       else if (r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping)
-       {
-               permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP;
-               if (texture->skin.glow)
-                       permutation |= SHADERPERMUTATION_GLOW;
-       }
        else
        {
+               if (modellighting)
+                       permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTION;
+               else if (r_glsl_deluxemapping.integer >= 1 && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping)
+               {
+                       if (r_refdef.worldmodel->brushq3.deluxemapping_modelspace)
+                               permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE;
+                       else
+                               permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
+               }
+               else if (r_glsl_deluxemapping.integer >= 2) // fake mode
+                       permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
                if (texture->skin.glow)
                        permutation |= SHADERPERMUTATION_GLOW;
        }
@@ -905,7 +990,11 @@ void R_SetupSurfaceShader(const entity_render_t *ent, const texture_t *texture,
        if (texture->colormapping)
                permutation |= SHADERPERMUTATION_COLORMAPPING;
        if (r_glsl_offsetmapping.integer)
+       {
                permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+               if (r_glsl_offsetmapping_reliefmapping.integer)
+                       permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+       }
        if (r_glsl_surfacenormalize.integer)
                permutation |= SHADERPERMUTATION_SURFACENORMALIZE;
        if (r_glsl_usehalffloat.integer)
@@ -940,7 +1029,7 @@ void R_SetupSurfaceShader(const entity_render_t *ent, const texture_t *texture,
        if (permutation & SHADERPERMUTATION_MODE_LIGHTSOURCE)
        {
                R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
-               if (r_glsl_permutation->loc_Texture_Cube >= 0) R_Mesh_TexBind(3, R_GetTexture(r_shadow_rtlight->currentcubemap));
+               //if (r_glsl_permutation->loc_Texture_Cube >= 0) R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap));
                if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);
                if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);
                if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, r_shadow_rtlight->ambientscale);
@@ -976,7 +1065,7 @@ void R_SetupSurfaceShader(const entity_render_t *ent, const texture_t *texture,
        {
                if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, r_ambient.value * 2.0f / 128.0f);
                if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, r_lightmapintensity * 2.0f);
-               if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, specularscale * 2.0f);
+               if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_lightmapintensity * specularscale * 2.0f);
        }
        if (r_glsl_permutation->loc_Texture_Normal >= 0) R_Mesh_TexBind(0, R_GetTexture(texture->skin.nmap));
        if (r_glsl_permutation->loc_Texture_Color >= 0) R_Mesh_TexBind(1, R_GetTexture(texture->basetexture));
@@ -1011,7 +1100,6 @@ void R_SetupSurfaceShader(const entity_render_t *ent, const texture_t *texture,
        if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, fograngerecip);
        if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, texture->specularpower);
        if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);
-       if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Bias, r_glsl_offsetmapping_bias.value);
        CHECKGLERROR
 }
 
@@ -1031,29 +1119,11 @@ void gl_main_start(void)
                R_BuildNormalizationCube();
        }
        R_BuildFogTexture();
-       shaderstring = NULL;
-       if (gl_support_fragment_shader)
-       {
-               shaderstring = (char *)FS_LoadFile("glsl/default.glsl", r_main_mempool, false, NULL);
-               if (shaderstring)
-                       Con_Printf("GLSL shader text loaded from disk\n");
-               // if we couldn't load the shader file, fall back to builtin shader
-               if (!shaderstring)
-               {
-                       if (shaderstring)
-                               Con_Printf("GLSL shader text loaded from fallback\n");
-                       shaderstring = Mem_Alloc(r_main_mempool, strlen(builtinshaderstring) + 1);
-                       strcpy(shaderstring, builtinshaderstring);
-               }
-       }
-       if (shaderstring)
-               Con_Printf("GLSL shader text loaded\n");
        memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
 }
 
 void gl_main_shutdown(void)
 {
-       int i;
        R_FreeTexturePool(&r_main_texturepool);
        r_bloom_texture_screen = NULL;
        r_bloom_texture_bloom = NULL;
@@ -1062,13 +1132,7 @@ void gl_main_shutdown(void)
        r_texture_black = NULL;
        r_texture_whitecube = NULL;
        r_texture_normalizationcube = NULL;
-       if (shaderstring)
-               Mem_Free(shaderstring);
-       shaderstring = NULL;
-       for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
-               if (r_glsl_permutations[i].program)
-                       GL_Backend_FreeProgram(r_glsl_permutations[i].program);
-       memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
+       R_GLSL_Restart_f();
 }
 
 extern void CL_ParseEntityLump(char *entitystring);
@@ -1101,10 +1165,11 @@ void GL_Main_Init(void)
 {
        r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
 
+       Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed\n");
        FOG_registercvars(); // FIXME: move this fog stuff to client?
        Cvar_RegisterVariable(&r_nearclip);
+       Cvar_RegisterVariable(&r_showsurfaces);
        Cvar_RegisterVariable(&r_showtris);
-       Cvar_RegisterVariable(&r_showtris_polygonoffset);
        Cvar_RegisterVariable(&r_shownormals);
        Cvar_RegisterVariable(&r_showlighting);
        Cvar_RegisterVariable(&r_showshadowvolumes);
@@ -1122,10 +1187,11 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_textureunits);
        Cvar_RegisterVariable(&r_glsl);
        Cvar_RegisterVariable(&r_glsl_offsetmapping);
+       Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
        Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
-       Cvar_RegisterVariable(&r_glsl_offsetmapping_bias);
        Cvar_RegisterVariable(&r_glsl_usehalffloat);
        Cvar_RegisterVariable(&r_glsl_surfacenormalize);
+       Cvar_RegisterVariable(&r_glsl_deluxemapping);
        Cvar_RegisterVariable(&r_lerpsprites);
        Cvar_RegisterVariable(&r_lerpmodels);
        Cvar_RegisterVariable(&r_waterscroll);
@@ -1521,6 +1587,8 @@ static void R_BlendView(void)
        qboolean dobloom;
        qboolean doblend;
        rmeshstate_t m;
+       float vertex3f[12];
+       float texcoord2f[3][8];
 
        // set the (poorly named) screenwidth and screenheight variables to
        // a power of 2 at least as large as the screen, these will define the
@@ -1539,10 +1607,10 @@ static void R_BlendView(void)
        GL_DepthTest(false);
        R_Mesh_Matrix(&identitymatrix);
        // vertex coordinates for a quad that covers the screen exactly
-       varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
-       varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
-       varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
-       varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
+       vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
+       vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
+       vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
+       vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
        if (dobloom)
        {
                int bloomwidth, bloomheight, x, dobloomblend, range;
@@ -1559,27 +1627,27 @@ static void R_BlendView(void)
                bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
                // set up a texcoord array for the full resolution screen image
                // (we have to keep this around to copy back during final render)
-               varray_texcoord2f[0][0] = 0;
-               varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
-               varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
-               varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
-               varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
-               varray_texcoord2f[0][5] = 0;
-               varray_texcoord2f[0][6] = 0;
-               varray_texcoord2f[0][7] = 0;
+               texcoord2f[0][0] = 0;
+               texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
+               texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
+               texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
+               texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
+               texcoord2f[0][5] = 0;
+               texcoord2f[0][6] = 0;
+               texcoord2f[0][7] = 0;
                // set up a texcoord array for the reduced resolution bloom image
                // (which will be additive blended over the screen image)
-               varray_texcoord2f[1][0] = 0;
-               varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
-               varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
-               varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
-               varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
-               varray_texcoord2f[1][5] = 0;
-               varray_texcoord2f[1][6] = 0;
-               varray_texcoord2f[1][7] = 0;
+               texcoord2f[1][0] = 0;
+               texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
+               texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
+               texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
+               texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
+               texcoord2f[1][5] = 0;
+               texcoord2f[1][6] = 0;
+               texcoord2f[1][7] = 0;
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = varray_vertex3f;
-               m.pointer_texcoord[0] = varray_texcoord2f[0];
+               m.pointer_vertex = vertex3f;
+               m.pointer_texcoord[0] = texcoord2f[0];
                m.tex[0] = R_GetTexture(r_bloom_texture_screen);
                R_Mesh_State(&m);
                // copy view into the full resolution screen image texture
@@ -1605,9 +1673,9 @@ static void R_BlendView(void)
                // we now have a darkened bloom image in the framebuffer, copy it into
                // the bloom image texture for more processing
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = varray_vertex3f;
+               m.pointer_vertex = vertex3f;
                m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
-               m.pointer_texcoord[0] = varray_texcoord2f[2];
+               m.pointer_texcoord[0] = texcoord2f[2];
                R_Mesh_State(&m);
                GL_ActiveTexture(0);
                qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.height - (r_view_y + bloomheight), bloomwidth, bloomheight);
@@ -1621,14 +1689,14 @@ static void R_BlendView(void)
                        xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
                        yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
                        // compute a texcoord array with the specified x and y offset
-                       varray_texcoord2f[2][0] = xoffset+0;
-                       varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
-                       varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
-                       varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
-                       varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
-                       varray_texcoord2f[2][5] = yoffset+0;
-                       varray_texcoord2f[2][6] = xoffset+0;
-                       varray_texcoord2f[2][7] = yoffset+0;
+                       texcoord2f[2][0] = xoffset+0;
+                       texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
+                       texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
+                       texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
+                       texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
+                       texcoord2f[2][5] = yoffset+0;
+                       texcoord2f[2][6] = xoffset+0;
+                       texcoord2f[2][7] = yoffset+0;
                        // this r value looks like a 'dot' particle, fading sharply to
                        // black at the edges
                        // (probably not realistic but looks good enough)
@@ -1654,14 +1722,14 @@ static void R_BlendView(void)
                        xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
                        yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
                        // compute a texcoord array with the specified x and y offset
-                       varray_texcoord2f[2][0] = xoffset+0;
-                       varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
-                       varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
-                       varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
-                       varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
-                       varray_texcoord2f[2][5] = yoffset+0;
-                       varray_texcoord2f[2][6] = xoffset+0;
-                       varray_texcoord2f[2][7] = yoffset+0;
+                       texcoord2f[2][0] = xoffset+0;
+                       texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
+                       texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
+                       texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
+                       texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
+                       texcoord2f[2][5] = yoffset+0;
+                       texcoord2f[2][6] = xoffset+0;
+                       texcoord2f[2][7] = yoffset+0;
                        // this r value looks like a 'dot' particle, fading sharply to
                        // black at the edges
                        // (probably not realistic but looks good enough)
@@ -1682,9 +1750,9 @@ static void R_BlendView(void)
                // put the original screen image back in place and blend the bloom
                // texture on it
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = varray_vertex3f;
+               m.pointer_vertex = vertex3f;
                m.tex[0] = R_GetTexture(r_bloom_texture_screen);
-               m.pointer_texcoord[0] = varray_texcoord2f[0];
+               m.pointer_texcoord[0] = texcoord2f[0];
 #if 0
                dobloomblend = false;
 #else
@@ -1694,7 +1762,7 @@ static void R_BlendView(void)
                        dobloomblend = false;
                        m.texcombinergb[1] = GL_ADD;
                        m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
-                       m.pointer_texcoord[1] = varray_texcoord2f[1];
+                       m.pointer_texcoord[1] = texcoord2f[1];
                }
                else
                        dobloomblend = true;
@@ -1708,9 +1776,9 @@ static void R_BlendView(void)
                if (dobloomblend)
                {
                        memset(&m, 0, sizeof(m));
-                       m.pointer_vertex = varray_vertex3f;
+                       m.pointer_vertex = vertex3f;
                        m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
-                       m.pointer_texcoord[0] = varray_texcoord2f[1];
+                       m.pointer_texcoord[0] = texcoord2f[1];
                        R_Mesh_State(&m);
                        GL_BlendFunc(GL_ONE, GL_ONE);
                        GL_Color(1,1,1,1);
@@ -1722,7 +1790,7 @@ static void R_BlendView(void)
        {
                // apply a color tint to the whole view
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = varray_vertex3f;
+               m.pointer_vertex = vertex3f;
                R_Mesh_State(&m);
                GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
@@ -1757,6 +1825,18 @@ void R_RenderView(void)
        r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
        r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
        r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
+       r_polygonfactor = 0;
+       r_polygonoffset = 0;
+       r_shadowpolygonfactor = r_polygonfactor + r_shadow_shadow_polygonfactor.value;
+       r_shadowpolygonoffset = r_polygonoffset + r_shadow_shadow_polygonoffset.value;
+       if (r_showsurfaces.integer)
+       {
+               r_rtworld = false;
+               r_rtworldshadows = false;
+               r_rtdlight = false;
+               r_rtdlightshadows = false;
+               r_lightmapintensity = 0;
+       }
 
        // GL is weird because it's bottom to top, r_view_y is top to bottom
        qglViewport(r_view_x, vid.height - (r_view_y + r_view_height), r_view_width, r_view_height);
@@ -1770,12 +1850,12 @@ void R_RenderView(void)
                R_TimeReport("setup");
 
        qglDepthFunc(GL_LEQUAL);
-       qglPolygonOffset(0, 0);
+       qglPolygonOffset(r_polygonfactor, r_polygonoffset);
        qglEnable(GL_POLYGON_OFFSET_FILL);
 
        R_RenderScene();
 
-       qglPolygonOffset(0, 0);
+       qglPolygonOffset(r_polygonfactor, r_polygonoffset);
        qglDisable(GL_POLYGON_OFFSET_FILL);
 
        R_BlendView();
@@ -1805,6 +1885,18 @@ void CSQC_R_ClearScreen (void)
        r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
        r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
        r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
+       r_polygonfactor = 0;
+       r_polygonoffset = 0;
+       r_shadowpolygonfactor = r_polygonfactor + r_shadow_shadow_polygonfactor.value;
+       r_shadowpolygonoffset = r_polygonoffset + r_shadow_shadow_polygonoffset.value;
+       if (r_showsurfaces.integer)
+       {
+               r_rtworld = false;
+               r_rtworldshadows = false;
+               r_rtdlight = false;
+               r_rtdlightshadows = false;
+               r_lightmapintensity = 0;
+       }
 
        // GL is weird because it's bottom to top, r_view_y is top to bottom
        qglViewport(r_view_x, vid.height - (r_view_y + r_view_height), r_view_width, r_view_height);
@@ -1822,12 +1914,12 @@ void CSQC_R_ClearScreen (void)
 void CSQC_R_RenderScene (void)
 {
        qglDepthFunc(GL_LEQUAL);
-       qglPolygonOffset(0, 0);
+       qglPolygonOffset(r_polygonfactor, r_polygonoffset);
        qglEnable(GL_POLYGON_OFFSET_FILL);
 
        R_RenderScene();
 
-       qglPolygonOffset(0, 0);
+       qglPolygonOffset(r_polygonfactor, r_polygonoffset);
        qglDisable(GL_POLYGON_OFFSET_FILL);
 
        R_BlendView();
@@ -1881,123 +1973,85 @@ void R_RenderScene(void)
 
        R_Shadow_UpdateWorldLightSelection();
 
-       for (r_showtrispass = 0;r_showtrispass <= (r_showtris.value > 0);r_showtrispass++)
+       if (cl.csqc_vidvars.drawworld)
        {
-               if (r_showtrispass)
-               {
-                       rmeshstate_t m;
-                       r_showtrispass = 0;
-                       GL_BlendFunc(GL_ONE, GL_ONE);
-                       GL_DepthTest(!r_showdisabledepthtest.integer);
-                       GL_DepthMask(GL_FALSE);
-                       memset(&m, 0, sizeof(m));
-                       R_Mesh_State(&m);
-                       //qglEnable(GL_LINE_SMOOTH);
-                       qglEnable(GL_POLYGON_OFFSET_LINE);
-                       qglPolygonOffset(0, r_showtris_polygonoffset.value);
-                       r_showtrispass = 1;
-               }
-
-               if (cl.csqc_vidvars.drawworld)
-               {
-                       // don't let sound skip if going slow
-                       if (r_refdef.extraupdate)
-                               S_ExtraUpdate ();
-
-                       if (r_showtrispass)
-                               GL_ShowTrisColor(0.025, 0.025, 0, 1);
-                       if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
-                       {
-                               r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
-                               if (r_timereport_active)
-                                       R_TimeReport("worldsky");
-                       }
-
-                       if (R_DrawBrushModelsSky() && r_timereport_active)
-                               R_TimeReport("bmodelsky");
-
-                       if (r_showtrispass)
-                               GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
-                       if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
-                       {
-                               r_refdef.worldmodel->Draw(r_refdef.worldentity);
-                               if (r_timereport_active)
-                                       R_TimeReport("world");
-                       }
-               }
-
                // don't let sound skip if going slow
                if (r_refdef.extraupdate)
                        S_ExtraUpdate ();
 
-               if (r_showtrispass)
-                       GL_ShowTrisColor(0, 0.015, 0, 1);
-
-               R_DrawModels();
-               if (r_timereport_active)
-                       R_TimeReport("models");
+               if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
+               {
+                       r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
+                       if (r_timereport_active)
+                               R_TimeReport("worldsky");
+               }
 
-               // don't let sound skip if going slow
-               if (r_refdef.extraupdate)
-                       S_ExtraUpdate ();
+               if (R_DrawBrushModelsSky() && r_timereport_active)
+                       R_TimeReport("bmodelsky");
 
-               if (r_showtrispass)
-                       GL_ShowTrisColor(0, 0, 0.033, 1);
-               R_ShadowVolumeLighting(false);
-               if (r_timereport_active)
-                       R_TimeReport("rtlights");
+               if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
+               {
+                       r_refdef.worldmodel->Draw(r_refdef.worldentity);
+                       if (r_timereport_active)
+                               R_TimeReport("world");
+               }
+       }
 
-               // don't let sound skip if going slow
-               if (r_refdef.extraupdate)
-                       S_ExtraUpdate ();
+       // don't let sound skip if going slow
+       if (r_refdef.extraupdate)
+               S_ExtraUpdate ();
 
-               if (r_showtrispass)
-                       GL_ShowTrisColor(0.1, 0, 0, 1);
+       R_DrawModels();
+       if (r_timereport_active)
+               R_TimeReport("models");
 
-               if (cl.csqc_vidvars.drawworld)
-               {
-                       R_DrawLightningBeams();
-                       if (r_timereport_active)
-                               R_TimeReport("lightning");
+       // don't let sound skip if going slow
+       if (r_refdef.extraupdate)
+               S_ExtraUpdate ();
 
-                       R_DrawParticles();
-                       if (r_timereport_active)
-                               R_TimeReport("particles");
+       R_ShadowVolumeLighting(false);
+       if (r_timereport_active)
+               R_TimeReport("rtlights");
 
-                       R_DrawExplosions();
-                       if (r_timereport_active)
-                               R_TimeReport("explosions");
-               }
+       // don't let sound skip if going slow
+       if (r_refdef.extraupdate)
+               S_ExtraUpdate ();
 
-               R_MeshQueue_RenderTransparent();
+       if (cl.csqc_vidvars.drawworld)
+       {
+               R_DrawLightningBeams();
                if (r_timereport_active)
-                       R_TimeReport("drawtrans");
+                       R_TimeReport("lightning");
 
-               if (cl.csqc_vidvars.drawworld)
-               {
-                       R_DrawCoronas();
-                       if (r_timereport_active)
-                               R_TimeReport("coronas");
-               }
-               if(cl.csqc_vidvars.drawcrosshair)
-               {
-                       R_DrawWorldCrosshair();
-                       if (r_timereport_active)
-                               R_TimeReport("crosshair");
-               }
+               R_DrawParticles();
+               if (r_timereport_active)
+                       R_TimeReport("particles");
 
-               VM_AddPolygonsToMeshQueue();
+               R_DrawExplosions();
+               if (r_timereport_active)
+                       R_TimeReport("explosions");
+       }
 
-               R_MeshQueue_Render();
+       R_MeshQueue_RenderTransparent();
+       if (r_timereport_active)
+               R_TimeReport("drawtrans");
 
-               if (r_showtrispass)
-               {
-                       //qglDisable(GL_LINE_SMOOTH);
-                       qglDisable(GL_POLYGON_OFFSET_LINE);
-               }
+       if (cl.csqc_vidvars.drawworld)
+       {
+               R_DrawCoronas();
+               if (r_timereport_active)
+                       R_TimeReport("coronas");
+       }
+       if(cl.csqc_vidvars.drawcrosshair)
+       {
+               R_DrawWorldCrosshair();
+               if (r_timereport_active)
+                       R_TimeReport("crosshair");
        }
 
-       r_showtrispass = 0;
+       VM_AddPolygonsToMeshQueue();
+
+       R_MeshQueue_Render();
 
        R_MeshQueue_EndScene();
 
@@ -2178,6 +2232,7 @@ void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, rtexture_
 {
        float fog = 0.0f, ifog;
        rmeshstate_t m;
+       float vertex3f[12];
 
        if (fogenabled)
                fog = VERTEXFOGTABLE(VectorDistance(origin, r_vieworigin));
@@ -2188,23 +2243,23 @@ void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, rtexture_
        GL_DepthMask(false);
        GL_DepthTest(!depthdisable);
 
-       varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
-       varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
-       varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
-       varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
-       varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
-       varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
-       varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
-       varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
-       varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
-       varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
-       varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
-       varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
+       vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
+       vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
+       vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
+       vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
+       vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
+       vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
+       vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
+       vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
+       vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
+       vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
+       vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
+       vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
 
        memset(&m, 0, sizeof(m));
        m.tex[0] = R_GetTexture(texture);
        m.pointer_texcoord[0] = spritetexcoord2f;
-       m.pointer_vertex = varray_vertex3f;
+       m.pointer_vertex = vertex3f;
        R_Mesh_State(&m);
        GL_Color(cr * ifog, cg * ifog, cb * ifog, ca);
        R_Mesh_Draw(0, 4, 2, polygonelements);
@@ -2285,6 +2340,36 @@ void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *plane
        }
 }
 
+static void R_DrawCollisionBrush(colbrushf_t *brush)
+{
+       int i;
+       rmeshstate_t m;
+       memset(&m, 0, sizeof(m));
+       m.pointer_vertex = brush->points->v;
+       R_Mesh_State(&m);
+       i = (int)(((size_t)brush) / sizeof(colbrushf_t));
+       GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f);
+       GL_LockArrays(0, brush->numpoints);
+       R_Mesh_Draw(0, brush->numpoints, brush->numtriangles, brush->elements);
+       GL_LockArrays(0, 0);
+}
+
+static void R_DrawCollisionSurface(entity_render_t *ent, msurface_t *surface)
+{
+       int i;
+       rmeshstate_t m;
+       if (!surface->num_collisiontriangles)
+               return;
+       memset(&m, 0, sizeof(m));
+       m.pointer_vertex = surface->data_collisionvertex3f;
+       R_Mesh_State(&m);
+       i = (int)(((size_t)surface) / sizeof(msurface_t));
+       GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f);
+       GL_LockArrays(0, surface->num_collisionvertices);
+       R_Mesh_Draw(0, surface->num_collisionvertices, surface->num_collisiontriangles, surface->data_collisionelement3i);
+       GL_LockArrays(0, 0);
+}
+
 static void R_Texture_AddLayer(texture_t *t, qboolean depthmask, int blendfunc1, int blendfunc2, texturelayertype_t type, rtexture_t *texture, const matrix4x4_t *matrix, float r, float g, float b, float a)
 {
        texturelayer_t *layer;
@@ -2465,6 +2550,29 @@ void R_UpdateAllTextureInfo(entity_render_t *ent)
                        R_UpdateTextureInfo(ent, ent->model->data_textures + i);
 }
 
+int rsurface_array_size = 0;
+float *rsurface_array_vertex3f = NULL;
+float *rsurface_array_svector3f = NULL;
+float *rsurface_array_tvector3f = NULL;
+float *rsurface_array_normal3f = NULL;
+float *rsurface_array_color4f = NULL;
+float *rsurface_array_texcoord3f = NULL;
+
+void R_Mesh_ResizeArrays(int newvertices)
+{
+       if (rsurface_array_size >= newvertices)
+               return;
+       if (rsurface_array_vertex3f)
+               Mem_Free(rsurface_array_vertex3f);
+       rsurface_array_size = (newvertices + 1023) & ~1023;
+       rsurface_array_vertex3f = Mem_Alloc(r_main_mempool, rsurface_array_size * sizeof(float[19]));
+       rsurface_array_svector3f = rsurface_array_vertex3f + rsurface_array_size * 3;
+       rsurface_array_tvector3f = rsurface_array_vertex3f + rsurface_array_size * 6;
+       rsurface_array_normal3f = rsurface_array_vertex3f + rsurface_array_size * 9;
+       rsurface_array_color4f = rsurface_array_vertex3f + rsurface_array_size * 12;
+       rsurface_array_texcoord3f = rsurface_array_vertex3f + rsurface_array_size * 16;
+}
+
 float *rsurface_vertex3f;
 float *rsurface_svector3f;
 float *rsurface_tvector3f;
@@ -2473,16 +2581,19 @@ float *rsurface_lightmapcolor4f;
 
 void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg, qboolean generatenormals, qboolean generatetangents)
 {
-       if ((ent->frameblend[0].lerp != 1 || ent->frameblend[0].frame != 0) && (surface->groupmesh->data_morphvertex3f || surface->groupmesh->data_vertexboneweights))
+       model_t *model = ent->model;
+       if (rsurface_array_size < model->surfmesh.num_vertices)
+               R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
+       if ((ent->frameblend[0].lerp != 1 || ent->frameblend[0].frame != 0) && (model->surfmesh.data_morphvertex3f || model->surfmesh.data_vertexboneweights))
        {
-               rsurface_vertex3f = varray_vertex3f;
-               Mod_Alias_GetMesh_Vertex3f(ent->model, ent->frameblend, surface->groupmesh, rsurface_vertex3f);
+               rsurface_vertex3f = rsurface_array_vertex3f;
+               Mod_Alias_GetMesh_Vertex3f(model, ent->frameblend, rsurface_vertex3f);
                if (generatetangents || (texture->textureflags & (Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2)))
                {
-                       rsurface_svector3f = varray_svector3f;
-                       rsurface_tvector3f = varray_tvector3f;
-                       rsurface_normal3f = varray_normal3f;
-                       Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, r_smoothnormals_areaweighting.integer);
+                       rsurface_svector3f = rsurface_array_svector3f;
+                       rsurface_tvector3f = rsurface_array_tvector3f;
+                       rsurface_normal3f = rsurface_array_normal3f;
+                       Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, model->surfmesh.data_texcoordtexture2f, model->surfmesh.data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, r_smoothnormals_areaweighting.integer);
                }
                else
                {
@@ -2490,8 +2601,8 @@ void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture
                        rsurface_tvector3f = NULL;
                        if (generatenormals)
                        {
-                               rsurface_normal3f = varray_normal3f;
-                               Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle, rsurface_normal3f, r_smoothnormals_areaweighting.integer);
+                               rsurface_normal3f = rsurface_array_normal3f;
+                               Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, rsurface_normal3f, r_smoothnormals_areaweighting.integer);
                        }
                        else
                                rsurface_normal3f = NULL;
@@ -2499,10 +2610,10 @@ void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture
        }
        else
        {
-               rsurface_vertex3f = surface->groupmesh->data_vertex3f;
-               rsurface_svector3f = surface->groupmesh->data_svector3f;
-               rsurface_tvector3f = surface->groupmesh->data_tvector3f;
-               rsurface_normal3f = surface->groupmesh->data_normal3f;
+               rsurface_vertex3f = model->surfmesh.data_vertex3f;
+               rsurface_svector3f = model->surfmesh.data_svector3f;
+               rsurface_tvector3f = model->surfmesh.data_tvector3f;
+               rsurface_normal3f = model->surfmesh.data_normal3f;
        }
        if (texture->textureflags & (Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2))
        {
@@ -2536,21 +2647,21 @@ void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture
                                VectorSet(up, 0, 0, 1);
                        }
                        for (i = 0;i < 4;i++)
-                               VectorMAMAMAM(1, center, v[i][0], forward, v[i][1], right, v[i][2], up, varray_vertex3f + (surface->num_firstvertex+i+j) * 3);
+                               VectorMAMAMAM(1, center, v[i][0], forward, v[i][1], right, v[i][2], up, rsurface_array_vertex3f + (surface->num_firstvertex+i+j) * 3);
                }
-               rsurface_vertex3f = varray_vertex3f;
-               rsurface_svector3f = varray_svector3f;
-               rsurface_tvector3f = varray_tvector3f;
-               rsurface_normal3f = varray_normal3f;
-               Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, r_smoothnormals_areaweighting.integer);
+               rsurface_vertex3f = rsurface_array_vertex3f;
+               rsurface_svector3f = rsurface_array_svector3f;
+               rsurface_tvector3f = rsurface_array_tvector3f;
+               rsurface_normal3f = rsurface_array_normal3f;
+               Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, model->surfmesh.data_texcoordtexture2f, model->surfmesh.data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, r_smoothnormals_areaweighting.integer);
        }
        R_Mesh_VertexPointer(rsurface_vertex3f);
 }
 
-static void RSurf_Draw(const msurface_t *surface)
+static void RSurf_Draw(model_t *model, const msurface_t *surface)
 {
        GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
        GL_LockArrays(0, 0);
 }
 
@@ -2559,11 +2670,12 @@ static void RSurf_DrawLightmap(const entity_render_t *ent, const texture_t *text
        int i;
        float f;
        float *v, *c, *c2;
+       model_t *model = ent->model;
        RSurf_SetVertexPointer(ent, texture, surface, modelorg, lightmode >= 2, false);
        if (lightmode >= 2)
        {
                // model lighting
-               vec4_t ambientcolor;
+               vec3_t ambientcolor;
                vec3_t diffusecolor;
                vec3_t lightdir;
                VectorCopy(ent->modellight_lightdir, lightdir);
@@ -2578,24 +2690,22 @@ static void RSurf_DrawLightmap(const entity_render_t *ent, const texture_t *text
                        int numverts = surface->num_vertices;
                        v = rsurface_vertex3f + 3 * surface->num_firstvertex;
                        c2 = rsurface_normal3f + 3 * surface->num_firstvertex;
-                       c = varray_color4f + 4 * surface->num_firstvertex;
+                       c = rsurface_array_color4f + 4 * surface->num_firstvertex;
                        // q3-style directional shading
                        for (i = 0;i < numverts;i++, v += 3, c2 += 3, c += 4)
                        {
                                if ((f = DotProduct(c2, lightdir)) > 0)
-                               {
                                        VectorMA(ambientcolor, f, diffusecolor, c);
-                                       c[3] = a;
-                               }
                                else
-                                       VectorCopy4(ambientcolor, c);
+                                       VectorCopy(ambientcolor, c);
+                               c[3] = a;
                        }
                        r = 1;
                        g = 1;
                        b = 1;
                        a = 1;
                        applycolor = false;
-                       rsurface_lightmapcolor4f = varray_color4f;
+                       rsurface_lightmapcolor4f = rsurface_array_color4f;
                }
                else
                {
@@ -2609,11 +2719,11 @@ static void RSurf_DrawLightmap(const entity_render_t *ent, const texture_t *text
        {
                if (surface->lightmapinfo && surface->lightmapinfo->stainsamples)
                {
-                       for (i = 0, c = varray_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
+                       for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
                        {
                                if (surface->lightmapinfo->samples)
                                {
-                                       const unsigned char *lm = surface->lightmapinfo->samples + (surface->groupmesh->data_lightmapoffsets + surface->num_firstvertex)[i];
+                                       const unsigned char *lm = surface->lightmapinfo->samples + (model->surfmesh.data_lightmapoffsets + surface->num_firstvertex)[i];
                                        float scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[0]] * (1.0f / 32768.0f);
                                        VectorScale(lm, scale, c);
                                        if (surface->lightmapinfo->styles[1] != 255)
@@ -2639,10 +2749,10 @@ static void RSurf_DrawLightmap(const entity_render_t *ent, const texture_t *text
                                else
                                        VectorClear(c);
                        }
-                       rsurface_lightmapcolor4f = varray_color4f;
+                       rsurface_lightmapcolor4f = rsurface_array_color4f;
                }
                else
-                       rsurface_lightmapcolor4f = surface->groupmesh->data_lightmapcolor4f;
+                       rsurface_lightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
        }
        else
                rsurface_lightmapcolor4f = NULL;
@@ -2650,7 +2760,7 @@ static void RSurf_DrawLightmap(const entity_render_t *ent, const texture_t *text
        {
                if (rsurface_lightmapcolor4f)
                {
-                       for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4)
+                       for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface_array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4)
                        {
                                f = 1 - VERTEXFOGTABLE(VectorDistance(v, modelorg));
                                c2[0] = c[0] * f;
@@ -2661,7 +2771,7 @@ static void RSurf_DrawLightmap(const entity_render_t *ent, const texture_t *text
                }
                else
                {
-                       for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c2 = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c2 += 4)
+                       for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c2 = (rsurface_array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c2 += 4)
                        {
                                f = 1 - VERTEXFOGTABLE(VectorDistance(v, modelorg));
                                c2[0] = f;
@@ -2670,22 +2780,22 @@ static void RSurf_DrawLightmap(const entity_render_t *ent, const texture_t *text
                                c2[3] = 1;
                        }
                }
-               rsurface_lightmapcolor4f = varray_color4f;
+               rsurface_lightmapcolor4f = rsurface_array_color4f;
        }
        if (applycolor && rsurface_lightmapcolor4f)
        {
-               for (i = 0, c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4)
+               for (i = 0, c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface_array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4)
                {
                        c2[0] = c[0] * r;
                        c2[1] = c[1] * g;
                        c2[2] = c[2] * b;
                        c2[3] = c[3] * a;
                }
-               rsurface_lightmapcolor4f = varray_color4f;
+               rsurface_lightmapcolor4f = rsurface_array_color4f;
        }
        R_Mesh_ColorPointer(rsurface_lightmapcolor4f);
        GL_Color(r, g, b, a);
-       RSurf_Draw(surface);
+       RSurf_Draw(model, surface);
 }
 
 static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *texture, int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t modelorg)
@@ -2693,6 +2803,7 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
        int texturesurfaceindex;
        int lightmode;
        const msurface_t *surface;
+       model_t *model = ent->model;
        qboolean applycolor;
        qboolean applyfog;
        rmeshstate_t m;
@@ -2700,8 +2811,8 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                return;
        r_shadow_rtlight = NULL;
        renderstats.entities_surfaces += texturenumsurfaces;
-       // FIXME: identify models using a better check than ent->model->brush.shadowmesh
-       lightmode = ((ent->effects & EF_FULLBRIGHT) || ent->model->brush.shadowmesh) ? 0 : 2;
+       // FIXME: identify models using a better check than model->brush.shadowmesh
+       lightmode = ((ent->effects & EF_FULLBRIGHT) || model->brush.shadowmesh) ? 0 : 2;
        GL_DepthTest(!(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
        if ((texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (ent->flags & RENDER_NOCULLFACE))
                qglDisable(GL_CULL_FACE);
@@ -2710,27 +2821,29 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                // transparent sky would be ridiculous
                if (!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
                {
-                       GL_DepthMask(true);
                        if (skyrendernow)
                        {
                                skyrendernow = false;
-                               if (skyrendermasked)
-                               {
-                                       R_Sky();
-                                       // restore entity matrix and GL_Color
-                                       R_Mesh_Matrix(&ent->matrix);
-                                       GL_Color(1,1,1,1);
-                               }
+                               R_Sky();
+                               // restore entity matrix
+                               R_Mesh_Matrix(&ent->matrix);
                        }
+                       GL_DepthMask(true);
                        // LordHavoc: HalfLife maps have freaky skypolys...
-                       //if (!ent->model->brush.ishlbsp)
+                       // LordHavoc: Quake3 never did sky masking (unlike software Quake
+                       // and Quake2), so disable the sky masking in Quake3 maps as it
+                       // causes problems with q3map2 sky tricks
+                       if (!model->brush.ishlbsp && model->type != mod_brushq3)
                        {
+                               GL_Color(fogcolor[0], fogcolor[1], fogcolor[2], 1);
+                               memset(&m, 0, sizeof(m));
+                               R_Mesh_State(&m);
                                if (skyrendermasked)
                                {
                                        // depth-only (masking)
                                        GL_ColorMask(0,0,0,0);
-                                       // just to make sure that braindead drivers don't draw anything
-                                       // despite that colormask...
+                                       // just to make sure that braindead drivers don't draw
+                                       // anything despite that colormask...
                                        GL_BlendFunc(GL_ZERO, GL_ONE);
                                }
                                else
@@ -2738,14 +2851,11 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                        // fog sky
                                        GL_BlendFunc(GL_ONE, GL_ZERO);
                                }
-                               GL_Color(fogcolor[0], fogcolor[1], fogcolor[2], 1);
-                               memset(&m, 0, sizeof(m));
-                               R_Mesh_State(&m);
                                for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                                {
                                        surface = texturesurfacelist[texturesurfaceindex];
                                        RSurf_SetVertexPointer(ent, texture, surface, modelorg, false, false);
-                                       RSurf_Draw(surface);
+                                       RSurf_Draw(model, surface);
                                }
                                if (skyrendermasked)
                                        GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
@@ -2782,11 +2892,11 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                        {
                                surface = texturesurfacelist[texturesurfaceindex];
                                RSurf_SetVertexPointer(ent, texture, surface, modelorg, false, true);
-                               R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+                               R_Mesh_TexCoordPointer(0, 2, model->surfmesh.data_texcoordtexture2f);
                                R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
                                R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
                                R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
-                               RSurf_Draw(surface);
+                               RSurf_Draw(model, surface);
                        }
                }
                else
@@ -2795,17 +2905,16 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                        {
                                surface = texturesurfacelist[texturesurfaceindex];
                                RSurf_SetVertexPointer(ent, texture, surface, modelorg, false, true);
-                               R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+                               R_Mesh_TexCoordPointer(0, 2, model->surfmesh.data_texcoordtexture2f);
                                R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
                                R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
                                R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
-                               R_Mesh_TexCoordPointer(4, 2, surface->groupmesh->data_texcoordlightmap2f);
+                               R_Mesh_TexCoordPointer(4, 2, model->surfmesh.data_texcoordlightmap2f);
                                if (surface->lightmaptexture)
                                {
                                        R_Mesh_TexBind(7, R_GetTexture(surface->lightmaptexture));
                                        if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
-                                               R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
-                                               //R_Mesh_TexBind(8, R_GetTexture(surface->deluxemaptexture));
+                                               R_Mesh_TexBind(8, R_GetTexture(surface->deluxemaptexture));
                                        R_Mesh_ColorPointer(NULL);
                                }
                                else
@@ -2813,9 +2922,9 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                        R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
                                        if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
                                                R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
-                                       R_Mesh_ColorPointer(surface->groupmesh->data_lightmapcolor4f);
+                                       R_Mesh_ColorPointer(model->surfmesh.data_lightmapcolor4f);
                                }
-                               RSurf_Draw(surface);
+                               RSurf_Draw(model, surface);
                        }
                }
                qglUseProgramObjectARB(0);
@@ -2856,15 +2965,15 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                m.tex[1] = R_GetTexture(layer->texture);
                                m.texmatrix[1] = layer->texmatrix;
                                m.texrgbscale[1] = layertexrgbscale;
-                               m.pointer_color = varray_color4f;
+                               m.pointer_color = rsurface_array_color4f;
                                R_Mesh_State(&m);
                                if (lightmode == 2)
                                {
                                        for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                                        {
                                                surface = texturesurfacelist[texturesurfaceindex];
-                                               R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordlightmap2f);
-                                               R_Mesh_TexCoordPointer(1, 2, surface->groupmesh->data_texcoordtexture2f);
+                                               R_Mesh_TexCoordPointer(0, 2, model->surfmesh.data_texcoordlightmap2f);
+                                               R_Mesh_TexCoordPointer(1, 2, model->surfmesh.data_texcoordtexture2f);
                                                R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
                                                RSurf_DrawLightmap(ent, texture, surface, modelorg, layercolor[0], layercolor[1], layercolor[2], layercolor[3], 2, applycolor, applyfog);
                                        }
@@ -2874,8 +2983,8 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                        for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                                        {
                                                surface = texturesurfacelist[texturesurfaceindex];
-                                               R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordlightmap2f);
-                                               R_Mesh_TexCoordPointer(1, 2, surface->groupmesh->data_texcoordtexture2f);
+                                               R_Mesh_TexCoordPointer(0, 2, model->surfmesh.data_texcoordlightmap2f);
+                                               R_Mesh_TexCoordPointer(1, 2, model->surfmesh.data_texcoordtexture2f);
                                                if (surface->lightmaptexture)
                                                {
                                                        R_Mesh_TexBind(0, R_GetTexture(surface->lightmaptexture));
@@ -2893,7 +3002,7 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                memset(&m, 0, sizeof(m));
                                m.tex[0] = R_GetTexture(layer->texture);
                                m.texmatrix[0] = layer->texmatrix;
-                               m.pointer_color = varray_color4f;
+                               m.pointer_color = rsurface_array_color4f;
                                m.texrgbscale[0] = layertexrgbscale;
                                R_Mesh_State(&m);
                                if (lightmode == 2)
@@ -2901,7 +3010,7 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                        for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                                        {
                                                surface = texturesurfacelist[texturesurfaceindex];
-                                               R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordlightmap2f);
+                                               R_Mesh_TexCoordPointer(0, 2, model->surfmesh.data_texcoordlightmap2f);
                                                R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
                                                RSurf_DrawLightmap(ent, texture, surface, modelorg, 1, 1, 1, 1, 2, false, false);
                                        }
@@ -2911,7 +3020,7 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                        for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                                        {
                                                surface = texturesurfacelist[texturesurfaceindex];
-                                               R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordlightmap2f);
+                                               R_Mesh_TexCoordPointer(0, 2, model->surfmesh.data_texcoordlightmap2f);
                                                if (surface->lightmaptexture)
                                                {
                                                        R_Mesh_TexBind(0, R_GetTexture(surface->lightmaptexture));
@@ -2928,13 +3037,13 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                memset(&m, 0, sizeof(m));
                                m.tex[0] = R_GetTexture(layer->texture);
                                m.texmatrix[0] = layer->texmatrix;
-                               m.pointer_color = varray_color4f;
+                               m.pointer_color = rsurface_array_color4f;
                                m.texrgbscale[0] = layertexrgbscale;
                                R_Mesh_State(&m);
                                for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                                {
                                        surface = texturesurfacelist[texturesurfaceindex];
-                                       R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+                                       R_Mesh_TexCoordPointer(0, 2, model->surfmesh.data_texcoordtexture2f);
                                        RSurf_DrawLightmap(ent, texture, surface, modelorg, layercolor[0], layercolor[1], layercolor[2], layercolor[3], 0, applycolor, applyfog);
                                }
                                break;
@@ -2943,14 +3052,14 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                m.tex[0] = R_GetTexture(layer->texture);
                                m.texmatrix[0] = layer->texmatrix;
                                m.texrgbscale[0] = layertexrgbscale;
-                               m.pointer_color = varray_color4f;
+                               m.pointer_color = rsurface_array_color4f;
                                R_Mesh_State(&m);
                                if (lightmode == 2)
                                {
                                        for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                                        {
                                                surface = texturesurfacelist[texturesurfaceindex];
-                                               R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+                                               R_Mesh_TexCoordPointer(0, 2, model->surfmesh.data_texcoordtexture2f);
                                                RSurf_DrawLightmap(ent, texture, surface, modelorg, layercolor[0], layercolor[1], layercolor[2], layercolor[3], 2, applycolor, applyfog);
                                        }
                                }
@@ -2959,7 +3068,7 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                        for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                                        {
                                                surface = texturesurfacelist[texturesurfaceindex];
-                                               R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+                                               R_Mesh_TexCoordPointer(0, 2, model->surfmesh.data_texcoordtexture2f);
                                                RSurf_DrawLightmap(ent, texture, surface, modelorg, layercolor[0], layercolor[1], layercolor[2], layercolor[3], 1, applycolor, applyfog);
                                        }
                                }
@@ -2968,13 +3077,13 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                memset(&m, 0, sizeof(m));
                                m.tex[0] = R_GetTexture(layer->texture);
                                m.texmatrix[0] = layer->texmatrix;
-                               m.pointer_color = varray_color4f;
+                               m.pointer_color = rsurface_array_color4f;
                                m.texrgbscale[0] = layertexrgbscale;
                                R_Mesh_State(&m);
                                for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                                {
                                        surface = texturesurfacelist[texturesurfaceindex];
-                                       R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+                                       R_Mesh_TexCoordPointer(0, 2, model->surfmesh.data_texcoordtexture2f);
                                        RSurf_DrawLightmap(ent, texture, surface, modelorg, layercolor[0], layercolor[1], layercolor[2], layercolor[3], 0, applycolor, applyfog);
                                }
                                break;
@@ -2993,9 +3102,9 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                        surface = texturesurfacelist[texturesurfaceindex];
                                        RSurf_SetVertexPointer(ent, texture, surface, modelorg, false, false);
                                        if (layer->texture)
-                                               R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
-                                       R_Mesh_ColorPointer(varray_color4f);
-                                       for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4)
+                                               R_Mesh_TexCoordPointer(0, 2, model->surfmesh.data_texcoordtexture2f);
+                                       R_Mesh_ColorPointer(rsurface_array_color4f);
+                                       for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (rsurface_array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4)
                                        {
                                                f = VERTEXFOGTABLE(VectorDistance(v, modelorg));
                                                c[0] = layercolor[0];
@@ -3003,7 +3112,7 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                                c[2] = layercolor[2];
                                                c[3] = f * layercolor[3];
                                        }
-                                       RSurf_Draw(surface);
+                                       RSurf_Draw(model, surface);
                                }
                                break;
                        default:
@@ -3023,49 +3132,8 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                        surface = texturesurfacelist[texturesurfaceindex];
                                        RSurf_SetVertexPointer(ent, texture, surface, modelorg, false, false);
                                        for (scale = 1;scale < layertexrgbscale;scale <<= 1)
-                                               RSurf_Draw(surface);
-                               }
-                       }
-               }
-               if (r_shownormals.integer && !r_showtrispass)
-               {
-                       int j, k;
-                       float v[3];
-                       GL_DepthTest(!r_showdisabledepthtest.integer);
-                       GL_DepthMask(texture->currentlayers->depthmask);
-                       GL_BlendFunc(texture->currentlayers->blendfunc1, texture->currentlayers->blendfunc2);
-                       memset(&m, 0, sizeof(m));
-                       R_Mesh_State(&m);
-                       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
-                       {
-                               surface = texturesurfacelist[texturesurfaceindex];
-                               RSurf_SetVertexPointer(ent, texture, surface, modelorg, false, true);
-                               GL_Color(1, 0, 0, 1);
-                               qglBegin(GL_LINES);
-                               for (j = 0, k = surface->num_firstvertex;j < surface->num_vertices;j++, k++)
-                               {
-                                       VectorCopy(rsurface_vertex3f + k * 3, v);
-                                       qglVertex3f(v[0], v[1], v[2]);
-                                       VectorMA(v, 8, rsurface_svector3f + k * 3, v);
-                                       qglVertex3f(v[0], v[1], v[2]);
+                                               RSurf_Draw(model, surface);
                                }
-                               GL_Color(0, 0, 1, 1);
-                               for (j = 0, k = surface->num_firstvertex;j < surface->num_vertices;j++, k++)
-                               {
-                                       VectorCopy(rsurface_vertex3f + k * 3, v);
-                                       qglVertex3f(v[0], v[1], v[2]);
-                                       VectorMA(v, 8, rsurface_tvector3f + k * 3, v);
-                                       qglVertex3f(v[0], v[1], v[2]);
-                               }
-                               GL_Color(0, 1, 0, 1);
-                               for (j = 0, k = surface->num_firstvertex;j < surface->num_vertices;j++, k++)
-                               {
-                                       VectorCopy(rsurface_vertex3f + k * 3, v);
-                                       qglVertex3f(v[0], v[1], v[2]);
-                                       VectorMA(v, 8, rsurface_normal3f + k * 3, v);
-                                       qglVertex3f(v[0], v[1], v[2]);
-                               }
-                               qglEnd();
                        }
                }
        }
@@ -3152,7 +3220,31 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
        t = NULL;
        texture = NULL;
        numsurfacelist = 0;
-       if (ent == r_refdef.worldentity)
+       if (r_showsurfaces.integer)
+       {
+               rmeshstate_t m;
+               GL_DepthTest(true);
+               GL_DepthMask(true);
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               memset(&m, 0, sizeof(m));
+               R_Mesh_State(&m);
+               for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
+               {
+                       if (ent == r_refdef.worldentity && !r_worldsurfacevisible[j])
+                               continue;
+                       texture = surface->texture->currentframe;
+                       if ((texture->currentmaterialflags & flagsmask) && surface->num_triangles)
+                       {
+                               int k = (int)(((size_t)surface) / sizeof(msurface_t));
+                               GL_Color((k & 15) * (1.0f / 16.0f), ((k >> 4) & 15) * (1.0f / 16.0f), ((k >> 8) & 15) * (1.0f / 16.0f), 0.2f);
+                               RSurf_SetVertexPointer(ent, texture, surface, modelorg, false, false);
+                               RSurf_Draw(ent->model, surface);
+                               renderstats.entities_triangles += surface->num_triangles;
+                       }
+                       renderstats.entities_surfaces++;
+               }
+       }
+       else if (ent == r_refdef.worldentity)
        {
                for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
                {
@@ -3218,9 +3310,105 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
        }
        if (numsurfacelist)
                R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
-       if (!r_showtrispass)
-               renderstats.entities_triangles += counttriangles;
+       renderstats.entities_triangles += counttriangles;
        if (gl_support_fragment_shader)
                qglUseProgramObjectARB(0);
+
+       if (r_showcollisionbrushes.integer && model->brush.num_brushes && !skysurfaces)
+       {
+               int i;
+               msurface_t *surface;
+               q3mbrush_t *brush;
+               R_Mesh_Matrix(&ent->matrix);
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+               GL_DepthMask(false);
+               GL_DepthTest(!r_showdisabledepthtest.integer);
+               qglPolygonOffset(r_polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_polygonoffset + r_showcollisionbrushes_polygonoffset.value);
+               for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
+                       if (brush->colbrushf && brush->colbrushf->numtriangles)
+                               R_DrawCollisionBrush(brush->colbrushf);
+               for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
+                       if (surface->num_collisiontriangles)
+                               R_DrawCollisionSurface(ent, surface);
+               qglPolygonOffset(r_polygonfactor, r_polygonoffset);
+       }
+
+       if (r_showtris.integer || r_shownormals.integer)
+       {
+               int k, l;
+               const int *elements;
+               rmeshstate_t m;
+               vec3_t v;
+               GL_DepthTest(true);
+               GL_DepthMask(true);
+               if (r_showdisabledepthtest.integer)
+                       qglDepthFunc(GL_ALWAYS);
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               memset(&m, 0, sizeof(m));
+               R_Mesh_State(&m);
+               for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
+               {
+                       if (ent == r_refdef.worldentity && !r_worldsurfacevisible[j])
+                               continue;
+                       texture = surface->texture->currentframe;
+                       if ((texture->currentmaterialflags & flagsmask) && surface->num_triangles)
+                       {
+                               RSurf_SetVertexPointer(ent, texture, surface, modelorg, false, r_shownormals.integer != 0);
+                               if (r_showtris.integer)
+                               {
+                                       if (!texture->currentlayers->depthmask)
+                                               GL_Color(r_showtris.value, 0, 0, 1);
+                                       else if (ent == r_refdef.worldentity)
+                                               GL_Color(r_showtris.value, r_showtris.value, r_showtris.value, 1);
+                                       else
+                                               GL_Color(0, r_showtris.value, 0, 1);
+                                       elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
+                                       qglBegin(GL_LINES);
+                                       for (k = 0;k < surface->num_triangles;k++, elements += 3)
+                                       {
+                                               qglArrayElement(elements[0]);qglArrayElement(elements[1]);
+                                               qglArrayElement(elements[1]);qglArrayElement(elements[2]);
+                                               qglArrayElement(elements[2]);qglArrayElement(elements[0]);
+                                       }
+                                       qglEnd();
+                               }
+                               if (r_shownormals.integer)
+                               {
+                                       GL_Color(r_shownormals.value, 0, 0, 1);
+                                       qglBegin(GL_LINES);
+                                       for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
+                                       {
+                                               VectorCopy(rsurface_vertex3f + l * 3, v);
+                                               qglVertex3f(v[0], v[1], v[2]);
+                                               VectorMA(v, 8, rsurface_svector3f + l * 3, v);
+                                               qglVertex3f(v[0], v[1], v[2]);
+                                       }
+                                       qglEnd();
+                                       GL_Color(0, 0, r_shownormals.value, 1);
+                                       qglBegin(GL_LINES);
+                                       for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
+                                       {
+                                               VectorCopy(rsurface_vertex3f + l * 3, v);
+                                               qglVertex3f(v[0], v[1], v[2]);
+                                               VectorMA(v, 8, rsurface_tvector3f + l * 3, v);
+                                               qglVertex3f(v[0], v[1], v[2]);
+                                       }
+                                       qglEnd();
+                                       GL_Color(0, r_shownormals.value, 0, 1);
+                                       qglBegin(GL_LINES);
+                                       for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
+                                       {
+                                               VectorCopy(rsurface_vertex3f + l * 3, v);
+                                               qglVertex3f(v[0], v[1], v[2]);
+                                               VectorMA(v, 8, rsurface_normal3f + l * 3, v);
+                                               qglVertex3f(v[0], v[1], v[2]);
+                                       }
+                                       qglEnd();
+                               }
+                       }
+               }
+               if (r_showdisabledepthtest.integer)
+                       qglDepthFunc(GL_LEQUAL);
+       }
 }