]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
patch from div0 that enables printf format warnings in gcc
[xonotic/darkplaces.git] / r_shadow.c
index 52351379f7a15c0f01c5048a771d28cb0be78c64..69ffabf3ecbb2f061c98c26e2748954017b3f9e4 100644 (file)
@@ -159,11 +159,12 @@ r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
 r_shadow_rendermode_t r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_NONE;
 
-mempool_t *r_shadow_mempool;
-
-int maxshadowelements;
+int maxshadowtriangles;
 int *shadowelements;
 
+int maxshadowvertices;
+float *shadowvertex3f;
+
 int maxshadowmark;
 int numshadowmark;
 int *shadowmark;
@@ -197,8 +198,9 @@ cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0
 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
-cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
-cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
+cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.5", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
+cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "2", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
+cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5", "changes attenuation texture generation (does not affect r_glsl lighting)"};
 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_glsl lighting)"};
 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
@@ -267,8 +269,10 @@ void r_shadow_start(void)
        r_shadow_filters_texturepool = NULL;
        R_Shadow_ValidateCvars();
        R_Shadow_MakeTextures();
-       maxshadowelements = 0;
+       maxshadowtriangles = 0;
        shadowelements = NULL;
+       maxshadowvertices = 0;
+       shadowvertex3f = NULL;
        maxvertexupdate = 0;
        vertexupdate = NULL;
        vertexremap = NULL;
@@ -294,10 +298,13 @@ void r_shadow_shutdown(void)
        r_shadow_attenuation3dtexture = NULL;
        R_FreeTexturePool(&r_shadow_texturepool);
        R_FreeTexturePool(&r_shadow_filters_texturepool);
-       maxshadowelements = 0;
+       maxshadowtriangles = 0;
        if (shadowelements)
                Mem_Free(shadowelements);
        shadowelements = NULL;
+       if (shadowvertex3f)
+               Mem_Free(shadowvertex3f);
+       shadowvertex3f = NULL;
        maxvertexupdate = 0;
        if (vertexupdate)
                Mem_Free(vertexupdate);
@@ -379,6 +386,7 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_gloss);
        Cvar_RegisterVariable(&r_shadow_gloss2intensity);
        Cvar_RegisterVariable(&r_shadow_glossintensity);
+       Cvar_RegisterVariable(&r_shadow_glossexponent);
        Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
        Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
        Cvar_RegisterVariable(&r_shadow_lightintensityscale);
@@ -405,10 +413,11 @@ void R_Shadow_Init(void)
        }
        Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
        R_Shadow_EditLights_Init();
-       r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
        r_shadow_worldlightchain = NULL;
-       maxshadowelements = 0;
+       maxshadowtriangles = 0;
        shadowelements = NULL;
+       maxshadowvertices = 0;
+       shadowvertex3f = NULL;
        maxvertexupdate = 0;
        vertexupdate = NULL;
        vertexremap = NULL;
@@ -447,17 +456,24 @@ matrix4x4_t matrix_attenuationz =
        }
 };
 
-int *R_Shadow_ResizeShadowElements(int numtris)
+void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
 {
        // make sure shadowelements is big enough for this volume
-       if (maxshadowelements < numtris * 24)
+       if (maxshadowtriangles < numtriangles)
        {
-               maxshadowelements = numtris * 24;
+               maxshadowtriangles = numtriangles;
                if (shadowelements)
                        Mem_Free(shadowelements);
-               shadowelements = (int *)Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
+               shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
+       }
+       // make sure shadowvertex3f is big enough for this volume
+       if (maxshadowvertices < numvertices)
+       {
+               maxshadowvertices = numvertices;
+               if (shadowvertex3f)
+                       Mem_Free(shadowvertex3f);
+               shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
        }
-       return shadowelements;
 }
 
 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
@@ -471,8 +487,8 @@ static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
                if (r_shadow_buffer_leaflist)
                        Mem_Free(r_shadow_buffer_leaflist);
                r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
-               r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
-               r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
+               r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
+               r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
        }
        if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
        {
@@ -481,8 +497,8 @@ static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
                if (r_shadow_buffer_surfacelist)
                        Mem_Free(r_shadow_buffer_surfacelist);
                r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
-               r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
-               r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
+               r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
+               r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
        }
 }
 
@@ -496,8 +512,8 @@ void R_Shadow_PrepareShadowMark(int numtris)
                        Mem_Free(shadowmark);
                if (shadowmarklist)
                        Mem_Free(shadowmarklist);
-               shadowmark = (int *)Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
-               shadowmarklist = (int *)Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
+               shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
+               shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
                shadowmarkcount = 0;
        }
        shadowmarkcount++;
@@ -510,12 +526,18 @@ void R_Shadow_PrepareShadowMark(int numtris)
        numshadowmark = 0;
 }
 
-int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
+int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
 {
        int i, j;
        int outtriangles = 0, outvertices = 0;
        const int *element;
        const float *vertex;
+       float ratio, direction[3], projectvector[3];
+
+       if (projectdirection)
+               VectorScale(projectdirection, projectdistance, projectvector);
+       else
+               VectorClear(projectvector);
 
        if (maxvertexupdate < innumvertices)
        {
@@ -524,8 +546,8 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *
                        Mem_Free(vertexupdate);
                if (vertexremap)
                        Mem_Free(vertexremap);
-               vertexupdate = (int *)Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
-               vertexremap = (int *)Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
+               vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
+               vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
                vertexupdatenum = 0;
        }
        vertexupdatenum++;
@@ -539,26 +561,49 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *
        for (i = 0;i < numshadowmarktris;i++)
                shadowmark[shadowmarktris[i]] = shadowmarkcount;
 
-       for (i = 0;i < numshadowmarktris;i++)
+       // create the vertices
+       if (projectdirection)
        {
-               element = inelement3i + shadowmarktris[i] * 3;
-               // make sure the vertices are created
-               for (j = 0;j < 3;j++)
+               for (i = 0;i < numshadowmarktris;i++)
                {
-                       if (vertexupdate[element[j]] != vertexupdatenum)
+                       element = inelement3i + shadowmarktris[i] * 3;
+                       for (j = 0;j < 3;j++)
                        {
-                               float ratio, direction[3];
-                               vertexupdate[element[j]] = vertexupdatenum;
-                               vertexremap[element[j]] = outvertices;
-                               vertex = invertex3f + element[j] * 3;
-                               // project one copy of the vertex to the sphere radius of the light
-                               // (FIXME: would projecting it to the light box be better?)
-                               VectorSubtract(vertex, projectorigin, direction);
-                               ratio = projectdistance / VectorLength(direction);
-                               VectorCopy(vertex, outvertex3f);
-                               VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
-                               outvertex3f += 6;
-                               outvertices += 2;
+                               if (vertexupdate[element[j]] != vertexupdatenum)
+                               {
+                                       vertexupdate[element[j]] = vertexupdatenum;
+                                       vertexremap[element[j]] = outvertices;
+                                       vertex = invertex3f + element[j] * 3;
+                                       // project one copy of the vertex according to projectvector
+                                       VectorCopy(vertex, outvertex3f);
+                                       VectorAdd(vertex, projectvector, (outvertex3f + 3));
+                                       outvertex3f += 6;
+                                       outvertices += 2;
+                               }
+                       }
+               }
+       }
+       else
+       {
+               for (i = 0;i < numshadowmarktris;i++)
+               {
+                       element = inelement3i + shadowmarktris[i] * 3;
+                       for (j = 0;j < 3;j++)
+                       {
+                               if (vertexupdate[element[j]] != vertexupdatenum)
+                               {
+                                       vertexupdate[element[j]] = vertexupdatenum;
+                                       vertexremap[element[j]] = outvertices;
+                                       vertex = invertex3f + element[j] * 3;
+                                       // project one copy of the vertex to the sphere radius of the light
+                                       // (FIXME: would projecting it to the light box be better?)
+                                       VectorSubtract(vertex, projectorigin, direction);
+                                       ratio = projectdistance / VectorLength(direction);
+                                       VectorCopy(vertex, outvertex3f);
+                                       VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
+                                       outvertex3f += 6;
+                                       outvertices += 2;
+                               }
                        }
                }
        }
@@ -631,29 +676,30 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *
        return outtriangles;
 }
 
-void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, int nummarktris, const int *marktris)
+void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris)
 {
        int tris, outverts;
        if (projectdistance < 0.1)
        {
-               Con_Printf("R_Shadow_Volume: projectdistance %f\n");
+               Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
                return;
        }
        if (!numverts || !nummarktris)
                return;
        // make sure shadowelements is big enough for this volume
-       if (maxshadowelements < nummarktris * 24)
-               R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
-       tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
-       renderstats.lights_dynamicshadowtriangles += tris;
-       R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
+       if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
+               R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
+       tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
+       r_refdef.stats.lights_dynamicshadowtriangles += tris;
+       R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
 }
 
