]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
added r_shadow_lightradiusscale cvar (similar to r_shadow_lightintensityscale)
[xonotic/darkplaces.git] / gl_rmain.c
index 6b4db9cdc772d804cbc1897fb9accb2d4d8f5295..eb72ccb4b8fbe8b7c574599b55de9ab268dfec74 100644 (file)
@@ -916,10 +916,10 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting)
                // lightmapped wall
                shaderfilename = "glsl/default.glsl";
                permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
-               if (r_glsl_deluxemapping.integer >= 1 && rsurface_lightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping)
+               if (r_glsl_deluxemapping.integer >= 1 && rsurface_uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping)
                {
                        // deluxemapping (light direction texture)
-                       if (rsurface_lightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping && r_refdef.worldmodel->brushq3.deluxemapping_modelspace)
+                       if (rsurface_uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping && r_refdef.worldmodel->brushq3.deluxemapping_modelspace)
                                permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE;
                        else
                                permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
@@ -1212,7 +1212,7 @@ void GL_Init (void)
        VID_CheckExtensions();
 
        // LordHavoc: report supported extensions
-       Con_DPrintf("\nengine extensions: %s\n", vm_sv_extensions );
+       Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
 
        // clear to black (loading plaque will be seen over this)
        CHECKGLERROR
@@ -2010,7 +2010,7 @@ void R_UpdateVariables(void)
 
        r_refdef.rtworld = r_shadow_realtime_world.integer;
        r_refdef.rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
-       r_refdef.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
+       r_refdef.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer && r_dynamic.integer;
        r_refdef.rtdlightshadows = r_refdef.rtdlight && (r_refdef.rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
        r_refdef.lightmapintensity = r_refdef.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
        if (r_showsurfaces.integer)
@@ -2107,7 +2107,7 @@ void R_RenderView(void)
 }
 
 extern void R_DrawLightningBeams (void);
-extern void VM_AddPolygonsToMeshQueue (void);
+extern void VM_CL_AddPolygonsToMeshQueue (void);
 extern void R_DrawPortals (void);
 void R_RenderScene(void)
 {
@@ -2197,7 +2197,7 @@ void R_RenderScene(void)
        {
                qglUseProgramObjectARB(0);CHECKGLERROR
        }
-       VM_AddPolygonsToMeshQueue();
+       VM_CL_AddPolygonsToMeshQueue();
 
        if (r_drawportals.integer)
        {
@@ -2587,9 +2587,6 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
 {
        model_t *model = ent->model;
 
-       // FIXME: identify models using a better check than ent->model->brush.shadowmesh
-       //int lightmode = ((ent->effects & EF_FULLBRIGHT) || ent->model->brush.shadowmesh) ? 0 : 2;
-
        // switch to an alternate material if this is a q1bsp animated material
        {
                texture_t *texture = t;
@@ -2620,6 +2617,8 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
        // pick a new currentskinframe if the material is animated
        if (t->numskinframes >= 2)
                t->currentskinframe = t->skinframes + ((int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes);
+       if (t->backgroundnumskinframes >= 2)
+               t->backgroundcurrentskinframe = t->backgroundskinframes + ((int)(t->backgroundskinframerate * (cl.time - ent->frame2time)) % t->backgroundnumskinframes);
 
        t->currentmaterialflags = t->basematerialflags;
        t->currentalpha = ent->alpha;
@@ -2639,19 +2638,24 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
                t->currenttexmatrix = r_waterscrollmatrix;
        else
                t->currenttexmatrix = identitymatrix;
+       if (t->backgroundnumskinframes && !(t->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
+               t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
 
        t->colormapping = VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
        t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
        t->glosstexture = r_texture_white;
+       t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white;
+       t->backgroundglosstexture = r_texture_white;
        t->specularpower = r_shadow_glossexponent.value;
        t->specularscale = 0;
        if (r_shadow_gloss.integer > 0)
        {
-               if (t->currentskinframe->gloss)
+               if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
                {
                        if (r_shadow_glossintensity.value > 0)
                        {
-                               t->glosstexture = t->currentskinframe->gloss;
+                               t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_black;
+                               t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_black;
                                t->specularscale = r_shadow_glossintensity.value;
                        }
                }
@@ -2807,10 +2811,9 @@ qboolean rsurface_generatedvertex;
 const entity_render_t *rsurface_entity;
 const model_t *rsurface_model;
 texture_t *rsurface_texture;
-rtexture_t *rsurface_lightmaptexture;
+qboolean rsurface_uselightmaptexture;
 rsurfmode_t rsurface_mode;
-texture_t *rsurface_glsl_texture;
-qboolean rsurface_glsl_uselightmap;
+int rsurface_lightmode; // 0 = lightmap or fullbright, 1 = color array from q3bsp, 2 = vertex shaded model
 
 void RSurf_CleanUp(void)
 {
@@ -2821,10 +2824,8 @@ void RSurf_CleanUp(void)
        }
        GL_AlphaTest(false);
        rsurface_mode = RSURFMODE_NONE;
-       rsurface_lightmaptexture = NULL;
+       rsurface_uselightmaptexture = false;
        rsurface_texture = NULL;
-       rsurface_glsl_texture = NULL;
-       rsurface_glsl_uselightmap = false;
 }
 
 void RSurf_ActiveEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
@@ -2960,10 +2961,14 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta
 
 void RSurf_DrawBatch_Simple(int texturenumsurfaces, msurface_t **texturesurfacelist)
 {
-       int texturesurfaceindex;
+       int i, j;
        const msurface_t *surface = texturesurfacelist[0];
-       int firstvertex = surface->num_firstvertex;
-       int endvertex = surface->num_firstvertex + surface->num_vertices;
+       const msurface_t *surface2;
+       int firstvertex;
+       int endvertex;
+       int numvertices;
+       int numtriangles;
+       // TODO: lock all array ranges before render, rather than on each surface
        if (texturenumsurfaces == 1)
        {
                GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
@@ -2974,68 +2979,160 @@ void RSurf_DrawBatch_Simple(int texturenumsurfaces, msurface_t **texturesurfacel
                #define MAXBATCHTRIANGLES 4096
                int batchtriangles = 0;
                int batchelements[MAXBATCHTRIANGLES*3];
-               for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+               for (i = 0;i < texturenumsurfaces;i = j)
                {
-                       surface = texturesurfacelist[texturesurfaceindex];
-                       if (surface->num_triangles >= 256 || (batchtriangles == 0 && texturesurfaceindex + 1 >= texturenumsurfaces))
+                       surface = texturesurfacelist[i];
+                       j = i + 1;
+                       if (surface->num_triangles > MAXBATCHTRIANGLES)
                        {
                                R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
                                continue;
                        }
-                       if (batchtriangles + surface->num_triangles > MAXBATCHTRIANGLES)
+                       memcpy(batchelements, rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
+                       batchtriangles = surface->num_triangles;
+                       firstvertex = surface->num_firstvertex;
+                       endvertex = surface->num_firstvertex + surface->num_vertices;
+                       for (;j < texturenumsurfaces;j++)
                        {
-                               R_Mesh_Draw(firstvertex, endvertex - firstvertex, batchtriangles, batchelements);
-                               batchtriangles = 0;
-                               firstvertex = surface->num_firstvertex;
-                               endvertex = surface->num_firstvertex + surface->num_vertices;
-                       }
-                       else
-                       {
-                               firstvertex = min(firstvertex, surface->num_firstvertex);
-                               endvertex = max(endvertex, surface->num_firstvertex + surface->num_vertices);
+                               surface2 = texturesurfacelist[j];
+                               if (batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
+                                       break;
+                               memcpy(batchelements + batchtriangles * 3, rsurface_model->surfmesh.data_element3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
+                               batchtriangles += surface2->num_triangles;
+                               firstvertex = min(firstvertex, surface2->num_firstvertex);
+                               endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
                        }
-                       memcpy(batchelements + batchtriangles * 3, rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
-                       batchtriangles += surface->num_triangles;
+                       surface2 = texturesurfacelist[j-1];
+                       numvertices = endvertex - firstvertex;
+                       R_Mesh_Draw(firstvertex, numvertices, batchtriangles, batchelements);
                }
-               if (batchtriangles)
-                       R_Mesh_Draw(firstvertex, endvertex - firstvertex, batchtriangles, batchelements);
        }
        else if (r_batchmode.integer == 1)
        {
-               int firsttriangle = 0;
-               int endtriangle = -1;
-               for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+               for (i = 0;i < texturenumsurfaces;i = j)
+               {
+                       surface = texturesurfacelist[i];
+                       for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
+                               if (texturesurfacelist[j] != surface2)
+                                       break;
+                       surface2 = texturesurfacelist[j-1];
+                       numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
+                       numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
+                       GL_LockArrays(surface->num_firstvertex, numvertices);
+                       R_Mesh_Draw(surface->num_firstvertex, numvertices, numtriangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+               }
+       }
+       else
+       {
+               for (i = 0;i < texturenumsurfaces;i++)
                {
-                       surface = texturesurfacelist[texturesurfaceindex];
-                       if (surface->num_firsttriangle != endtriangle)
+                       surface = texturesurfacelist[i];
+                       GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+               }
+       }
+}
+
+static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit)
+{
+       int i;
+       int j;
+       const msurface_t *surface = texturesurfacelist[0];
+       const msurface_t *surface2;
+       int firstvertex;
+       int endvertex;
+       int numvertices;
+       int numtriangles;
+       // TODO: lock all array ranges before render, rather than on each surface
+       if (texturenumsurfaces == 1)
+       {
+               R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
+               if (deluxemaptexunit >= 0)
+                       R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
+               GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+       }
+       else if (r_batchmode.integer == 2)
+       {
+               #define MAXBATCHTRIANGLES 4096
+               int batchtriangles = 0;
+               int batchelements[MAXBATCHTRIANGLES*3];
+               for (i = 0;i < texturenumsurfaces;i = j)
+               {
+                       surface = texturesurfacelist[i];
+                       R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
+                       if (deluxemaptexunit >= 0)
+                               R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
+                       j = i + 1;
+                       if (surface->num_triangles > MAXBATCHTRIANGLES)
                        {
-                               if (endtriangle > firsttriangle)
-                               {
-                                       GL_LockArrays(firstvertex, endvertex - firstvertex);
-                                       R_Mesh_Draw(firstvertex, endvertex - firstvertex, endtriangle - firsttriangle, (rsurface_model->surfmesh.data_element3i + 3 * firsttriangle));
-                               }
-                               firstvertex = surface->num_firstvertex;
-                               endvertex = surface->num_firstvertex + surface->num_vertices;
-                               firsttriangle = surface->num_firsttriangle;
+                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+                               continue;
                        }
-                       else
+                       memcpy(batchelements, rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
+                       batchtriangles = surface->num_triangles;
+                       firstvertex = surface->num_firstvertex;
+                       endvertex = surface->num_firstvertex + surface->num_vertices;
+                       for (;j < texturenumsurfaces;j++)
                        {
-                               firstvertex = min(firstvertex, surface->num_firstvertex);
-                               endvertex = max(endvertex, surface->num_firstvertex + surface->num_vertices);
+                               surface2 = texturesurfacelist[j];
+                               if (surface2->lightmaptexture != surface->lightmaptexture || batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
+                                       break;
+                               memcpy(batchelements + batchtriangles * 3, rsurface_model->surfmesh.data_element3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
+                               batchtriangles += surface2->num_triangles;
+                               firstvertex = min(firstvertex, surface2->num_firstvertex);
+                               endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
                        }
-                       endtriangle = surface->num_firsttriangle + surface->num_triangles;
+                       surface2 = texturesurfacelist[j-1];
+                       numvertices = endvertex - firstvertex;
+                       R_Mesh_Draw(firstvertex, numvertices, batchtriangles, batchelements);
                }
-               if (endtriangle > firsttriangle)
+       }
+       else if (r_batchmode.integer == 1)
+       {
+#if 0
+               Con_Printf("%s batch sizes ignoring lightmap:", rsurface_texture->name);
+               for (i = 0;i < texturenumsurfaces;i = j)
                {
-                       GL_LockArrays(firstvertex, endvertex - firstvertex);
-                       R_Mesh_Draw(firstvertex, endvertex - firstvertex, endtriangle - firsttriangle, (rsurface_model->surfmesh.data_element3i + 3 * firsttriangle));
+                       surface = texturesurfacelist[i];
+                       for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
+                               if (texturesurfacelist[j] != surface2)
+                                       break;
+                       Con_Printf(" %i", j - i);
                }
+               Con_Printf("\n");
+               Con_Printf("%s batch sizes honoring lightmap:", rsurface_texture->name);
+#endif
+               for (i = 0;i < texturenumsurfaces;i = j)
+               {
+                       surface = texturesurfacelist[i];
+                       R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
+                       if (deluxemaptexunit >= 0)
+                               R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
+                       for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
+                               if (texturesurfacelist[j] != surface2 || texturesurfacelist[j]->lightmaptexture != surface->lightmaptexture)
+                                       break;
+#if 0
+                       Con_Printf(" %i", j - i);
+#endif
+                       surface2 = texturesurfacelist[j-1];
+                       numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
+                       numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
+                       GL_LockArrays(surface->num_firstvertex, numvertices);
+                       R_Mesh_Draw(surface->num_firstvertex, numvertices, numtriangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+               }
+#if 0
+               Con_Printf("\n");
+#endif
        }
        else
        {
-               for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+               for (i = 0;i < texturenumsurfaces;i++)
                {
-                       surface = texturesurfacelist[texturesurfaceindex];
+                       surface = texturesurfacelist[i];
+                       R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
+                       if (deluxemaptexunit >= 0)
+                               R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
                        GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
                        R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
                }
@@ -3072,161 +3169,199 @@ static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, msurface_t **te
        }
 }
 
-static void RSurf_DrawBatch_Lightmap(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, int lightmode, qboolean applycolor, qboolean applyfog)
+static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, msurface_t **texturesurfacelist)
 {
        int texturesurfaceindex;
        int i;
        float f;
        float *v, *c, *c2;
-       // TODO: optimize
-       if (lightmode >= 2)
-       {
-               // model lighting
-               vec3_t ambientcolor;
-               vec3_t diffusecolor;
-               vec3_t lightdir;
-               VectorCopy(rsurface_entity->modellight_lightdir, lightdir);
-               ambientcolor[0] = rsurface_entity->modellight_ambient[0] * r * 0.5f;
-               ambientcolor[1] = rsurface_entity->modellight_ambient[1] * g * 0.5f;
-               ambientcolor[2] = rsurface_entity->modellight_ambient[2] * b * 0.5f;
-               diffusecolor[0] = rsurface_entity->modellight_diffuse[0] * r * 0.5f;
-               diffusecolor[1] = rsurface_entity->modellight_diffuse[1] * g * 0.5f;
-               diffusecolor[2] = rsurface_entity->modellight_diffuse[2] * b * 0.5f;
-               if (VectorLength2(diffusecolor) > 0)
-               {
-                       // generate color arrays for the surfaces in this list
-                       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+       if (rsurface_lightmapcolor4f)
+       {
+               // generate color arrays for the surfaces in this list
+               for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+               {
+                       const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+                       for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface_array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4)
                        {
-                               const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
-                               int numverts = surface->num_vertices;
-                               v = rsurface_vertex3f + 3 * surface->num_firstvertex;
-                               c2 = rsurface_normal3f + 3 * surface->num_firstvertex;
-                               c = rsurface_array_color4f + 4 * surface->num_firstvertex;
-                               // q3-style directional shading
-                               for (i = 0;i < numverts;i++, v += 3, c2 += 3, c += 4)
-                               {
-                                       if ((f = DotProduct(c2, lightdir)) > 0)
-                                               VectorMA(ambientcolor, f, diffusecolor, c);
-                                       else
-                                               VectorCopy(ambientcolor, c);
-                                       c[3] = a;
-                               }
+                               f = 1 - VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
+                               c2[0] = c[0] * f;
+                               c2[1] = c[1] * f;
+                               c2[2] = c[2] * f;
+                               c2[3] = c[3];
                        }
-                       r = 1;
-                       g = 1;
-                       b = 1;
-                       a = 1;
-                       applycolor = false;
-                       rsurface_lightmapcolor4f = rsurface_array_color4f;
                }
-               else
+       }
+       else
+       {
+               for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                {
-                       r = ambientcolor[0];
-                       g = ambientcolor[1];
-                       b = ambientcolor[2];
-                       rsurface_lightmapcolor4f = NULL;
+                       const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+                       for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c2 = (rsurface_array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c2 += 4)
+                       {
+                               f = 1 - VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
+                               c2[0] = f;
+                               c2[1] = f;
+                               c2[2] = f;
+                               c2[3] = 1;
+                       }
                }
        }
-       else if (lightmode >= 1 || !rsurface_lightmaptexture)
+       rsurface_lightmapcolor4f = rsurface_array_color4f;
+}
+
+static void RSurf_DrawBatch_GL11_ApplyColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a)
+{
+       int texturesurfaceindex;
+       int i;
+       float *c, *c2;
+       if (!rsurface_lightmapcolor4f)
+               return;
+       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
        {
-               if (texturesurfacelist[0]->lightmapinfo && texturesurfacelist[0]->lightmapinfo->stainsamples)
+               const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+               for (i = 0, c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface_array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4)
                {
-                       // generate color arrays for the surfaces in this list
-                       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+                       c2[0] = c[0] * r;
+                       c2[1] = c[1] * g;
+                       c2[2] = c[2] * b;
+                       c2[3] = c[3] * a;
+               }
+       }
+       rsurface_lightmapcolor4f = rsurface_array_color4f;
+}
+
+static void RSurf_DrawBatch_GL11_Lightmap(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
+{
+       // TODO: optimize
+       rsurface_lightmapcolor4f = NULL;
+       if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
+       if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
+       R_Mesh_ColorPointer(rsurface_lightmapcolor4f);
+       GL_Color(r, g, b, a);
+       RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 0, -1);
+}
+
+static void RSurf_DrawBatch_GL11_Unlit(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
+{
+       // TODO: optimize applyfog && applycolor case
+       // just apply fog if necessary, and tint the fog color array if necessary
+       rsurface_lightmapcolor4f = NULL;
+       if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
+       if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
+       R_Mesh_ColorPointer(rsurface_lightmapcolor4f);
+       GL_Color(r, g, b, a);
+       RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+}
+
+static void RSurf_DrawBatch_GL11_VertexColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
+{
+       int texturesurfaceindex;
+       int i;
+       float *c;
+       // TODO: optimize
+       if (texturesurfacelist[0]->lightmapinfo && texturesurfacelist[0]->lightmapinfo->stainsamples)
+       {
+               // generate color arrays for the surfaces in this list
+               for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+               {
+                       const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+                       for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
                        {
-                               const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
-                               for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
+                               if (surface->lightmapinfo->samples)
                                {
-                                       if (surface->lightmapinfo->samples)
+                                       const unsigned char *lm = surface->lightmapinfo->samples + (rsurface_model->surfmesh.data_lightmapoffsets + surface->num_firstvertex)[i];
+                                       float scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[0]] * (1.0f / 32768.0f);
+                                       VectorScale(lm, scale, c);
+                                       if (surface->lightmapinfo->styles[1] != 255)
                                        {
-                                               const unsigned char *lm = surface->lightmapinfo->samples + (rsurface_model->surfmesh.data_lightmapoffsets + surface->num_firstvertex)[i];
-                                               float scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[0]] * (1.0f / 32768.0f);
-                                               VectorScale(lm, scale, c);
-                                               if (surface->lightmapinfo->styles[1] != 255)
+                                               int size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
+                                               lm += size3;
+                                               scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f);
+                                               VectorMA(c, scale, lm, c);
+                                               if (surface->lightmapinfo->styles[2] != 255)
                                                {
-                                                       int size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
                                                        lm += size3;
-                                                       scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f);
+                                                       scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f);
                                                        VectorMA(c, scale, lm, c);
-                                                       if (surface->lightmapinfo->styles[2] != 255)
+                                                       if (surface->lightmapinfo->styles[3] != 255)
                                                        {
                                                                lm += size3;
-                                                               scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f);
+                                                               scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[3]] * (1.0f / 32768.0f);
                                                                VectorMA(c, scale, lm, c);
-                                                               if (surface->lightmapinfo->styles[3] != 255)
-                                                               {
-                                                                       lm += size3;
-                                                                       scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[3]] * (1.0f / 32768.0f);
-                                                                       VectorMA(c, scale, lm, c);
-                                                               }
                                                        }
                                                }
                                        }
-                                       else
-                                               VectorClear(c);
-                                       c[3] = 1;
-                               }
-                       }
-                       rsurface_lightmapcolor4f = rsurface_array_color4f;
-               }
-               else
-                       rsurface_lightmapcolor4f = rsurface_model->surfmesh.data_lightmapcolor4f;
-       }
-       else
-       {
-               // just lightmap it
-               rsurface_lightmapcolor4f = NULL;
-       }
-       if (applyfog)
-       {
-               if (rsurface_lightmapcolor4f)
-               {
-                       // generate color arrays for the surfaces in this list
-                       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
-                       {
-                               const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
-                               for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface_array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4)
-                               {
-                                       f = 1 - VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
-                                       c2[0] = c[0] * f;
-                                       c2[1] = c[1] * f;
-                                       c2[2] = c[2] * f;
-                                       c2[3] = c[3];
-                               }
-                       }
-               }
-               else
-               {
-                       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
-                       {
-                               const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
-                               for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c2 = (rsurface_array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c2 += 4)
-                               {
-                                       f = 1 - VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
-                                       c2[0] = f;
-                                       c2[1] = f;
-                                       c2[2] = f;
-                                       c2[3] = 1;
                                }
+                               else
+                                       VectorClear(c);
+                               c[3] = 1;
                        }
                }
                rsurface_lightmapcolor4f = rsurface_array_color4f;
        }
-       if (applycolor && rsurface_lightmapcolor4f)
-       {
+       else
+               rsurface_lightmapcolor4f = rsurface_model->surfmesh.data_lightmapcolor4f;
+       if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
+       if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
+       R_Mesh_ColorPointer(rsurface_lightmapcolor4f);
+       GL_Color(r, g, b, a);
+       RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+}
+
+static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
+{
+       int texturesurfaceindex;
+       int i;
+       float f;
+       float *v, *c, *c2;
+       vec3_t ambientcolor;
+       vec3_t diffusecolor;
+       vec3_t lightdir;
+       // TODO: optimize
+       // model lighting
+       VectorCopy(rsurface_entity->modellight_lightdir, lightdir);
+       ambientcolor[0] = rsurface_entity->modellight_ambient[0] * r * 0.5f;
+       ambientcolor[1] = rsurface_entity->modellight_ambient[1] * g * 0.5f;
+       ambientcolor[2] = rsurface_entity->modellight_ambient[2] * b * 0.5f;
+       diffusecolor[0] = rsurface_entity->modellight_diffuse[0] * r * 0.5f;
+       diffusecolor[1] = rsurface_entity->modellight_diffuse[1] * g * 0.5f;
+       diffusecolor[2] = rsurface_entity->modellight_diffuse[2] * b * 0.5f;
+       if (VectorLength2(diffusecolor) > 0)
+       {
+               // generate color arrays for the surfaces in this list
                for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                {
                        const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
-                       for (i = 0, c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface_array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4)
+                       int numverts = surface->num_vertices;
+                       v = rsurface_vertex3f + 3 * surface->num_firstvertex;
+                       c2 = rsurface_normal3f + 3 * surface->num_firstvertex;
+                       c = rsurface_array_color4f + 4 * surface->num_firstvertex;
+                       // q3-style directional shading
+                       for (i = 0;i < numverts;i++, v += 3, c2 += 3, c += 4)
                        {
-                               c2[0] = c[0] * r;
-                               c2[1] = c[1] * g;
-                               c2[2] = c[2] * b;
-                               c2[3] = c[3] * a;
+                               if ((f = DotProduct(c2, lightdir)) > 0)
+                                       VectorMA(ambientcolor, f, diffusecolor, c);
+                               else
+                                       VectorCopy(ambientcolor, c);
+                               c[3] = a;
                        }
                }
+               r = 1;
+               g = 1;
+               b = 1;
+               a = 1;
+               applycolor = false;
                rsurface_lightmapcolor4f = rsurface_array_color4f;
        }
+       else
+       {
+               r = ambientcolor[0];
+               g = ambientcolor[1];
+               b = ambientcolor[2];
+               rsurface_lightmapcolor4f = NULL;
+       }
+       if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
+       if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
        R_Mesh_ColorPointer(rsurface_lightmapcolor4f);
        GL_Color(r, g, b, a);
        RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
@@ -3234,6 +3369,8 @@ static void RSurf_DrawBatch_Lightmap(int texturenumsurfaces, msurface_t **textur
 
 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
 {
+       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_mode != RSURFMODE_SHOWSURFACES)
        {
                rsurface_mode = RSURFMODE_SHOWSURFACES;
@@ -3266,6 +3403,8 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **te
                // restore entity matrix
                R_Mesh_Matrix(&rsurface_entity->matrix);
        }
+       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
        GL_DepthMask(true);
        // LordHavoc: HalfLife maps have freaky skypolys so don't use
        // skymasking on them, and Quake3 never did sky masking (unlike
@@ -3300,37 +3439,26 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **te
 
 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **texturesurfacelist)
 {
-       int lightmode;
-       // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh
-       lightmode = ((rsurface_entity->effects & EF_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2;
        if (rsurface_mode != RSURFMODE_GLSL)
        {
                rsurface_mode = RSURFMODE_GLSL;
-               rsurface_glsl_texture = NULL;
-               rsurface_glsl_uselightmap = false;
                R_Mesh_ResetTextureState();
        }
-       if (rsurface_glsl_texture != rsurface_texture || rsurface_glsl_uselightmap != (rsurface_lightmaptexture != NULL))
-       {
-               rsurface_glsl_texture = rsurface_texture;
-               rsurface_glsl_uselightmap = rsurface_lightmaptexture != NULL;
-               GL_BlendFunc(rsurface_texture->currentlayers[0].blendfunc1, rsurface_texture->currentlayers[0].blendfunc2);
-               GL_DepthMask(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_BLENDED));
-               GL_Color(rsurface_entity->colormod[0], rsurface_entity->colormod[1], rsurface_entity->colormod[2], rsurface_texture->currentalpha);
-               R_SetupSurfaceShader(vec3_origin, lightmode == 2);
-               //permutation_deluxemapping = permutation_lightmapping = R_SetupSurfaceShader(vec3_origin, lightmode == 2, false);
-               //if (r_glsl_deluxemapping.integer)
-               //      permutation_deluxemapping = R_SetupSurfaceShader(vec3_origin, lightmode == 2, true);
-               R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f);
-               R_Mesh_TexCoordPointer(4, 2, rsurface_model->surfmesh.data_texcoordlightmap2f);
-               GL_AlphaTest((rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
-       }
+
+       R_SetupSurfaceShader(vec3_origin, rsurface_lightmode == 2);
        if (!r_glsl_permutation)
                return;
-       RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist);
+
+       if (rsurface_lightmode == 2)
+               RSurf_PrepareVerticesForBatch(true, r_glsl_permutation->loc_Texture_Normal, texturenumsurfaces, texturesurfacelist);
+       else
+               RSurf_PrepareVerticesForBatch(r_glsl_permutation->loc_Texture_Normal, r_glsl_permutation->loc_Texture_Normal, texturenumsurfaces, texturesurfacelist);
+       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);
+       R_Mesh_TexCoordPointer(4, 2, rsurface_model->surfmesh.data_texcoordlightmap2f);
+
        if (rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
        {
                R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
@@ -3338,9 +3466,9 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **t
                        R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
                R_Mesh_ColorPointer(NULL);
        }
-       else if (rsurface_lightmaptexture)
+       else if (rsurface_uselightmaptexture)
        {
-               R_Mesh_TexBind(7, R_GetTexture(rsurface_lightmaptexture));
+               R_Mesh_TexBind(7, R_GetTexture(texturesurfacelist[0]->lightmaptexture));
                if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
                        R_Mesh_TexBind(8, R_GetTexture(texturesurfacelist[0]->deluxemaptexture));
                R_Mesh_ColorPointer(NULL);
@@ -3352,22 +3480,25 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **t
                        R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
                R_Mesh_ColorPointer(rsurface_model->surfmesh.data_lightmapcolor4f);
        }
-       RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+
+       if (rsurface_uselightmaptexture && !(rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
+               RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 7, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? 8 : -1);
+       else
+               RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+       if (rsurface_texture->backgroundnumskinframes && !(rsurface_texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
+       {
+       }
 }
 
 static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **texturesurfacelist)
 {
        // OpenGL 1.3 path - anything not completely ancient
        int texturesurfaceindex;
-       int lightmode;
        qboolean applycolor;
        qboolean applyfog;
        rmeshstate_t m;
        int layerindex;
        const texturelayer_t *layer;
-       CHECKGLERROR
-       // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh
-       lightmode = ((rsurface_entity->effects & EF_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2;
        if (rsurface_mode != RSURFMODE_MULTIPASS)
                rsurface_mode = RSURFMODE_MULTIPASS;
        RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
@@ -3410,17 +3541,19 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **t
                {
                case TEXTURELAYERTYPE_LITTEXTURE:
                        memset(&m, 0, sizeof(m));
-                       if (lightmode >= 1 || !rsurface_lightmaptexture)
-                               m.tex[0] = R_GetTexture(r_texture_white);
-                       else
-                               m.tex[0] = R_GetTexture(rsurface_lightmaptexture);
+                       m.tex[0] = R_GetTexture(r_texture_white);
                        m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordlightmap2f;
                        m.tex[1] = R_GetTexture(layer->texture);
                        m.texmatrix[1] = layer->texmatrix;
                        m.texrgbscale[1] = layertexrgbscale;
                        m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
                        R_Mesh_TextureState(&m);
-                       RSurf_DrawBatch_Lightmap(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], lightmode, applycolor, applyfog);
+                       if (rsurface_lightmode == 2)
+                               RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
+                       else if (rsurface_uselightmaptexture)
+                               RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
+                       else
+                               RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
                        break;
                case TEXTURELAYERTYPE_TEXTURE:
                        memset(&m, 0, sizeof(m));
@@ -3429,7 +3562,7 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **t
                        m.texrgbscale[0] = layertexrgbscale;
                        m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
                        R_Mesh_TextureState(&m);
-                       RSurf_DrawBatch_Lightmap(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], 0, applycolor, applyfog);
+                       RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
                        break;
                case TEXTURELAYERTYPE_FOG:
                        memset(&m, 0, sizeof(m));
@@ -3476,14 +3609,10 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **t
 {
        // OpenGL 1.1 - crusty old voodoo path
        int texturesurfaceindex;
-       int lightmode;
        qboolean applyfog;
        rmeshstate_t m;
        int layerindex;
        const texturelayer_t *layer;
-       CHECKGLERROR
-       // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh
-       lightmode = ((rsurface_entity->effects & EF_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2;
        if (rsurface_mode != RSURFMODE_MULTIPASS)
                rsurface_mode = RSURFMODE_MULTIPASS;
        RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
@@ -3511,13 +3640,15 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **t
                                // two-pass lit texture with 2x rgbscale
                                // first the lightmap pass
                                memset(&m, 0, sizeof(m));
-                               if (lightmode >= 1 || !rsurface_lightmaptexture)
-                                       m.tex[0] = R_GetTexture(r_texture_white);
-                               else
-                                       m.tex[0] = R_GetTexture(rsurface_lightmaptexture);
+                               m.tex[0] = R_GetTexture(r_texture_white);
                                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordlightmap2f;
                                R_Mesh_TextureState(&m);
-                               RSurf_DrawBatch_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, lightmode, false, false);
+                               if (rsurface_lightmode == 2)
+                                       RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
+                               else if (rsurface_uselightmaptexture)
+                                       RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
+                               else
+                                       RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
                                GL_LockArrays(0, 0);
                                // then apply the texture to it
                                GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
@@ -3526,7 +3657,7 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **t
                                m.texmatrix[0] = layer->texmatrix;
                                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
                                R_Mesh_TextureState(&m);
-                               RSurf_DrawBatch_Lightmap(texturenumsurfaces, texturesurfacelist, layer->color[0] * 0.5f, layer->color[1] * 0.5f, layer->color[2] * 0.5f, layer->color[3], 0, layer->color[0] != 2 || layer->color[1] != 2 || layer->color[2] != 2 || layer->color[3] != 1, false);
+                               RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layer->color[0] * 0.5f, layer->color[1] * 0.5f, layer->color[2] * 0.5f, layer->color[3], layer->color[0] != 2 || layer->color[1] != 2 || layer->color[2] != 2 || layer->color[3] != 1, false);
                        }
                        else
                        {
@@ -3536,7 +3667,10 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **t
                                m.texmatrix[0] = layer->texmatrix;
                                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
                                R_Mesh_TextureState(&m);
-                               RSurf_DrawBatch_Lightmap(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], lightmode == 2 ? 2 : 1, layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
+                               if (rsurface_lightmode == 2)
+                                       RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
+                               else
+                                       RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
                        }
                        break;
                case TEXTURELAYERTYPE_TEXTURE:
@@ -3546,7 +3680,7 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **t
                        m.texmatrix[0] = layer->texmatrix;
                        m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
                        R_Mesh_TextureState(&m);
-                       RSurf_DrawBatch_Lightmap(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], 0, layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
+                       RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
                        break;
                case TEXTURELAYERTYPE_FOG:
                        // singletexture fogging
@@ -3598,14 +3732,20 @@ static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **textur
        r_shadow_rtlight = NULL;
        r_refdef.stats.entities_surfaces += texturenumsurfaces;
        CHECKGLERROR
-       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 (r_showsurfaces.integer)
                R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
        else if (rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY)
                R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
        else if (rsurface_texture->currentnumlayers)
        {
+               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
+               GL_BlendFunc(rsurface_texture->currentlayers[0].blendfunc1, rsurface_texture->currentlayers[0].blendfunc2);
+               GL_DepthMask(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_BLENDED));
+               GL_Color(rsurface_entity->colormod[0], rsurface_entity->colormod[1], rsurface_entity->colormod[2], rsurface_texture->currentalpha);
+               GL_AlphaTest((rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
+               // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh
+               rsurface_lightmode = ((rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2;
                if (r_glsl.integer && gl_support_fragment_shader)
                        R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist);
                else if (gl_combine.integer && r_textureunits.integer >= 2)
@@ -3617,13 +3757,13 @@ static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **textur
        GL_LockArrays(0, 0);
 }
 
-#define BATCHSIZE 256
 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
 {
-       int surfacelistindex;
-       int batchcount;
-       texture_t *t;
-       msurface_t *texturesurfacelist[BATCHSIZE];
+       int i, j;
+       int texturenumsurfaces, endsurface;
+       msurface_t *surface;
+       msurface_t *texturesurfacelist[1024];
+
        // if the model is static it doesn't matter what value we give for
        // wantnormals and wanttangents, so this logic uses only rules applicable
        // to a model, knowing that they are meaningless otherwise
@@ -3631,54 +3771,59 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
                RSurf_ActiveEntity(ent, false, false);
        else
                RSurf_ActiveEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
-       batchcount = 0;
-       t = NULL;
-       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
-       {
-               msurface_t *surface = ent->model->data_surfaces + surfacelist[surfacelistindex];
 
-               if (t != surface->texture || rsurface_lightmaptexture != surface->lightmaptexture)
+       for (i = 0;i < numsurfaces;i = j)
+       {
+               j = i + 1;
+               surface = rsurface_model->data_surfaces + surfacelist[i];
+               rsurface_texture = surface->texture;
+               rsurface_uselightmaptexture = surface->lightmaptexture != NULL;
+               // scan ahead until we find a different texture
+               endsurface = min(i + 1024, numsurfaces);
+               texturenumsurfaces = 0;
+               texturesurfacelist[texturenumsurfaces++] = surface;
+               for (;j < endsurface;j++)
                {
-                       if (batchcount > 0)
-                               if (!(rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY)) // transparent sky is too difficult
-                                       R_DrawTextureSurfaceList(batchcount, texturesurfacelist);
-                       batchcount = 0;
-                       t = surface->texture;
-                       rsurface_lightmaptexture = surface->lightmaptexture;
-                       R_UpdateTextureInfo(ent, t);
-                       rsurface_texture = t->currentframe;
+                       surface = rsurface_model->data_surfaces + surfacelist[j];
+                       if (rsurface_texture != surface->texture || rsurface_uselightmaptexture != (surface->lightmaptexture != NULL))
+                               break;
+                       texturesurfacelist[texturenumsurfaces++] = surface;
                }
-
-               texturesurfacelist[batchcount++] = surface;
+               // render the range of surfaces
+               R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
        }
-       if (batchcount > 0)
-               if (!(rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY)) // transparent sky is too difficult
-                       R_DrawTextureSurfaceList(batchcount, texturesurfacelist);
+
        RSurf_CleanUp();
 }
 
-void R_QueueTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist)
+void R_QueueSurfaceList(int numsurfaces, msurface_t **surfacelist)
 {
-       int texturesurfaceindex;
+       int i, j;
        vec3_t tempcenter, center;
-       if (rsurface_texture->currentmaterialflags & MATERIALFLAG_BLENDED)
-       {
-               // drawing sky transparently would be too difficult
-               if (!(rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY))
+       // break the surface list down into batches by texture and use of lightmapping
+       for (i = 0;i < numsurfaces;i = j)
+       {
+               j = i + 1;
+               rsurface_texture = surfacelist[i]->texture;
+               rsurface_uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
+               if (rsurface_texture->currentmaterialflags & MATERIALFLAG_BLENDED)
+               {
+                       // transparent surfaces get pushed off into the transparent queue
+                       const msurface_t *surface = surfacelist[i];
+                       tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
+                       tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
+                       tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
+                       Matrix4x4_Transform(&rsurface_entity->matrix, tempcenter, center);
+                       R_MeshQueue_AddTransparent(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_view.origin : center, R_DrawSurface_TransparentCallback, rsurface_entity, surface - rsurface_model->data_surfaces, r_shadow_rtlight);
+               }
+               else
                {
-                       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
-                       {
-                               const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
-                               tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
-                               tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
-                               tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
-                               Matrix4x4_Transform(&rsurface_entity->matrix, tempcenter, center);
-                               R_MeshQueue_AddTransparent(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_view.origin : center, R_DrawSurface_TransparentCallback, rsurface_entity, surface - rsurface_model->data_surfaces, r_shadow_rtlight);
-                       }
+                       // simply scan ahead until we find a different texture
+                       for (;j < numsurfaces && rsurface_texture == surfacelist[j]->texture && rsurface_uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++);
+                       // render the range of surfaces
+                       R_DrawTextureSurfaceList(j - i, surfacelist + i);
                }
        }
-       else
-               R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
 }
 
 extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
@@ -3725,7 +3870,7 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
        flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
        f = 0;
        t = NULL;
-       rsurface_lightmaptexture = NULL;
+       rsurface_uselightmaptexture = false;
        rsurface_texture = NULL;
        numsurfacelist = 0;
        if (ent == r_refdef.worldentity)
@@ -3742,21 +3887,8 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
                        {
                                // process this surface
                                surface = model->data_surfaces + j;
-                               // if texture or lightmap has changed, start a new batch
-                               if (t != surface->texture || rsurface_lightmaptexture != surface->lightmaptexture)
-                               {
-                                       if (numsurfacelist)
-                                       {
-                                               R_QueueTextureSurfaceList(numsurfacelist, surfacelist);
-                                               numsurfacelist = 0;
-                                       }
-                                       t = surface->texture;
-                                       rsurface_lightmaptexture = surface->lightmaptexture;
-                                       rsurface_texture = t->currentframe;
-                                       f = rsurface_texture->currentmaterialflags & flagsmask;
-                               }
                                // if this surface fits the criteria, add it to the list
-                               if (f && surface->num_triangles)
+                               if (surface->texture->currentmaterialflags & flagsmask && surface->num_triangles)
                                {
                                        // if lightmap parameters changed, rebuild lightmap texture
                                        if (surface->cached_dlight)
@@ -3766,7 +3898,7 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
                                        counttriangles += surface->num_triangles;
                                        if (numsurfacelist >= maxsurfacelist)
                                        {
-                                               R_QueueTextureSurfaceList(numsurfacelist, surfacelist);
+                                               R_QueueSurfaceList(numsurfacelist, surfacelist);
                                                numsurfacelist = 0;
                                        }
                                }
@@ -3779,21 +3911,8 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
                endsurface = surface + model->nummodelsurfaces;
                for (;surface < endsurface;surface++)
                {
-                       // if texture or lightmap has changed, start a new batch
-                       if (t != surface->texture || rsurface_lightmaptexture != surface->lightmaptexture)
-                       {
-                               if (numsurfacelist)
-                               {
-                                       R_QueueTextureSurfaceList(numsurfacelist, surfacelist);
-                                       numsurfacelist = 0;
-                               }
-                               t = surface->texture;
-                               rsurface_lightmaptexture = surface->lightmaptexture;
-                               rsurface_texture = t->currentframe;
-                               f = rsurface_texture->currentmaterialflags & flagsmask;
-                       }
                        // if this surface fits the criteria, add it to the list
-                       if (f && surface->num_triangles)
+                       if (surface->texture->currentmaterialflags & flagsmask && surface->num_triangles)
                        {
                                // if lightmap parameters changed, rebuild lightmap texture
                                if (surface->cached_dlight)
@@ -3803,14 +3922,14 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
                                counttriangles += surface->num_triangles;
                                if (numsurfacelist >= maxsurfacelist)
                                {
-                                       R_QueueTextureSurfaceList(numsurfacelist, surfacelist);
+                                       R_QueueSurfaceList(numsurfacelist, surfacelist);
                                        numsurfacelist = 0;
                                }
                        }
                }
        }
        if (numsurfacelist)
-               R_QueueTextureSurfaceList(numsurfacelist, surfacelist);
+               R_QueueSurfaceList(numsurfacelist, surfacelist);
        r_refdef.stats.entities_triangles += counttriangles;
        RSurf_CleanUp();