]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
removed trailing comments on cvar declarations and Cmd_AddCommand calls
[xonotic/darkplaces.git] / gl_rmain.c
index 3404cd0d5fd1ed9942cedc07a90c7ba5802a8db6..7f96334fec4f7d13b39265fbcbcaf801241eab3d 100644 (file)
@@ -46,6 +46,10 @@ cvar_t r_showdisabledepthtest = {0, "r_showdisabledepthtest", "0", "disables dep
 cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
 cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
+cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
+cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling"};
+cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
+cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
 cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
 cvar_t r_fullbright = {0, "r_fullbright","0", "make everything bright cheat (not allowed in multiplayer)"};
 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
@@ -94,7 +98,7 @@ cvar_t developer_texturelogging = {0, "developer_texturelogging", "0", "produces
 
 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers)"};
 
-cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"}; // used for testing renderer code changes, otherwise does nothing
+cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
 cvar_t r_batchmode = {0, "r_batchmode", "1", "selects method of rendering multiple surfaces with one driver call (values are 0, 1, 2, etc...)"};
 
 typedef struct r_glsl_bloomshader_s
@@ -621,7 +625,8 @@ static const char *builtinshaderstring =
 "      //\n"
 "      // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
 "      // provide significant illumination, large = slow = pain.\n"
-"      color.rgb *= myhalf(max(1.0 - dot(CubeVector, CubeVector), 0.0));\n"
+"//    color.rgb *= myhalf(max(1.0 - dot(CubeVector, CubeVector), 0.0));\n"
+"      color.rgb *= myhalf(max(2.0 - 2.0 * length(CubeVector), 0.0) / (1 + dot(CubeVector, CubeVector)));\n"
 "\n"
 "\n"
 "\n"
@@ -1117,7 +1122,7 @@ void GL_Main_Init(void)
 {
        r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
 
-       Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed\n");
+       Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
        FOG_registercvars(); // FIXME: move this fog stuff to client?
        Cvar_RegisterVariable(&r_nearclip);
        Cvar_RegisterVariable(&r_showsurfaces);
@@ -1131,6 +1136,10 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_showdisabledepthtest);
        Cvar_RegisterVariable(&r_drawportals);
        Cvar_RegisterVariable(&r_drawentities);
+       Cvar_RegisterVariable(&r_cullentities_trace);
+       Cvar_RegisterVariable(&r_cullentities_trace_samples);
+       Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
+       Cvar_RegisterVariable(&r_cullentities_trace_delay);
        Cvar_RegisterVariable(&r_drawviewmodel);
        Cvar_RegisterVariable(&r_speeds);
        Cvar_RegisterVariable(&r_fullbrights);
@@ -1267,6 +1276,53 @@ int R_CullBox(const vec3_t mins, const vec3_t maxs)
        return false;
 }
 
+int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
+{
+       int i;
+       const mplane_t *p;
+       for (i = 0;i < numplanes;i++)
+       {
+               p = planes + i;
+               switch(p->signbits)
+               {
+               default:
+               case 0:
+                       if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
+                               return true;
+                       break;
+               case 1:
+                       if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
+                               return true;
+                       break;
+               case 2:
+                       if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
+                               return true;
+                       break;
+               case 3:
+                       if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
+                               return true;
+                       break;
+               case 4:
+                       if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
+                               return true;
+                       break;
+               case 5:
+                       if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
+                               return true;
+                       break;
+               case 6:
+                       if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
+                               return true;
+                       break;
+               case 7:
+                       if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
+                               return true;
+                       break;
+               }
+       }
+       return false;
+}
+
 //==================================================================================
 
 static void R_UpdateEntityLighting(entity_render_t *ent)
@@ -1316,6 +1372,20 @@ static void R_View_UpdateEntityVisible (void)
                        ent = r_refdef.entities[i];
                        r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && ((ent->effects & EF_NODEPTHTEST) || r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.worldmodel, r_viewcache.world_leafvisible, ent->mins, ent->maxs));
                }