-void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
+void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
 {
        int t, tend;
        const int *e;
        const float *v[3];
+       float normal[3];
        if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
                return;
        tend = firsttriangle + numtris;
@@ -662,56 +708,88 @@ void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *inv
         && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
        {
                // surface box entirely inside light box, no box cull
-               for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
-                       if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
-                               shadowmarklist[numshadowmark++] = t;
+               if (projectdirection)
+               {
+                       for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+                       {
+                               TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
+                               if (DotProduct(normal, projectdirection) < 0)
+                                       shadowmarklist[numshadowmark++] = t;
+                       }
+               }
+               else
+               {
+                       for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+                               if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
+                                       shadowmarklist[numshadowmark++] = t;
+               }
        }
        else
        {
                // surface box not entirely inside light box, cull each triangle
-               for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+               if (projectdirection)
+               {
+                       for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+                       {
+                               v[0] = invertex3f + e[0] * 3;
+                               v[1] = invertex3f + e[1] * 3;
+                               v[2] = invertex3f + e[2] * 3;
+                               TriangleNormal(v[0], v[1], v[2], normal);
+                               if (DotProduct(normal, projectdirection) < 0
+                                && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
+                                && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
+                                && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
+                                && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
+                                && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
+                                && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
+                                       shadowmarklist[numshadowmark++] = t;
+                       }
+               }
+               else
                {
-                       v[0] = invertex3f + e[0] * 3;
-                       v[1] = invertex3f + e[1] * 3;
-                       v[2] = invertex3f + e[2] * 3;
-                       if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
-                        && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
-                        && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
-                        && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
-                        && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
-                        && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
-                        && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
-                               shadowmarklist[numshadowmark++] = t;
+                       for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+                       {
+                               v[0] = invertex3f + e[0] * 3;
+                               v[1] = invertex3f + e[1] * 3;
+                               v[2] = invertex3f + e[2] * 3;
+                               if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
+                                && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
+                                && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
+                                && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
+                                && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
+                                && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
+                                && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
+                                       shadowmarklist[numshadowmark++] = t;
+                       }
                }
        }
 }
 
 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
 {
-       rmeshstate_t m;
        if (r_shadow_compilingrtlight)
        {
                // if we're compiling an rtlight, capture the mesh
-               Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
+               Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
                return;
        }
-       renderstats.lights_shadowtriangles += numtriangles;
-       memset(&m, 0, sizeof(m));
-       m.pointer_vertex = vertex3f;
-       R_Mesh_State(&m);
+       r_refdef.stats.lights_shadowtriangles += numtriangles;
+       CHECKGLERROR
+       R_Mesh_VertexPointer(vertex3f);
        GL_LockArrays(0, numvertices);
        if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
        {
                // decrement stencil if backface is behind depthbuffer
-               qglCullFace(GL_BACK); // quake is backwards, this culls front faces
-               qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
+               GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
+               qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
                R_Mesh_Draw(0, numvertices, numtriangles, element3i);
                // increment stencil if frontface is behind depthbuffer
-               qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
-               qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
+               GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
+               qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
        }
        R_Mesh_Draw(0, numvertices, numtriangles, element3i);
        GL_LockArrays(0, 0);
+       CHECKGLERROR
 }
 
 static void R_Shadow_MakeTextures(void)
@@ -736,7 +814,7 @@ static void R_Shadow_MakeTextures(void)
                        intensity = 1.0f - sqrt(DotProduct(v, v));
                        if (intensity > 0)
                                intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
-                       d = bound(0, intensity, 255);
+                       d = (int)bound(0, intensity, 255);
                        data[(y*ATTEN2DSIZE+x)*4+0] = d;
                        data[(y*ATTEN2DSIZE+x)*4+1] = d;
                        data[(y*ATTEN2DSIZE+x)*4+2] = d;
@@ -744,7 +822,7 @@ static void R_Shadow_MakeTextures(void)
                }
        }
        r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
