]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
fix bugs with bbox vs bbox traces (the collision box's planes didn't have correct...
[xonotic/darkplaces.git] / gl_rmain.c
index fb0295c14296e7aa7ccdd3273dd26377215e3267..4bc35ef45e34b8fbab9280557a1ae4f13099cd7a 100644 (file)
@@ -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 (false)
-       {
-               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)
@@ -949,20 +1038,34 @@ void R_SetupSurfaceShader(const entity_render_t *ent, const texture_t *texture,
        }
        else if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTION)
        {
-               if (r_glsl_permutation->loc_AmbientColor >= 0)
-                       qglUniform3fARB(r_glsl_permutation->loc_AmbientColor, ent->modellight_ambient[0], ent->modellight_ambient[1], ent->modellight_ambient[2]);
-               if (r_glsl_permutation->loc_DiffuseColor >= 0)
-                       qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor, ent->modellight_diffuse[0], ent->modellight_diffuse[1], ent->modellight_diffuse[2]);
-               if (r_glsl_permutation->loc_SpecularColor >= 0)
-                       qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, ent->modellight_diffuse[0] * texture->specularscale, ent->modellight_diffuse[1] * texture->specularscale, ent->modellight_diffuse[2] * texture->specularscale);
-               if (r_glsl_permutation->loc_LightDir >= 0)
-                       qglUniform3fARB(r_glsl_permutation->loc_LightDir, ent->modellight_lightdir[0], ent->modellight_lightdir[1], ent->modellight_lightdir[2]);
+               if (texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
+               {
+                       if (r_glsl_permutation->loc_AmbientColor >= 0)
+                               qglUniform3fARB(r_glsl_permutation->loc_AmbientColor, 1, 1, 1);
+                       if (r_glsl_permutation->loc_DiffuseColor >= 0)
+                               qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor, 0, 0, 0);
+                       if (r_glsl_permutation->loc_SpecularColor >= 0)
+                               qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, 0, 0, 0);
+                       if (r_glsl_permutation->loc_LightDir >= 0)
+                               qglUniform3fARB(r_glsl_permutation->loc_LightDir, 0, 0, -1);
+               }
+               else
+               {
+                       if (r_glsl_permutation->loc_AmbientColor >= 0)
+                               qglUniform3fARB(r_glsl_permutation->loc_AmbientColor, ent->modellight_ambient[0], ent->modellight_ambient[1], ent->modellight_ambient[2]);
+                       if (r_glsl_permutation->loc_DiffuseColor >= 0)
+                               qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor, ent->modellight_diffuse[0], ent->modellight_diffuse[1], ent->modellight_diffuse[2]);
+                       if (r_glsl_permutation->loc_SpecularColor >= 0)
+                               qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, ent->modellight_diffuse[0] * texture->specularscale, ent->modellight_diffuse[1] * texture->specularscale, ent->modellight_diffuse[2] * texture->specularscale);
+                       if (r_glsl_permutation->loc_LightDir >= 0)
+                               qglUniform3fARB(r_glsl_permutation->loc_LightDir, ent->modellight_lightdir[0], ent->modellight_lightdir[1], ent->modellight_lightdir[2]);
+               }
        }
        else
        {
                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));
@@ -980,12 +1083,23 @@ void R_SetupSurfaceShader(const entity_render_t *ent, const texture_t *texture,
                        qglUniform3fARB(r_glsl_permutation->loc_FogColor, fogcolor[0], fogcolor[1], fogcolor[2]);
        }
        if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, modelorg[0], modelorg[1], modelorg[2]);
-       if (r_glsl_permutation->loc_Color_Pants >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, ent->colormap_pantscolor[0], ent->colormap_pantscolor[1], ent->colormap_pantscolor[2]);
-       if (r_glsl_permutation->loc_Color_Shirt >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, ent->colormap_shirtcolor[0], ent->colormap_shirtcolor[1], ent->colormap_shirtcolor[2]);
+       if (r_glsl_permutation->loc_Color_Pants >= 0)
+       {
+               if (texture->skin.pants)
+                       qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, ent->colormap_pantscolor[0], ent->colormap_pantscolor[1], ent->colormap_pantscolor[2]);
+               else
+                       qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
+       }
+       if (r_glsl_permutation->loc_Color_Shirt >= 0)
+       {
+               if (texture->skin.shirt)
+                       qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, ent->colormap_shirtcolor[0], ent->colormap_shirtcolor[1], ent->colormap_shirtcolor[2]);
+               else
+                       qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
+       }
        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
 }
 
@@ -1005,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;
@@ -1036,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);
@@ -1075,6 +1165,7 @@ 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_showtris);
@@ -1096,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);
@@ -1495,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
@@ -1513,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;
@@ -1533,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
@@ -1579,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);
@@ -1595,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)
@@ -1628,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)
@@ -1656,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
@@ -1668,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;
@@ -1682,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);
@@ -1696,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]);
@@ -2152,6 +2246,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));
@@ -2162,23 +2257,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);
@@ -2439,6 +2534,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;
@@ -2447,15 +2565,17 @@ 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 (rsurface_array_size < surface->groupmesh->num_vertices)
+               R_Mesh_ResizeArrays(surface->groupmesh->num_vertices);
        if ((ent->frameblend[0].lerp != 1 || ent->frameblend[0].frame != 0) && (surface->groupmesh->data_morphvertex3f || surface->groupmesh->data_vertexboneweights))
        {
-               rsurface_vertex3f = varray_vertex3f;
+               rsurface_vertex3f = rsurface_array_vertex3f;
                Mod_Alias_GetMesh_Vertex3f(ent->model, ent->frameblend, surface->groupmesh, rsurface_vertex3f);
                if (generatetangents || (texture->textureflags & (Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2)))
                {
-                       rsurface_svector3f = varray_svector3f;
-                       rsurface_tvector3f = varray_tvector3f;
-                       rsurface_normal3f = varray_normal3f;
+                       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, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, r_smoothnormals_areaweighting.integer);
                }
                else
@@ -2464,7 +2584,7 @@ void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture
                        rsurface_tvector3f = NULL;
                        if (generatenormals)
                        {
-                               rsurface_normal3f = varray_normal3f;
+                               rsurface_normal3f = rsurface_array_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);
                        }
                        else
@@ -2510,12 +2630,12 @@ 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;
+               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, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, r_smoothnormals_areaweighting.integer);
        }
        R_Mesh_VertexPointer(rsurface_vertex3f);
@@ -2537,7 +2657,7 @@ static void RSurf_DrawLightmap(const entity_render_t *ent, const texture_t *text
        if (lightmode >= 2)
        {
                // model lighting
-               vec4_t ambientcolor;
+               vec3_t ambientcolor;
                vec3_t diffusecolor;
                vec3_t lightdir;
                VectorCopy(ent->modellight_lightdir, lightdir);
@@ -2552,24 +2672,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
                {
@@ -2583,7 +2701,7 @@ 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)
                                {
@@ -2613,7 +2731,7 @@ 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;
@@ -2624,7 +2742,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;
@@ -2635,7 +2753,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;
@@ -2644,18 +2762,18 @@ 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);
@@ -2778,8 +2896,7 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                {
                                        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
@@ -2830,7 +2947,7 @@ 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)
                                {
@@ -2867,7 +2984,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)
@@ -2902,7 +3019,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);
                                for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
@@ -2917,7 +3034,7 @@ 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)
                                {
@@ -2942,7 +3059,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);
                                for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
@@ -2968,8 +3085,8 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                        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_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];