+               if(r_cullentities_trace.integer)
+               {
+                       for (i = 0;i < r_refdef.numentities;i++)
+                       {
+                               ent = r_refdef.entities[i];
+                               if(r_viewcache.entityvisible[i] && !(ent->effects & EF_NODEPTHTEST) && !(ent->model && (ent->model->name[0] == '*')))
+                               {
+                                       if(Mod_CanSeeBox_Trace(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.worldmodel, r_view.origin, ent->mins, ent->maxs))
+                                               ent->last_trace_visibility = realtime;
+                                       if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
+                                               r_viewcache.entityvisible[i] = 0;
+                               }
+                       }
+               }
        }
        else
        {
@@ -1379,6 +1449,8 @@ void R_DrawModels(void)
 
 static void R_View_SetFrustum(void)
 {
+       double slopex, slopey;
+
        // break apart the view matrix into vectors for various purposes
        Matrix4x4_ToVectors(&r_view.matrix, r_view.forward, r_view.left, r_view.up, r_view.origin);
        VectorNegate(r_view.left, r_view.right);
@@ -1447,10 +1519,12 @@ static void R_View_SetFrustum(void)
 
 
 
-       VectorMAM(1, r_view.forward, 1.0 / -r_view.frustum_x, r_view.left, r_view.frustum[0].normal);
-       VectorMAM(1, r_view.forward, 1.0 /  r_view.frustum_x, r_view.left, r_view.frustum[1].normal);
-       VectorMAM(1, r_view.forward, 1.0 / -r_view.frustum_y, r_view.up, r_view.frustum[2].normal);
-       VectorMAM(1, r_view.forward, 1.0 /  r_view.frustum_y, r_view.up, r_view.frustum[3].normal);
+       slopex = 1.0 / r_view.frustum_x;
+       slopey = 1.0 / r_view.frustum_y;
+       VectorMA(r_view.forward, -slopex, r_view.left, r_view.frustum[0].normal);
+       VectorMA(r_view.forward,  slopex, r_view.left, r_view.frustum[1].normal);
+       VectorMA(r_view.forward, -slopey, r_view.up  , r_view.frustum[2].normal);
+       VectorMA(r_view.forward,  slopey, r_view.up  , r_view.frustum[3].normal);
        VectorCopy(r_view.forward, r_view.frustum[4].normal);
        VectorNormalize(r_view.frustum[0].normal);
        VectorNormalize(r_view.frustum[1].normal);
@@ -1467,6 +1541,12 @@ static void R_View_SetFrustum(void)
        PlaneClassify(&r_view.frustum[3]);
        PlaneClassify(&r_view.frustum[4]);
 
+       // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
+       VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[0]);
+       VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward,  1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[1]);
+       VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left,  1024 * slopey, r_view.up, r_view.frustumcorner[2]);
+       VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward,  1024 * slopex, r_view.left,  1024 * slopey, r_view.up, r_view.frustumcorner[3]);
+
        // LordHavoc: note to all quake engine coders, Quake had a special case
        // for 90 degrees which assumed a square view (wrong), so I removed it,
        // Quake2 has it disabled as well.
@@ -2109,6 +2189,8 @@ void R_RenderView(void)
 extern void R_DrawLightningBeams (void);
 extern void VM_CL_AddPolygonsToMeshQueue (void);
 extern void R_DrawPortals (void);
+extern cvar_t cl_locs_show;
+static void R_DrawLocs(void);
 void R_RenderScene(void)
 {
        // don't let sound skip if going slow
@@ -2199,6 +2281,13 @@ void R_RenderScene(void)
        }
        VM_CL_AddPolygonsToMeshQueue();
 
+       if (cl_locs_show.integer)
+       {
+               R_DrawLocs();
+               if (r_timereport_active)
+                       R_TimeReport("showlocs");
+       }
+
        if (r_drawportals.integer)
        {
                R_DrawPortals();
@@ -2327,7 +2416,7 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight
                GL_DepthMask(true);
        }
        GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