-       if (r_shadow_texture3d.integer)
+       if (r_shadow_texture3d.integer && gl_texture3d)
        {
                for (z = 0;z < ATTEN3DSIZE;z++)
                {
@@ -758,7 +836,7 @@ static void R_Shadow_MakeTextures(void)
                                        intensity = 1.0f - sqrt(DotProduct(v, v));
                                        if (intensity > 0)
                                                intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
-                                       d = bound(0, intensity, 255);
+                                       d = (int)bound(0, intensity, 255);
                                        data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
                                        data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
                                        data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
@@ -782,8 +860,6 @@ void R_Shadow_ValidateCvars(void)
 // light currently being rendered
 rtlight_t *r_shadow_rtlight;
 
-// this is the location of the eye in entity space
-vec3_t r_shadow_entityeyeorigin;
 // this is the location of the light in entity space
 vec3_t r_shadow_entitylightorigin;
 // this transforms entity coordinates to light filter cubemap coordinates
@@ -797,8 +873,6 @@ matrix4x4_t r_shadow_entitytoattenuationz;
 
 void R_Shadow_RenderMode_Begin(void)
 {
-       rmeshstate_t m;
-
        R_Shadow_ValidateCvars();
 
        if (!r_shadow_attenuation2dtexture
@@ -807,15 +881,13 @@ void R_Shadow_RenderMode_Begin(void)
         || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
                R_Shadow_MakeTextures();
 
-       memset(&m, 0, sizeof(m));
-       R_Mesh_State(&m);
+       CHECKGLERROR
+       R_Mesh_ColorPointer(NULL);
+       R_Mesh_ResetTextureState();
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthMask(false);
-       GL_DepthTest(true);
        GL_Color(0, 0, 0, 1);
-       qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
-       qglEnable(GL_CULL_FACE);
-       GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
+       GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
 
        r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
 
@@ -839,100 +911,89 @@ void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
 
 void R_Shadow_RenderMode_Reset(void)
 {
-       rmeshstate_t m;
+       CHECKGLERROR
        if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
        {
-               qglUseProgramObjectARB(0);
-               // HACK HACK HACK: work around for bug in NVIDIAI 6xxx drivers that causes GL_OUT_OF_MEMORY and/or software rendering
-               qglBegin(GL_TRIANGLES);
-               qglEnd();
-               CHECKGLERROR
+               qglUseProgramObjectARB(0);CHECKGLERROR
        }
        else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
-               qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
-       memset(&m, 0, sizeof(m));
-       R_Mesh_State(&m);
+       {
+               qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
+       }
+       R_Mesh_ColorPointer(NULL);
+       R_Mesh_ResetTextureState();
 }
 
 void R_Shadow_RenderMode_StencilShadowVolumes(void)
 {
+       CHECKGLERROR
        R_Shadow_RenderMode_Reset();
        GL_Color(1, 1, 1, 1);
        GL_ColorMask(0, 0, 0, 0);
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthMask(false);
-       GL_DepthTest(true);
-       if (!r_showtrispass)
-               qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
-       //if (r_shadow_shadow_polygonoffset.value != 0)
-       //{
-       //      qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
-       //      qglEnable(GL_POLYGON_OFFSET_FILL);
-       //}
-       //else
-       //      qglDisable(GL_POLYGON_OFFSET_FILL);
-       qglDepthFunc(GL_LESS);
-       qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
-       qglEnable(GL_STENCIL_TEST);
-       qglStencilFunc(GL_ALWAYS, 128, ~0);
+       qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
+       qglDepthFunc(GL_LESS);CHECKGLERROR
+       qglEnable(GL_STENCIL_TEST);CHECKGLERROR
+       qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
        r_shadow_rendermode = r_shadow_shadowingrendermode;
        if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
        {
-               qglDisable(GL_CULL_FACE);
-               qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
-               qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
-               qglStencilMask(~0);
-               qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
-               qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
-               qglStencilMask(~0);
-               qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
+               GL_CullFace(GL_NONE);
+               qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
+               qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
+               qglStencilMask(~0);CHECKGLERROR
+               qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
+               qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
+               qglStencilMask(~0);CHECKGLERROR
+               qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
        }
        else
        {
-               qglEnable(GL_CULL_FACE);
-               qglStencilMask(~0);
+               GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
+               qglStencilMask(~0);CHECKGLERROR
                // this is changed by every shadow render so its value here is unimportant
-               qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+               qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
        }
        GL_Clear(GL_STENCIL_BUFFER_BIT);
-       renderstats.lights_clears++;
+       r_refdef.stats.lights_clears++;
 }
 
 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
 {
+       CHECKGLERROR
        R_Shadow_RenderMode_Reset();
-       GL_BlendFunc(GL_ONE, GL_ONE);
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
        GL_DepthMask(false);
-       GL_DepthTest(true);
-       if (!r_showtrispass)
-               qglPolygonOffset(0, 0);
-       //qglDisable(GL_POLYGON_OFFSET_FILL);
+       qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
+       //qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
        GL_Color(1, 1, 1, 1);
-       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
+       GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
        if (transparent)
-               qglDepthFunc(GL_LEQUAL);
+       {
+               qglDepthFunc(GL_LEQUAL);CHECKGLERROR
+       }
        else
-               qglDepthFunc(GL_EQUAL);
-       qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
-       qglEnable(GL_CULL_FACE);
+       {
+               qglDepthFunc(GL_EQUAL);CHECKGLERROR
+       }
        if (stenciltest)
-               qglEnable(GL_STENCIL_TEST);
+       {
+               qglEnable(GL_STENCIL_TEST);CHECKGLERROR
+       }
        else
-               qglDisable(GL_STENCIL_TEST);
-       qglStencilMask(~0);
-       qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+       {
+               qglDisable(GL_STENCIL_TEST);CHECKGLERROR
+       }
+       qglStencilMask(~0);CHECKGLERROR
+       qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
        // only draw light where this geometry was already rendered AND the
        // stencil is 128 (values other than this mean shadow)
-       qglStencilFunc(GL_EQUAL, 128, ~0);
+       qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
        r_shadow_rendermode = r_shadow_lightingrendermode;
        // do global setup needed for the chosen lighting mode
        if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
        {
-               R_Mesh_VertexPointer(varray_vertex3f);
-               R_Mesh_TexCoordPointer(0, 2, varray_texcoord2f[0]);
-               R_Mesh_TexCoordPointer(1, 3, varray_svector3f);
-               R_Mesh_TexCoordPointer(2, 3, varray_tvector3f);
-               R_Mesh_TexCoordPointer(3, 3, varray_normal3f);
                R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
                R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
                R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
@@ -940,75 +1001,91 @@ void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
                R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
                R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
                R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
+               R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
+               R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
+               R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
                //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
-               GL_BlendFunc(GL_ONE, GL_ONE);
-               GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+               GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
                CHECKGLERROR
        }
 }
 
 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
 {
+       CHECKGLERROR
        R_Shadow_RenderMode_Reset();
        GL_BlendFunc(GL_ONE, GL_ONE);
        GL_DepthMask(false);
-       GL_DepthTest(!r_showdisabledepthtest.integer);
-       if (!r_showtrispass)
-               qglPolygonOffset(0, 0);
-       GL_Color(0.0, 0.0125, 0.1, 1);
-       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
-       qglDepthFunc(GL_GEQUAL);
-       qglCullFace(GL_FRONT); // this culls back
-       qglDisable(GL_CULL_FACE);
-       qglDisable(GL_STENCIL_TEST);
+       qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
+       GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
+       GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
+       if (r_showshadowvolumes.integer >= 2)
+       {
+               qglDepthFunc(GL_ALWAYS);CHECKGLERROR
+       }
+       else
+       {
+               qglDepthFunc(GL_GEQUAL);CHECKGLERROR
+       }
+       qglDisable(GL_STENCIL_TEST);CHECKGLERROR
        r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
 }
 
 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
 {
+       CHECKGLERROR
        R_Shadow_RenderMode_Reset();
        GL_BlendFunc(GL_ONE, GL_ONE);
        GL_DepthMask(false);
-       GL_DepthTest(!r_showdisabledepthtest.integer);
-       if (!r_showtrispass)
-               qglPolygonOffset(0, 0);
-       GL_Color(0.1, 0.0125, 0, 1);
-       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
-       if (transparent)
-               qglDepthFunc(GL_LEQUAL);
+       qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
+       GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
+       GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
+       if (r_showshadowvolumes.integer >= 2)
+       {
+               qglDepthFunc(GL_ALWAYS);CHECKGLERROR
+       }
+       else if (transparent)
+       {
+               qglDepthFunc(GL_LEQUAL);CHECKGLERROR
+       }
        else
-               qglDepthFunc(GL_EQUAL);
-       qglCullFace(GL_FRONT); // this culls back
-       qglEnable(GL_CULL_FACE);
+       {
+               qglDepthFunc(GL_EQUAL);CHECKGLERROR
+       }
        if (stenciltest)
-               qglEnable(GL_STENCIL_TEST);
+       {
+               qglEnable(GL_STENCIL_TEST);CHECKGLERROR
+       }
        else
-               qglDisable(GL_STENCIL_TEST);
+       {
+               qglDisable(GL_STENCIL_TEST);CHECKGLERROR
+       }
        r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
 }
 
 void R_Shadow_RenderMode_End(void)
 {
+       CHECKGLERROR
        R_Shadow_RenderMode_Reset();
        R_Shadow_RenderMode_ActiveLight(NULL);
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthMask(true);
-       GL_DepthTest(true);
-       if (!r_showtrispass)
-               qglPolygonOffset(0, 0);
-       //qglDisable(GL_POLYGON_OFFSET_FILL);
+       qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
+       //qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
        GL_Color(1, 1, 1, 1);
-       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
-       GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
-       qglDepthFunc(GL_LEQUAL);
-       qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
-       qglEnable(GL_CULL_FACE);
-       qglDisable(GL_STENCIL_TEST);
-       qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+       GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
+       GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
+       qglDepthFunc(GL_LEQUAL);CHECKGLERROR
        if (gl_support_stenciltwoside)
-               qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
-       qglStencilMask(~0);
-       qglStencilFunc(GL_ALWAYS, 128, ~0);
+       {
+               qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
+       }
+       qglDisable(GL_STENCIL_TEST);CHECKGLERROR
+       qglStencilMask(~0);CHECKGLERROR
+       qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
+       qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
+       GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
        r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
 }
 
@@ -1022,18 +1099,18 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
        float vertex3f[256*3];
 
        // if view is inside the light box, just say yes it's visible
-       if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
+       if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
        {
-               GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
+               GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
                return false;
        }
 
        // create a temporary brush describing the area the light can affect in worldspace
-       VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
-       VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
-       VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
-       VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
-       VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
+       VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
+       VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
+       VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
+       VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
+       VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
        VectorSet   (planes[ 5].normal,  1, 0, 0);         planes[ 5].dist =  maxs[0];
        VectorSet   (planes[ 6].normal, -1, 0, 0);         planes[ 6].dist = -mins[0];
        VectorSet   (planes[ 7].normal, 0,  1, 0);         planes[ 7].dist =  maxs[1];
@@ -1058,6 +1135,7 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
        // if that mesh is not empty, check what area of the screen it covers
        x1 = y1 = x2 = y2 = 0;
        v[3] = 1.0f;
+       //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
        for (i = 0;i < mesh.numvertices;i++)
        {
                VectorCopy(mesh.vertex3f + i * 3, v);
@@ -1078,42 +1156,36 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
        }
 
        // now convert the scissor rectangle to integer screen coordinates
-       ix1 = x1 - 1.0f;
-       iy1 = y1 - 1.0f;
-       ix2 = x2 + 1.0f;
-       iy2 = y2 + 1.0f;
+       ix1 = (int)(x1 - 1.0f);
+       iy1 = (int)(y1 - 1.0f);
+       ix2 = (int)(x2 + 1.0f);
+       iy2 = (int)(y2 + 1.0f);
        //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
 
        // clamp it to the screen
-       if (ix1 < r_view_x) ix1 = r_view_x;
-       if (iy1 < r_view_y) iy1 = r_view_y;
-       if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
-       if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
+       if (ix1 < r_view.x) ix1 = r_view.x;
+       if (iy1 < r_view.y) iy1 = r_view.y;
+       if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
+       if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
 
        // if it is inside out, it's not visible
        if (ix2 <= ix1 || iy2 <= iy1)
                return true;
 
        // the light area is visible, set up the scissor rectangle
-       GL_Scissor(ix1, vid.height - iy2, ix2 - ix1, iy2 - iy1);
-       //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
-       //qglEnable(GL_SCISSOR_TEST);
-       renderstats.lights_scissored++;
+       GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
+       //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
+       //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
+       r_refdef.stats.lights_scissored++;
        return false;
 }
 
-extern float *rsurface_vertex3f;
-extern float *rsurface_svector3f;
-extern float *rsurface_tvector3f;
-extern float *rsurface_normal3f;
-extern void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg, qboolean generatenormals, qboolean generatetangents);
-
 static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor)
 {
        int numverts = surface->num_vertices;
        float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
        float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
-       float *color4f = varray_color4f + 4 * surface->num_firstvertex;
+       float *color4f = rsurface_array_color4f + 4 * surface->num_firstvertex;
        float dist, dot, distintensity, shadeintensity, v[3], n[3];
        if (r_textureunits.integer >= 3)
        {
@@ -1127,9 +1199,9 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_
                                color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
                                color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
                                color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
-                               if (fogenabled)
+                               if (r_refdef.fogenabled)
                                {
-                                       float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
+                                       float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
                                        VectorScale(color4f, f, color4f);
                                }
                        }
@@ -1160,9 +1232,9 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_
                                        color4f[1] = ambientcolor[1] * distintensity;
                                        color4f[2] = ambientcolor[2] * distintensity;
                                }
-                               if (fogenabled)
+                               if (r_refdef.fogenabled)
                                {
-                                       float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
+                                       float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
                                        VectorScale(color4f, f, color4f);
                                }
                        }
@@ -1194,9 +1266,9 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_
                                        color4f[1] = ambientcolor[1] * distintensity;
                                        color4f[2] = ambientcolor[2] * distintensity;
                                }
-                               if (fogenabled)
+                               if (r_refdef.fogenabled)
                                {
-                                       float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
+                                       float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
                                        VectorScale(color4f, f, color4f);
                                }
                        }
@@ -1208,114 +1280,107 @@ static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_
 }
 
 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
-#define USETEXMATRIX
 
-#ifndef USETEXMATRIX
-// this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
-// if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
-static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
+static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
 {
-       do
+       int surfacelistindex;
+       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
        {
-               tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
-               tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
-               tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
-               vertex3f += 3;
-               tc3f += 3;
+               const msurface_t *surface = surfacelist[surfacelistindex];
+               int i;
+               float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
+               const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
+               const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
+               const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
+               const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
+               float lightdir[3];
+               for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
+               {
+                       VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
+                       // the cubemap normalizes this for us
+                       out3f[0] = DotProduct(svector3f, lightdir);
+                       out3f[1] = DotProduct(tvector3f, lightdir);
+                       out3f[2] = DotProduct(normal3f, lightdir);
+               }
        }
-       while (--numverts);
 }
 
-static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
+static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
 {
-       do
+       int surfacelistindex;
+       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
        {
-               tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
-               tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
-               vertex3f += 3;
-               tc2f += 2;
+               const msurface_t *surface = surfacelist[surfacelistindex];
+               int i;
+               float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
+               const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
+               const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
+               const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
+               const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
+               float lightdir[3], eyedir[3], halfdir[3];
+               for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
+               {
+                       VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
+                       VectorNormalize(lightdir);
+                       VectorSubtract(rsurface_modelorg, vertex3f, eyedir);
+                       VectorNormalize(eyedir);
+                       VectorAdd(lightdir, eyedir, halfdir);
+                       // the cubemap normalizes this for us
+                       out3f[0] = DotProduct(svector3f, halfdir);
+                       out3f[1] = DotProduct(tvector3f, halfdir);
+                       out3f[2] = DotProduct(normal3f, halfdir);
+               }
        }
-       while (--numverts);
 }
-#endif
 
-static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin)
+static void R_Shadow_RenderSurfacesLighting_VisibleLighting(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
 {
-       int i;
-       float lightdir[3];
-       for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
-       {
-               VectorSubtract(relativelightorigin, vertex3f, lightdir);
-               // the cubemap normalizes this for us
-               out3f[0] = DotProduct(svector3f, lightdir);
-               out3f[1] = DotProduct(tvector3f, lightdir);
-               out3f[2] = DotProduct(normal3f, lightdir);
-       }
+       // used to display how many times a surface is lit for level design purposes
+       GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
+       R_Mesh_ColorPointer(NULL);
+       R_Mesh_ResetTextureState();
+       RSurf_PrepareVerticesForBatch(false, false, numsurfaces, surfacelist);
+       RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
+       GL_LockArrays(0, 0);
 }
 
-static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin, const vec3_t relativeeyeorigin)
+static void R_Shadow_RenderSurfacesLighting_Light_GLSL(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
 {
-       int i;
-       float lightdir[3], eyedir[3], halfdir[3];
-       for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
+       // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
+       RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
+       R_SetupSurfaceShader(lightcolorbase, false);
+       R_Mesh_TexCoordPointer(0, 2, rsurface_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);
+       if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
        {
-               VectorSubtract(relativelightorigin, vertex3f, lightdir);
-               VectorNormalize(lightdir);
-               VectorSubtract(relativeeyeorigin, vertex3f, eyedir);
-               VectorNormalize(eyedir);
-               VectorAdd(lightdir, eyedir, halfdir);
-               // the cubemap normalizes this for us
-               out3f[0] = DotProduct(svector3f, halfdir);
-               out3f[1] = DotProduct(tvector3f, halfdir);
-               out3f[2] = DotProduct(normal3f, halfdir);
+               qglDepthFunc(GL_EQUAL);CHECKGLERROR
        }
-}
-
-static void R_Shadow_RenderSurfacesLighting_VisibleLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
-{
-       // used to display how many times a surface is lit for level design purposes
-       int surfacelistindex;
-       rmeshstate_t m;
-       GL_Color(0.1, 0.025, 0, 1);
-       memset(&m, 0, sizeof(m));
-       R_Mesh_State(&m);
-       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+       RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
+       GL_LockArrays(0, 0);
+       if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
        {
-               const msurface_t *surface = surfacelist[surfacelistindex];
-               RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, false, false);
-               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);
-               GL_LockArrays(0, 0);
+               qglDepthFunc(GL_LEQUAL);CHECKGLERROR
        }
 }
 
-static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
+static void R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(int numsurfaces, msurface_t **surfacelist, float r, float g, float b)
 {
-       // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
-       int surfacelistindex;
-       R_SetupSurfaceShader(ent, texture, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, pantstexture, shirttexture, normalmaptexture, glosstexture, specularscale, dopants, doshirt);
-       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+       // shared final code for all the dot3 layers
+       int renders;
+       GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
+       for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
        {
-               const msurface_t *surface = surfacelist[surfacelistindex];
-               const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
-               RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, false, true);
-               R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
-               R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
-               R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
-               R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
+               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
        }
 }
 
-static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
+static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
 {
-       int renders;
-       float color2[3];
        rmeshstate_t m;
-       const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
-       GL_Color(1,1,1,1);
        // colorscale accounts for how much we multiply the brightness
        // during combine.
        //
@@ -1323,84 +1388,52 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(const entity_
        // performed to get more brightness than otherwise possible.
        //
        // Limit mult to 64 for sanity sake.
+       GL_Color(1,1,1,1);
        if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
        {
                // 3 3D combine path (Geforce3, Radeon 8500)
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
-#else
-               m.pointer_texcoord3f[0] = varray_texcoord3f[0];
-               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
-#endif
                m.tex[1] = R_GetTexture(basetexture);
-               m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[1] = texture->currenttexmatrix;
+               m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[1] = rsurface_texture->currenttexmatrix;
                m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[2] = rsurface_vertex3f;
                m.texmatrix[2] = r_shadow_entitytolight;
-#else
-               m.pointer_texcoord3f[2] = varray_texcoord3f[2];
-               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
-#endif
                GL_BlendFunc(GL_ONE, GL_ONE);
        }
        else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
        {
                // 2 3D combine path (Geforce3, original Radeon)
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
-#else
-               m.pointer_texcoord3f[0] = varray_texcoord3f[0];
-               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
-#endif
                m.tex[1] = R_GetTexture(basetexture);
-               m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[1] = texture->currenttexmatrix;
+               m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[1] = rsurface_texture->currenttexmatrix;
                GL_BlendFunc(GL_ONE, GL_ONE);
        }
        else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
        {
                // 4 2D combine path (Geforce3, Radeon 8500)
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
-#else
-               m.pointer_texcoord[0] = varray_texcoord2f[0];
-               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
-#endif
                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[1] = rsurface_vertex3f;
                m.texmatrix[1] = r_shadow_entitytoattenuationz;
-#else
-               m.pointer_texcoord[1] = varray_texcoord2f[1];
-               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
-#endif
                m.tex[2] = R_GetTexture(basetexture);
-               m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[2] = texture->currenttexmatrix;
+               m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[2] = rsurface_texture->currenttexmatrix;
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
                        m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
-#ifdef USETEXMATRIX
                        m.pointer_texcoord3f[3] = rsurface_vertex3f;
                        m.texmatrix[3] = r_shadow_entitytolight;
-#else
-                       m.pointer_texcoord3f[3] = varray_texcoord3f[3];
-                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
-#endif
                }
                GL_BlendFunc(GL_ONE, GL_ONE);
        }
@@ -1408,94 +1441,54 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(const entity_
        {
                // 3 2D combine path (Geforce3, original Radeon)
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
-#else
-               m.pointer_texcoord[0] = varray_texcoord2f[0];
-               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
-#endif
                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[1] = rsurface_vertex3f;
                m.texmatrix[1] = r_shadow_entitytoattenuationz;
-#else
-               m.pointer_texcoord[1] = varray_texcoord2f[1];
-               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
-#endif
                m.tex[2] = R_GetTexture(basetexture);
-               m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[2] = texture->currenttexmatrix;
+               m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[2] = rsurface_texture->currenttexmatrix;
                GL_BlendFunc(GL_ONE, GL_ONE);
        }
        else
        {
                // 2/2/2 2D combine path (any dot3 card)
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
-#else
-               m.pointer_texcoord[0] = varray_texcoord2f[0];
-               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
-#endif
                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[1] = rsurface_vertex3f;
                m.texmatrix[1] = r_shadow_entitytoattenuationz;
-#else
-               m.pointer_texcoord[1] = varray_texcoord2f[1];
-               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
-#endif
-               R_Mesh_State(&m);
+               R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                GL_BlendFunc(GL_ONE, GL_ZERO);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
+               // second pass
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(basetexture);
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
                        m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
-#ifdef USETEXMATRIX
                        m.pointer_texcoord3f[1] = rsurface_vertex3f;
                        m.texmatrix[1] = r_shadow_entitytolight;
-#else
-                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
-#endif
                }
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
        }
        // this final code is shared
-       R_Mesh_State(&m);
-       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
-       VectorScale(lightcolorbase, colorscale, color2);
-       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-       for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
-       {
-               GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-       }
-       GL_LockArrays(0, 0);
+       R_Mesh_TextureState(&m);
+       R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
 }
 