-       GL_CullFace((ent->flags & RENDER_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
+       GL_CullFace((ent->effects & EF_DOUBLESIDED) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
        R_Mesh_VertexPointer(nomodelvertex3f);
        if (r_refdef.fogenabled)
        {
@@ -2587,9 +2676,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;
@@ -2633,8 +2719,8 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
                t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
        else if (t->currentalpha < 1)
                t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
-       if (ent->flags & RENDER_NOCULLFACE)
-               t->currentmaterialflags |= MATERIALFLAG_NOSHADOW;
+       if (ent->effects & EF_DOUBLESIDED)
+               t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
        if (ent->effects & EF_NODEPTHTEST)
                t->currentmaterialflags |= MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_NOSHADOW;
        if (t->currentmaterialflags & MATERIALFLAG_WATER && r_waterscroll.value != 0)
@@ -2816,8 +2902,7 @@ const model_t *rsurface_model;
 texture_t *rsurface_texture;
 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)
 {
@@ -2830,21 +2915,38 @@ void RSurf_CleanUp(void)
        rsurface_mode = RSURFMODE_NONE;
        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)
+void RSurf_ActiveWorldEntity(void)
+{
+       RSurf_CleanUp();
+       rsurface_entity = r_refdef.worldentity;
+       rsurface_model = r_refdef.worldmodel;
+       if (rsurface_array_size < rsurface_model->surfmesh.num_vertices)
+               R_Mesh_ResizeArrays(rsurface_model->surfmesh.num_vertices);
+       R_Mesh_Matrix(&identitymatrix);
+       VectorCopy(r_view.origin, rsurface_modelorg);
+       rsurface_modelvertex3f  = rsurface_model->surfmesh.data_vertex3f;
+       rsurface_modelsvector3f = rsurface_model->surfmesh.data_svector3f;
+       rsurface_modeltvector3f = rsurface_model->surfmesh.data_tvector3f;
+       rsurface_modelnormal3f  = rsurface_model->surfmesh.data_normal3f;
+       rsurface_generatedvertex = false;
+       rsurface_vertex3f  = rsurface_modelvertex3f;
+       rsurface_svector3f = rsurface_modelsvector3f;
+       rsurface_tvector3f = rsurface_modeltvector3f;
+       rsurface_normal3f  = rsurface_modelnormal3f;
+}
+
+void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
 {
        RSurf_CleanUp();
-       Matrix4x4_Transform(&ent->inversematrix, r_view.origin, rsurface_modelorg);
        rsurface_entity = ent;
        rsurface_model = ent->model;
        if (rsurface_array_size < rsurface_model->surfmesh.num_vertices)
                R_Mesh_ResizeArrays(rsurface_model->surfmesh.num_vertices);
        R_Mesh_Matrix(&ent->matrix);
        Matrix4x4_Transform(&ent->inversematrix, r_view.origin, rsurface_modelorg);
-       if ((rsurface_entity->frameblend[0].lerp != 1 || rsurface_entity->frameblend[0].frame != 0) && rsurface_model->surfmesh.isanimated)
+       if (rsurface_model->surfmesh.isanimated && (rsurface_entity->frameblend[0].lerp != 1 || rsurface_entity->frameblend[0].frame != 0))
        {
                if (wanttangents)
                {
@@ -3096,6 +3198,19 @@ static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, msurfa
        }
        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)
+               {
+                       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];
@@ -3105,12 +3220,18 @@ static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, msurfa
                        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
        {
@@ -3156,173 +3277,208 @@ 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_uselightmaptexture)
+       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);
-       if (rsurface_uselightmaptexture && !(rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
-               RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 0, -1);
-       else
-               RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+       RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
 }
 
 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
+       GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
        if (rsurface_mode != RSURFMODE_SHOWSURFACES)
        {
                rsurface_mode = RSURFMODE_SHOWSURFACES;
@@ -3356,7 +3512,7 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **te
                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_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_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
@@ -3394,59 +3550,45 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **t
        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_uselightmaptexture)
+
+       R_SetupSurfaceShader(vec3_origin, rsurface_lightmode == 2);
+       if (!r_glsl_permutation)
+               return;
+
+       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)
        {
-               int lightmode;
-               rsurface_glsl_texture = rsurface_texture;
-               rsurface_glsl_uselightmap = rsurface_uselightmaptexture;
-               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);
-               // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh
-               lightmode = ((rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2;
-               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);
-               RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist);
-               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_FULLBRIGHT)
-               {
-                       R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
-                       if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
-                               R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
-                       R_Mesh_ColorPointer(NULL);
-               }
-               else if (rsurface_uselightmaptexture)
-               {
-                       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);
-               }
-               else
-               {
-                       R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
-                       if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
-                               R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
-                       R_Mesh_ColorPointer(rsurface_model->surfmesh.data_lightmapcolor4f);
-               }
+               R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
+               if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
+                       R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
+               R_Mesh_ColorPointer(NULL);
+       }
+       else if (rsurface_uselightmaptexture)
+       {
+               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);
        }
        else