-static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
+static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
 {
-       int renders;
-       float color2[3];
        rmeshstate_t m;
-       const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
-       GL_Color(1,1,1,1);
        // colorscale accounts for how much we multiply the brightness
        // during combine.
        //
@@ -1503,49 +1496,39 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(const entity_
        // performed to get more brightness than otherwise possible.
        //
        // Limit mult to 64 for sanity sake.
+       GL_Color(1,1,1,1);
+       // generate normalization cubemap texcoords
+       R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(numsurfaces, surfacelist);
        if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
        {
                // 3/2 3D combine path (Geforce3, Radeon 8500)
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(normalmaptexture);
                m.texcombinergb[0] = GL_REPLACE;
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
+               m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
                m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[2] = rsurface_vertex3f;
                m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
-#else
-               m.pointer_texcoord3f[2] = varray_texcoord3f[2];
-               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
-#endif
-               R_Mesh_State(&m);
+               R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                GL_BlendFunc(GL_ONE, GL_ZERO);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
+               // second pass
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(basetexture);
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
                        m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
-#ifdef USETEXMATRIX
                        m.pointer_texcoord3f[1] = rsurface_vertex3f;
                        m.texmatrix[1] = r_shadow_entitytolight;
-#else
-                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
-#endif
                }
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
        }
@@ -1553,53 +1536,39 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(const entity_
        {
                // 1/2/2 3D combine path (original Radeon)
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
-#else
-               m.pointer_texcoord3f[0] = varray_texcoord3f[0];
-               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
-#endif
-               R_Mesh_State(&m);
+               R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                GL_BlendFunc(GL_ONE, GL_ZERO);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
+               // second pass
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(normalmaptexture);
                m.texcombinergb[0] = GL_REPLACE;
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
-               R_Mesh_State(&m);
+               m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
+               R_Mesh_TextureState(&m);
                GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
+               // second pass
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(basetexture);
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
                        m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
-#ifdef USETEXMATRIX
                        m.pointer_texcoord3f[1] = rsurface_vertex3f;
                        m.texmatrix[1] = r_shadow_entitytolight;
-#else
-                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
-#endif
                }
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
        }
@@ -1607,88 +1576,62 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(const entity_
        {
                // 2/2 3D combine path (original Radeon)
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(normalmaptexture);
                m.texcombinergb[0] = GL_REPLACE;
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
-               R_Mesh_State(&m);
+               m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
+               R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                GL_BlendFunc(GL_ONE, GL_ZERO);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
+               // second pass
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(basetexture);
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[1] = rsurface_vertex3f;
                m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
-#else
-               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
-#endif
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
        }
        else if (r_textureunits.integer >= 4)
        {
                // 4/2 2D combine path (Geforce3, Radeon 8500)
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(normalmaptexture);
                m.texcombinergb[0] = GL_REPLACE;
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
+               m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
                m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[2] = rsurface_vertex3f;
                m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
-#else
-               m.pointer_texcoord[2] = varray_texcoord2f[2];
-               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
-#endif
                m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[3] = rsurface_vertex3f;
                m.texmatrix[3] = r_shadow_entitytoattenuationz;
-#else
-               m.pointer_texcoord[3] = varray_texcoord2f[3];
-               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
-#endif
-               R_Mesh_State(&m);
+               R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                GL_BlendFunc(GL_ONE, GL_ZERO);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
+               // second pass
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(basetexture);
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
                        m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
-#ifdef USETEXMATRIX
                        m.pointer_texcoord3f[1] = rsurface_vertex3f;
                        m.texmatrix[1] = r_shadow_entitytolight;
-#else
-                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
-#endif
                }
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
        }
@@ -1696,152 +1639,105 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(const entity_
        {
                // 2/2/2 2D combine path (any dot3 card)
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
-#else
-               m.pointer_texcoord[0] = varray_texcoord2f[0];
-               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
-#endif
                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[1] = rsurface_vertex3f;
                m.texmatrix[1] = r_shadow_entitytoattenuationz;
-#else
-               m.pointer_texcoord[1] = varray_texcoord2f[1];
-               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
-#endif
-               R_Mesh_State(&m);
+               R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                GL_BlendFunc(GL_ONE, GL_ZERO);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
+               // second pass
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(normalmaptexture);
                m.texcombinergb[0] = GL_REPLACE;
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
-               R_Mesh_State(&m);
+               m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
+               R_Mesh_TextureState(&m);
                GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
+               // second pass
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(basetexture);
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
                        m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
-#ifdef USETEXMATRIX
                        m.pointer_texcoord3f[1] = rsurface_vertex3f;
                        m.texmatrix[1] = r_shadow_entitytolight;
-#else
-                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
-#endif
                }
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
        }
        // this final code is shared
-       R_Mesh_State(&m);
-       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
-       VectorScale(lightcolorbase, colorscale, color2);
-       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-       for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
-       {
-               GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-       }
-       GL_LockArrays(0, 0);
+       R_Mesh_TextureState(&m);
+       R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
 }
 
-static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
+static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
 {
-       int renders;
-       float color2[3];
+       float glossexponent;
        rmeshstate_t m;
-       const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
        // FIXME: detect blendsquare!
        //if (!gl_support_blendsquare)
        //      return;
        GL_Color(1,1,1,1);
-       if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
+       // generate normalization cubemap texcoords
+       R_Shadow_GenTexCoords_Specular_NormalCubeMap(numsurfaces, surfacelist);
+       if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
        {
                // 2/0/0/1/2 3D combine blendsquare path
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(normalmaptexture);
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-               R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
-               R_Mesh_State(&m);
+               m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
+               R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                // this squares the result
                GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
-               memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
-               R_Mesh_State(&m);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               // second and third pass
+               R_Mesh_ResetTextureState();
                // square alpha in framebuffer a few times to make it shiny
                GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
-               // these comments are a test run through this math for intensity 0.5
-               // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
-               // 0.25 * 0.25 = 0.0625 (this is another pass)
-               // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
+                       RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
+               // fourth pass
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
-#else
-               m.pointer_texcoord3f[0] = varray_texcoord3f[0];
-               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
-#endif
-               R_Mesh_State(&m);
+               R_Mesh_TextureState(&m);
                GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
+               // fifth pass
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(glosstexture);
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
                        m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
-#ifdef USETEXMATRIX
                        m.pointer_texcoord3f[1] = rsurface_vertex3f;
                        m.texmatrix[1] = r_shadow_entitytolight;
-#else
-                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
-#endif
                }
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
        }
@@ -1849,406 +1745,327 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(const entity
        {
                // 2/0/0/2 3D combine blendsquare path
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(normalmaptexture);
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-               R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
-               R_Mesh_State(&m);
+               m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
+               R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                // this squares the result
                GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
-               memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
-               R_Mesh_State(&m);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               // second and third pass
+               R_Mesh_ResetTextureState();
                // square alpha in framebuffer a few times to make it shiny
                GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
-               // these comments are a test run through this math for intensity 0.5
-               // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
-               // 0.25 * 0.25 = 0.0625 (this is another pass)
-               // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
+                       RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
+               // fourth pass
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(glosstexture);
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[1] = rsurface_vertex3f;
                m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
-#else
-               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-               R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
-#endif
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
        }
        else
        {
                // 2/0/0/2/2 2D combine blendsquare path
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(normalmaptexture);
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-               R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
-               R_Mesh_State(&m);
+               m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
+               R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                // this squares the result
                GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
-               memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
-               R_Mesh_State(&m);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               // second and third pass
+               R_Mesh_ResetTextureState();
                // square alpha in framebuffer a few times to make it shiny
                GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
-               // these comments are a test run through this math for intensity 0.5
-               // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
-               // 0.25 * 0.25 = 0.0625 (this is another pass)
-               // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
+                       RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
+               // fourth pass
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
-#else
-               m.pointer_texcoord[0] = varray_texcoord2f[0];
-               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
-#endif
                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
                m.pointer_texcoord3f[1] = rsurface_vertex3f;
                m.texmatrix[1] = r_shadow_entitytoattenuationz;
-#else
-               m.pointer_texcoord[1] = varray_texcoord2f[1];
-               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
-#endif
-               R_Mesh_State(&m);
+               R_Mesh_TextureState(&m);
                GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
+               RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
                GL_LockArrays(0, 0);
 
+               // fifth pass
                memset(&m, 0, sizeof(m));
-               m.pointer_vertex = rsurface_vertex3f;
                m.tex[0] = R_GetTexture(glosstexture);
-               m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
-               m.texmatrix[0] = texture->currenttexmatrix;
+               m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
                        m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
-#ifdef USETEXMATRIX
                        m.pointer_texcoord3f[1] = rsurface_vertex3f;
                        m.texmatrix[1] = r_shadow_entitytolight;
-#else
-                       m.pointer_texcoord3f[1] = varray_texcoord3f[1];
-                       R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
-#endif
                }
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
        }
-       R_Mesh_State(&m);
-       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
-       VectorScale(lightcolorbase, colorscale, color2);
-       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-       for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
-       {
-               GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
-       }
-       GL_LockArrays(0, 0);
+       // this final code is shared
+       R_Mesh_TextureState(&m);
+       R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
 }
 
-static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
+static void R_Shadow_RenderSurfacesLighting_Light_Dot3(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
 {
        // ARB path (any Geforce, any Radeon)
-       int surfacelistindex;
        qboolean doambient = r_shadow_rtlight->ambientscale > 0;
        qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
        qboolean dospecular = specularscale > 0;
        if (!doambient && !dodiffuse && !dospecular)
                return;
-       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+       RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
+       R_Mesh_ColorPointer(NULL);
+       if (doambient)
+               R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
+       if (dodiffuse)
+               R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
+       if (dopants)
        {
-               const msurface_t *surface = surfacelist[surfacelistindex];
-               RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, false, true);
                if (doambient)
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale);
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
                if (dodiffuse)
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale);
-               if (dopants)
-               {
-                       if (doambient)
-                               R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale);
-                       if (dodiffuse)
-                               R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale);
-               }
-               if (doshirt)
-               {
-                       if (doambient)
-                               R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale);
-                       if (dodiffuse)
-                               R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale);
-               }
-               if (dospecular)
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(ent, texture, surface, lightcolorbase, glosstexture, normalmaptexture, specularscale);
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
+       }
+       if (doshirt)
+       {
+               if (doambient)
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
+               if (dodiffuse)
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
        }
+       if (dospecular)
+               R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(numsurfaces, surfacelist, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
 }
 
-void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const msurface_t *surface, vec3_t diffusecolor2, vec3_t ambientcolor2)
+void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const model_t *model, int numsurfaces, msurface_t **surfacelist, vec3_t diffusecolor2, vec3_t ambientcolor2)
 {
+       int surfacelistindex;
        int renders;
-       const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
-       R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
-       for (renders = 0;renders < 64 && (ambientcolor2[0] > renders || ambientcolor2[1] > renders || ambientcolor2[2] > renders || diffusecolor2[0] > renders || diffusecolor2[1] > renders || diffusecolor2[2] > renders);renders++)
+       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+       {
+               const msurface_t *surface = surfacelist[surfacelistindex];
+               R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
+       }
+       for (renders = 0;renders < 64;renders++)
        {
-               int i;
-               float *c;
-#if 1
-               // due to low fillrate on the cards this vertex lighting path is
-               // designed for, we manually cull all triangles that do not
-               // contain a lit vertex
-               int draw;
                const int *e;
+               int stop;
+               int firstvertex;
+               int lastvertex;
                int newnumtriangles;
                int *newe;
                int newelements[3072];
-               draw = false;
+               stop = true;
+               firstvertex = 0;
+               lastvertex = 0;
                newnumtriangles = 0;
                newe = newelements;
-               for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
-               {
-                       if (newnumtriangles >= 1024)
+               for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+               {
+                       const msurface_t *surface = surfacelist[surfacelistindex];
+                       const int *elements = rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
+                       int i;
+                       // due to low fillrate on the cards this vertex lighting path is
+                       // designed for, we manually cull all triangles that do not
+                       // contain a lit vertex
+                       // this builds batches of triangles from multiple surfaces and
+                       // renders them at once
+                       for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
                        {
-                               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
-                               GL_LockArrays(0, 0);
-                               newnumtriangles = 0;
-                               newe = newelements;
-                       }
-                       if (VectorLength2(varray_color4f + e[0] * 4) + VectorLength2(varray_color4f + e[1] * 4) + VectorLength2(varray_color4f + e[2] * 4) >= 0.01)
-                       {
-                               newe[0] = e[0];
-                               newe[1] = e[1];
-                               newe[2] = e[2];
-                               newnumtriangles++;
-                               newe += 3;
-                               draw = true;
+                               if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
+                               {
+                                       if (newnumtriangles)
+                                       {
+                                               firstvertex = min(firstvertex, e[0]);
+                                               lastvertex = max(lastvertex, e[0]);
+                                       }
+                                       else
+                                       {
+                                               firstvertex = e[0];
+                                               lastvertex = e[0];
+                                       }
+                                       firstvertex = min(firstvertex, e[1]);
+                                       lastvertex = max(lastvertex, e[1]);
+                                       firstvertex = min(firstvertex, e[2]);
+                                       lastvertex = max(lastvertex, e[2]);
+                                       newe[0] = e[0];
+                                       newe[1] = e[1];
+                                       newe[2] = e[2];
+                                       newnumtriangles++;
+                                       newe += 3;
+                                       if (newnumtriangles >= 1024)
+                                       {
+                                               GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
+                                               R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
+                                               newnumtriangles = 0;
+                                               newe = newelements;
+                                               stop = false;
+                                       }
+                               }
                        }
                }
                if (newnumtriangles >= 1)
                {
-                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
-                       GL_LockArrays(0, 0);
-                       draw = true;
+                       GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
+                       R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
+                       stop = false;
                }
-               if (!draw)
-                       break;
-#else
-               for (i = 0, c = varray_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
-                       if (VectorLength2(c))
-                               goto goodpass;
-               break;
-goodpass:
-               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
-               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
                GL_LockArrays(0, 0);
-#endif
+               // if we couldn't find any lit triangles, exit early
+               if (stop)
+                       break;
                // now reduce the intensity for the next overbright pass
-               for (i = 0, c = varray_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
-               {
-                       c[0] = max(0, c[0] - 1);
-                       c[1] = max(0, c[1] - 1);
-                       c[2] = max(0, c[2] - 1);
+               // we have to clamp to 0 here incase the drivers have improper
+               // handling of negative colors
+               // (some old drivers even have improper handling of >1 color)
+               stop = true;
+               for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+               {
+                       int i;
+                       float *c;
+                       const msurface_t *surface = surfacelist[surfacelistindex];
+                       for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
+                       {
+                               if (c[0] > 1 || c[1] > 1 || c[2] > 1)
+                               {
+                                       c[0] = max(0, c[0] - 1);
+                                       c[1] = max(0, c[1] - 1);
+                                       c[2] = max(0, c[2] - 1);
+                                       stop = false;
+                               }
+                               else
+                                       VectorClear(c);
+                       }
                }
+               // another check...
+               if (stop)
+                       break;
        }
 }
 
-static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
+static void R_Shadow_RenderSurfacesLighting_Light_Vertex(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
 {
-       int surfacelistindex;
+       // OpenGL 1.1 path (anything)
+       model_t *model = rsurface_entity->model;
        float ambientcolorbase[3], diffusecolorbase[3];
        float ambientcolorpants[3], diffusecolorpants[3];
        float ambientcolorshirt[3], diffusecolorshirt[3];
        rmeshstate_t m;
-       VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2, ambientcolorbase);
-       VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2, diffusecolorbase);
-       VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2, ambientcolorpants);
-       VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2, diffusecolorpants);
-       VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2, ambientcolorshirt);
-       VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2, diffusecolorshirt);
+       VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorbase);
+       VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorbase);
+       VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorpants);
+       VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorpants);
+       VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
+       VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+       R_Mesh_ColorPointer(rsurface_array_color4f);
        memset(&m, 0, sizeof(m));
        m.tex[0] = R_GetTexture(basetexture);
+       m.texmatrix[0] = rsurface_texture->currenttexmatrix;
+       m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
        if (r_textureunits.integer >= 2)
        {
-               // voodoo2
+               // voodoo2 or TNT
                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
                m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
-#else
-               m.pointer_texcoord[1] = varray_texcoord2f[1];
-               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
-#endif
+               m.pointer_texcoord3f[1] = rsurface_vertex3f;
                if (r_textureunits.integer >= 3)
                {
-                       // Geforce3/Radeon class but not using dot3
+                       // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
                        m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
-#ifdef USETEXMATRIX
                        m.texmatrix[2] = r_shadow_entitytoattenuationz;
-#else
-                       m.pointer_texcoord[2] = varray_texcoord2f[2];
-                       R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
-#endif
+                       m.pointer_texcoord3f[2] = rsurface_vertex3f;
                }
        }
-       m.pointer_color = varray_color4f;
-       R_Mesh_State(&m);
-       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+       R_Mesh_TextureState(&m);
+       RSurf_PrepareVerticesForBatch(true, false, numsurfaces, surfacelist);
+       R_Mesh_TexBind(0, R_GetTexture(basetexture));
+       R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorbase, ambientcolorbase);
+       if (dopants)
        {
-               const msurface_t *surface = surfacelist[surfacelistindex];
-               RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, true, false);
-               // OpenGL 1.1 path (anything)
-               R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
-               R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
-               if (r_textureunits.integer >= 2)
-               {
-                       // voodoo2 or TNT
-#ifdef USETEXMATRIX
-                       R_Mesh_TexCoordPointer(1, 3, rsurface_vertex3f);
-#else
-                       R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
-#endif
-                       if (r_textureunits.integer >= 3)
-                       {
-                               // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
-#ifdef USETEXMATRIX
-                               R_Mesh_TexCoordPointer(2, 3, rsurface_vertex3f);
-#else
-                               R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
-#endif
-                       }
-               }
-               R_Mesh_TexBind(0, R_GetTexture(basetexture));
-               R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorbase, ambientcolorbase);
-               if (dopants)
-               {
-                       R_Mesh_TexBind(0, R_GetTexture(pantstexture));
-                       R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorpants, ambientcolorpants);
-               }
-               if (doshirt)
-               {
-                       R_Mesh_TexBind(0, R_GetTexture(shirttexture));
-                       R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorshirt, ambientcolorshirt);
-               }
+               R_Mesh_TexBind(0, R_GetTexture(pantstexture));
+               R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorpants, ambientcolorpants);
+       }
+       if (doshirt)
+       {
+               R_Mesh_TexBind(0, R_GetTexture(shirttexture));
+               R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorshirt, ambientcolorshirt);
        }
 }
 