-               RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist);
-       if (!r_glsl_permutation)
-               return;
+       {
+               R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
+               if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
+                       R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
+               R_Mesh_ColorPointer(rsurface_model->surfmesh.data_lightmapcolor4f);
+       }
+
        if (rsurface_uselightmaptexture && !(rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
                RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 7, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? 8 : -1);
        else
@@ -3460,17 +3602,11 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **t
 {
        // 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
-       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
-       // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh
-       lightmode = ((rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2;
        if (rsurface_mode != RSURFMODE_MULTIPASS)
                rsurface_mode = RSURFMODE_MULTIPASS;
        RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
@@ -3520,7 +3656,12 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **t
                        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));
@@ -3529,7 +3670,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));
@@ -3576,16 +3717,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
-       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
-       // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh
-       lightmode = ((rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2;
        if (rsurface_mode != RSURFMODE_MULTIPASS)
                rsurface_mode = RSURFMODE_MULTIPASS;
        RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
@@ -3616,7 +3751,12 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **t
                                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);
@@ -3625,7 +3765,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
                        {
@@ -3635,7 +3775,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:
@@ -3645,7 +3788,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
@@ -3703,6 +3846,14 @@ static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **textur
                R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
        else if (rsurface_texture->currentnumlayers)
        {
+               GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
+               GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_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)
@@ -3714,95 +3865,288 @@ 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;
+       texture_t *texture;
+       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
-       if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
-               RSurf_ActiveEntity(ent, false, false);
+       if (ent == r_refdef.worldentity)
+               RSurf_ActiveWorldEntity();
+       else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
+               RSurf_ActiveModelEntity(ent, false, false);
        else
-               RSurf_ActiveEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
-       batchcount = 0;
-       t = NULL;
-       rsurface_uselightmaptexture = false;
-       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
-       {
-               msurface_t *surface = ent->model->data_surfaces + surfacelist[surfacelistindex];
+               RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
 
-               if (t != surface->texture || rsurface_uselightmaptexture != (surface->lightmaptexture != NULL))
+       for (i = 0;i < numsurfaces;i = j)
+       {
+               j = i + 1;
+               surface = rsurface_model->data_surfaces + surfacelist[i];
+               texture = surface->texture;
+               rsurface_texture = texture->currentframe;
+               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_uselightmaptexture = (surface->lightmaptexture != NULL);
-                       R_UpdateTextureInfo(ent, t);
-                       rsurface_texture = t->currentframe;
+                       surface = rsurface_model->data_surfaces + surfacelist[j];
+                       if (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 flagsmask)
 {
-       int texturesurfaceindex;
+       int i, j;
        vec3_t tempcenter, center;
-       if (rsurface_texture->currentmaterialflags & MATERIALFLAG_BLENDED)
+       texture_t *texture;
+       // break the surface list down into batches by texture and use of lightmapping
+       for (i = 0;i < numsurfaces;i = j)
        {
-               // drawing sky transparently would be too difficult
-               if (!(rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY))
+               j = i + 1;
+               // texture is the base texture pointer, rsurface_texture is the
+               // current frame/skin the texture is directing us to use (for example
+               // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
+               // use skin 1 instead)
+               texture = surfacelist[i]->texture;
+               rsurface_texture = texture->currentframe;
+               rsurface_uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
+               if (!(rsurface_texture->currentmaterialflags & flagsmask))
                {
-                       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+                       // if this texture is not the kind we want, skip ahead to the next one
+                       for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
+                               ;
+                       continue;
+               }
+               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
+               {
+                       // simply scan ahead until we find a different texture or lightmap state
+                       for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface_uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
+                               ;
+                       // render the range of surfaces
+                       R_DrawTextureSurfaceList(j - i, surfacelist + i);
+               }
+       }
+}
+
+float locboxvertex3f[6*4*3] =
+{
+       1,0,1, 1,0,0, 1,1,0, 1,1,1,
+       0,1,1, 0,1,0, 0,0,0, 0,0,1,
+       1,1,1, 1,1,0, 0,1,0, 0,1,1,
+       0,0,1, 0,0,0, 1,0,0, 1,0,1,
+       0,0,1, 1,0,1, 1,1,1, 0,1,1,
+       1,0,0, 0,0,0, 0,1,0, 1,1,0
+};
+
+int locboxelement3i[6*2*3] =
+{
+        0, 1, 2, 0, 2, 3,
+        4, 5, 6, 4, 6, 7,
+        8, 9,10, 8,10,11,
+       12,13,14, 12,14,15,
+       16,17,18, 16,18,19,
+       20,21,22, 20,22,23
+};
+
+void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
+{
+       int i, j;
+       cl_locnode_t *loc = (cl_locnode_t *)ent;
+       vec3_t mins, size;
+       float vertex3f[6*4*3];
+       CHECKGLERROR
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
+       GL_CullFace(GL_NONE);
+       R_Mesh_Matrix(&identitymatrix);
+
+       R_Mesh_VertexPointer(vertex3f);
+       R_Mesh_ColorPointer(NULL);
+       R_Mesh_ResetTextureState();
+
+       i = surfacelist[0];
+       GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_view.colorscale,
+                        ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_view.colorscale,
+                        ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_view.colorscale,
+                       surfacelist[0] < 0 ? 0.5f : 0.125f);
+
+       if (VectorCompare(loc->mins, loc->maxs))
+       {
+               VectorSet(size, 2, 2, 2);
+               VectorMA(loc->mins, -0.5f, size, mins);
+       }
+       else
+       {
+               VectorCopy(loc->mins, mins);
+               VectorSubtract(loc->maxs, loc->mins, size);
+       }
+
+       for (i = 0;i < 6*4*3;)
+               for (j = 0;j < 3;j++, i++)
+                       vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
+
+       R_Mesh_Draw(0, 6*4, 6*2, locboxelement3i);
+}
+
+void R_DrawLocs(void)
+{
+       int index;
+       cl_locnode_t *loc, *nearestloc;
+       vec3_t center;
+       nearestloc = CL_Locs_FindNearest(cl.movement_origin);
+       for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
+       {
+               VectorLerp(loc->mins, 0.5f, loc->maxs, center);
+               R_MeshQueue_AddTransparent(center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
+       }
+}
+
+void R_DrawCollisionBrushes(entity_render_t *ent)
+{
+       int i;
+       q3mbrush_t *brush;
+       msurface_t *surface;
+       model_t *model = ent->model;
+       if (!model->brush.num_brushes)
+               return;
+       CHECKGLERROR
+       R_Mesh_ColorPointer(NULL);
+       R_Mesh_ResetTextureState();
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+       GL_DepthMask(false);
+       GL_DepthTest(!r_showdisabledepthtest.integer);
+       qglPolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);CHECKGLERROR
+       for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
+               if (brush->colbrushf && brush->colbrushf->numtriangles)
+                       R_DrawCollisionBrush(brush->colbrushf);
+       for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
+               if (surface->num_collisiontriangles)
+                       R_DrawCollisionSurface(ent, surface);
+       qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
+}
+
+void R_DrawTrianglesAndNormals(entity_render_t *ent, qboolean drawtris, qboolean drawnormals, int flagsmask)
+{
+       int i, j, k, l;
+       const int *elements;
+       msurface_t *surface;
+       model_t *model = ent->model;
+       vec3_t v;
+       CHECKGLERROR
+       GL_DepthTest(!r_showdisabledepthtest.integer);
+       GL_DepthMask(true);
+       GL_BlendFunc(GL_ONE, GL_ZERO);
+       R_Mesh_ColorPointer(NULL);
+       R_Mesh_ResetTextureState();
+       for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
+       {
+               if (ent == r_refdef.worldentity && !r_viewcache.world_surfacevisible[j])
+                       continue;
+               rsurface_texture = surface->texture->currentframe;
+               if ((rsurface_texture->currentmaterialflags & flagsmask) && surface->num_triangles)
+               {
+                       RSurf_PrepareVerticesForBatch(true, true, 1, &surface);
+                       if (drawtris)
                        {
-                               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);
+                               if (!rsurface_texture->currentlayers->depthmask)
+                                       GL_Color(r_showtris.value * r_view.colorscale, 0, 0, 1);
+                               else if (ent == r_refdef.worldentity)
+                                       GL_Color(r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, 1);
+                               else
+                                       GL_Color(0, r_showtris.value * r_view.colorscale, 0, 1);
+                               elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
+                               CHECKGLERROR
+                               qglBegin(GL_LINES);
+                               for (k = 0;k < surface->num_triangles;k++, elements += 3)
+                               {
+                                       qglArrayElement(elements[0]);qglArrayElement(elements[1]);
+                                       qglArrayElement(elements[1]);qglArrayElement(elements[2]);
+                                       qglArrayElement(elements[2]);qglArrayElement(elements[0]);
+                               }
+                               qglEnd();
+                               CHECKGLERROR
+                       }
+                       if (drawnormals)
+                       {
+                               GL_Color(r_shownormals.value * r_view.colorscale, 0, 0, 1);
+                               qglBegin(GL_LINES);
+                               for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
+                               {
+                                       VectorCopy(rsurface_vertex3f + l * 3, v);
+                                       qglVertex3f(v[0], v[1], v[2]);
+                                       VectorMA(v, 8, rsurface_svector3f + l * 3, v);
+                                       qglVertex3f(v[0], v[1], v[2]);
+                               }
+                               qglEnd();
+                               CHECKGLERROR
+                               GL_Color(0, 0, r_shownormals.value * r_view.colorscale, 1);
+                               qglBegin(GL_LINES);
+                               for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
+                               {
+                                       VectorCopy(rsurface_vertex3f + l * 3, v);
+                                       qglVertex3f(v[0], v[1], v[2]);
+                                       VectorMA(v, 8, rsurface_tvector3f + l * 3, v);
+                                       qglVertex3f(v[0], v[1], v[2]);
+                               }
+                               qglEnd();
+                               CHECKGLERROR
+                               GL_Color(0, r_shownormals.value * r_view.colorscale, 0, 1);
+                               qglBegin(GL_LINES);
+                               for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
+                               {
+                                       VectorCopy(rsurface_vertex3f + l * 3, v);
+                                       qglVertex3f(v[0], v[1], v[2]);
+                                       VectorMA(v, 8, rsurface_normal3f + l * 3, v);
+                                       qglVertex3f(v[0], v[1], v[2]);
+                               }
+                               qglEnd();
+                               CHECKGLERROR
                        }
                }
        }
-       else
-               R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
+       rsurface_texture = NULL;
 }
 
 extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
-void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
+void R_DrawWorldSurfaces(qboolean skysurfaces)
 {
-       int i, j, k, l, endj, f, flagsmask;
+       int i, j, endj, f, flagsmask;
        int counttriangles = 0;
-       msurface_t *surface, *endsurface, **surfacechain;
+       msurface_t *surface, **surfacechain;
        texture_t *t;
-       q3mbrush_t *brush;
-       model_t *model = ent->model;
-       const int *elements;
+       model_t *model = r_refdef.worldmodel;
        const int maxsurfacelist = 1024;
        int numsurfacelist = 0;
        msurface_t *surfacelist[1024];
-       vec3_t v;
        if (model == NULL)
                return;
 
-       // 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
-       if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
-               RSurf_ActiveEntity(ent, false, false);
-       else
-               RSurf_ActiveEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
+       RSurf_ActiveWorldEntity();
 
        // update light styles
        if (!skysurfaces && model->brushq1.light_styleupdatechains)
@@ -3819,192 +4163,127 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
                }
        }
 
-       R_UpdateAllTextureInfo(ent);
+       R_UpdateAllTextureInfo(r_refdef.worldentity);
        flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
        f = 0;
        t = NULL;
        rsurface_uselightmaptexture = false;
        rsurface_texture = NULL;
        numsurfacelist = 0;
-       if (ent == r_refdef.worldentity)
-       {
-               j = model->firstmodelsurface;
-               endj = j + model->nummodelsurfaces;
-               while (j < endj)
-               {
-                       // quickly skip over non-visible surfaces
-                       for (;j < endj && !r_viewcache.world_surfacevisible[j];j++)
-                               ;
-                       // quickly iterate over visible surfaces
-                       for (;j < endj && r_viewcache.world_surfacevisible[j];j++)
-                       {
-                               // process this surface
-                               surface = model->data_surfaces + j;
-                               // if texture or lightmap has changed, start a new batch
-                               if (t != surface->texture || rsurface_uselightmaptexture != (surface->lightmaptexture != NULL))
-                               {
-                                       if (numsurfacelist)
-                                       {
-                                               R_QueueTextureSurfaceList(numsurfacelist, surfacelist);
-                                               numsurfacelist = 0;
-                                       }
-                                       t = surface->texture;
-                                       rsurface_uselightmaptexture = surface->lightmaptexture != NULL;
-                                       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 lightmap parameters changed, rebuild lightmap texture
-                                       if (surface->cached_dlight)
-                                               R_BuildLightMap(ent, surface);
-                                       // add face to draw list
-                                       surfacelist[numsurfacelist++] = surface;
-                                       counttriangles += surface->num_triangles;
-                                       if (numsurfacelist >= maxsurfacelist)
-                                       {
-                                               R_QueueTextureSurfaceList(numsurfacelist, surfacelist);
-                                               numsurfacelist = 0;
-                                       }
-                               }
-                       }
-               }
-       }
-       else
+       j = model->firstmodelsurface;
+       endj = j + model->nummodelsurfaces;
+       while (j < endj)
        {
-               surface = model->data_surfaces + model->firstmodelsurface;
-               endsurface = surface + model->nummodelsurfaces;
-               for (;surface < endsurface;surface++)
+               // quickly skip over non-visible surfaces
+               for (;j < endj && !r_viewcache.world_surfacevisible[j];j++)
+                       ;
+               // quickly iterate over visible surfaces
+               for (;j < endj && r_viewcache.world_surfacevisible[j];j++)
                {
-                       // if texture or lightmap has changed, start a new batch
-                       if (t != surface->texture || rsurface_uselightmaptexture != (surface->lightmaptexture != NULL))
-                       {
-                               if (numsurfacelist)
-                               {
-                                       R_QueueTextureSurfaceList(numsurfacelist, surfacelist);
-                                       numsurfacelist = 0;
-                               }
-                               t = surface->texture;
-                               rsurface_uselightmaptexture = (surface->lightmaptexture != NULL);
-                               rsurface_texture = t->currentframe;
-                               f = rsurface_texture->currentmaterialflags & flagsmask;
-                       }
+                       // process this surface
+                       surface = model->data_surfaces + j;
                        // if this surface fits the criteria, add it to the list
-                       if (f && surface->num_triangles)
+                       if (surface->num_triangles)
                        {
                                // if lightmap parameters changed, rebuild lightmap texture
                                if (surface->cached_dlight)
-                                       R_BuildLightMap(ent, surface);
+                                       R_BuildLightMap(r_refdef.worldentity, surface);
                                // add face to draw list
                                surfacelist[numsurfacelist++] = surface;
                                counttriangles += surface->num_triangles;
                                if (numsurfacelist >= maxsurfacelist)
                                {
-                                       R_QueueTextureSurfaceList(numsurfacelist, surfacelist);
+                                       R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
                                        numsurfacelist = 0;
                                }
                        }
                }
        }
        if (numsurfacelist)
-               R_QueueTextureSurfaceList(numsurfacelist, surfacelist);
+               R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
        r_refdef.stats.entities_triangles += counttriangles;
        RSurf_CleanUp();
 
-       if (r_showcollisionbrushes.integer && model->brush.num_brushes && !skysurfaces)
+       if (r_showcollisionbrushes.integer && !skysurfaces)
+               R_DrawCollisionBrushes(r_refdef.worldentity);
+
+       if (r_showtris.integer || r_shownormals.integer)
+               R_DrawTrianglesAndNormals(r_refdef.worldentity, r_showtris.integer, r_shownormals.integer, flagsmask);
+}
+
+void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces)
+{
+       int i, f, flagsmask;
+       int counttriangles = 0;
+       msurface_t *surface, *endsurface, **surfacechain;
+       texture_t *t;
+       model_t *model = ent->model;
+       const int maxsurfacelist = 1024;
+       int numsurfacelist = 0;
+       msurface_t *surfacelist[1024];
+       if (model == NULL)
+               return;
+
+       // 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
+       if (ent == r_refdef.worldentity)
+               RSurf_ActiveWorldEntity();
+       else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
+               RSurf_ActiveModelEntity(ent, false, false);
+       else
+               RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
+
+       // update light styles
+       if (!skysurfaces && model->brushq1.light_styleupdatechains)
        {
-               CHECKGLERROR
-               R_Mesh_Matrix(&ent->matrix);
-               R_Mesh_ColorPointer(NULL);
-               R_Mesh_ResetTextureState();
-               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
-               GL_DepthMask(false);
-               GL_DepthTest(!r_showdisabledepthtest.integer);
-               qglPolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);CHECKGLERROR
-               for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
-                       if (brush->colbrushf && brush->colbrushf->numtriangles)
-                               R_DrawCollisionBrush(brush->colbrushf);
-               for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
-                       if (surface->num_collisiontriangles)
-                               R_DrawCollisionSurface(ent, surface);
-               qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
+               for (i = 0;i < model->brushq1.light_styles;i++)
+               {
+                       if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
+                       {
+                               model->brushq1.light_stylevalue[i] = r_refdef.lightstylevalue[model->brushq1.light_style[i]];
+                               if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
+                                       for (;(surface = *surfacechain);surfacechain++)
+                                               surface->cached_dlight = true;
+                       }
+               }
        }
 