-void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist)
+void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist)
 {
        // FIXME: support MATERIALFLAG_NODEPTHTEST
        vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
-       rtexture_t *basetexture;
-       rtexture_t *pantstexture;
-       rtexture_t *shirttexture;
-       rtexture_t *glosstexture;
-       float specularscale;
-       qboolean dopants, doshirt;
-       glosstexture = r_texture_black;
-       specularscale = 0;
-       if (r_shadow_gloss.integer > 0)
-       {
-               if (texture->skin.gloss)
-               {
-                       if (r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
-                       {
-                               glosstexture = texture->skin.gloss;
-                               specularscale = r_shadow_rtlight->specularscale * r_shadow_glossintensity.value;
-                       }
-               }
-               else
-               {
-                       if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
-                       {
-                               glosstexture = r_texture_white;
-                               specularscale = r_shadow_rtlight->specularscale * r_shadow_gloss2intensity.value;
-                       }
-               }
-       }
        // calculate colors to render this texture with
-       lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * ent->colormod[0] * texture->currentalpha;
-       lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * ent->colormod[1] * texture->currentalpha;
-       lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * ent->colormod[2] * texture->currentalpha;
-       if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
+       lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
+       lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
+       lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
+       if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * rsurface_texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
                return;
-       if ((texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (ent->flags & RENDER_NOCULLFACE))
-               qglDisable(GL_CULL_FACE);
-       else
-               qglEnable(GL_CULL_FACE);
-       dopants = texture->skin.pants != NULL && VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f);
-       doshirt = texture->skin.shirt != NULL && VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
-       if (dopants + doshirt)
+       GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
+       GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
+       if (rsurface_texture->colormapping)
        {
+               qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
+               qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
                if (dopants)
                {
-                       lightcolorpants[0] = lightcolorbase[0] * ent->colormap_pantscolor[0];
-                       lightcolorpants[1] = lightcolorbase[1] * ent->colormap_pantscolor[1];
-                       lightcolorpants[2] = lightcolorbase[2] * ent->colormap_pantscolor[2];
+                       lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
+                       lightcolorpants[1] = lightcolorbase[1] * rsurface_entity->colormap_pantscolor[1];
+                       lightcolorpants[2] = lightcolorbase[2] * rsurface_entity->colormap_pantscolor[2];
                }
                else
-               {
-                       pantstexture = r_texture_black;
                        VectorClear(lightcolorpants);
-               }
                if (doshirt)
                {
-                       shirttexture = texture->skin.shirt;
-                       lightcolorshirt[0] = lightcolorbase[0] * ent->colormap_shirtcolor[0];
-                       lightcolorshirt[1] = lightcolorbase[1] * ent->colormap_shirtcolor[1];
-                       lightcolorshirt[2] = lightcolorbase[2] * ent->colormap_shirtcolor[2];
+                       lightcolorshirt[0] = lightcolorbase[0] * rsurface_entity->colormap_shirtcolor[0];
+                       lightcolorshirt[1] = lightcolorbase[1] * rsurface_entity->colormap_shirtcolor[1];
+                       lightcolorshirt[2] = lightcolorbase[2] * rsurface_entity->colormap_shirtcolor[2];
                }
                else
-               {
-                       shirttexture = r_texture_black;
                        VectorClear(lightcolorshirt);
-               }
                switch (r_shadow_rendermode)
                {
                case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
-                       R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, dopants, doshirt);
+                       GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
+                       R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_GLSL:
-                       R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, dopants, doshirt);
+                       R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_DOT3:
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, dopants, doshirt);
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
-                       R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, dopants, doshirt);
+                       R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
                        break;
                default:
                        Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
@@ -2257,20 +2074,20 @@ void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t
        }
        else
        {
-               basetexture = texture->skin.merged ? texture->skin.merged : texture->skin.base;
                switch (r_shadow_rendermode)
                {
                case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
-                       R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, basetexture, r_texture_black, r_texture_black, texture->skin.nmap, glosstexture, specularscale, false, false);
+                       GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
+                       R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_GLSL:
-                       R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, basetexture, r_texture_black, r_texture_black, texture->skin.nmap, glosstexture, specularscale, false, false);
+                       R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_DOT3:
-                       R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, basetexture, r_texture_black, r_texture_black, texture->skin.nmap, glosstexture, specularscale, false, false);
+                       R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
-                       R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, basetexture, r_texture_black, r_texture_black, texture->skin.nmap, glosstexture, specularscale, false, false);
+                       R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
                        break;
                default:
                        Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
@@ -2281,8 +2098,7 @@ void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t
 
 void R_RTLight_Update(dlight_t *light, int isstatic)
 {
-       int j, k;
-       float scale;
+       double scale;
        rtlight_t *rtlight = &light->rtlight;
        R_RTLight_Uncompile(rtlight);
        memset(rtlight, 0, sizeof(*rtlight));
@@ -2300,7 +2116,7 @@ void R_RTLight_Update(dlight_t *light, int isstatic)
        rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
        rtlight->cubemapname[0] = 0;
        if (light->cubemapname[0])
-               strcpy(rtlight->cubemapname, light->cubemapname);
+               strlcpy(rtlight->cubemapname, light->cubemapname, sizeof(rtlight->cubemapname));
        else if (light->cubemapnum > 0)
                sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
        rtlight->shadow = light->shadow;
@@ -2313,17 +2129,11 @@ void R_RTLight_Update(dlight_t *light, int isstatic)
        rtlight->specularscale = light->specularscale;
        rtlight->flags = light->flags;
        Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
-       // ConcatScale won't work here because this needs to scale rotate and
-       // translate, not just rotate
-       scale = 1.0f / rtlight->radius;
-       for (k = 0;k < 3;k++)
-               for (j = 0;j < 4;j++)
-                       rtlight->matrix_worldtolight.m[k][j] *= scale;
-
-       rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
-       rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
-       VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
-       rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
+       // this has to scale both rotate and translate because this is an already
+       // inverted matrix (it transforms from world to light space, not the other
+       // way around)
+       scale = 1.0 / rtlight->radius;
+       Matrix4x4_Scale(&rtlight->matrix_worldtolight, scale, scale);
 }
 
 // compiles rtlight geometry
@@ -2357,7 +2167,7 @@ void R_RTLight_Compile(rtlight_t *rtlight)
                R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
                model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
                numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
-               data = (unsigned char *)Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
+               data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
                rtlight->static_numleafs = numleafs;
                rtlight->static_numleafpvsbytes = numleafpvsbytes;
                rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
@@ -2371,7 +2181,7 @@ void R_RTLight_Compile(rtlight_t *rtlight)
                if (numsurfaces)
                        memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
                if (model->CompileShadowVolume && rtlight->shadow)
-                       model->CompileShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
+                       model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
                // now we're done compiling the rtlight
                r_shadow_compilingrtlight = NULL;
        }
@@ -2393,7 +2203,8 @@ void R_RTLight_Compile(rtlight_t *rtlight)
                }
        }
 
-       Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles (in %i meshes)\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], shadowtris, shadowmeshes);
+       if (developer.integer >= 10)
+               Con_Printf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles (in %i meshes)\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], shadowtris, shadowmeshes);
 }
 
 void R_RTLight_Uncompile(rtlight_t *rtlight)
@@ -2425,6 +2236,7 @@ void R_Shadow_UncompileWorldLights(void)
 
 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
 {
+       model_t *model = ent->model;
        vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
        vec_t relativeshadowradius;
        if (ent == r_refdef.worldentity)
@@ -2433,29 +2245,31 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfa
                {
                        shadowmesh_t *mesh;
                        R_Mesh_Matrix(&ent->matrix);
+                       CHECKGLERROR
                        for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
                        {
-                               renderstats.lights_shadowtriangles += mesh->numtriangles;
+                               r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
                                R_Mesh_VertexPointer(mesh->vertex3f);
                                GL_LockArrays(0, mesh->numverts);
                                if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
                                {
                                        // decrement stencil if backface is behind depthbuffer
-                                       qglCullFace(GL_BACK); // quake is backwards, this culls front faces
-                                       qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
+                                       GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
+                                       qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
                                        R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
                                        // increment stencil if frontface is behind depthbuffer
-                                       qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
-                                       qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
+                                       GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
+                                       qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
                                }
                                R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
                                GL_LockArrays(0, 0);
                        }
+                       CHECKGLERROR
                }
                else if (numsurfaces)
                {
                        R_Mesh_Matrix(&ent->matrix);
-                       ent->model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
+                       model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
                }
        }
        else
@@ -2469,28 +2283,32 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfa
                relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
                relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
                R_Mesh_Matrix(&ent->matrix);
-               ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
+               model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
        }
 }
 
 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
 {
        // set up properties for rendering light onto this entity
+       RSurf_ActiveEntity(ent, true, true);
        Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
        Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
        Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
        Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
-       Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
-       R_Mesh_Matrix(&ent->matrix);
+       if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
+               R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
 }
 
 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
 {
+       model_t *model = ent->model;
+       if (!model->DrawLight)
+               return;
        R_Shadow_SetupEntityLight(ent);
        if (ent == r_refdef.worldentity)
-               ent->model->DrawLight(ent, numsurfaces, surfacelist);
+               model->DrawLight(ent, numsurfaces, surfacelist);
        else
-               ent->model->DrawLight(ent, ent->model->nummodelsurfaces, ent->model->surfacelist);
+               model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist);
 }
 
 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