-       if (r_showtris.integer || r_shownormals.integer)
+       R_UpdateAllTextureInfo(ent);
+       flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
+       f = 0;
+       t = NULL;
+       rsurface_uselightmaptexture = false;
+       rsurface_texture = NULL;
+       numsurfacelist = 0;
+       surface = model->data_surfaces + model->firstmodelsurface;
+       endsurface = surface + model->nummodelsurfaces;
+       for (;surface < endsurface;surface++)
        {
-               CHECKGLERROR
-               GL_DepthTest(!r_showdisabledepthtest.integer);
-               GL_DepthMask(true);
-               GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_Mesh_ColorPointer(NULL);
-               R_Mesh_ResetTextureState();
-               for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
+               // if this surface fits the criteria, add it to the list
+               if (surface->num_triangles)
                {
-                       if (ent == r_refdef.worldentity && !r_viewcache.world_surfacevisible[j])
-                               continue;
-                       rsurface_texture = surface->texture->currentframe;
-                       if ((rsurface_texture->currentmaterialflags & flagsmask) && surface->num_triangles)
+                       // if lightmap parameters changed, rebuild lightmap texture
+                       if (surface->cached_dlight)
+                               R_BuildLightMap(ent, surface);
+                       // add face to draw list
+                       surfacelist[numsurfacelist++] = surface;
+                       counttriangles += surface->num_triangles;
+                       if (numsurfacelist >= maxsurfacelist)
                        {
-                               RSurf_PrepareVerticesForBatch(true, true, 1, &surface);
-                               if (r_showtris.integer)
-                               {
-                                       if (!rsurface_texture->currentlayers->depthmask)
-                                               GL_Color(r_showtris.value * r_view.colorscale, 0, 0, 1);
-                                       else if (ent == r_refdef.worldentity)
-                                               GL_Color(r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, 1);
-                                       else
-                                               GL_Color(0, r_showtris.value * r_view.colorscale, 0, 1);
-                                       elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
-                                       CHECKGLERROR
-                                       qglBegin(GL_LINES);
-                                       for (k = 0;k < surface->num_triangles;k++, elements += 3)
-                                       {
-                                               qglArrayElement(elements[0]);qglArrayElement(elements[1]);
-                                               qglArrayElement(elements[1]);qglArrayElement(elements[2]);
-                                               qglArrayElement(elements[2]);qglArrayElement(elements[0]);
-                                       }
-                                       qglEnd();
-                                       CHECKGLERROR
-                               }
-                               if (r_shownormals.integer)
-                               {
-                                       GL_Color(r_shownormals.value * r_view.colorscale, 0, 0, 1);
-                                       qglBegin(GL_LINES);
-                                       for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
-                                       {
-                                               VectorCopy(rsurface_vertex3f + l * 3, v);
-                                               qglVertex3f(v[0], v[1], v[2]);
-                                               VectorMA(v, 8, rsurface_svector3f + l * 3, v);
-                                               qglVertex3f(v[0], v[1], v[2]);
-                                       }
-                                       qglEnd();
-                                       CHECKGLERROR
-                                       GL_Color(0, 0, r_shownormals.value * r_view.colorscale, 1);
-                                       qglBegin(GL_LINES);
-                                       for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
-                                       {
-                                               VectorCopy(rsurface_vertex3f + l * 3, v);
-                                               qglVertex3f(v[0], v[1], v[2]);
-                                               VectorMA(v, 8, rsurface_tvector3f + l * 3, v);
-                                               qglVertex3f(v[0], v[1], v[2]);
-                                       }
-                                       qglEnd();
-                                       CHECKGLERROR
-                                       GL_Color(0, r_shownormals.value * r_view.colorscale, 0, 1);
-                                       qglBegin(GL_LINES);
-                                       for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
-                                       {
-                                               VectorCopy(rsurface_vertex3f + l * 3, v);
-                                               qglVertex3f(v[0], v[1], v[2]);
-                                               VectorMA(v, 8, rsurface_normal3f + l * 3, v);
-                                               qglVertex3f(v[0], v[1], v[2]);
-                                       }
-                                       qglEnd();
-                                       CHECKGLERROR
-                               }
+                               R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
+                               numsurfacelist = 0;
                        }
                }
-               rsurface_texture = NULL;
        }
+       if (numsurfacelist)
+               R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
+       r_refdef.stats.entities_triangles += counttriangles;
+       RSurf_CleanUp();
+
+       if (r_showcollisionbrushes.integer && !skysurfaces)
+               R_DrawCollisionBrushes(ent);
+
+       if (r_showtris.integer || r_shownormals.integer)
+               R_DrawTrianglesAndNormals(ent, r_showtris.integer, r_shownormals.integer, flagsmask);
 }