@@ -2574,7 +2392,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        if (numleafs)
        {
                for (i = 0;i < numleafs;i++)
-                       if (r_worldleafvisible[leaflist[i]])
+                       if (r_viewcache.world_leafvisible[leaflist[i]])
                                break;
                if (i == numleafs)
                        return;
@@ -2597,16 +2415,19 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        {
                for (i = 0;i < r_refdef.numentities;i++)
                {
+                       model_t *model;
                        entity_render_t *ent = r_refdef.entities[i];
                        if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
-                        && ent->model
+                        && (model = ent->model)
                         && !(ent->flags & RENDER_TRANSPARENT)
                         && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
                        {
                                // about the VectorDistance2 - light emitting entities should not cast their own shadow
-                               if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
+                               vec3_t org;
+                               Matrix4x4_OriginFromMatrix(&ent->matrix, org);
+                               if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
                                        shadowentities[numshadowentities++] = ent;
-                               if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
+                               if (r_viewcache.entityvisible[i] && (ent->flags & RENDER_LIGHT) && model->DrawLight)
                                        lightentities[numlightentities++] = ent;
                        }
                }
@@ -2623,10 +2444,10 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        // make this the active rtlight for rendering purposes
        R_Shadow_RenderMode_ActiveLight(rtlight);
        // count this light in the r_speeds
-       renderstats.lights++;
+       r_refdef.stats.lights++;
 
        usestencil = false;
-       if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
+       if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
        {
                // draw stencil shadow volumes to mask off pixels that are in shadow
                // so that they won't receive lighting
@@ -2676,7 +2497,7 @@ void R_ShadowVolumeLighting(qboolean visible)
 
        R_Shadow_RenderMode_Begin();
 
-       flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
+       flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
        if (r_shadow_debuglight.integer >= 0)
        {
                for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
@@ -2687,13 +2508,100 @@ void R_ShadowVolumeLighting(qboolean visible)
                for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
                        if (light->flags & flag)
                                R_DrawRTLight(&light->rtlight, visible);
-       if (r_rtdlight)
+       if (r_refdef.rtdlight)
                for (lnum = 0;lnum < r_refdef.numlights;lnum++)
                        R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
 
        R_Shadow_RenderMode_End();
 }
 
+extern void R_SetupView(const matrix4x4_t *matrix);
+extern cvar_t r_shadows_throwdistance;
+void R_DrawModelShadows(void)
+{
+       int i;
+       float relativethrowdistance;
+       entity_render_t *ent;
+       vec3_t relativelightorigin;
+       vec3_t relativelightdirection;
+       vec3_t relativeshadowmins, relativeshadowmaxs;
+       float vertex3f[12];
+
+       if (!r_drawentities.integer || !gl_stencil)
+               return;
+
+       CHECKGLERROR
+       GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
+
+       r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
+
+       if (gl_ext_stenciltwoside.integer)
+               r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
+       else
+               r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
+
+       R_Shadow_RenderMode_StencilShadowVolumes();
+
+       for (i = 0;i < r_refdef.numentities;i++)
+       {
+               ent = r_refdef.entities[i];
+               // cast shadows from anything that is not a submodel of the map
+               if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
+               {
+                       relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
+                       VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
+                       VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
+                       VectorNegate(ent->modellight_lightdir, relativelightdirection);
+                       VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
+                       R_Mesh_Matrix(&ent->matrix);
+                       ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
+               }
+       }
+
+       // not really the right mode, but this will disable any silly stencil features
+       R_Shadow_RenderMode_VisibleLighting(true, true);
+
+       // vertex coordinates for a quad that covers the screen exactly
+       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;
+
+       // set up ortho view for rendering this pass
+       GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
+       GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
+       GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
+       GL_ScissorTest(true);
+       R_Mesh_Matrix(&identitymatrix);
+       R_Mesh_ResetTextureState();
+       R_Mesh_VertexPointer(vertex3f);
+       R_Mesh_ColorPointer(NULL);
+
+       // set up a 50% darkening blend on shadowed areas
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       GL_DepthTest(false);
+       GL_DepthMask(false);
+       qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
+       GL_Color(0, 0, 0, 0.5);
+       GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
+       qglDepthFunc(GL_ALWAYS);CHECKGLERROR
+       qglEnable(GL_STENCIL_TEST);CHECKGLERROR
+       qglStencilMask(~0);CHECKGLERROR
+       qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
+       qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
+
+       // apply the blend to the shadowed areas
+       R_Mesh_Draw(0, 4, 2, polygonelements);
+
+       // restore perspective view
+       R_SetupView(&r_view.matrix);
+
+       // restore other state to normal
+       GL_DepthTest(true);
+       R_Shadow_RenderMode_End();
+}
+
+
 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
 typedef struct suffixinfo_s
 {
@@ -2801,7 +2709,7 @@ rtexture_t *R_Shadow_Cubemap(const char *basename)
        if (i >= MAX_CUBEMAPS)
                return r_texture_whitecube;
        numcubemaps++;
-       strcpy(cubemaps[i].basename, basename);
+       strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
        cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
        if (!cubemaps[i].texture)
                cubemaps[i].texture = r_texture_whitecube;
@@ -2817,7 +2725,7 @@ void R_Shadow_FreeCubemaps(void)
 dlight_t *R_Shadow_NewWorldLight(void)
 {
        dlight_t *light;
-       light = (dlight_t *)Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
+       light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
        light->next = r_shadow_worldlightchain;
        r_shadow_worldlightchain = light;
        return light;
@@ -2882,14 +2790,17 @@ void R_Shadow_SelectLight(dlight_t *light)
                r_shadow_selectedlight->selected = true;
 }
 
-void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
 {
+       // this is never batched (there can be only one)
        float scale = r_editlights_cursorgrid.value * 0.5f;
-       R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[0]->tex, NULL, false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
+       R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[1]->tex, NULL, false, r_editlights_cursorlocation, r_view.right, r_view.up, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
 }
 
-void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
 {
+       // this is never batched (due to the ent parameter changing every time)
+       // so numsurfaces == 1 and surfacelist[0] == lightnumber
        float intensity;
        const dlight_t *light = (dlight_t *)ent;
        intensity = 0.5;
@@ -2897,7 +2808,7 @@ void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, in
                intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
        if (!light->shadow)
                intensity *= 0.5f;
-       R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacenumber]->tex, NULL, false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
+       R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacelist[0]]->tex, NULL, false, light->origin, r_view.right, r_view.up, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
 }
 
 void R_Shadow_DrawLightSprites(void)
@@ -2918,12 +2829,12 @@ void R_Shadow_SelectLightInView(void)
        bestrating = 0;
        for (light = r_shadow_worldlightchain;light;light = light->next)
        {
-               VectorSubtract(light->origin, r_vieworigin, temp);
-               rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
+               VectorSubtract(light->origin, r_view.origin, temp);
+               rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
                if (rating >= 0.95)
                {
                        rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
-                       if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
+                       if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_view.origin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
                        {
                                bestrating = rating;
                                best = light;
@@ -3003,8 +2914,10 @@ void R_Shadow_LoadWorldLights(void)
                        // remove quotes on cubemapname
                        if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
                        {
-                               cubemapname[strlen(cubemapname)-1] = 0;
-                               strcpy(cubemapname, cubemapname + 1);
+                               size_t namelen;
+                               namelen = strlen(cubemapname) - 2;
+                               memmove(cubemapname, cubemapname + 1, namelen);
+                               cubemapname[namelen] = '\0';
                        }
                        if (a < 8)
                        {
@@ -3148,7 +3061,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                data = r_refdef.worldmodel->brush.entities;
        if (!data)
                return;
-       for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
+       for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++)
        {
                type = LIGHTTYPE_MINUSX;
                origin[0] = origin[1] = origin[2] = 0;
@@ -3166,19 +3079,19 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                islight = false;
                while (1)
                {
-                       if (!COM_ParseToken(&data, false))
+                       if (!COM_ParseTokenConsole(&data))
                                break; // error
                        if (com_token[0] == '}')
                                break; // end of entity
                        if (com_token[0] == '_')
-                               strcpy(key, com_token + 1);
+                               strlcpy(key, com_token + 1, sizeof(key));
                        else
-                               strcpy(key, com_token);
+                               strlcpy(key, com_token, sizeof(key));
                        while (key[strlen(key)-1] == ' ') // remove trailing spaces
                                key[strlen(key)-1] = 0;
-                       if (!COM_ParseToken(&data, false))
+                       if (!COM_ParseTokenConsole(&data))
                                break; // error
-                       strcpy(value, com_token);
+                       strlcpy(value, com_token, sizeof(value));
 
                        // now that we have the key pair worked out...
                        if (!strcmp("light", key))
@@ -3349,8 +3262,8 @@ void R_Shadow_SetCursorLocationForView(void)
        vec_t dist, push;
        vec3_t dest, endpos;
        trace_t trace;
-       VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
-       trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
+       VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
+       trace = CL_TraceBox(r_view.origin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
        if (trace.fraction < 1)
        {
                dist = trace.fraction * r_editlights_cursordistance.value;
@@ -3358,7 +3271,7 @@ void R_Shadow_SetCursorLocationForView(void)
                if (push > dist)
                        push = dist;
                push = -push;
-               VectorMA(trace.endpos, push, r_viewforward, endpos);
+               VectorMA(trace.endpos, push, r_view.forward, endpos);
                VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
        }
        else
@@ -3653,7 +3566,7 @@ void R_Shadow_EditLights_Edit_f(void)
                        return;
                }
                if (Cmd_Argc() == 3)
-                       strcpy(cubemapname, Cmd_Argv(2));
+                       strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
                else
                        cubemapname[0] = 0;
        }
@@ -3923,7 +3836,7 @@ void R_Shadow_EditLights_CopyInfo_f(void)
        r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
        r_shadow_bufferlight.style = r_shadow_selectedlight->style;
        if (r_shadow_selectedlight->cubemapname)
-               strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
+               strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
        else
                r_shadow_bufferlight.cubemapname[0] = 0;
        r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;