]> git.rm.cloudns.org Git - xonotic/darkplaces.git/commitdiff
UNMERGE
authorhavoc havoc@d7cf8633-e32d-0410-b094-e92efae38249 <>
Sat, 1 May 2010 16:48:33 +0000 (16:48 +0000)
committerRudolf Polzer <divverent@alientrap.org>
Fri, 24 Sep 2010 20:02:55 +0000 (22:02 +0200)
overhauled vertex formats, now supports 100% interleaved arrays
rendering mode, reworked vertexbuffer management to be a more robust
system, added fully vertex buffered rendering options
(gl_vbo_dynamicvertex, gl_vbo_dynamicindex) which are off by default
(they seem to hurt fps in tests here)
centralized handling of "generic" mesh rendering (fixed function stuff)

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10109 d7cf8633-e32d-0410-b094-e92efae38249
::stable-branch::unmerge=38185bc1aea210514d6970e3c36a25ad97615e5f

19 files changed:
cl_particles.c
cl_screen.c
client.h
clvm_cmds.c
gl_backend.c
gl_backend.h
gl_draw.c
gl_rmain.c
gl_rsurf.c
glquake.h
mathlib.h
model_shared.c
model_shared.h
r_explosion.c
r_shadow.c
r_shadow.h
render.h
vid.h
vid_shared.c

index 05f7b246b1c1e4dd82fb0d7df8a1f8239d9f7204..3448959704d239328ea055fb7b7425ac7861fa3a 100644 (file)
@@ -2309,11 +2309,15 @@ void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rtlight_t
        particletexture_t *tex;
        float right[3], up[3], size, ca;
        float alphascale = (1.0f / 65536.0f) * cl_particles_alpha.value;
+       float particle_vertex3f[BATCHSIZE*12], particle_texcoord2f[BATCHSIZE*8], particle_color4f[BATCHSIZE*16];
 
        RSurf_ActiveWorldEntity();
 
        r_refdef.stats.drawndecals += numsurfaces;
        R_Mesh_ResetTextureState();
+       R_Mesh_VertexPointer(particle_vertex3f, 0, 0);
+       R_Mesh_TexCoordPointer(0, 2, particle_texcoord2f, 0, 0);
+       R_Mesh_ColorPointer(particle_color4f, 0, 0);
        GL_DepthMask(false);
        GL_DepthRange(0, 1);
        GL_PolygonOffset(0, 0);
@@ -2370,8 +2374,7 @@ void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rtlight_t
        // (this assumes they all use one particle font texture!)
        GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
        R_SetupShader_Generic(particletexture[63].texture, NULL, GL_MODULATE, 1);
-       R_Mesh_PrepareVertices_Generic_Arrays(numsurfaces * 4, particle_vertex3f, particle_color4f, particle_texcoord2f);
-       R_Mesh_Draw(0, numsurfaces * 4, 0, numsurfaces * 2, NULL, NULL, 0, particle_elements, NULL, 0);
+       R_Mesh_Draw(0, numsurfaces * 4, 0, numsurfaces * 2, NULL, particle_elements, 0, 0);
 }
 
 void R_DrawDecals (void)
@@ -2474,6 +2477,9 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh
 
        r_refdef.stats.particles += numsurfaces;
        R_Mesh_ResetTextureState();
+       R_Mesh_VertexPointer(particle_vertex3f, 0, 0);
+       R_Mesh_TexCoordPointer(0, 2, particle_texcoord2f, 0, 0);
+       R_Mesh_ColorPointer(particle_color4f, 0, 0);
        GL_DepthMask(false);
        GL_DepthRange(0, 1);
        GL_PolygonOffset(0, 0);
@@ -2679,7 +2685,6 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh
        texture = NULL;
        batchstart = 0;
        batchcount = 0;
-       R_Mesh_PrepareVertices_Generic_Arrays(numsurfaces * 4, particle_vertex3f, particle_color4f, particle_texcoord2f);
        for (surfacelistindex = 0;surfacelistindex < numsurfaces;)
        {
                p = cl.particles + surfacelist[surfacelistindex];
@@ -2717,7 +2722,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh
                }
 
                batchcount = surfacelistindex - batchstart;
-               R_Mesh_Draw(batchstart * 4, batchcount * 4, batchstart * 2, batchcount * 2, NULL, NULL, 0, particle_elements, NULL, 0);
+               R_Mesh_Draw(batchstart * 4, batchcount * 4, batchstart * 2, batchcount * 2, NULL, particle_elements, 0, 0);
        }
 }
 
index 73a4a44bd931d9f9feb852a94ee9786e8c6baee4..c09ad9ce61583d9d708741f771c412f9dd54b193 100644 (file)
@@ -775,7 +775,6 @@ void R_TimeReport_EndFrame(void)
 "%7i lightmap updates (%7i pixels)\n"
 "%4i lights%4i clears%4i scissored%7i light%7i shadow%7i dynamic\n"
 "rendered%6i meshes%8i triangles bloompixels%8i copied%8i drawn\n"
-"updated%5i indexbuffers%8i bytes%5i vertexbuffers%8i bytes\n"
 "%s"
 , loc ? "Location: " : "", loc ? loc->name : ""
 , r_refdef.stats.renders, r_refdef.view.origin[0], r_refdef.view.origin[1], r_refdef.view.origin[2], r_refdef.view.forward[0], r_refdef.view.forward[1], r_refdef.view.forward[2]
@@ -785,7 +784,6 @@ void R_TimeReport_EndFrame(void)
 , r_refdef.stats.lightmapupdates, r_refdef.stats.lightmapupdatepixels
 , r_refdef.stats.lights, r_refdef.stats.lights_clears, r_refdef.stats.lights_scissored, r_refdef.stats.lights_lighttriangles, r_refdef.stats.lights_shadowtriangles, r_refdef.stats.lights_dynamicshadowtriangles
 , r_refdef.stats.meshes, r_refdef.stats.meshes_elements / 3, r_refdef.stats.bloom_copypixels, r_refdef.stats.bloom_drawpixels
-, r_refdef.stats.indexbufferuploadcount, r_refdef.stats.indexbufferuploadsize, r_refdef.stats.vertexbufferuploadcount, r_refdef.stats.vertexbufferuploadsize
 , r_speeds_timestring);
 
                memset(&r_refdef.stats, 0, sizeof(r_refdef.stats));
@@ -1913,7 +1911,10 @@ static void SCR_DrawLoadingStack(void)
                GL_DepthRange(0, 1);
                GL_PolygonOffset(0, 0);
                GL_DepthTest(false);
+               R_Mesh_VertexPointer(verts, 0, 0);
+               R_Mesh_ColorPointer(colors, 0, 0);
                R_Mesh_ResetTextureState();
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
                verts[2] = verts[5] = verts[8] = verts[11] = 0;
                verts[0] = verts[9] = 0;
                verts[1] = verts[4] = vid_conheight.integer - scr_loadingscreen_barheight.value;
@@ -1931,9 +1932,7 @@ static void SCR_DrawLoadingStack(void)
                sscanf(scr_loadingscreen_barcolor.string, "%f %f %f", &colors[8], &colors[9], &colors[10]); colors[11] = 1;
                sscanf(scr_loadingscreen_barcolor.string, "%f %f %f", &colors[12], &colors[13], &colors[14]);  colors[15] = 1;
 
-               R_Mesh_PrepareVertices_Generic_Arrays(4, verts, colors, NULL);
-               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
-               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
 
                // make sure everything is cleared, including the progress indicator
                if(loadingscreenheight < 8)
@@ -1983,20 +1982,25 @@ static void SCR_DrawLoadingScreen_SharedSetup (qboolean clear)
 static void SCR_DrawLoadingScreen (qboolean clear)
 {
        // we only need to draw the image if it isn't already there
+       GL_Color(1,1,1,1);
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        GL_DepthRange(0, 1);
        GL_PolygonOffset(0, 0);
        GL_DepthTest(false);
-       R_Mesh_ResetTextureState();
-       GL_Color(1,1,1,1);
-       R_Mesh_PrepareVertices_Generic_Arrays(4, loadingscreentexture_vertex3f, NULL, loadingscreentexture_texcoord2f);
+       R_Mesh_ColorPointer(NULL, 0, 0);
        if(loadingscreentexture)
        {
+               R_Mesh_VertexPointer(loadingscreentexture_vertex3f, 0, 0);
+               R_Mesh_ResetTextureState();
                R_SetupShader_Generic(loadingscreentexture, NULL, GL_MODULATE, 1);
-               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+               R_Mesh_TexCoordPointer(0, 2, loadingscreentexture_texcoord2f, 0, 0);
+               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
        }
+       R_Mesh_VertexPointer(loadingscreenpic_vertex3f, 0, 0);
+       R_Mesh_ResetTextureState();
        R_SetupShader_Generic(loadingscreenpic->tex, NULL, GL_MODULATE, 1);
-       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+       R_Mesh_TexCoordPointer(0, 2, loadingscreenpic_texcoord2f, 0, 0);
+       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
        SCR_DrawLoadingStack();
 }
 
index b90ca35b512c6e821db2613fb9b1ed92a095a408..848e44277a603866363f6b5308a257cc73edf502 100644 (file)
--- a/client.h
+++ b/client.h
@@ -368,11 +368,6 @@ typedef struct entity_render_s
        float *animcache_normal3f;
        float *animcache_svector3f;
        float *animcache_tvector3f;
-       // interleaved arrays for rendering and dynamic vertex buffers for them
-       r_vertexposition_t *animcache_vertexposition;
-       r_meshbuffer_t *animcache_vertexpositionbuffer;
-       r_vertexmesh_t *animcache_vertexmesh;
-       r_meshbuffer_t *animcache_vertexmeshbuffer;
 
        // current lighting from map (updated ONLY by client code, not renderer)
        vec3_t modellight_ambient;
@@ -1556,10 +1551,6 @@ typedef struct r_refdef_stats_s
        int bloom;
        int bloom_copypixels;
        int bloom_drawpixels;
-       int indexbufferuploadcount;
-       int indexbufferuploadsize;
-       int vertexbufferuploadcount;
-       int vertexbufferuploadsize;
 }
 r_refdef_stats_t;
 
index cae5257c728634327455d48ca80d2aa532ab0c22..3c3a984bed86dd06c9a1136b2eba34588a0b6782 100644 (file)
@@ -3075,7 +3075,9 @@ static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t
        R_Mesh_ResetTextureState();
        R_EntityMatrix(&identitymatrix);
        GL_CullFace(GL_NONE);
-       R_Mesh_PrepareVertices_Generic_Arrays(polys->num_vertices, polys->data_vertex3f, polys->data_color4f, polys->data_texcoord2f);
+       R_Mesh_VertexPointer(polys->data_vertex3f, 0, 0);
+       R_Mesh_ColorPointer(polys->data_color4f, 0, 0);
+       R_Mesh_TexCoordPointer(0, 2, polys->data_texcoord2f, 0, 0);
 
        for (surfacelistindex = 0;surfacelistindex < numsurfaces;)
        {
@@ -3092,7 +3094,7 @@ static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t
                        VectorCopy(polys->data_triangles[surfacelist[surfacelistindex]].elements, polys->data_sortedelement3s + 3*numtriangles);
                        numtriangles++;
                }
-               R_Mesh_Draw(0, polys->num_vertices, 0, numtriangles, NULL, NULL, 0, polys->data_sortedelement3s, NULL, 0);
+               R_Mesh_Draw(0, polys->num_vertices, 0, numtriangles, NULL, polys->data_sortedelement3s, 0, 0);
        }
 }
 
index df64d630f9789fdcffce746a8664765ed9b8b13c..bd2d422099059861b5d98052afe578e8b31954e3 100644 (file)
@@ -3,9 +3,9 @@
 #include "cl_collision.h"
 
 cvar_t gl_mesh_drawrangeelements = {0, "gl_mesh_drawrangeelements", "1", "use glDrawRangeElements function if available instead of glDrawElements (for performance comparisons or bug testing)"};
+cvar_t gl_mesh_testarrayelement = {0, "gl_mesh_testarrayelement", "0", "use glBegin(GL_TRIANGLES);glArrayElement();glEnd(); primitives instead of glDrawElements (useful to test for driver bugs with glDrawElements)"};
 cvar_t gl_mesh_testmanualfeeding = {0, "gl_mesh_testmanualfeeding", "0", "use glBegin(GL_TRIANGLES);glTexCoord2f();glVertex3f();glEnd(); primitives instead of glDrawElements (useful to test for driver bugs with glDrawElements)"};
-cvar_t gl_mesh_prefer_short_elements = {CVAR_SAVE, "gl_mesh_prefer_short_elements", "1", "use GL_UNSIGNED_SHORT element arrays instead of GL_UNSIGNED_INT"};
-cvar_t gl_mesh_separatearrays = {0, "gl_mesh_separatearrays", "1", "use several separate vertex arrays rather than one combined stream"};
+cvar_t gl_mesh_prefer_short_elements = {0, "gl_mesh_prefer_short_elements", "1", "use GL_UNSIGNED_SHORT element arrays instead of GL_UNSIGNED_INT"};
 cvar_t gl_paranoid = {0, "gl_paranoid", "0", "enables OpenGL error checking and other tests"};
 cvar_t gl_printcheckerror = {0, "gl_printcheckerror", "0", "prints all OpenGL error checks, useful to identify location of driver crashes"};
 
@@ -15,8 +15,6 @@ cvar_t r_waterwarp = {CVAR_SAVE, "r_waterwarp", "1", "warp view while underwater
 cvar_t gl_polyblend = {CVAR_SAVE, "gl_polyblend", "1", "tints view while underwater, hurt, etc"};
 cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1", "enables OpenGL dithering (16bit looks bad with this off)"};
 cvar_t gl_vbo = {CVAR_SAVE, "gl_vbo", "3", "make use of GL_ARB_vertex_buffer_object extension to store static geometry in video memory for faster rendering, 0 disables VBO allocation or use, 1 enables VBOs for vertex and triangle data, 2 only for vertex data, 3 for vertex data and triangle data of simple meshes (ones with only one surface)"};
-cvar_t gl_vbo_dynamicvertex = {CVAR_SAVE, "gl_vbo_dynamicvertex", "0", "make use of GL_ARB_vertex_buffer_object extension when rendering dynamic (animated/procedural) geometry such as text and particles"};
-cvar_t gl_vbo_dynamicindex = {CVAR_SAVE, "gl_vbo_dynamicindex", "0", "make use of GL_ARB_vertex_buffer_object extension when rendering dynamic (animated/procedural) geometry such as text and particles"};
 cvar_t gl_fbo = {CVAR_SAVE, "gl_fbo", "1", "make use of GL_ARB_framebuffer_object extension to enable shadowmaps and other features using pixel formats different from the framebuffer"};
 
 cvar_t v_flipped = {0, "v_flipped", "0", "mirror the screen (poor man's left handed mode)"};
@@ -93,17 +91,23 @@ void GL_PrintError(int errornumber, char *filename, int linenumber)
 
 void SCR_ScreenShot_f (void);
 
+typedef struct gl_bufferobjectinfo_s
+{
+       int target;
+       int object;
+       size_t size;
+       char name[MAX_QPATH];
+}
+gl_bufferobjectinfo_t;
+
 typedef struct gltextureunit_s
 {
-       int pointer_texcoord_components;
-       int pointer_texcoord_gltype;
-       size_t pointer_texcoord_stride;
-       const void *pointer_texcoord_pointer;
-       const r_meshbuffer_t *pointer_texcoord_vertexbuffer;
+       const void *pointer_texcoord;
        size_t pointer_texcoord_offset;
-
+       int pointer_texcoord_buffer;
        int t2d, t3d, tcubemap, trectangle;
        int arrayenabled;
+       unsigned int arraycomponents;
        int rgbscale, alphascale;
        int combine;
        int combinergb, combinealpha;
@@ -136,37 +140,14 @@ typedef struct gl_state_s
        int vertexbufferobject;
        int elementbufferobject;
        qboolean pointer_color_enabled;
-
-       int pointer_vertex_components;
-       int pointer_vertex_gltype;
-       size_t pointer_vertex_stride;
-       const void *pointer_vertex_pointer;
-       const r_meshbuffer_t *pointer_vertex_vertexbuffer;
+       const void *pointer_vertex;
+       const void *pointer_color;
        size_t pointer_vertex_offset;
-
-       int pointer_color_components;
-       int pointer_color_gltype;
-       size_t pointer_color_stride;
-       const void *pointer_color_pointer;
-       const r_meshbuffer_t *pointer_color_vertexbuffer;
        size_t pointer_color_offset;
+       int pointer_vertex_buffer;
+       int pointer_color_buffer;
 
-       void *preparevertices_tempdata;
-       size_t preparevertices_tempdatamaxsize;
-       r_meshbuffer_t *preparevertices_dynamicvertexbuffer;
-       r_vertexposition_t *preparevertices_vertexposition;
-       r_vertexgeneric_t *preparevertices_vertexgeneric;
-       r_vertexmesh_t *preparevertices_vertexmesh;
-       int preparevertices_numvertices;
-
-       r_meshbuffer_t *draw_dynamicindexbuffer;
-
-       qboolean usevbo_staticvertex;
-       qboolean usevbo_staticindex;
-       qboolean usevbo_dynamicvertex;
-       qboolean usevbo_dynamicindex;
-
-       memexpandablearray_t meshbufferarray;
+       memexpandablearray_t bufferobjectinfoarray;
 
        qboolean active;
 }
@@ -245,11 +226,7 @@ static void gl_backend_start(void)
 {
        memset(&gl_state, 0, sizeof(gl_state));
 
-       gl_state.usevbo_staticvertex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo;
-       gl_state.usevbo_staticindex = (vid.support.arb_vertex_buffer_object && (gl_vbo.integer == 1 || gl_vbo.integer == 3)) || vid.forcevbo;
-       gl_state.usevbo_dynamicvertex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicvertex.integer) || vid.forcevbo;
-       gl_state.usevbo_dynamicindex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicindex.integer) || vid.forcevbo;
-       Mem_ExpandableArray_NewArray(&gl_state.meshbufferarray, r_main_mempool, sizeof(r_meshbuffer_t), 128);
+       Mem_ExpandableArray_NewArray(&gl_state.bufferobjectinfoarray, r_main_mempool, sizeof(gl_bufferobjectinfo_t), 128);
 
        Con_DPrintf("OpenGL backend started.\n");
 
@@ -262,12 +239,7 @@ static void gl_backend_shutdown(void)
 {
        Con_DPrint("OpenGL Backend shutting down\n");
 
-       if (gl_state.preparevertices_tempdata)
-               Mem_Free(gl_state.preparevertices_tempdata);
-       if (gl_state.preparevertices_dynamicvertexbuffer)
-               R_Mesh_DestroyMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer);
-
-       Mem_ExpandableArray_FreeArray(&gl_state.meshbufferarray);
+       Mem_ExpandableArray_FreeArray(&gl_state.bufferobjectinfoarray);
 
        memset(&gl_state, 0, sizeof(gl_state));
 }
@@ -309,15 +281,13 @@ void gl_backend_init(void)
        Cvar_RegisterVariable(&v_flipped);
        Cvar_RegisterVariable(&gl_dither);
        Cvar_RegisterVariable(&gl_vbo);
-       Cvar_RegisterVariable(&gl_vbo_dynamicvertex);
-       Cvar_RegisterVariable(&gl_vbo_dynamicindex);
        Cvar_RegisterVariable(&gl_paranoid);
        Cvar_RegisterVariable(&gl_printcheckerror);
 
        Cvar_RegisterVariable(&gl_mesh_drawrangeelements);
+       Cvar_RegisterVariable(&gl_mesh_testarrayelement);
        Cvar_RegisterVariable(&gl_mesh_testmanualfeeding);
        Cvar_RegisterVariable(&gl_mesh_prefer_short_elements);
-       Cvar_RegisterVariable(&gl_mesh_separatearrays);
 
        Cmd_AddCommand("gl_vbostats", GL_VBOStats_f, "prints a list of all buffer objects (vertex data and triangle elements) and total video memory used by them");
 
@@ -1064,10 +1034,6 @@ void R_Mesh_Start(void)
 {
        BACKENDACTIVECHECK
        CHECKGLERROR
-       gl_state.usevbo_staticvertex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo;
-       gl_state.usevbo_staticindex = (vid.support.arb_vertex_buffer_object && (gl_vbo.integer == 1 || gl_vbo.integer == 3)) || vid.forcevbo;
-       gl_state.usevbo_dynamicvertex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicvertex.integer) || vid.forcevbo;
-       gl_state.usevbo_dynamicindex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicindex.integer) || vid.forcevbo;
        if (gl_printcheckerror.integer && !gl_paranoid.integer)
        {
                Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n");
@@ -1173,84 +1139,46 @@ void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
 
 // renders triangles using vertices from the active arrays
 int paranoidblah = 0;
-void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const r_meshbuffer_t *element3i_indexbuffer, size_t element3i_bufferoffset, const unsigned short *element3s, const r_meshbuffer_t *element3s_indexbuffer, size_t element3s_bufferoffset)
+void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int bufferobject3i, int bufferobject3s)
 {
        unsigned int numelements = numtriangles * 3;
-       int bufferobject3i;
-       size_t bufferoffset3i;
-       int bufferobject3s;
-       size_t bufferoffset3s;
        if (numvertices < 3 || numtriangles < 1)
        {
                if (numvertices < 0 || numtriangles < 0 || developer_extra.integer)
-                       Con_DPrintf("R_Mesh_Draw(%d, %d, %d, %d, %8p, %8p, %8x, %8p, %8p, %8x);\n", firstvertex, numvertices, firsttriangle, numtriangles, (void *)element3i, (void *)element3i_indexbuffer, (int)element3i_bufferoffset, (void *)element3s, (void *)element3s_indexbuffer, (int)element3s_bufferoffset);
-               return;
-       }
-       if (gl_state.pointer_vertex_pointer == NULL)
-       {
-               Con_DPrintf("R_Mesh_Draw with no vertex pointer!\n");
+                       Con_DPrintf("R_Mesh_Draw(%d, %d, %d, %d, %8p, %8p, %i, %i);\n", firstvertex, numvertices, firsttriangle, numtriangles, (void *)element3i, (void *)element3s, bufferobject3i, bufferobject3s);
                return;
        }
        if (!gl_mesh_prefer_short_elements.integer)
        {
                if (element3i)
                        element3s = NULL;
-               if (element3i_indexbuffer)
-                       element3i_indexbuffer = NULL;
+               if (bufferobject3i)
+                       bufferobject3s = 0;
        }
-       // adjust the pointers for firsttriangle
        if (element3i)
                element3i += firsttriangle * 3;
-       if (element3i_indexbuffer)
-               element3i_bufferoffset += firsttriangle * 3 * sizeof(*element3i);
        if (element3s)
                element3s += firsttriangle * 3;
-       if (element3s_indexbuffer)
-               element3s_bufferoffset += firsttriangle * 3 * sizeof(*element3s);
-       // check if the user specified to ignore static index buffers
-       if (!gl_state.usevbo_staticindex || (gl_vbo.integer == 3 && !vid.forcevbo && (element3i_bufferoffset || element3s_bufferoffset)))
-       {
-               element3i_indexbuffer = NULL;
-               element3s_indexbuffer = NULL;
-       }
-       // upload a dynamic index buffer if needed
-       if (element3s)
+       switch (gl_vbo.integer)
        {
-               if (!element3s_indexbuffer && gl_state.usevbo_dynamicindex)
-               {
-                       if (gl_state.draw_dynamicindexbuffer)
-                               R_Mesh_UpdateMeshBuffer(gl_state.draw_dynamicindexbuffer, (void *)element3s, numelements * sizeof(*element3s));
-                       else
-                               gl_state.draw_dynamicindexbuffer = R_Mesh_CreateMeshBuffer((void *)element3s, numelements * sizeof(*element3s), "temporary", true, true);
-                       element3s_indexbuffer = gl_state.draw_dynamicindexbuffer;
-                       element3s_bufferoffset = 0;
-               }
-       }
-       else if (element3i)
-       {
-               if (!element3i_indexbuffer && gl_state.usevbo_dynamicindex)
-               {
-                       if (gl_state.draw_dynamicindexbuffer)
-                               R_Mesh_UpdateMeshBuffer(gl_state.draw_dynamicindexbuffer, (void *)element3i, numelements * sizeof(*element3i));
-                       else
-                               gl_state.draw_dynamicindexbuffer = R_Mesh_CreateMeshBuffer((void *)element3i, numelements * sizeof(*element3i), "temporary", true, true);
-                       element3i_indexbuffer = gl_state.draw_dynamicindexbuffer;
-                       element3i_bufferoffset = 0;
-               }
+       default:
+       case 0:
+       case 2:
+               bufferobject3i = bufferobject3s = 0;
+               break;
+       case 1:
+               break;
+       case 3:
+               if (firsttriangle)
+                       bufferobject3i = bufferobject3s = 0;
+               break;
        }
-       bufferobject3i = element3i_indexbuffer ? element3i_indexbuffer->bufferobject : 0;
-       bufferoffset3i = element3i_bufferoffset;
-       bufferobject3s = element3s_indexbuffer ? element3s_indexbuffer->bufferobject : 0;
-       bufferoffset3s = element3s_bufferoffset;
        CHECKGLERROR
        r_refdef.stats.meshes++;
        r_refdef.stats.meshes_elements += numelements;
        if (gl_paranoid.integer)
        {
-               unsigned int i;
-               // LordHavoc: disabled this - it needs to be updated to handle components and gltype and stride in each array
-#if 0
-               unsigned int j, size;
+               unsigned int i, j, size;
                const int *p;
                // note: there's no validation done here on buffer objects because it
                // is somewhat difficult to get at the data, and gl_paranoid can be
@@ -1260,7 +1188,7 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
                if (!qglIsEnabled(GL_VERTEX_ARRAY))
                        Con_Print("R_Mesh_Draw: vertex array not enabled\n");
                CHECKGLERROR
-               if (gl_state.pointer_vertex_pointer)
+               if (gl_state.pointer_vertex)
                        for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++)
                                paranoidblah += *p;
                if (gl_state.pointer_color_enabled)
@@ -1285,7 +1213,6 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
                                                paranoidblah += *p;
                        }
                }
-#endif
                if (element3i)
                {
                        for (i = 0;i < (unsigned int) numtriangles * 3;i++)
@@ -1320,119 +1247,83 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
                        qglBegin(GL_TRIANGLES);
                        for (i = 0;i < (unsigned int) numtriangles * 3;i++)
                        {
-                               if (element3i)
-                                       element = element3i[i];
-                               else if (element3s)
-                                       element = element3s[i];
-                               else
-                                       element = firstvertex + i;
+                               element = element3i ? element3i[i] : element3s[i];
                                for (j = 0;j < vid.texarrayunits;j++)
                                {
-                                       if (gl_state.units[j].pointer_texcoord_pointer && gl_state.units[j].arrayenabled)
+                                       if (gl_state.units[j].pointer_texcoord && gl_state.units[j].arrayenabled)
                                        {
-                                               if (gl_state.units[j].pointer_texcoord_gltype == GL_FLOAT)
+                                               if (vid.texarrayunits > 1)
                                                {
-                                                       p = (const GLfloat *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
-                                                       if (vid.texarrayunits > 1)
+                                                       if (gl_state.units[j].arraycomponents == 4)
                                                        {
-                                                               if (gl_state.units[j].pointer_texcoord_components == 4)
-                                                                       qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
-                                                               else if (gl_state.units[j].pointer_texcoord_components == 3)
-                                                                       qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
-                                                               else if (gl_state.units[j].pointer_texcoord_components == 2)
-                                                                       qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
-                                                               else
-                                                                       qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
+                                                               p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 4;
+                                                               qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
                                                        }
-                                                       else
+                                                       else if (gl_state.units[j].arraycomponents == 3)
                                                        {
-                                                               if (gl_state.units[j].pointer_texcoord_components == 4)
-                                                                       qglTexCoord4f(p[0], p[1], p[2], p[3]);
-                                                               else if (gl_state.units[j].pointer_texcoord_components == 3)
-                                                                       qglTexCoord3f(p[0], p[1], p[2]);
-                                                               else if (gl_state.units[j].pointer_texcoord_components == 2)
-                                                                       qglTexCoord2f(p[0], p[1]);
-                                                               else
-                                                                       qglTexCoord1f(p[0]);
+                                                               p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 3;
+                                                               qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
                                                        }
-                                               }
-                                               else if (gl_state.units[j].pointer_texcoord_gltype == GL_SHORT)
-                                               {
-                                                       const GLshort *s = (const GLshort *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
-                                                       if (vid.texarrayunits > 1)
+                                                       else if (gl_state.units[j].arraycomponents == 2)
                                                        {
-                                                               if (gl_state.units[j].pointer_texcoord_components == 4)
-                                                                       qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2], s[3]);
-                                                               else if (gl_state.units[j].pointer_texcoord_components == 3)
-                                                                       qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2]);
-                                                               else if (gl_state.units[j].pointer_texcoord_components == 2)
-                                                                       qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, s[0], s[1]);
-                                                               else if (gl_state.units[j].pointer_texcoord_components == 1)
-                                                                       qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, s[0]);
+                                                               p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 2;
+                                                               qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
                                                        }
                                                        else
                                                        {
-                                                               if (gl_state.units[j].pointer_texcoord_components == 4)
-                                                                       qglTexCoord4f(s[0], s[1], s[2], s[3]);
-                                                               else if (gl_state.units[j].pointer_texcoord_components == 3)
-                                                                       qglTexCoord3f(s[0], s[1], s[2]);
-                                                               else if (gl_state.units[j].pointer_texcoord_components == 2)
-                                                                       qglTexCoord2f(s[0], s[1]);
-                                                               else if (gl_state.units[j].pointer_texcoord_components == 1)
-                                                                       qglTexCoord1f(s[0]);
+                                                               p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 1;
+                                                               qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
                                                        }
                                                }
-                                               else if (gl_state.units[j].pointer_texcoord_gltype == GL_BYTE)
+                                               else
                                                {
-                                                       const GLbyte *sb = (const GLbyte *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
-                                                       if (vid.texarrayunits > 1)
+                                                       if (gl_state.units[j].arraycomponents == 4)
+                                                       {
+                                                               p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 4;
+                                                               qglTexCoord4f(p[0], p[1], p[2], p[3]);
+                                                       }
+                                                       else if (gl_state.units[j].arraycomponents == 3)
                                                        {
-                                                               if (gl_state.units[j].pointer_texcoord_components == 4)
-                                                                       qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2], sb[3]);
-                                                               else if (gl_state.units[j].pointer_texcoord_components == 3)
-                                                                       qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2]);
-                                                               else if (gl_state.units[j].pointer_texcoord_components == 2)
-                                                                       qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, sb[0], sb[1]);
-                                                               else if (gl_state.units[j].pointer_texcoord_components == 1)
-                                                                       qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, sb[0]);
+                                                               p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 3;
+                                                               qglTexCoord3f(p[0], p[1], p[2]);
+                                                       }
+                                                       else if (gl_state.units[j].arraycomponents == 2)
+                                                       {
+                                                               p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 2;
+                                                               qglTexCoord2f(p[0], p[1]);
                                                        }
                                                        else
                                                        {
-                                                               if (gl_state.units[j].pointer_texcoord_components == 4)
-                                                                       qglTexCoord4f(sb[0], sb[1], sb[2], sb[3]);
-                                                               else if (gl_state.units[j].pointer_texcoord_components == 3)
-                                                                       qglTexCoord3f(sb[0], sb[1], sb[2]);
-                                                               else if (gl_state.units[j].pointer_texcoord_components == 2)
-                                                                       qglTexCoord2f(sb[0], sb[1]);
-                                                               else if (gl_state.units[j].pointer_texcoord_components == 1)
-                                                                       qglTexCoord1f(sb[0]);
+                                                               p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 1;
+                                                               qglTexCoord1f(p[0]);
                                                        }
                                                }
                                        }
                                }
-                               if (gl_state.pointer_color_pointer && gl_state.pointer_color_enabled && gl_state.pointer_color_components == 4)
+                               if (gl_state.pointer_color && gl_state.pointer_color_enabled)
                                {
-                                       if (gl_state.pointer_color_gltype == GL_FLOAT)
-                                       {
-                                               p = (const GLfloat *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
-                                               qglColor4f(p[0], p[1], p[2], p[3]);
-                                       }
-                                       else if (gl_state.pointer_color_gltype == GL_UNSIGNED_BYTE)
-                                       {
-                                               const GLubyte *ub = (const GLubyte *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
-                                               qglColor4ub(ub[0], ub[1], ub[2], ub[3]);
-                                       }
-                               }
-                               if (gl_state.pointer_vertex_gltype == GL_FLOAT)
-                               {
-                                       p = (const GLfloat *)((const unsigned char *)gl_state.pointer_vertex_pointer + element * gl_state.pointer_vertex_stride);
-                                       if (gl_state.pointer_vertex_components == 4)
-                                               qglVertex4f(p[0], p[1], p[2], p[3]);
-                                       else if (gl_state.pointer_vertex_components == 3)
-                                               qglVertex3f(p[0], p[1], p[2]);
-                                       else
-                                               qglVertex2f(p[0], p[1]);
+                                       p = ((const GLfloat *)(gl_state.pointer_color)) + element * 4;
+                                       qglColor4f(p[0], p[1], p[2], p[3]);
                                }
+                               p = ((const GLfloat *)(gl_state.pointer_vertex)) + element * 3;
+                               qglVertex3f(p[0], p[1], p[2]);
+                       }
+                       qglEnd();
+                       CHECKGLERROR
+               }
+               else if (gl_mesh_testarrayelement.integer)
+               {
+                       int i;
+                       qglBegin(GL_TRIANGLES);
+                       if (element3i)
+                       {
+                               for (i = 0;i < numtriangles * 3;i++)
+                                       qglArrayElement(element3i[i]);
+                       }
+                       else if (element3s)
+                       {
+                               for (i = 0;i < numtriangles * 3;i++)
+                                       qglArrayElement(element3s[i]);
                        }
                        qglEnd();
                        CHECKGLERROR
@@ -1442,7 +1333,7 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
                        GL_BindEBO(bufferobject3s);
                        if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
                        {
-                               qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s);
+                               qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, (void *)(firsttriangle * sizeof(unsigned short[3])));
                                CHECKGLERROR
                        }
                        else
@@ -1456,7 +1347,7 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
                        GL_BindEBO(bufferobject3i);
                        if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
                        {
-                               qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, (void *)bufferoffset3i);
+                               qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, (void *)(firsttriangle * sizeof(unsigned int[3])));
                                CHECKGLERROR
                        }
                        else
@@ -1493,11 +1384,6 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
                                CHECKGLERROR
                        }
                }
-               else
-               {
-                       qglDrawArrays(GL_TRIANGLES, firstvertex, numvertices);
-                       CHECKGLERROR
-               }
        }
 }
 
@@ -1506,91 +1392,52 @@ void R_Mesh_Finish(void)
 {
 }
 
-r_meshbuffer_t *R_Mesh_CreateMeshBuffer(const void *data, size_t size, const char *name, qboolean isindexbuffer, qboolean isdynamic)
+int R_Mesh_CreateStaticBufferObject(unsigned int target, void *data, size_t size, const char *name)
 {
-       int bufferobject = 0;
-       void *devicebuffer = NULL;
-       r_meshbuffer_t *buffer;
-       if (!(isdynamic ? (isindexbuffer ? gl_state.usevbo_dynamicindex : gl_state.usevbo_dynamicvertex) : (isindexbuffer ? gl_state.usevbo_staticindex : gl_state.usevbo_staticvertex)))
-               return NULL;
-       if (isindexbuffer)
-       {
-               r_refdef.stats.indexbufferuploadcount++;
-               r_refdef.stats.indexbufferuploadsize += size;
-       }
-       else
-       {
-               r_refdef.stats.vertexbufferuploadcount++;
-               r_refdef.stats.vertexbufferuploadsize += size;
-       }
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-               qglGenBuffersARB(1, (GLuint *)&bufferobject);
-               if (isindexbuffer)
-                       GL_BindEBO(bufferobject);
-               else
-                       GL_BindVBO(bufferobject);
-               qglBufferDataARB(isindexbuffer ? GL_ELEMENT_ARRAY_BUFFER_ARB : GL_ARRAY_BUFFER_ARB, size, data, isdynamic ? GL_STREAM_DRAW_ARB : GL_STATIC_DRAW_ARB);
-               break;
-       }
-       buffer = (r_meshbuffer_t *)Mem_ExpandableArray_AllocRecord(&gl_state.meshbufferarray);
-       memset(buffer, 0, sizeof(*buffer));
-       buffer->bufferobject = bufferobject;
-       buffer->devicebuffer = devicebuffer;
-       buffer->size = size;
-       buffer->isindexbuffer = isindexbuffer;
-       buffer->isdynamic = isdynamic;
-       strlcpy(buffer->name, name, sizeof(buffer->name));
-       return buffer;
-}
+       gl_bufferobjectinfo_t *info;
+       GLuint bufferobject;
 
-void R_Mesh_UpdateMeshBuffer(r_meshbuffer_t *buffer, const void *data, size_t size)
-{
-       if (!buffer || (!buffer->bufferobject && !buffer->devicebuffer))
-               return;
-       if (buffer->isindexbuffer)
-       {
-               r_refdef.stats.indexbufferuploadcount++;
-               r_refdef.stats.indexbufferuploadsize += size;
-       }
-       else
-       {
-               r_refdef.stats.vertexbufferuploadcount++;
-               r_refdef.stats.vertexbufferuploadsize += size;
-       }
-       switch(vid.renderpath)
+       if (!gl_vbo.integer)
+               return 0;
+
+       qglGenBuffersARB(1, &bufferobject);
+       switch(target)
        {
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-               if (buffer->isindexbuffer)
-                       GL_BindEBO(buffer->bufferobject);
-               else
-                       GL_BindVBO(buffer->bufferobject);
-               qglBufferDataARB(buffer->isindexbuffer ? GL_ELEMENT_ARRAY_BUFFER_ARB : GL_ARRAY_BUFFER_ARB, size, data, buffer->isdynamic ? GL_STREAM_DRAW_ARB : GL_STATIC_DRAW_ARB);
-               break;
+       case GL_ELEMENT_ARRAY_BUFFER_ARB: GL_BindEBO(bufferobject);break;
+       case GL_ARRAY_BUFFER_ARB: GL_BindVBO(bufferobject);break;
+       default: Sys_Error("R_Mesh_CreateStaticBufferObject: unknown target type %i\n", target);return 0;
        }
+       qglBufferDataARB(target, size, data, GL_STATIC_DRAW_ARB);
+
+       info = (gl_bufferobjectinfo_t *) Mem_ExpandableArray_AllocRecord(&gl_state.bufferobjectinfoarray);
+       memset(info, 0, sizeof(*info));
+       info->target = target;
+       info->object = bufferobject;
+       info->size = size;
+       strlcpy(info->name, name, sizeof(info->name));
+
+       return (int)bufferobject;
 }
 
-void R_Mesh_DestroyMeshBuffer(r_meshbuffer_t *buffer)
+void R_Mesh_DestroyBufferObject(int bufferobject)
 {
-       if (!buffer)
-               return;
-       switch(vid.renderpath)
+       int i, endindex;
+       gl_bufferobjectinfo_t *info;
+
+       qglDeleteBuffersARB(1, (GLuint *)&bufferobject);
+
+       endindex = Mem_ExpandableArray_IndexRange(&gl_state.bufferobjectinfoarray);
+       for (i = 0;i < endindex;i++)
        {
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-               qglDeleteBuffersARB(1, (GLuint *)&buffer->bufferobject);
-               break;
+               info = (gl_bufferobjectinfo_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.bufferobjectinfoarray, i);
+               if (!info)
+                       continue;
+               if (info->object == bufferobject)
+               {
+                       Mem_ExpandableArray_FreeRecord(&gl_state.bufferobjectinfoarray, (void *)info);
+                       break;
+               }
        }
-       Mem_ExpandableArray_FreeRecord(&gl_state.meshbufferarray, (void *)buffer);
 }
 
 void GL_Mesh_ListVBOs(qboolean printeach)
@@ -1598,45 +1445,47 @@ void GL_Mesh_ListVBOs(qboolean printeach)
        int i, endindex;
        size_t ebocount = 0, ebomemory = 0;
        size_t vbocount = 0, vbomemory = 0;
-       r_meshbuffer_t *buffer;
-       endindex = Mem_ExpandableArray_IndexRange(&gl_state.meshbufferarray);
+       gl_bufferobjectinfo_t *info;
+       endindex = Mem_ExpandableArray_IndexRange(&gl_state.bufferobjectinfoarray);
        for (i = 0;i < endindex;i++)
        {
-               buffer = (r_meshbuffer_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.meshbufferarray, i);
-               if (!buffer)
+               info = (gl_bufferobjectinfo_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.bufferobjectinfoarray, i);
+               if (!info)
                        continue;
-               if (buffer->isindexbuffer) {ebocount++;ebomemory += buffer->size;if (printeach) Con_Printf("indexbuffer #%i %s = %i bytes%s\n", i, buffer->name, (int)buffer->size, buffer->isdynamic ? " (dynamic)" : " (static)");}
-               else                       {vbocount++;vbomemory += buffer->size;if (printeach) Con_Printf("vertexbuffer #%i %s = %i bytes%s\n", i, buffer->name, (int)buffer->size, buffer->isdynamic ? " (dynamic)" : " (static)");}
+               switch(info->target)
+               {
+               case GL_ELEMENT_ARRAY_BUFFER_ARB: ebocount++;ebomemory += info->size;if (printeach) Con_Printf("EBO #%i %s = %i bytes\n", info->object, info->name, (int)info->size);break;
+               case GL_ARRAY_BUFFER_ARB: vbocount++;vbomemory += info->size;if (printeach) Con_Printf("VBO #%i %s = %i bytes\n", info->object, info->name, (int)info->size);break;
+               default: Con_Printf("gl_vbostats: unknown target type %i\n", info->target);break;
+               }
        }
-       Con_Printf("vertex buffers: %i indexbuffers totalling %i bytes (%.3f MB), %i vertexbuffers totalling %i bytes (%.3f MB), combined %i bytes (%.3fMB)\n", (int)ebocount, (int)ebomemory, ebomemory / 1048576.0, (int)vbocount, (int)vbomemory, vbomemory / 1048576.0, (int)(ebomemory + vbomemory), (ebomemory + vbomemory) / 1048576.0);
+       Con_Printf("vertex buffers: %i element buffers totalling %i bytes (%.3f MB), %i vertex buffers totalling %i bytes (%.3f MB), combined %i bytes (%.3fMB)\n", (int)ebocount, (int)ebomemory, ebomemory / 1048576.0, (int)vbocount, (int)vbomemory, vbomemory / 1048576.0, (int)(ebomemory + vbomemory), (ebomemory + vbomemory) / 1048576.0);
 }
 
-
-
-void R_Mesh_VertexPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
+void R_Mesh_VertexPointer(const float *vertex3f, int bufferobject, size_t bufferoffset)
 {
-       int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
-       if (gl_state.pointer_vertex_components != components || gl_state.pointer_vertex_gltype != gltype || gl_state.pointer_vertex_stride != stride || gl_state.pointer_vertex_pointer != pointer || gl_state.pointer_vertex_vertexbuffer != vertexbuffer || gl_state.pointer_vertex_offset != bufferoffset)
+       if (!gl_vbo.integer || gl_mesh_testarrayelement.integer)
+               bufferobject = 0;
+       if (gl_state.pointer_vertex != vertex3f || gl_state.pointer_vertex_buffer != bufferobject || gl_state.pointer_vertex_offset != bufferoffset)
        {
-               gl_state.pointer_vertex_components = components;
-               gl_state.pointer_vertex_gltype = gltype;
-               gl_state.pointer_vertex_stride = stride;
-               gl_state.pointer_vertex_pointer = pointer;
-               gl_state.pointer_vertex_vertexbuffer = vertexbuffer;
+               gl_state.pointer_vertex = vertex3f;
+               gl_state.pointer_vertex_buffer = bufferobject;
                gl_state.pointer_vertex_offset = bufferoffset;
                CHECKGLERROR
                GL_BindVBO(bufferobject);
-               qglVertexPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
+               qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), bufferobject ? (void *)bufferoffset : vertex3f);CHECKGLERROR
        }
 }
 
-void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
+void R_Mesh_ColorPointer(const float *color4f, int bufferobject, size_t bufferoffset)
 {
-       // note: vertexbuffer may be non-NULL even if pointer is NULL, so check
-       // the pointer only.
-       if (pointer)
+       // note: this can not rely on bufferobject to decide whether a color array
+       // is supplied, because surfmesh_t shares one vbo for all arrays, which
+       // means that a valid vbo may be supplied even if there is no color array.
+       if (color4f)
        {
-               int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
+               if (!gl_vbo.integer || gl_mesh_testarrayelement.integer)
+                       bufferobject = 0;
                // caller wants color array enabled
                if (!gl_state.pointer_color_enabled)
                {
@@ -1644,17 +1493,14 @@ void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *
                        CHECKGLERROR
                        qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
                }
-               if (gl_state.pointer_color_components != components || gl_state.pointer_color_gltype != gltype || gl_state.pointer_color_stride != stride || gl_state.pointer_color_pointer != pointer || gl_state.pointer_color_vertexbuffer != vertexbuffer || gl_state.pointer_color_offset != bufferoffset)
+               if (gl_state.pointer_color != color4f || gl_state.pointer_color_buffer != bufferobject || gl_state.pointer_color_offset != bufferoffset)
                {
-                       gl_state.pointer_color_components = components;
-                       gl_state.pointer_color_gltype = gltype;
-                       gl_state.pointer_color_stride = stride;
-                       gl_state.pointer_color_pointer = pointer;
-                       gl_state.pointer_color_vertexbuffer = vertexbuffer;
+                       gl_state.pointer_color = color4f;
+                       gl_state.pointer_color_buffer = bufferobject;
                        gl_state.pointer_color_offset = bufferoffset;
                        CHECKGLERROR
                        GL_BindVBO(bufferobject);
-                       qglColorPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
+                       qglColorPointer(4, GL_FLOAT, sizeof(float[4]), bufferobject ? (void *)bufferoffset : color4f);CHECKGLERROR
                }
        }
        else
@@ -1671,16 +1517,17 @@ void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *
        }
 }
 
-void R_Mesh_TexCoordPointer(unsigned int unitnum, int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
+void R_Mesh_TexCoordPointer(unsigned int unitnum, unsigned int numcomponents, const float *texcoord, int bufferobject, size_t bufferoffset)
 {
        gltextureunit_t *unit = gl_state.units + unitnum;
        // update array settings
        CHECKGLERROR
        // note: there is no need to check bufferobject here because all cases
        // that involve a valid bufferobject also supply a texcoord array
-       if (pointer)
+       if (texcoord)
        {
-               int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
+               if (!gl_vbo.integer || gl_mesh_testarrayelement.integer)
+                       bufferobject = 0;
                // texture array unit is enabled, enable the array
                if (!unit->arrayenabled)
                {
@@ -1689,17 +1536,15 @@ void R_Mesh_TexCoordPointer(unsigned int unitnum, int components, int gltype, si
                        qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
                }
                // texcoord array
-               if (unit->pointer_texcoord_components != components || unit->pointer_texcoord_gltype != gltype || unit->pointer_texcoord_stride != stride || unit->pointer_texcoord_pointer != pointer || unit->pointer_texcoord_vertexbuffer != vertexbuffer || unit->pointer_texcoord_offset != bufferoffset)
+               if (unit->pointer_texcoord != texcoord || unit->pointer_texcoord_buffer != bufferobject || unit->pointer_texcoord_offset != bufferoffset || unit->arraycomponents != numcomponents)
                {
-                       unit->pointer_texcoord_components = components;
-                       unit->pointer_texcoord_gltype = gltype;
-                       unit->pointer_texcoord_stride = stride;
-                       unit->pointer_texcoord_pointer = pointer;
-                       unit->pointer_texcoord_vertexbuffer = vertexbuffer;
+                       unit->pointer_texcoord = texcoord;
+                       unit->pointer_texcoord_buffer = bufferobject;
                        unit->pointer_texcoord_offset = bufferoffset;
+                       unit->arraycomponents = numcomponents;
                        GL_ClientActiveTexture(unitnum);
                        GL_BindVBO(bufferobject);
-                       qglTexCoordPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR
+                       qglTexCoordPointer(unit->arraycomponents, GL_FLOAT, sizeof(float) * unit->arraycomponents, bufferobject ? (void *)bufferoffset : texcoord);CHECKGLERROR
                }
        }
        else
@@ -2084,467 +1929,3 @@ void R_Mesh_ResetTextureState(void)
                break;
        }
 }
-
-
-
-r_vertexposition_t *R_Mesh_PrepareVertices_Position_Lock(int numvertices)
-{
-       size_t size;
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL11:
-               size = sizeof(r_vertexposition_t) * numvertices;
-               if (gl_state.preparevertices_tempdatamaxsize < size)
-               {
-                       gl_state.preparevertices_tempdatamaxsize = size;
-                       gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize);
-               }
-               gl_state.preparevertices_vertexposition = (r_vertexposition_t *)gl_state.preparevertices_tempdata;
-               gl_state.preparevertices_numvertices = numvertices;
-               return gl_state.preparevertices_vertexposition;
-       default:
-               Sys_Error("R_Mesh_PrepareVertices_Position_Lock: unrecognized vid.renderpath\n");
-               return NULL;
-       }
-}
-
-qboolean R_Mesh_PrepareVertices_Position_Unlock(void)
-{
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL11:
-               R_Mesh_PrepareVertices_Position(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexposition, NULL);
-               gl_state.preparevertices_vertexposition = NULL;
-               gl_state.preparevertices_numvertices = 0;
-               return true;
-       default:
-               Sys_Error("R_Mesh_PrepareVertices_Position_Lock: unrecognized vid.renderpath\n");
-               return false;
-       }
-}
-
-void R_Mesh_PrepareVertices_Position_Arrays(int numvertices, const float *vertex3f)
-{
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-               R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
-               R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
-               R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               break;
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL11:
-               R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
-               R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
-               R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               if (vid.texunits >= 2)
-                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               if (vid.texunits >= 3)
-                       R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               break;
-       default:
-               Sys_Error("R_Mesh_PrepareVertices_Position_Lock: unrecognized vid.renderpath\n");
-               return;
-       }
-}
-
-void R_Mesh_PrepareVertices_Position(int numvertices, const r_vertexposition_t *vertex, const r_meshbuffer_t *vertexbuffer)
-{
-       // upload temporary vertexbuffer for this rendering
-       if (!gl_state.usevbo_staticvertex)
-               vertexbuffer = NULL;
-       if (!vertexbuffer && gl_state.usevbo_dynamicvertex)
-       {
-               if (gl_state.preparevertices_dynamicvertexbuffer)
-                       R_Mesh_UpdateMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer, vertex, numvertices * sizeof(*vertex));
-               else
-                       gl_state.preparevertices_dynamicvertexbuffer = R_Mesh_CreateMeshBuffer(vertex, numvertices * sizeof(*vertex), "temporary", false, true);
-               vertexbuffer = gl_state.preparevertices_dynamicvertexbuffer;
-       }
-       if (vertexbuffer)
-       {
-               switch(vid.renderpath)
-               {
-               case RENDERPATH_GL20:
-               case RENDERPATH_CGGL:
-                       R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               case RENDERPATH_GL13:
-                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               case RENDERPATH_GL11:
-                       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
-                       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       break;
-               }
-               return;
-       }
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-               R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-       case RENDERPATH_GL13:
-               R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-       case RENDERPATH_GL11:
-               R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
-               R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
-               R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               break;
-       }
-}
-
-
-
-r_vertexgeneric_t *R_Mesh_PrepareVertices_Generic_Lock(int numvertices)
-{
-       size_t size;
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL11:
-               size = sizeof(r_vertexgeneric_t) * numvertices;
-               if (gl_state.preparevertices_tempdatamaxsize < size)
-               {
-                       gl_state.preparevertices_tempdatamaxsize = size;
-                       gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize);
-               }
-               gl_state.preparevertices_vertexgeneric = (r_vertexgeneric_t *)gl_state.preparevertices_tempdata;
-               gl_state.preparevertices_numvertices = numvertices;
-               return gl_state.preparevertices_vertexgeneric;
-       default:
-               Sys_Error("R_Mesh_PrepareVertices_Generic_Lock: unrecognized vid.renderpath\n");
-               return NULL;
-       }
-}
-
-qboolean R_Mesh_PrepareVertices_Generic_Unlock(void)
-{
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL11:
-               R_Mesh_PrepareVertices_Generic(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexgeneric, NULL);
-               gl_state.preparevertices_vertexgeneric = NULL;
-               gl_state.preparevertices_numvertices = 0;
-               return true;
-       default:
-               Sys_Error("R_Mesh_PrepareVertices_Generic_Lock: unrecognized vid.renderpath\n");
-               return false;
-       }
-}
-
-void R_Mesh_PrepareVertices_Generic_Arrays(int numvertices, const float *vertex3f, const float *color4f, const float *texcoord2f)
-{
-       int i;
-       r_vertexgeneric_t *vertex;
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-               if (gl_mesh_separatearrays.integer)
-               {
-                       R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
-                       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoord2f, NULL, 0);
-                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       return;
-               }
-               break;
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL11:
-               if (gl_mesh_separatearrays.integer)
-               {
-                       R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
-                       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoord2f, NULL, 0);
-                       if (vid.texunits >= 2)
-                               R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       if (vid.texunits >= 3)
-                               R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       return;
-               }
-               break;
-       default:
-               Sys_Error("R_Mesh_PrepareVertices_Position_Lock: unrecognized vid.renderpath\n");
-               return;
-       }
-
-       // no quick path for this case, convert to vertex structs
-       vertex = R_Mesh_PrepareVertices_Generic_Lock(numvertices);
-       for (i = 0;i < numvertices;i++)
-               VectorCopy(vertex3f + 3*i, vertex[i].vertex3f);
-       if (color4f)
-       {
-               for (i = 0;i < numvertices;i++)
-                       Vector4Scale(color4f + 4*i, 255.0f, vertex[i].color4ub);
-       }
-       else
-       {
-               float tempcolor4f[4];
-               unsigned char tempcolor4ub[4];
-               Vector4Scale(gl_state.color4f, 255.0f, tempcolor4f);
-               tempcolor4ub[0] = (unsigned char)bound(0.0f, tempcolor4f[0], 255.0f);
-               tempcolor4ub[1] = (unsigned char)bound(0.0f, tempcolor4f[1], 255.0f);
-               tempcolor4ub[2] = (unsigned char)bound(0.0f, tempcolor4f[2], 255.0f);
-               tempcolor4ub[3] = (unsigned char)bound(0.0f, tempcolor4f[3], 255.0f);
-               for (i = 0;i < numvertices;i++)
-                       Vector4Copy(tempcolor4ub, vertex[i].color4ub);
-       }
-       if (texcoord2f)
-               for (i = 0;i < numvertices;i++)
-                       Vector2Copy(texcoord2f + 2*i, vertex[i].texcoord2f);
-       R_Mesh_PrepareVertices_Generic_Unlock();
-       R_Mesh_PrepareVertices_Generic(numvertices, vertex, NULL);
-}
-
-void R_Mesh_PrepareVertices_Generic(int numvertices, const r_vertexgeneric_t *vertex, const r_meshbuffer_t *vertexbuffer)
-{
-       // upload temporary vertexbuffer for this rendering
-       if (!gl_state.usevbo_staticvertex)
-               vertexbuffer = NULL;
-       if (!vertexbuffer && gl_state.usevbo_dynamicvertex)
-       {
-               if (gl_state.preparevertices_dynamicvertexbuffer)
-                       R_Mesh_UpdateMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer, vertex, numvertices * sizeof(*vertex));
-               else
-                       gl_state.preparevertices_dynamicvertexbuffer = R_Mesh_CreateMeshBuffer(vertex, numvertices * sizeof(*vertex), "temporary", false, true);
-               vertexbuffer = gl_state.preparevertices_dynamicvertexbuffer;
-       }
-       if (vertexbuffer)
-       {
-               switch(vid.renderpath)
-               {
-               case RENDERPATH_GL20:
-               case RENDERPATH_CGGL:
-                       R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               case RENDERPATH_GL13:
-                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               case RENDERPATH_GL11:
-                       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
-                       R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , vertexbuffer, (int)((unsigned char *)vertex->color4ub           - (unsigned char *)vertex));
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , vertexbuffer, (int)((unsigned char *)vertex->texcoord2f         - (unsigned char *)vertex));
-                       break;
-               }
-               return;
-       }
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-               R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-               R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-       case RENDERPATH_GL13:
-               R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-       case RENDERPATH_GL11:
-               R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
-               R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , NULL, 0);
-               R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , NULL, 0);
-               break;
-       }
-}
-
-
-
-r_vertexmesh_t *R_Mesh_PrepareVertices_Mesh_Lock(int numvertices)
-{
-       size_t size;
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL11:
-               size = sizeof(r_vertexmesh_t) * numvertices;
-               if (gl_state.preparevertices_tempdatamaxsize < size)
-               {
-                       gl_state.preparevertices_tempdatamaxsize = size;
-                       gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize);
-               }
-               gl_state.preparevertices_vertexmesh = (r_vertexmesh_t *)gl_state.preparevertices_tempdata;
-               gl_state.preparevertices_numvertices = numvertices;
-               return gl_state.preparevertices_vertexmesh;
-       default:
-               Sys_Error("R_Mesh_PrepareVertices_Mesh_Lock: unrecognized vid.renderpath\n");
-               return NULL;
-       }
-}
-
-qboolean R_Mesh_PrepareVertices_Mesh_Unlock(void)
-{
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL11:
-               R_Mesh_PrepareVertices_Mesh(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexmesh, NULL);
-               gl_state.preparevertices_vertexmesh = NULL;
-               gl_state.preparevertices_numvertices = 0;
-               return true;
-       default:
-               Sys_Error("R_Mesh_PrepareVertices_Mesh_Lock: unrecognized vid.renderpath\n");
-               return false;
-       }
-}
-
-void R_Mesh_PrepareVertices_Mesh_Arrays(int numvertices, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *color4f, const float *texcoordtexture2f, const float *texcoordlightmap2f)
-{
-       int i;
-       r_vertexmesh_t *vertex;
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-               if (gl_mesh_separatearrays.integer)
-               {
-                       R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
-                       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoordtexture2f, NULL, 0);
-                       R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), svector3f, NULL, 0);
-                       R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), tvector3f, NULL, 0);
-                       R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), normal3f, NULL, 0);
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), texcoordlightmap2f, NULL, 0);
-                       return;
-               }
-               break;
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL11:
-               if (gl_mesh_separatearrays.integer)
-               {
-                       R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
-                       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoordtexture2f, NULL, 0);
-                       if (vid.texunits >= 2)
-                               R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), texcoordlightmap2f, NULL, 0);
-                       if (vid.texunits >= 3)
-                               R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       return;
-               }
-               break;
-       default:
-               Sys_Error("R_Mesh_PrepareVertices_Position_Lock: unrecognized vid.renderpath\n");
-               return;
-       }
-
-       vertex = R_Mesh_PrepareVertices_Mesh_Lock(numvertices);
-       for (i = 0;i < numvertices;i++)
-               VectorCopy(vertex3f + 3*i, vertex[i].vertex3f);
-       if (svector3f)
-               for (i = 0;i < numvertices;i++)
-                       VectorCopy(svector3f + 3*i, vertex[i].svector3f);
-       if (tvector3f)
-               for (i = 0;i < numvertices;i++)
-                       VectorCopy(tvector3f + 3*i, vertex[i].tvector3f);
-       if (normal3f)
-               for (i = 0;i < numvertices;i++)
-                       VectorCopy(normal3f + 3*i, vertex[i].normal3f);
-       if (color4f)
-       {
-               for (i = 0;i < numvertices;i++)
-                       Vector4Scale(color4f + 4*i, 255.0f, vertex[i].color4ub);
-       }
-       else
-       {
-               float tempcolor4f[4];
-               unsigned char tempcolor4ub[4];
-               Vector4Scale(gl_state.color4f, 255.0f, tempcolor4f);
-               tempcolor4ub[0] = (unsigned char)bound(0.0f, tempcolor4f[0], 255.0f);
-               tempcolor4ub[1] = (unsigned char)bound(0.0f, tempcolor4f[1], 255.0f);
-               tempcolor4ub[2] = (unsigned char)bound(0.0f, tempcolor4f[2], 255.0f);
-               tempcolor4ub[3] = (unsigned char)bound(0.0f, tempcolor4f[3], 255.0f);
-               for (i = 0;i < numvertices;i++)
-                       Vector4Copy(tempcolor4ub, vertex[i].color4ub);
-       }
-       if (texcoordtexture2f)
-               for (i = 0;i < numvertices;i++)
-                       Vector2Copy(texcoordtexture2f + 2*i, vertex[i].texcoordtexture2f);
-       if (texcoordlightmap2f)
-               for (i = 0;i < numvertices;i++)
-                       Vector2Copy(texcoordlightmap2f + 2*i, vertex[i].texcoordlightmap2f);
-       R_Mesh_PrepareVertices_Mesh_Unlock();
-       R_Mesh_PrepareVertices_Mesh(numvertices, vertex, NULL);
-}
-
-void R_Mesh_PrepareVertices_Mesh(int numvertices, const r_vertexmesh_t *vertex, const r_meshbuffer_t *vertexbuffer)
-{
-       // upload temporary vertexbuffer for this rendering
-       if (!gl_state.usevbo_staticvertex)
-               vertexbuffer = NULL;
-       if (!vertexbuffer && gl_state.usevbo_dynamicvertex)
-       {
-               if (gl_state.preparevertices_dynamicvertexbuffer)
-                       R_Mesh_UpdateMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer, vertex, numvertices * sizeof(*vertex));
-               else
-                       gl_state.preparevertices_dynamicvertexbuffer = R_Mesh_CreateMeshBuffer(vertex, numvertices * sizeof(*vertex), "temporary", false, true);
-               vertexbuffer = gl_state.preparevertices_dynamicvertexbuffer;
-       }
-       if (vertexbuffer)
-       {
-               switch(vid.renderpath)
-               {
-               case RENDERPATH_GL20:
-               case RENDERPATH_CGGL:
-                       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
-                       R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , vertexbuffer, (int)((unsigned char *)vertex->color4ub           - (unsigned char *)vertex));
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , vertexbuffer, (int)((unsigned char *)vertex->texcoordtexture2f  - (unsigned char *)vertex));
-                       R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(*vertex), vertex->svector3f         , vertexbuffer, (int)((unsigned char *)vertex->svector3f          - (unsigned char *)vertex));
-                       R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(*vertex), vertex->tvector3f         , vertexbuffer, (int)((unsigned char *)vertex->tvector3f          - (unsigned char *)vertex));
-                       R_Mesh_TexCoordPointer(3, 4, GL_FLOAT        , sizeof(*vertex), vertex->normal3f          , vertexbuffer, (int)((unsigned char *)vertex->normal3f           - (unsigned char *)vertex));
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, vertexbuffer, (int)((unsigned char *)vertex->texcoordlightmap2f - (unsigned char *)vertex));
-                       break;
-               case RENDERPATH_GL13:
-                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, vertexbuffer, (int)((unsigned char *)vertex->texcoordlightmap2f - (unsigned char *)vertex));
-               case RENDERPATH_GL11:
-                       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
-                       R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , vertexbuffer, (int)((unsigned char *)vertex->color4ub           - (unsigned char *)vertex));
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , vertexbuffer, (int)((unsigned char *)vertex->texcoordtexture2f  - (unsigned char *)vertex));
-                       break;
-               }
-               return;
-       }
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-               R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
-               R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , NULL, 0);
-               R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , NULL, 0);
-               R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(*vertex), vertex->svector3f         , NULL, 0);
-               R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(*vertex), vertex->tvector3f         , NULL, 0);
-               R_Mesh_TexCoordPointer(3, 4, GL_FLOAT        , sizeof(*vertex), vertex->normal3f          , NULL, 0);
-               R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, NULL, 0);
-               break;
-       case RENDERPATH_GL13:
-               R_Mesh_TexCoordPointer(1, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, NULL, 0);
-       case RENDERPATH_GL11:
-               R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
-               R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , NULL, 0);
-               R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , NULL, 0);
-               break;
-       }
-}
index 952cecd782c3df11f2ddc99a17ffaf73d8199aa1..6643c29f0dad8c2d78e955ffbfc695e5109fdd4f 100644 (file)
@@ -59,36 +59,28 @@ void R_Mesh_Start(void);
 // (only valid after R_Mesh_Start)
 void R_Mesh_Finish(void);
 
-
-// vertex buffer and index buffer creation/updating/freeing
-r_meshbuffer_t *R_Mesh_CreateMeshBuffer(const void *data, size_t size, const char *name, qboolean isindexbuffer, qboolean isdynamic);
-void R_Mesh_UpdateMeshBuffer(r_meshbuffer_t *buffer, const void *data, size_t size);
-void R_Mesh_DestroyMeshBuffer(r_meshbuffer_t *buffer);
+// allocates a static element array buffer object
+// (storing triangle data in video memory)
+int R_Mesh_CreateStaticEBO(void *data, size_t size);
+// frees an element array buffer object
+void R_Mesh_DestroyEBO(int bufferobject);
+// allocates a static vertex/element array buffer object
+// (storing vertex or element data in video memory)
+// target is GL_ELEMENT_ARRAY_BUFFER_ARB (triangle elements)
+// or GL_ARRAY_BUFFER_ARB (vertex data)
+int R_Mesh_CreateStaticBufferObject(unsigned int target, void *data, size_t size, const char *name);
+// frees a vertex/element array buffer object
+void R_Mesh_DestroyBufferObject(int bufferobject);
 void GL_Mesh_ListVBOs(qboolean printeach);
 
-r_vertexposition_t *R_Mesh_PrepareVertices_Position_Lock(int numvertices);
-qboolean R_Mesh_PrepareVertices_Position_Unlock(void); // if this returns false, you need to prepare the mesh again!
-void R_Mesh_PrepareVertices_Position_Arrays(int numvertices, const float *vertex3f);
-void R_Mesh_PrepareVertices_Position(int numvertices, const r_vertexposition_t *vertex, const r_meshbuffer_t *buffer);
-
-r_vertexgeneric_t *R_Mesh_PrepareVertices_Generic_Lock(int numvertices);
-qboolean R_Mesh_PrepareVertices_Generic_Unlock(void);
-void R_Mesh_PrepareVertices_Generic_Arrays(int numvertices, const float *vertex3f, const float *color4f, const float *texcoord2f);
-void R_Mesh_PrepareVertices_Generic(int numvertices, const r_vertexgeneric_t *vertex, const r_meshbuffer_t *vertexbuffer);
-
-r_vertexmesh_t *R_Mesh_PrepareVertices_Mesh_Lock(int numvertices);
-qboolean R_Mesh_PrepareVertices_Mesh_Unlock(void); // if this returns false, you need to prepare the mesh again!
-void R_Mesh_PrepareVertices_Mesh_Arrays(int numvertices, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *color4f, const float *texcoordtexture2f, const float *texcoordlightmap2f);
-void R_Mesh_PrepareVertices_Mesh(int numvertices, const r_vertexmesh_t *vertex, const r_meshbuffer_t *buffer);
-
 // sets up the requested vertex transform matrix
 void R_EntityMatrix(const matrix4x4_t *matrix);
 // sets the vertex array pointer
-void R_Mesh_VertexPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset);
+void R_Mesh_VertexPointer(const float *vertex3f, int bufferobject, size_t bufferoffset);
 // sets the color array pointer (GL_Color only works when this is NULL)
-void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset);
+void R_Mesh_ColorPointer(const float *color4f, int bufferobject, size_t bufferoffset);
 // sets the texcoord array pointer for an array unit
-void R_Mesh_TexCoordPointer(unsigned int unitnum, int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset);
+void R_Mesh_TexCoordPointer(unsigned int unitnum, unsigned int numcomponents, const float *texcoord, int bufferobject, size_t bufferoffset);
 // returns current texture bound to this identifier
 int R_Mesh_TexBound(unsigned int unitnum, int id);
 // copies a section of the framebuffer to a 2D texture
@@ -103,7 +95,7 @@ void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, i
 void R_Mesh_ResetTextureState(void);
 
 // renders a mesh
-void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const r_meshbuffer_t *element3i_indexbuffer, size_t element3i_bufferoffset, const unsigned short *element3s, const r_meshbuffer_t *element3s_indexbuffer, size_t element3s_bufferoffset);
+void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int bufferobject3i, int bufferobject3s);
 
 // saves a section of the rendered frame to a .tga or .jpg file
 qboolean SCR_ScreenShot(char *filename, unsigned char *buffer1, unsigned char *buffer2, int x, int y, int width, int height, qboolean flipx, qboolean flipy, qboolean flipdiagonal, qboolean jpeg, qboolean png, qboolean gammacorrect, qboolean keep_alpha);
index 7a05e3a3850fd0d79f4aac3e663fc9e122a53fae..6821819cdfd58a30e7d2d93ff30974f60f930d01 100644 (file)
--- a/gl_draw.c
+++ b/gl_draw.c
@@ -1046,21 +1046,16 @@ void DrawQ_ProcessDrawFlag(int flags, qboolean alpha)
 
 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
 {
-       float floats[36];
+       float floats[20];
 
        _DrawQ_SetupAndProcessDrawFlag(flags, pic, alpha);
        if(!r_draw2d.integer && !r_draw2d_force)
                return;
+       GL_Color(red, green, blue, alpha);
 
+       R_Mesh_VertexPointer(floats, 0, 0);
+       R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
-       floats[12] = 0.0f;floats[13] = 0.0f;
-       floats[14] = 1.0f;floats[15] = 0.0f;
-       floats[16] = 1.0f;floats[17] = 1.0f;
-       floats[18] = 0.0f;floats[19] = 1.0f;
-       floats[20] = floats[24] = floats[28] = floats[32] = red;
-       floats[21] = floats[25] = floats[29] = floats[33] = green;
-       floats[22] = floats[26] = floats[30] = floats[34] = blue;
-       floats[23] = floats[27] = floats[31] = floats[35] = alpha;
        if (pic)
        {
                if (width == 0)
@@ -1068,8 +1063,14 @@ void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, flo
                if (height == 0)
                        height = pic->height;
                R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
-
-#if 0
+               R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
+
+#if 1
+               floats[12] = 0.0f;floats[13] = 0.0f;
+               floats[14] = 1.0f;floats[15] = 0.0f;
+               floats[16] = 1.0f;floats[17] = 1.0f;
+               floats[18] = 0.0f;floats[19] = 1.0f;
+#else
       // AK07: lets be texel correct on the corners
       {
          float horz_offset = 0.5f / pic->width;
@@ -1091,13 +1092,12 @@ void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, flo
        floats[3] = floats[6] = x + width;
        floats[7] = floats[10] = y + height;
 
-       R_Mesh_PrepareVertices_Generic_Arrays(4, floats, floats + 20, floats + 12);
-       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
 }
 
 void DrawQ_RotPic(float x, float y, cachepic_t *pic, float width, float height, float org_x, float org_y, float angle, float red, float green, float blue, float alpha, int flags)
 {
-       float floats[36];
+       float floats[20];
        float af = DEG2RAD(-angle); // forward
        float ar = DEG2RAD(-angle + 90); // right
        float sinaf = sin(af);
@@ -1108,7 +1108,10 @@ void DrawQ_RotPic(float x, float y, cachepic_t *pic, float width, float height,
        _DrawQ_SetupAndProcessDrawFlag(flags, pic, alpha);
        if(!r_draw2d.integer && !r_draw2d_force)
                return;
+       GL_Color(red, green, blue, alpha);
 
+       R_Mesh_VertexPointer(floats, 0, 0);
+       R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
        if (pic)
        {
@@ -1117,6 +1120,12 @@ void DrawQ_RotPic(float x, float y, cachepic_t *pic, float width, float height,
                if (height == 0)
                        height = pic->height;
                R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
+               R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
+
+               floats[12] = 0.0f;floats[13] = 0.0f;
+               floats[14] = 1.0f;floats[15] = 0.0f;
+               floats[16] = 1.0f;floats[17] = 1.0f;
+               floats[18] = 0.0f;floats[19] = 1.0f;
        }
        else
                R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
@@ -1139,27 +1148,20 @@ void DrawQ_RotPic(float x, float y, cachepic_t *pic, float width, float height,
        floats[9]  = x - cosaf*org_x + cosar*(height-org_y);
        floats[10] = y - sinaf*org_x + sinar*(height-org_y);
 
-       floats[12] = 0.0f;floats[13] = 0.0f;
-       floats[14] = 1.0f;floats[15] = 0.0f;
-       floats[16] = 1.0f;floats[17] = 1.0f;
-       floats[18] = 0.0f;floats[19] = 1.0f;
-       floats[20] = floats[24] = floats[28] = floats[32] = red;
-       floats[21] = floats[25] = floats[29] = floats[33] = green;
-       floats[22] = floats[26] = floats[30] = floats[34] = blue;
-       floats[23] = floats[27] = floats[31] = floats[35] = alpha;
-
-       R_Mesh_PrepareVertices_Generic_Arrays(4, floats, floats + 20, floats + 12);
-       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
 }
 
 void DrawQ_Fill(float x, float y, float width, float height, float red, float green, float blue, float alpha, int flags)
 {
-       float floats[36];
+       float floats[12];
 
        _DrawQ_SetupAndProcessDrawFlag(flags, NULL, alpha);
        if(!r_draw2d.integer && !r_draw2d_force)
                return;
+       GL_Color(red, green, blue, alpha);
 
+       R_Mesh_VertexPointer(floats, 0, 0);
+       R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
        R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
 
@@ -1168,17 +1170,8 @@ void DrawQ_Fill(float x, float y, float width, float height, float red, float gr
        floats[1] = floats[4] = y;
        floats[3] = floats[6] = x + width;
        floats[7] = floats[10] = y + height;
-       floats[12] = 0.0f;floats[13] = 0.0f;
-       floats[14] = 1.0f;floats[15] = 0.0f;
-       floats[16] = 1.0f;floats[17] = 1.0f;
-       floats[18] = 0.0f;floats[19] = 1.0f;
-       floats[20] = floats[24] = floats[28] = floats[32] = red;
-       floats[21] = floats[25] = floats[29] = floats[33] = green;
-       floats[22] = floats[26] = floats[30] = floats[34] = blue;
-       floats[23] = floats[27] = floats[31] = floats[35] = alpha;
-
-       R_Mesh_PrepareVertices_Generic_Arrays(4, floats, floats + 20, floats + 12);
-       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+
+       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
 }
 
 /// color tag printing
@@ -1485,9 +1478,12 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
        if(!r_draw2d.integer && !r_draw2d_force)
                return startx + DrawQ_TextWidth_UntilWidth_TrackColors_Scale(text, &maxlen, w, h, sw, sh, NULL, ignorecolorcodes, fnt, 1000000000);
 
+       R_Mesh_ColorPointer(color4f, 0, 0);
        R_Mesh_ResetTextureState();
        if (!fontmap)
                R_Mesh_TexBind(0, fnt->tex);
+       R_Mesh_TexCoordPointer(0, 2, texcoord2f, 0, 0);
+       R_Mesh_VertexPointer(vertex3f, 0, 0);
        R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1);
 
        ac = color4f;
@@ -1617,8 +1613,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                                                if (batchcount)
                                                {
                                                        // switching from freetype to non-freetype rendering
-                                                       R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f);
-                                                       R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0);
+                                                       R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
                                                        batchcount = 0;
                                                        ac = color4f;
                                                        at = texcoord2f;
@@ -1655,8 +1650,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                                batchcount++;
                                if (batchcount >= QUADELEMENTS_MAXQUADS)
                                {
-                                       R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f);
-                                       R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0);
+                                       R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
                                        batchcount = 0;
                                        ac = color4f;
                                        at = texcoord2f;
@@ -1670,8 +1664,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                                        if (batchcount)
                                        {
                                                // we need a different character map, render what we currently have:
-                                               R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f);
-                                               R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0);
+                                               R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
                                                batchcount = 0;
                                                ac = color4f;
                                                at = texcoord2f;
@@ -1730,8 +1723,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                                batchcount++;
                                if (batchcount >= QUADELEMENTS_MAXQUADS)
                                {
-                                       R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f);
-                                       R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0);
+                                       R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
                                        batchcount = 0;
                                        ac = color4f;
                                        at = texcoord2f;
@@ -1749,10 +1741,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                }
        }
        if (batchcount > 0)
-       {
-               R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f);
-               R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0);
-       }
+               R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0);
 
        if (outcolor)
                *outcolor = colorindex;
@@ -1829,6 +1818,8 @@ void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height
        if(!r_draw2d.integer && !r_draw2d_force)
                return;
 
+       R_Mesh_VertexPointer(floats, 0, 0);
+       R_Mesh_ColorPointer(floats + 20, 0, 0);
        R_Mesh_ResetTextureState();
        if (pic)
        {
@@ -1837,6 +1828,11 @@ void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height
                if (height == 0)
                        height = pic->height;
                R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1);
+               R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0);
+               floats[12] = s1;floats[13] = t1;
+               floats[14] = s2;floats[15] = t2;
+               floats[16] = s4;floats[17] = t4;
+               floats[18] = s3;floats[19] = t3;
        }
        else
                R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
@@ -1846,17 +1842,12 @@ void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height
        floats[1] = floats[4] = y;
        floats[3] = floats[6] = x + width;
        floats[7] = floats[10] = y + height;
-       floats[12] = s1;floats[13] = t1;
-       floats[14] = s2;floats[15] = t2;
-       floats[16] = s4;floats[17] = t4;
-       floats[18] = s3;floats[19] = t3;
        floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1;
        floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2;
        floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4;
        floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3;
 
-       R_Mesh_PrepareVertices_Generic_Arrays(4, floats, floats + 20, floats + 12);
-       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
 }
 
 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags, qboolean hasalpha)
@@ -1867,11 +1858,13 @@ void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags, qboolean hasalpha)
                return;
        DrawQ_ProcessDrawFlag(flags, hasalpha);
 
+       R_Mesh_VertexPointer(mesh->data_vertex3f, 0, 0);
+       R_Mesh_ColorPointer(mesh->data_color4f, 0, 0);
        R_Mesh_ResetTextureState();
+       R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f, 0, 0);
        R_SetupShader_Generic(mesh->texture, NULL, GL_MODULATE, 1);
 
-       R_Mesh_PrepareVertices_Generic_Arrays(mesh->num_vertices, mesh->data_vertex3f, mesh->data_color4f, mesh->data_texcoord2f);
-       R_Mesh_Draw(0, mesh->num_vertices, 0, mesh->num_triangles, mesh->data_element3i, NULL, 0, mesh->data_element3s, NULL, 0);
+       R_Mesh_Draw(0, mesh->num_vertices, 0, mesh->num_triangles, mesh->data_element3i, mesh->data_element3s, 0, 0);
 }
 
 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
@@ -1967,6 +1960,8 @@ void R_DrawGamma(void)
                break;
        }
        // all the blends ignore depth
+       R_Mesh_VertexPointer(blendvertex3f, 0, 0);
+       R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
        R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
        GL_DepthMask(true);
@@ -1986,9 +1981,8 @@ void R_DrawGamma(void)
                GL_BlendFunc(GL_DST_COLOR, GL_ONE);
                while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
                {
-                       GL_Color(c[0] - 1, c[1] - 1, c[2] - 1, 1);
-                       R_Mesh_PrepareVertices_Generic_Arrays(3, blendvertex3f, NULL, NULL);
-                       R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+                       GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
+                       R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);
                        VectorScale(c, 0.5, c);
                }
        }
@@ -2003,9 +1997,8 @@ void R_DrawGamma(void)
        if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
        {
                GL_BlendFunc(GL_ONE, GL_ONE);
-               GL_Color(c[0] - 1, c[1] - 1, c[2] - 1, 1);
-               R_Mesh_PrepareVertices_Generic_Arrays(3, blendvertex3f, NULL, NULL);
-               R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+               GL_Color(c[0], c[1], c[2], 1);
+               R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);
        }
 }
 
index a9c9a06b983bfac025f44b666da8550b81a9906c..7cae34d3e374b9e4a81332a8b6401469fd41d2d9 100644 (file)
@@ -170,6 +170,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)"};
+cvar_t r_batchmode = {0, "r_batchmode", "1", "selects method of rendering multiple surfaces with one driver call (values are 0, 1, 2, etc...)"};
 cvar_t r_track_sprites = {CVAR_SAVE, "r_track_sprites", "1", "track SPR_LABEL* sprites by putting them as indicator at the screen border to rotate to"};
 cvar_t r_track_sprites_flags = {CVAR_SAVE, "r_track_sprites_flags", "1", "1: Rotate sprites accodringly, 2: Make it a continuous rotation"};
 cvar_t r_track_sprites_scalew = {CVAR_SAVE, "r_track_sprites_scalew", "1", "width scaling of tracked sprites"};
@@ -656,7 +657,7 @@ static const char *builtinshaderstring =
 "      gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n"
 "      TexCoord1 = gl_MultiTexCoord0.xy;\n"
 "#ifdef USEBLOOM\n"
-"      TexCoord2 = gl_MultiTexCoord4.xy;\n"
+"      TexCoord2 = gl_MultiTexCoord1.xy;\n"
 "#endif\n"
 "}\n"
 "#endif\n"
@@ -1939,7 +1940,7 @@ const char *builtincgshaderstring =
 "float4 gl_Vertex : POSITION,\n"
 "uniform float4x4 ModelViewProjectionMatrix,\n"
 "float4 gl_MultiTexCoord0 : TEXCOORD0,\n"
-"float4 gl_MultiTexCoord1 : TEXCOORD4,\n"
+"float4 gl_MultiTexCoord1 : TEXCOORD1,\n"
 "out float4 gl_Position : POSITION,\n"
 "out float2 TexCoord1 : TEXCOORD0,\n"
 "out float2 TexCoord2 : TEXCOORD1\n"
@@ -4578,7 +4579,6 @@ extern rtexture_t *r_shadow_prepassgeometrydepthtexture;
 extern rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
-extern cvar_t gl_mesh_separatearrays;
 static qboolean R_BlendFuncAllowsColormod(int src, int dst)
 {
        // a blendfunc allows colormod if:
@@ -4674,7 +4674,7 @@ static qboolean R_BlendFuncAllowsColormod(int src, int dst)
                        return false;
        }
 }
-void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist)
+void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass)
 {
        // select a permutation of the lighting shader appropriate to this
        // combination of texture, entity, light source, and fogging, only use the
@@ -4698,6 +4698,12 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        mode = SHADERMODE_GENERIC;
                        permutation |= SHADERPERMUTATION_DIFFUSE;
                }
+               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+               R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
+               R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
+               R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
+               R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0);
+               R_Mesh_ColorPointer(NULL, 0, 0);
                GL_AlphaTest(false);
                GL_BlendFunc(GL_ONE, GL_ZERO);
                allow_colormod = R_BlendFuncAllowsColormod(GL_ONE, GL_ZERO);
@@ -4725,6 +4731,15 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                mode = SHADERMODE_DEFERREDGEOMETRY;
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
+               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+               R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
+               R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
+               R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
+               R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0);
+               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND)
+                       R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
+               else
+                       R_Mesh_ColorPointer(NULL, 0, 0);
                GL_AlphaTest(false);
                GL_BlendFunc(GL_ONE, GL_ZERO);
                allow_colormod = R_BlendFuncAllowsColormod(GL_ONE, GL_ZERO);
@@ -4784,6 +4799,24 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                }
                if (rsurface.texture->reflectmasktexture)
                        permutation |= SHADERPERMUTATION_REFLECTCUBE;
+               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+               if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING))
+               {
+                       R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
+               }
+               else
+               {
+                       R_Mesh_TexCoordPointer(1, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(2, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(3, 0, NULL, 0, 0);
+               }
+               //R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0);
+               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND)
+                       R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
+               else
+                       R_Mesh_ColorPointer(NULL, 0, 0);
                GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
                GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
                allow_colormod = R_BlendFuncAllowsColormod(GL_SRC_ALPHA, GL_ONE);
@@ -4833,6 +4866,24 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= SHADERPERMUTATION_REFLECTION;
                if (rsurface.texture->reflectmasktexture)
                        permutation |= SHADERPERMUTATION_REFLECTCUBE;
+               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+               if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING))
+               {
+                       R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
+               }
+               else
+               {
+                       R_Mesh_TexCoordPointer(1, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(2, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(3, 0, NULL, 0, 0);
+               }
+               R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0);
+               if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND)
+                       R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
+               else
+                       R_Mesh_ColorPointer(NULL, 0, 0);
                GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
                GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
                allow_colormod = R_BlendFuncAllowsColormod(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
@@ -4890,6 +4941,21 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
                if (rsurface.texture->reflectmasktexture)
                        permutation |= SHADERPERMUTATION_REFLECTCUBE;
+               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+               if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING))
+               {
+                       R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
+               }
+               else
+               {
+                       R_Mesh_TexCoordPointer(1, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(2, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(3, 0, NULL, 0, 0);
+               }
+               R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0);
+               R_Mesh_ColorPointer(NULL, 0, 0);
                GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
                GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
                allow_colormod = R_BlendFuncAllowsColormod(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
@@ -4940,6 +5006,21 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
                if (rsurface.texture->reflectmasktexture)
                        permutation |= SHADERPERMUTATION_REFLECTCUBE;
+               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+               if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING))
+               {
+                       R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
+               }
+               else
+               {
+                       R_Mesh_TexCoordPointer(1, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(2, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(3, 0, NULL, 0, 0);
+               }
+               R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0);
+               R_Mesh_ColorPointer(NULL, 0, 0);
                GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
                GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
                allow_colormod = R_BlendFuncAllowsColormod(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
@@ -5003,6 +5084,11 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                if (r_shadow_glossexact.integer)
                                        permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
                        }
+                       R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
+                       if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND)
+                               R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
+                       else
+                               R_Mesh_ColorPointer(NULL, 0, 0);
                }
                else if (r_glsl_deluxemapping.integer >= 2)
                {
@@ -5015,16 +5101,41 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                if (r_shadow_glossexact.integer)
                                        permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
                        }
+                       R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
+                       if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND)
+                               R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
+                       else
+                               R_Mesh_ColorPointer(NULL, 0, 0);
                }
                else if (rsurface.uselightmaptexture)
                {
                        // ordinary lightmapping (q1bsp, q3bsp)
                        mode = SHADERMODE_LIGHTMAP;
+                       R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
+                       if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND)
+                               R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
+                       else
+                               R_Mesh_ColorPointer(NULL, 0, 0);
                }
                else
                {
                        // ordinary vertex coloring (q3bsp)
                        mode = SHADERMODE_VERTEXCOLOR;
+                       R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0);
+                       R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
+               }
+               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+               if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING))
+               {
+                       R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
+                       R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
+               }
+               else
+               {
+                       R_Mesh_TexCoordPointer(1, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(2, 0, NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(3, 0, NULL, 0, 0);
                }
                GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
                GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
@@ -5035,22 +5146,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        switch(vid.renderpath)
        {
        case RENDERPATH_GL20:
-               if (gl_mesh_separatearrays.integer)
-               {
-                       RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0), texturenumsurfaces, texturesurfacelist);
-                       R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
-                       R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
-                       R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
-                       R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
-                       R_Mesh_TexCoordPointer(3, 4, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
-               }
-               else
-               {
-                       RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0), texturenumsurfaces, texturesurfacelist);
-                       R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmeshbuffer);
-               }
                R_SetupShader_SetPermutationGLSL(mode, permutation);
                if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
                if (mode == SHADERMODE_LIGHTSOURCE)
@@ -5181,22 +5276,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                break;
        case RENDERPATH_CGGL:
 #ifdef SUPPORTCG
-               if (gl_mesh_separatearrays.integer)
-               {
-                       RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0), texturenumsurfaces, texturesurfacelist);
-                       R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
-                       R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
-                       R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
-                       R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
-                       R_Mesh_TexCoordPointer(3, 4, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
-               }
-               else
-               {
-                       RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0), texturenumsurfaces, texturesurfacelist);
-                       R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmeshbuffer);
-               }
                R_SetupShader_SetPermutationCG(mode, permutation);
                if (r_cg_permutation->fp_ModelToReflectCube) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);cgGLSetMatrixParameterfc(r_cg_permutation->fp_ModelToReflectCube, m16f);}CHECKCGERROR
                if (mode == SHADERMODE_LIGHTSOURCE)
@@ -6560,6 +6639,7 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&developer_texturelogging);
        Cvar_RegisterVariable(&gl_lightmaps);
        Cvar_RegisterVariable(&r_test);
+       Cvar_RegisterVariable(&r_batchmode);
        Cvar_RegisterVariable(&r_glsl_saturation);
        Cvar_RegisterVariable(&r_framedatasize);
        if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
@@ -6827,41 +6907,6 @@ void R_AnimCache_ClearCache(void)
                ent->animcache_normal3f = NULL;
                ent->animcache_svector3f = NULL;
                ent->animcache_tvector3f = NULL;
-               ent->animcache_vertexposition = NULL;
-               ent->animcache_vertexmesh = NULL;
-               ent->animcache_vertexpositionbuffer = NULL;
-               ent->animcache_vertexmeshbuffer = NULL;
-       }
-}
-
-void R_AnimCache_UpdateEntityMeshBuffers(entity_render_t *ent, int numvertices)
-{
-       int i;
-       if (!ent->animcache_vertexmesh && ent->animcache_normal3f)
-               ent->animcache_vertexmesh = R_FrameData_Alloc(sizeof(r_vertexmesh_t)*numvertices);
-       if (!ent->animcache_vertexposition)
-               ent->animcache_vertexposition = R_FrameData_Alloc(sizeof(r_vertexposition_t)*numvertices);
-       if (ent->animcache_vertexposition)
-       {
-               for (i = 0;i < numvertices;i++)
-                       VectorCopy(ent->animcache_vertex3f + 3*i, ent->animcache_vertexposition[i].vertex3f);
-               // TODO: upload vertex buffer?
-       }
-       if (ent->animcache_vertexmesh)
-       {
-               memcpy(ent->animcache_vertexmesh, ent->model->surfmesh.vertexmesh, sizeof(r_vertexmesh_t)*numvertices);
-               for (i = 0;i < numvertices;i++)
-                       VectorCopy(ent->animcache_vertex3f + 3*i, ent->animcache_vertexmesh[i].vertex3f);
-               if (ent->animcache_svector3f)
-                       for (i = 0;i < numvertices;i++)
-                               VectorCopy(ent->animcache_svector3f + 3*i, ent->animcache_vertexmesh[i].svector3f);
-               if (ent->animcache_tvector3f)
-                       for (i = 0;i < numvertices;i++)
-                               VectorCopy(ent->animcache_tvector3f + 3*i, ent->animcache_vertexmesh[i].tvector3f);
-               if (ent->animcache_normal3f)
-                       for (i = 0;i < numvertices;i++)
-                               VectorCopy(ent->animcache_normal3f + 3*i, ent->animcache_vertexmesh[i].normal3f);
-               // TODO: upload vertex buffer?
        }
 }
 
@@ -6872,7 +6917,7 @@ qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qbool
        // see if it's already cached this frame
        if (ent->animcache_vertex3f)
        {
-               // add normals/tangents if needed (this only happens with multiple views, reflections, cameras, etc)
+               // add normals/tangents if needed
                if (wantnormals || wanttangents)
                {
                        if (ent->animcache_normal3f)
@@ -6890,10 +6935,7 @@ qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qbool
                                        ent->animcache_tvector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
                                }
                                if (!r_framedata_failed)
-                               {
                                        model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
-                                       R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
-                               }
                        }
                }
        }
@@ -6913,10 +6955,7 @@ qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qbool
                        ent->animcache_tvector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
                }
                if (!r_framedata_failed)
-               {
                        model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
-                       R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
-               }
        }
        return !r_framedata_failed;
 }
@@ -6924,7 +6963,7 @@ qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qbool
 void R_AnimCache_CacheVisibleEntities(void)
 {
        int i;
-       qboolean wantnormals = true;
+       qboolean wantnormals = !r_showsurfaces.integer;
        qboolean wanttangents = !r_showsurfaces.integer;
 
        switch(vid.renderpath)
@@ -6938,9 +6977,6 @@ void R_AnimCache_CacheVisibleEntities(void)
                break;
        }
 
-       if (r_shownormals.integer)
-               wanttangents = wantnormals = true;
-
        // TODO: thread this
        // NOTE: R_PrepareRTLights() also caches entities
 
@@ -7972,10 +8008,10 @@ void R_Bloom_CopyBloomTexture(float colorscale)
        R_SetViewport(&r_bloomstate.viewport);
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_Color(colorscale, colorscale, colorscale, 1);
-       R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.screentexcoord2f);
-       // TODO: do boxfilter scale-down in shader?
+       // TODO: optimize with multitexture or GLSL
+       R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
        R_SetupShader_Generic(r_bloomstate.texture_screen, NULL, GL_MODULATE, 1);
-       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
        r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
 
        // we now have a bloom image in the framebuffer
@@ -7998,6 +8034,8 @@ void R_Bloom_MakeTexture(void)
        r_refdef.stats.bloom++;
 
        R_ResetViewRendering2D();
+       R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
+       R_Mesh_ColorPointer(NULL, 0, 0);
 
        // we have a bloom image in the framebuffer
        CHECKGLERROR
@@ -8008,10 +8046,10 @@ void R_Bloom_MakeTexture(void)
                x *= 2;
                r = bound(0, r_bloom_colorexponent.value / x, 1);
                GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
-               GL_Color(r,r,r,1);
-               R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.bloomtexcoord2f);
+               GL_Color(r, r, r, 1);
                R_SetupShader_Generic(r_bloomstate.texture_bloom, NULL, GL_MODULATE, 1);
-               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+               R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
+               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
                r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
 
                // copy the vertically blurred bloom view to a texture
@@ -8027,6 +8065,7 @@ void R_Bloom_MakeTexture(void)
        if(range >= 1)
                brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
        R_SetupShader_Generic(r_bloomstate.texture_bloom, NULL, GL_MODULATE, 1);
+       R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f, 0, 0);
 
        for (dir = 0;dir < 2;dir++)
        {
@@ -8058,8 +8097,7 @@ void R_Bloom_MakeTexture(void)
                        if(range >= 1)
                                r *= (1 - x*x/(float)(range*range));
                        GL_Color(r, r, r, 1);
-                       R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.offsettexcoord2f);
-                       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+                       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
                        r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
                        GL_BlendFunc(GL_ONE, GL_ONE);
                }
@@ -8074,18 +8112,18 @@ void R_Bloom_MakeTexture(void)
        if (r_bloom_colorsubtract.value > 0 && vid.support.ext_blend_subtract)
        {
                GL_BlendFunc(GL_ONE, GL_ZERO);
-               GL_Color(1,1,1,1);
-               R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.bloomtexcoord2f);
                R_SetupShader_Generic(r_bloomstate.texture_bloom, NULL, GL_MODULATE, 1);
-               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+               R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
+               GL_Color(1, 1, 1, 1);
+               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
                r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
 
                GL_BlendFunc(GL_ONE, GL_ONE);
                qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
                R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+               R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
                GL_Color(r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 1);
-               R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.bloomtexcoord2f);
-               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
                r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
                qglBlendEquationEXT(GL_FUNC_ADD_EXT);
 
@@ -8171,6 +8209,8 @@ static void R_BlendView(void)
                        if (r_bloom_blur.value < 1) { Cvar_SetValueQuick(&r_bloom_blur, 1); }
 
                        R_ResetViewRendering2D();
+                       R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
+                       R_Mesh_ColorPointer(NULL, 0, 0);
 
                        if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))
                        {
@@ -8205,9 +8245,9 @@ static void R_BlendView(void)
                                {
                                        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                                        GL_Color(1, 1, 1, cl.motionbluralpha);
-                                       R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.screentexcoord2f);
                                        R_SetupShader_Generic(r_bloomstate.texture_screen, NULL, GL_MODULATE, 1);
-                                       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+                                       R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
+                                       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
                                        r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
                                }
                        }
@@ -8223,11 +8263,12 @@ static void R_BlendView(void)
                        {
                                // apply a color tint to the whole view
                                R_ResetViewRendering2D();
-                               GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
-                               R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
+                               R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
+                               R_Mesh_ColorPointer(NULL, 0, 0);
                                R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
                                GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-                               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+                               GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
+                               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
                        }
                        break; // no screen processing, no bloom, skip it
                }
@@ -8251,9 +8292,12 @@ static void R_BlendView(void)
                sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
 
                R_ResetViewRendering2D();
+               R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
+               R_Mesh_ColorPointer(NULL, 0, 0);
                GL_Color(1, 1, 1, 1);
-               R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_bloomstate.screentexcoord2f, r_bloomstate.bloomtexcoord2f);
                GL_BlendFunc(GL_ONE, GL_ZERO);
+               R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
+               R_Mesh_TexCoordPointer(1, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
 
                switch(vid.renderpath)
                {
@@ -8290,7 +8334,7 @@ static void R_BlendView(void)
                default:
                        break;
                }
-               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
                r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
                break;
        case RENDERPATH_GL13:
@@ -8299,11 +8343,12 @@ static void R_BlendView(void)
                {
                        // apply a color tint to the whole view
                        R_ResetViewRendering2D();
-                       GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
-                       R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
+                       R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
+                       R_Mesh_ColorPointer(NULL, 0, 0);
                        R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
                        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-                       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+                       GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
+                       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
                }
                break;
        }
@@ -8895,10 +8940,11 @@ void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, floa
                        c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
                }
        }
-       R_Mesh_PrepareVertices_Generic_Arrays(8, vertex3f, color4f, NULL);
+       R_Mesh_VertexPointer(vertex3f, 0, 0);
+       R_Mesh_ColorPointer(color4f, 0, 0);
        R_Mesh_ResetTextureState();
        R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
-       R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
+       R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
 }
 
 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
@@ -9044,7 +9090,9 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight
        GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
        GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
        R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+       R_Mesh_VertexPointer(rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
        memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
+       R_Mesh_ColorPointer(color4f, 0, 0);
        for (i = 0, c = color4f;i < 6;i++, c += 4)
        {
                c[0] *= rsurface.colormod[0];
@@ -9056,7 +9104,7 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight
        {
                for (i = 0, c = color4f;i < 6;i++, c += 4)
                {
-                       f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
+                       f1 = RSurf_FogVertex(rsurface.vertex3f + 3*i);
                        f2 = 1 - f1;
                        c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
                        c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
@@ -9064,8 +9112,7 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight
                }
        }
        R_Mesh_ResetTextureState();
-       R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
-       R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
+       R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, nomodelelement3s, 0, 0);
 }
 
 void R_DrawNoModel(entity_render_t *ent)
@@ -9517,7 +9564,7 @@ texture_t *R_GetCurrentTexture(texture_t *t)
        }
        else
        {
-               t->backgroundbasetexture = r_texture_white;
+               t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white;
                t->backgroundnmaptexture = r_texture_blanknormalmap;
                t->backgroundglosstexture = r_texture_black;
                t->backgroundglowtexture = NULL;
@@ -9667,51 +9714,24 @@ rsurfacestate_t rsurface;
 
 void R_Mesh_ResizeArrays(int newvertices)
 {
-       unsigned char *base;
-       size_t size;
+       float *base;
        if (rsurface.array_size >= newvertices)
                return;
-       if (rsurface.array_base)
-               Mem_Free(rsurface.array_base);
+       if (rsurface.array_modelvertex3f)
+               Mem_Free(rsurface.array_modelvertex3f);
        rsurface.array_size = (newvertices + 1023) & ~1023;
-       size = 0;
-       size += rsurface.array_size * sizeof(*rsurface.array_modelvertexmesh);
-       size += rsurface.array_size * sizeof(*rsurface.array_batchvertexmesh);
-       size += rsurface.array_size * sizeof(*rsurface.array_modelvertexposition);
-       size += rsurface.array_size * sizeof(*rsurface.array_batchvertexposition);
-       size += rsurface.array_size * sizeof(float[3]);
-       size += rsurface.array_size * sizeof(float[3]);
-       size += rsurface.array_size * sizeof(float[3]);
-       size += rsurface.array_size * sizeof(float[3]);
-       size += rsurface.array_size * sizeof(float[3]);
-       size += rsurface.array_size * sizeof(float[3]);
-       size += rsurface.array_size * sizeof(float[3]);
-       size += rsurface.array_size * sizeof(float[3]);
-       size += rsurface.array_size * sizeof(float[4]);
-       size += rsurface.array_size * sizeof(float[2]);
-       size += rsurface.array_size * sizeof(float[2]);
-       size += rsurface.array_size * sizeof(float[4]);
-       size += rsurface.array_size * sizeof(int[3]);
-       size += rsurface.array_size * sizeof(unsigned short[3]);
-       rsurface.array_base = base = (unsigned char *)Mem_Alloc(r_main_mempool, size);
-       rsurface.array_modelvertexmesh         = (r_vertexmesh_t     *)base;base += rsurface.array_size * sizeof(*rsurface.array_modelvertexmesh);
-       rsurface.array_batchvertexmesh         = (r_vertexmesh_t     *)base;base += rsurface.array_size * sizeof(*rsurface.array_batchvertexmesh);
-       rsurface.array_modelvertexposition     = (r_vertexposition_t *)base;base += rsurface.array_size * sizeof(*rsurface.array_modelvertexposition);
-       rsurface.array_batchvertexposition     = (r_vertexposition_t *)base;base += rsurface.array_size * sizeof(*rsurface.array_batchvertexposition);
-       rsurface.array_modelvertex3f           = (float              *)base;base += rsurface.array_size * sizeof(float[3]);
-       rsurface.array_modelsvector3f          = (float              *)base;base += rsurface.array_size * sizeof(float[3]);
-       rsurface.array_modeltvector3f          = (float              *)base;base += rsurface.array_size * sizeof(float[3]);
-       rsurface.array_modelnormal3f           = (float              *)base;base += rsurface.array_size * sizeof(float[3]);
-       rsurface.array_batchvertex3f           = (float              *)base;base += rsurface.array_size * sizeof(float[3]);
-       rsurface.array_batchsvector3f          = (float              *)base;base += rsurface.array_size * sizeof(float[3]);
-       rsurface.array_batchtvector3f          = (float              *)base;base += rsurface.array_size * sizeof(float[3]);
-       rsurface.array_batchnormal3f           = (float              *)base;base += rsurface.array_size * sizeof(float[3]);
-       rsurface.array_batchlightmapcolor4f    = (float              *)base;base += rsurface.array_size * sizeof(float[4]);
-       rsurface.array_batchtexcoordtexture2f  = (float              *)base;base += rsurface.array_size * sizeof(float[2]);
-       rsurface.array_batchtexcoordlightmap2f = (float              *)base;base += rsurface.array_size * sizeof(float[2]);
-       rsurface.array_passcolor4f             = (float              *)base;base += rsurface.array_size * sizeof(float[4]);
-       rsurface.array_batchelement3i          = (int                *)base;base += rsurface.array_size * sizeof(int[3]);
-       rsurface.array_batchelement3s          = (unsigned short     *)base;base += rsurface.array_size * sizeof(unsigned short[3]);
+       base = (float *)Mem_Alloc(r_main_mempool, rsurface.array_size * sizeof(float[33]));
+       rsurface.array_modelvertex3f     = base + rsurface.array_size * 0;
+       rsurface.array_modelsvector3f    = base + rsurface.array_size * 3;
+       rsurface.array_modeltvector3f    = base + rsurface.array_size * 6;
+       rsurface.array_modelnormal3f     = base + rsurface.array_size * 9;
+       rsurface.array_deformedvertex3f  = base + rsurface.array_size * 12;
+       rsurface.array_deformedsvector3f = base + rsurface.array_size * 15;
+       rsurface.array_deformedtvector3f = base + rsurface.array_size * 18;
+       rsurface.array_deformednormal3f  = base + rsurface.array_size * 21;
+       rsurface.array_texcoord3f        = base + rsurface.array_size * 24;
+       rsurface.array_color4f           = base + rsurface.array_size * 27;
+       rsurface.array_generatedtexcoordtexture2f = base + rsurface.array_size * 31;
 }
 
 void RSurf_ActiveWorldEntity(void)
@@ -9753,80 +9773,48 @@ void RSurf_ActiveWorldEntity(void)
        rsurface.basepolygonfactor = r_refdef.polygonfactor;
        rsurface.basepolygonoffset = r_refdef.polygonoffset;
        rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
-       rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+       rsurface.modelvertex3f_bufferobject = model->surfmesh.vbo;
        rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
        rsurface.modelsvector3f = model->surfmesh.data_svector3f;
-       rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+       rsurface.modelsvector3f_bufferobject = model->surfmesh.vbo;
        rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
        rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
-       rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+       rsurface.modeltvector3f_bufferobject = model->surfmesh.vbo;
        rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
        rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
-       rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+       rsurface.modelnormal3f_bufferobject = model->surfmesh.vbo;
        rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
        rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
-       rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+       rsurface.modellightmapcolor4f_bufferobject = model->surfmesh.vbo;
        rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
        rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
-       rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+       rsurface.modeltexcoordtexture2f_bufferobject = model->surfmesh.vbo;
        rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
        rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
-       rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+       rsurface.modeltexcoordlightmap2f_bufferobject = model->surfmesh.vbo;
        rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
        rsurface.modelelement3i = model->surfmesh.data_element3i;
-       rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
-       rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
        rsurface.modelelement3s = model->surfmesh.data_element3s;
-       rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
-       rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
+       rsurface.modelelement3i_bufferobject = model->surfmesh.ebo3i;
+       rsurface.modelelement3s_bufferobject = model->surfmesh.ebo3s;
        rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
-       rsurface.modelnumvertices = model->surfmesh.num_vertices;
-       rsurface.modelnumtriangles = model->surfmesh.num_triangles;
+       rsurface.modelnum_vertices = model->surfmesh.num_vertices;
+       rsurface.modelnum_triangles = model->surfmesh.num_triangles;
        rsurface.modelsurfaces = model->data_surfaces;
-       rsurface.modelvertexmesh = model->surfmesh.vertexmesh;
-       rsurface.modelvertexmeshbuffer = model->surfmesh.vertexmeshbuffer;
-       rsurface.modelvertexposition = model->surfmesh.vertexposition;
-       rsurface.modelvertexpositionbuffer = model->surfmesh.vertexpositionbuffer;
-       rsurface.modelgeneratedvertex = false;
-       rsurface.batchgeneratedvertex = false;
-       rsurface.batchfirstvertex = 0;
-       rsurface.batchnumvertices = 0;
-       rsurface.batchfirsttriangle = 0;
-       rsurface.batchnumtriangles = 0;
-       rsurface.batchvertex3f  = NULL;
-       rsurface.batchvertex3f_vertexbuffer = NULL;
-       rsurface.batchvertex3f_bufferoffset = 0;
-       rsurface.batchsvector3f = NULL;
-       rsurface.batchsvector3f_vertexbuffer = NULL;
-       rsurface.batchsvector3f_bufferoffset = 0;
-       rsurface.batchtvector3f = NULL;
-       rsurface.batchtvector3f_vertexbuffer = NULL;
-       rsurface.batchtvector3f_bufferoffset = 0;
-       rsurface.batchnormal3f  = NULL;
-       rsurface.batchnormal3f_vertexbuffer = NULL;
-       rsurface.batchnormal3f_bufferoffset = 0;
-       rsurface.batchlightmapcolor4f = NULL;
-       rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
-       rsurface.batchlightmapcolor4f_bufferoffset = 0;
-       rsurface.batchtexcoordtexture2f = NULL;
-       rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-       rsurface.batchtexcoordtexture2f_bufferoffset = 0;
-       rsurface.batchtexcoordlightmap2f = NULL;
-       rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
-       rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
-       rsurface.batchvertexmesh = NULL;
-       rsurface.batchvertexmeshbuffer = NULL;
-       rsurface.batchvertexposition = NULL;
-       rsurface.batchvertexpositionbuffer = NULL;
-       rsurface.batchelement3i = NULL;
-       rsurface.batchelement3i_indexbuffer = NULL;
-       rsurface.batchelement3i_bufferoffset = 0;
-       rsurface.batchelement3s = NULL;
-       rsurface.batchelement3s_indexbuffer = NULL;
-       rsurface.batchelement3s_bufferoffset = 0;
-       rsurface.passcolor4f = NULL;
-       rsurface.passcolor4f_vertexbuffer = NULL;
-       rsurface.passcolor4f_bufferoffset = 0;
+       rsurface.generatedvertex = false;
+       rsurface.vertex3f  = rsurface.modelvertex3f;
+       rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
+       rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
+       rsurface.svector3f = rsurface.modelsvector3f;
+       rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
+       rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
+       rsurface.tvector3f = rsurface.modeltvector3f;
+       rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
+       rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
+       rsurface.normal3f  = rsurface.modelnormal3f;
+       rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
+       rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
+       rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
 }
 
 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
@@ -9879,10 +9867,6 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
                        rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
                        rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
                        rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
-                       rsurface.modelvertexmesh = ent->animcache_vertexmesh;
-                       rsurface.modelvertexmeshbuffer = ent->animcache_vertexmeshbuffer;
-                       rsurface.modelvertexposition = ent->animcache_vertexposition;
-                       rsurface.modelvertexpositionbuffer = ent->animcache_vertexpositionbuffer;
                }
                else if (wanttangents)
                {
@@ -9891,10 +9875,6 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
                        rsurface.modeltvector3f = rsurface.array_modeltvector3f;
                        rsurface.modelnormal3f = rsurface.array_modelnormal3f;
                        model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f);
-                       rsurface.modelvertexmesh = NULL;
-                       rsurface.modelvertexmeshbuffer = NULL;
-                       rsurface.modelvertexposition = NULL;
-                       rsurface.modelvertexpositionbuffer = NULL;
                }
                else if (wantnormals)
                {
@@ -9903,10 +9883,6 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
                        rsurface.modeltvector3f = NULL;
                        rsurface.modelnormal3f = rsurface.array_modelnormal3f;
                        model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, NULL, NULL);
-                       rsurface.modelvertexmesh = NULL;
-                       rsurface.modelvertexmeshbuffer = NULL;
-                       rsurface.modelvertexposition = NULL;
-                       rsurface.modelvertexpositionbuffer = NULL;
                }
                else
                {
@@ -9915,115 +9891,77 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
                        rsurface.modeltvector3f = NULL;
                        rsurface.modelnormal3f = NULL;
                        model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.array_modelvertex3f, NULL, NULL, NULL);
-                       rsurface.modelvertexmesh = NULL;
-                       rsurface.modelvertexmeshbuffer = NULL;
-                       rsurface.modelvertexposition = NULL;
-                       rsurface.modelvertexpositionbuffer = NULL;
                }
-               rsurface.modelvertex3f_vertexbuffer = 0;
+               rsurface.modelvertex3f_bufferobject = 0;
                rsurface.modelvertex3f_bufferoffset = 0;
-               rsurface.modelsvector3f_vertexbuffer = 0;
+               rsurface.modelsvector3f_bufferobject = 0;
                rsurface.modelsvector3f_bufferoffset = 0;
-               rsurface.modeltvector3f_vertexbuffer = 0;
+               rsurface.modeltvector3f_bufferobject = 0;
                rsurface.modeltvector3f_bufferoffset = 0;
-               rsurface.modelnormal3f_vertexbuffer = 0;
+               rsurface.modelnormal3f_bufferobject = 0;
                rsurface.modelnormal3f_bufferoffset = 0;
-               rsurface.modelgeneratedvertex = true;
+               rsurface.generatedvertex = true;
        }
        else
        {
                rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
-               rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+               rsurface.modelvertex3f_bufferobject = model->surfmesh.vbo;
                rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
                rsurface.modelsvector3f = model->surfmesh.data_svector3f;
-               rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+               rsurface.modelsvector3f_bufferobject = model->surfmesh.vbo;
                rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
                rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
-               rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+               rsurface.modeltvector3f_bufferobject = model->surfmesh.vbo;
                rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
                rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
-               rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+               rsurface.modelnormal3f_bufferobject = model->surfmesh.vbo;
                rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
-               rsurface.modelvertexmesh = model->surfmesh.vertexmesh;
-               rsurface.modelvertexmeshbuffer = model->surfmesh.vertexmeshbuffer;
-               rsurface.modelvertexposition = model->surfmesh.vertexposition;
-               rsurface.modelvertexpositionbuffer = model->surfmesh.vertexpositionbuffer;
-               rsurface.modelgeneratedvertex = false;
+               rsurface.generatedvertex = false;
        }
        rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
-       rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+       rsurface.modellightmapcolor4f_bufferobject = model->surfmesh.vbo;
        rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
        rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
-       rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+       rsurface.modeltexcoordtexture2f_bufferobject = model->surfmesh.vbo;
        rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
        rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
-       rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+       rsurface.modeltexcoordlightmap2f_bufferobject = model->surfmesh.vbo;
        rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
        rsurface.modelelement3i = model->surfmesh.data_element3i;
-       rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
-       rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
        rsurface.modelelement3s = model->surfmesh.data_element3s;
-       rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
-       rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
+       rsurface.modelelement3i_bufferobject = model->surfmesh.ebo3i;
+       rsurface.modelelement3s_bufferobject = model->surfmesh.ebo3s;
        rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
-       rsurface.modelnumvertices = model->surfmesh.num_vertices;
-       rsurface.modelnumtriangles = model->surfmesh.num_triangles;
+       rsurface.modelnum_vertices = model->surfmesh.num_vertices;
+       rsurface.modelnum_triangles = model->surfmesh.num_triangles;
        rsurface.modelsurfaces = model->data_surfaces;
-       rsurface.batchgeneratedvertex = false;
-       rsurface.batchfirstvertex = 0;
-       rsurface.batchnumvertices = 0;
-       rsurface.batchfirsttriangle = 0;
-       rsurface.batchnumtriangles = 0;
-       rsurface.batchvertex3f  = NULL;
-       rsurface.batchvertex3f_vertexbuffer = NULL;
-       rsurface.batchvertex3f_bufferoffset = 0;
-       rsurface.batchsvector3f = NULL;
-       rsurface.batchsvector3f_vertexbuffer = NULL;
-       rsurface.batchsvector3f_bufferoffset = 0;
-       rsurface.batchtvector3f = NULL;
-       rsurface.batchtvector3f_vertexbuffer = NULL;
-       rsurface.batchtvector3f_bufferoffset = 0;
-       rsurface.batchnormal3f  = NULL;
-       rsurface.batchnormal3f_vertexbuffer = NULL;
-       rsurface.batchnormal3f_bufferoffset = 0;
-       rsurface.batchlightmapcolor4f = NULL;
-       rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
-       rsurface.batchlightmapcolor4f_bufferoffset = 0;
-       rsurface.batchtexcoordtexture2f = NULL;
-       rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-       rsurface.batchtexcoordtexture2f_bufferoffset = 0;
-       rsurface.batchtexcoordlightmap2f = NULL;
-       rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
-       rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
-       rsurface.batchvertexmesh = NULL;
-       rsurface.batchvertexmeshbuffer = NULL;
-       rsurface.batchvertexposition = NULL;
-       rsurface.batchvertexpositionbuffer = NULL;
-       rsurface.batchelement3i = NULL;
-       rsurface.batchelement3i_indexbuffer = NULL;
-       rsurface.batchelement3i_bufferoffset = 0;
-       rsurface.batchelement3s = NULL;
-       rsurface.batchelement3s_indexbuffer = NULL;
-       rsurface.batchelement3s_bufferoffset = 0;
-       rsurface.passcolor4f = NULL;
-       rsurface.passcolor4f_vertexbuffer = NULL;
-       rsurface.passcolor4f_bufferoffset = 0;
+       rsurface.vertex3f  = rsurface.modelvertex3f;
+       rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
+       rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
+       rsurface.svector3f = rsurface.modelsvector3f;
+       rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
+       rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
+       rsurface.tvector3f = rsurface.modeltvector3f;
+       rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
+       rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
+       rsurface.normal3f  = rsurface.modelnormal3f;
+       rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
+       rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
+       rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
 }
 
 void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qboolean wantnormals, qboolean wanttangents)
 {
-       int i;
-
        rsurface.entity = r_refdef.scene.worldentity;
        rsurface.skeleton = NULL;
        rsurface.ent_skinnum = 0;
        rsurface.ent_qwskin = -1;
        rsurface.ent_shadertime = shadertime;
        rsurface.ent_flags = entflags;
-       rsurface.modelnumvertices = numvertices;
-       rsurface.modelnumtriangles = numtriangles;
-       if (rsurface.array_size < rsurface.modelnumvertices)
-               R_Mesh_ResizeArrays(rsurface.modelnumvertices);
+       rsurface.modelnum_vertices = numvertices;
+       rsurface.modelnum_triangles = numtriangles;
+       if (rsurface.array_size < rsurface.modelnum_vertices)
+               R_Mesh_ResizeArrays(rsurface.modelnum_vertices);
        rsurface.matrix = *matrix;
        rsurface.inversematrix = *inversematrix;
        rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
@@ -10068,108 +10006,50 @@ void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inve
                rsurface.modeltvector3f = NULL;
                rsurface.modelnormal3f = NULL;
        }
-       rsurface.modelvertexmesh = NULL;
-       rsurface.modelvertexmeshbuffer = NULL;
-       rsurface.modelvertexposition = NULL;
-       rsurface.modelvertexpositionbuffer = NULL;
-       rsurface.modelvertex3f_vertexbuffer = 0;
+       rsurface.modelvertex3f_bufferobject = 0;
        rsurface.modelvertex3f_bufferoffset = 0;
-       rsurface.modelsvector3f_vertexbuffer = 0;
+       rsurface.modelsvector3f_bufferobject = 0;
        rsurface.modelsvector3f_bufferoffset = 0;
-       rsurface.modeltvector3f_vertexbuffer = 0;
+       rsurface.modeltvector3f_bufferobject = 0;
        rsurface.modeltvector3f_bufferoffset = 0;
-       rsurface.modelnormal3f_vertexbuffer = 0;
+       rsurface.modelnormal3f_bufferobject = 0;
        rsurface.modelnormal3f_bufferoffset = 0;
-       rsurface.modelgeneratedvertex = true;
+       rsurface.generatedvertex = true;
        rsurface.modellightmapcolor4f  = color4f;
-       rsurface.modellightmapcolor4f_vertexbuffer = 0;
+       rsurface.modellightmapcolor4f_bufferobject = 0;
        rsurface.modellightmapcolor4f_bufferoffset = 0;
        rsurface.modeltexcoordtexture2f  = texcoord2f;
-       rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
+       rsurface.modeltexcoordtexture2f_bufferobject = 0;
        rsurface.modeltexcoordtexture2f_bufferoffset = 0;
        rsurface.modeltexcoordlightmap2f  = NULL;
-       rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
+       rsurface.modeltexcoordlightmap2f_bufferobject = 0;
        rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
        rsurface.modelelement3i = element3i;
-       rsurface.modelelement3i_indexbuffer = NULL;
-       rsurface.modelelement3i_bufferoffset = 0;
        rsurface.modelelement3s = element3s;
-       rsurface.modelelement3s_indexbuffer = NULL;
-       rsurface.modelelement3s_bufferoffset = 0;
+       rsurface.modelelement3i_bufferobject = 0;
+       rsurface.modelelement3s_bufferobject = 0;
        rsurface.modellightmapoffsets = NULL;
        rsurface.modelsurfaces = NULL;
-       rsurface.batchgeneratedvertex = false;
-       rsurface.batchfirstvertex = 0;
-       rsurface.batchnumvertices = 0;
-       rsurface.batchfirsttriangle = 0;
-       rsurface.batchnumtriangles = 0;
-       rsurface.batchvertex3f  = NULL;
-       rsurface.batchvertex3f_vertexbuffer = NULL;
-       rsurface.batchvertex3f_bufferoffset = 0;
-       rsurface.batchsvector3f = NULL;
-       rsurface.batchsvector3f_vertexbuffer = NULL;
-       rsurface.batchsvector3f_bufferoffset = 0;
-       rsurface.batchtvector3f = NULL;
-       rsurface.batchtvector3f_vertexbuffer = NULL;
-       rsurface.batchtvector3f_bufferoffset = 0;
-       rsurface.batchnormal3f  = NULL;
-       rsurface.batchnormal3f_vertexbuffer = NULL;
-       rsurface.batchnormal3f_bufferoffset = 0;
-       rsurface.batchlightmapcolor4f = NULL;
-       rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
-       rsurface.batchlightmapcolor4f_bufferoffset = 0;
-       rsurface.batchtexcoordtexture2f = NULL;
-       rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-       rsurface.batchtexcoordtexture2f_bufferoffset = 0;
-       rsurface.batchtexcoordlightmap2f = NULL;
-       rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
-       rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
-       rsurface.batchvertexmesh = NULL;
-       rsurface.batchvertexmeshbuffer = NULL;
-       rsurface.batchvertexposition = NULL;
-       rsurface.batchvertexpositionbuffer = NULL;
-       rsurface.batchelement3i = NULL;
-       rsurface.batchelement3i_indexbuffer = NULL;
-       rsurface.batchelement3i_bufferoffset = 0;
-       rsurface.batchelement3s = NULL;
-       rsurface.batchelement3s_indexbuffer = NULL;
-       rsurface.batchelement3s_bufferoffset = 0;
-       rsurface.passcolor4f = NULL;
-       rsurface.passcolor4f_vertexbuffer = NULL;
-       rsurface.passcolor4f_bufferoffset = 0;
-
-       if (rsurface.modelnumvertices && rsurface.modelelement3i)
+       rsurface.vertex3f  = rsurface.modelvertex3f;
+       rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
+       rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
+       rsurface.svector3f = rsurface.modelsvector3f;
+       rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
+       rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
+       rsurface.tvector3f = rsurface.modeltvector3f;
+       rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
+       rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
+       rsurface.normal3f  = rsurface.modelnormal3f;
+       rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
+       rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
+       rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
+
+       if (rsurface.modelnum_vertices && rsurface.modelelement3i)
        {
                if ((wantnormals || wanttangents) && !normal3f)
-               {
-                       Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
-                       rsurface.modelnormal3f = rsurface.array_modelnormal3f;
-               }
+                       Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
                if (wanttangents && !svector3f)
-               {
-                       Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
-                       rsurface.modelsvector3f = rsurface.array_modelsvector3f;
-                       rsurface.modeltvector3f = rsurface.array_modeltvector3f;
-               }
-       }
-
-       // now convert arrays into vertexmesh structs
-       for (i = 0;i < numvertices;i++)
-       {
-               VectorCopy(rsurface.modelvertex3f + 3*i, rsurface.array_modelvertexposition[i].vertex3f);
-               VectorCopy(rsurface.modelvertex3f + 3*i, rsurface.array_modelvertexmesh[i].vertex3f);
-               if (rsurface.modelsvector3f)
-                       VectorCopy(rsurface.modelsvector3f + 3*i, rsurface.array_modelvertexmesh[i].svector3f);
-               if (rsurface.modeltvector3f)
-                       VectorCopy(rsurface.modeltvector3f + 3*i, rsurface.array_modelvertexmesh[i].tvector3f);
-               if (rsurface.modelnormal3f)
-                       VectorCopy(rsurface.modelnormal3f + 3*i, rsurface.array_modelvertexmesh[i].normal3f);
-               if (rsurface.modellightmapcolor4f)
-                       Vector4Scale(rsurface.modellightmapcolor4f + 4*i, 255.0f, rsurface.array_modelvertexmesh[i].color4ub);
-               if (rsurface.modeltexcoordtexture2f)
-                       Vector2Copy(rsurface.modeltexcoordtexture2f + 2*i, rsurface.array_modelvertexmesh[i].texcoordtexture2f);
-               if (rsurface.modeltexcoordlightmap2f)
-                       Vector2Copy(rsurface.modeltexcoordlightmap2f + 2*i, rsurface.array_modelvertexmesh[i].texcoordlightmap2f);
+                       Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
        }
 }
 
@@ -10205,456 +10085,70 @@ float RSurf_FogVertex(const float *v)
        return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
 }
 
-void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
-{
-       int i;
-       for (i = 0;i < numelements;i++)
-               outelement3i[i] = inelement3i[i] + adjust;
-}
-
 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
-extern cvar_t gl_vbo;
-void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
+void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, const msurface_t **texturesurfacelist)
 {
        int deformindex;
-       int firsttriangle;
-       int numtriangles;
-       int firstvertex;
-       int endvertex;
-       int numvertices;
-       int surfacefirsttriangle;
-       int surfacenumtriangles;
-       int surfacefirstvertex;
-       int surfaceendvertex;
-       int surfacenumvertices;
-       int surfaceadjustvertex;
-       int needsupdate;
+       int texturesurfaceindex;
        int i, j;
-       qboolean gaps;
-       qboolean dynamicvertex;
        float amplitude;
        float animpos;
        float scale;
+       const float *v1, *in_tc;
+       float *out_tc;
        float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
        float waveparms[4];
        q3shaderinfo_deform_t *deform;
-       const msurface_t *surface, *firstsurface;
-       r_vertexposition_t *vertexposition;
-       r_vertexmesh_t *vertexmesh;
-       if (!texturenumsurfaces)
-               return;
-       // find vertex range of this surface batch
-       gaps = false;
-       firstsurface = texturesurfacelist[0];
-       firsttriangle = firstsurface->num_firsttriangle;
-       numtriangles = 0;
-       firstvertex = endvertex = firstsurface->num_firstvertex;
-       for (i = 0;i < texturenumsurfaces;i++)
-       {
-               surface = texturesurfacelist[i];
-               if (surface != firstsurface + i)
-                       gaps = true;
-               surfacefirstvertex = surface->num_firstvertex;
-               surfaceendvertex = surfacefirstvertex + surface->num_vertices;
-               surfacenumtriangles = surface->num_triangles;
-               if (firstvertex > surfacefirstvertex)
-                       firstvertex = surfacefirstvertex;
-               if (endvertex < surfaceendvertex)
-                       endvertex = surfaceendvertex;
-               numtriangles += surfacenumtriangles;
-       }
-       if (!numtriangles)
-               return;
-
-       // we now know the vertex range used, and if there are any gaps in it
-       rsurface.batchfirstvertex = firstvertex;
-       rsurface.batchnumvertices = endvertex - firstvertex;
-       rsurface.batchfirsttriangle = firsttriangle;
-       rsurface.batchnumtriangles = numtriangles;
-
-       // this variable holds flags for which properties have been updated that
-       // may require regenerating vertexmesh or vertexposition arrays...
-       needsupdate = 0;
-
-       if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
-               needsupdate |= BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_NOGAPS;
-       for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform;deformindex++, deform++)
+       // if vertices are dynamic (animated models), generate them into the temporary rsurface.array_model* arrays and point rsurface.model* at them instead of the static data from the model itself
+       if (rsurface.generatedvertex)
        {
-               switch (deform->deform)
+               if (rsurface.texture->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
+                       generatenormals = true;
+               for (i = 0;i < Q3MAXDEFORMS;i++)
                {
-               default:
-               case Q3DEFORM_PROJECTIONSHADOW:
-               case Q3DEFORM_TEXT0:
-               case Q3DEFORM_TEXT1:
-               case Q3DEFORM_TEXT2:
-               case Q3DEFORM_TEXT3:
-               case Q3DEFORM_TEXT4:
-               case Q3DEFORM_TEXT5:
-               case Q3DEFORM_TEXT6:
-               case Q3DEFORM_TEXT7:
-               case Q3DEFORM_NONE:
-                       break;
-               case Q3DEFORM_AUTOSPRITE:
-                       batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS;
-                       needsupdate |= BATCHNEED_VERTEXPOSITION | BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
-                       break;
-               case Q3DEFORM_AUTOSPRITE2:
-                       batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS;
-                       needsupdate |= BATCHNEED_VERTEXPOSITION | BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
-                       break;
-               case Q3DEFORM_NORMAL:
-                       batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS;
-                       needsupdate |= BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
-                       break;
-               case Q3DEFORM_WAVE:
-                       batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS;
-                       needsupdate |= BATCHNEED_VERTEXPOSITION | BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
-                       break;
-               case Q3DEFORM_BULGE:
-                       batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS;
-                       needsupdate |= BATCHNEED_VERTEXPOSITION | BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
-                       break;
-               case Q3DEFORM_MOVE:
-                       batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS;
-                       needsupdate |= BATCHNEED_VERTEXPOSITION | BATCHNEED_VERTEXMESH_VERTEX;
-                       break;
-               }
-       }
-       switch(rsurface.texture->tcgen.tcgen)
-       {
-       default:
-       case Q3TCGEN_TEXTURE:
-               break;
-       case Q3TCGEN_LIGHTMAP:
-               batchneed |= BATCHNEED_ARRAY_LIGHTMAP | BATCHNEED_NOGAPS;
-               needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP;
-               break;
-       case Q3TCGEN_VECTOR:
-               batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS;
-               needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
-               break;
-       case Q3TCGEN_ENVIRONMENT:
-               batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS;
-               needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
-               break;
-       }
-       if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
-       {
-               batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS;
-               needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
-       }
-
-       // check if any dynamic vertex processing must occur
-       dynamicvertex = false;
-
-       if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
-       {
-               dynamicvertex = true;
-               batchneed |= BATCHNEED_NOGAPS;
-               needsupdate |= (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP));
-       }
-
-       if (needsupdate & batchneed & BATCHNEED_VERTEXPOSITION)
-       {
-               dynamicvertex = true;
-               batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS;
-               needsupdate |= (batchneed & BATCHNEED_VERTEXPOSITION);
-       }
-
-       if (dynamicvertex || gaps || rsurface.batchfirstvertex)
-       {
-               // when copying, we need to consider the regeneration of vertexmesh, any dependencies it may have must be set...
-               if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)      batchneed |= BATCHNEED_ARRAY_VERTEX;
-               if (batchneed & BATCHNEED_VERTEXMESH_NORMAL)      batchneed |= BATCHNEED_ARRAY_NORMAL;
-               if (batchneed & BATCHNEED_VERTEXMESH_VECTOR)      batchneed |= BATCHNEED_ARRAY_VECTOR;
-               if (batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) batchneed |= BATCHNEED_ARRAY_VERTEXCOLOR;
-               if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD)    batchneed |= BATCHNEED_ARRAY_TEXCOORD;
-               if (batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP)    batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
-       }
-
-       // when the model data has no vertex buffer (dynamic mesh), we need to
-       // eliminate gaps
-       if (!rsurface.modelvertexmeshbuffer || (!gl_vbo.integer && !vid.forcevbo))
-               batchneed |= BATCHNEED_NOGAPS;
-
-       // if needsupdate, we have to do a dynamic vertex batch for sure
-       if (needsupdate & batchneed)
-               dynamicvertex = true;
-
-       // see if we need to build vertexmesh from arrays
-       if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
-               dynamicvertex = true;
-
-       // see if we need to build vertexposition from arrays
-       if (!rsurface.modelvertexposition && (batchneed & BATCHNEED_VERTEXPOSITION))
-               dynamicvertex = true;
-
-       // if gaps are unacceptable, and there are gaps, it's a dynamic batch...
-       if ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex))
-               dynamicvertex = true;
-
-       // if there is a chance of animated vertex colors, it's a dynamic batch
-       if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
-               dynamicvertex = true;
-
-       rsurface.batchvertex3f = rsurface.modelvertex3f;
-       rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
-       rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
-       rsurface.batchsvector3f = rsurface.modelsvector3f;
-       rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
-       rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
-       rsurface.batchtvector3f = rsurface.modeltvector3f;
-       rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
-       rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
-       rsurface.batchnormal3f = rsurface.modelnormal3f;
-       rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
-       rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
-       rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
-       rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
-       rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
-       rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
-       rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
-       rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
-       rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
-       rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
-       rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
-       rsurface.batchvertexposition = rsurface.modelvertexposition;
-       rsurface.batchvertexpositionbuffer = rsurface.modelvertexpositionbuffer;
-       rsurface.batchvertexmesh = rsurface.modelvertexmesh;
-       rsurface.batchvertexmeshbuffer = rsurface.modelvertexmeshbuffer;
-       rsurface.batchelement3i = rsurface.modelelement3i;
-       rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
-       rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
-       rsurface.batchelement3s = rsurface.modelelement3s;
-       rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
-       rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
-
-       // if any dynamic vertex processing has to occur in software, we copy the
-       // entire surface list together before processing to rebase the vertices
-       // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
-       //
-       // if any gaps exist and we do not have a static vertex buffer, we have to
-       // copy the surface list together to avoid wasting upload bandwidth on the
-       // vertices in the gaps.
-       //
-       // if gaps exist and we have a static vertex buffer, we still have to
-       // combine the index buffer ranges into one dynamic index buffer.
-       //
-       // in all cases we end up with data that can be drawn in one call.
-
-       if (!dynamicvertex)
-       {
-               // static vertex data, just set pointers...
-               rsurface.batchgeneratedvertex = false;
-               // if there are gaps, we want to build a combined index buffer,
-               // otherwise use the original static buffer with an appropriate offset
-               if (gaps)
-               {
-                       firsttriangle = 0;
-                       numtriangles = 0;
-                       for (i = 0;i < texturenumsurfaces;i++)
-                       {
-                               surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
-                               surfacenumtriangles = texturesurfacelist[i]->num_triangles;
-                               memcpy(rsurface.array_batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
-                               numtriangles += surfacenumtriangles;
-                       }
-                       rsurface.batchelement3i = rsurface.array_batchelement3i;
-                       rsurface.batchelement3i_indexbuffer = NULL;
-                       rsurface.batchelement3i_bufferoffset = 0;
-                       rsurface.batchelement3s = NULL;
-                       rsurface.batchelement3s_indexbuffer = NULL;
-                       rsurface.batchelement3s_bufferoffset = 0;
-                       if (endvertex <= 65536)
-                       {
-                               rsurface.batchelement3s = rsurface.array_batchelement3s;
-                               for (i = 0;i < numtriangles*3;i++)
-                                       rsurface.array_batchelement3s[i] = rsurface.array_batchelement3i[i];
-                       }
-                       rsurface.batchfirsttriangle = firsttriangle;
-                       rsurface.batchnumtriangles = numtriangles;
-               }
-               return;
-       }
-
-       // something needs software processing, do it for real...
-       // we only directly handle interleaved array data in this case...
-       rsurface.batchgeneratedvertex = true;
-
-       // now copy the vertex data into a combined array and make an index array
-       // (this is what Quake3 does all the time)
-       //if (gaps || rsurface.batchfirstvertex)
-       {
-               rsurface.batchvertexposition = NULL;
-               rsurface.batchvertexpositionbuffer = NULL;
-               rsurface.batchvertexmesh = NULL;
-               rsurface.batchvertexmeshbuffer = NULL;
-               rsurface.batchvertex3f = NULL;
-               rsurface.batchvertex3f_vertexbuffer = NULL;
-               rsurface.batchvertex3f_bufferoffset = 0;
-               rsurface.batchsvector3f = NULL;
-               rsurface.batchsvector3f_vertexbuffer = NULL;
-               rsurface.batchsvector3f_bufferoffset = 0;
-               rsurface.batchtvector3f = NULL;
-               rsurface.batchtvector3f_vertexbuffer = NULL;
-               rsurface.batchtvector3f_bufferoffset = 0;
-               rsurface.batchnormal3f = NULL;
-               rsurface.batchnormal3f_vertexbuffer = NULL;
-               rsurface.batchnormal3f_bufferoffset = 0;
-               rsurface.batchlightmapcolor4f = NULL;
-               rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
-               rsurface.batchlightmapcolor4f_bufferoffset = 0;
-               rsurface.batchtexcoordtexture2f = NULL;
-               rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-               rsurface.batchtexcoordtexture2f_bufferoffset = 0;
-               rsurface.batchtexcoordlightmap2f = NULL;
-               rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
-               rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
-               rsurface.batchelement3i = rsurface.array_batchelement3i;
-               rsurface.batchelement3i_indexbuffer = NULL;
-               rsurface.batchelement3i_bufferoffset = 0;
-               rsurface.batchelement3s = NULL;
-               rsurface.batchelement3s_indexbuffer = NULL;
-               rsurface.batchelement3s_bufferoffset = 0;
-               // we'll only be setting up certain arrays as needed
-               if (batchneed & BATCHNEED_VERTEXPOSITION)
-                       rsurface.batchvertexposition = rsurface.array_batchvertexposition;
-               if (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
-                       rsurface.batchvertexmesh = rsurface.array_batchvertexmesh;
-               if (batchneed & BATCHNEED_ARRAY_VERTEX)
-                       rsurface.batchvertex3f = rsurface.array_batchvertex3f;
-               if (batchneed & BATCHNEED_ARRAY_NORMAL)
-                       rsurface.batchnormal3f = rsurface.array_batchnormal3f;
-               if (batchneed & BATCHNEED_ARRAY_VECTOR)
-               {
-                       rsurface.batchsvector3f = rsurface.array_batchsvector3f;
-                       rsurface.batchtvector3f = rsurface.array_batchtvector3f;
-               }
-               if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
-                       rsurface.batchlightmapcolor4f = rsurface.array_batchlightmapcolor4f;
-               if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
-                       rsurface.batchtexcoordtexture2f = rsurface.array_batchtexcoordtexture2f;
-               if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
-                       rsurface.batchtexcoordlightmap2f = rsurface.array_batchtexcoordlightmap2f;
-               numvertices = 0;
-               numtriangles = 0;
-               for (i = 0;i < texturenumsurfaces;i++)
-               {
-                       surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
-                       surfacenumvertices = texturesurfacelist[i]->num_vertices;
-                       surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
-                       surfaceadjustvertex = numvertices - surfacefirstvertex;
-                       surfacenumtriangles = texturesurfacelist[i]->num_triangles;
-                       // copy only the data requested
-                       if ((batchneed & BATCHNEED_VERTEXPOSITION) && rsurface.modelvertexposition)
-                               memcpy(rsurface.array_batchvertexposition + numvertices, rsurface.modelvertexposition + surfacefirstvertex, surfacenumvertices * sizeof(rsurface.batchvertexposition[0]));
-                       if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) && rsurface.modelvertexmesh)
-                               memcpy(rsurface.array_batchvertexmesh + numvertices, rsurface.modelvertexmesh + surfacefirstvertex, surfacenumvertices * sizeof(rsurface.batchvertexmesh[0]));
-                       if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
-                       {
-                               if (batchneed & BATCHNEED_ARRAY_VERTEX)
-                                       memcpy(rsurface.array_batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
-                               if ((batchneed & BATCHNEED_ARRAY_NORMAL) && rsurface.modelnormal3f)
-                                       memcpy(rsurface.array_batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
-                               if ((batchneed & BATCHNEED_ARRAY_VECTOR) && rsurface.modelsvector3f)
-                               {
-                                       memcpy(rsurface.array_batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
-                                       memcpy(rsurface.array_batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
-                               }
-                               if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && rsurface.modellightmapcolor4f)
-                                       memcpy(rsurface.array_batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
-                               if ((batchneed & BATCHNEED_ARRAY_TEXCOORD) && rsurface.modeltexcoordtexture2f)
-                                       memcpy(rsurface.array_batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
-                               if ((batchneed & BATCHNEED_ARRAY_LIGHTMAP) && rsurface.modeltexcoordlightmap2f)
-                                       memcpy(rsurface.array_batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
-                       }
-                       RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.array_batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
-                       numvertices += surfacenumvertices;
-                       numtriangles += surfacenumtriangles;
-               }
-
-               // generate a 16bit index array as well if possible
-               // (in general, dynamic batches fit)
-               if (numvertices <= 65536)
-               {
-                       rsurface.batchelement3s = rsurface.array_batchelement3s;
-                       for (i = 0;i < numtriangles*3;i++)
-                               rsurface.array_batchelement3s[i] = rsurface.array_batchelement3i[i];
-               }
-
-               // since we've copied everything, the batch now starts at 0
-               rsurface.batchfirstvertex = 0;
-               rsurface.batchnumvertices = numvertices;
-               rsurface.batchfirsttriangle = 0;
-               rsurface.batchnumtriangles = numtriangles;
-       }
-
-       // q1bsp surfaces rendered in vertex color mode have to have colors
-       // calculated based on lightstyles
-       if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
-       {
-               // generate color arrays for the surfaces in this list
-               int c[4];
-               int scale;
-               int size3;
-               const int *offsets;
-               const unsigned char *lm;
-               numvertices = 0;
-               rsurface.batchlightmapcolor4f = rsurface.array_batchlightmapcolor4f;
-               rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
-               rsurface.batchlightmapcolor4f_bufferoffset = 0;
-               for (i = 0;i < texturenumsurfaces;i++)
-               {
-                       surface = texturesurfacelist[i];
-                       offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
-                       surfacenumvertices = surface->num_vertices;
-                       if (surface->lightmapinfo->samples)
-                       {
-                               for (j = 0;j < surfacenumvertices;j++)
-                               {
-                                       lm = surface->lightmapinfo->samples + offsets[j];
-                                       scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
-                                       VectorScale(lm, scale, c);
-                                       if (surface->lightmapinfo->styles[1] != 255)
-                                       {
-                                               size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
-                                               lm += size3;
-                                               scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
-                                               VectorMA(c, scale, lm, c);
-                                               if (surface->lightmapinfo->styles[2] != 255)
-                                               {
-                                                       lm += size3;
-                                                       scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
-                                                       VectorMA(c, scale, lm, c);
-                                                       if (surface->lightmapinfo->styles[3] != 255)
-                                                       {
-                                                               lm += size3;
-                                                               scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
-                                                               VectorMA(c, scale, lm, c);
-                                                       }
-                                               }
-                                       }
-                                       c[0] >>= 15;
-                                       c[1] >>= 15;
-                                       c[2] >>= 15;
-                                       Vector4Set(rsurface.array_batchlightmapcolor4f + 4*numvertices, min(c[0], 255) * (1.0f / 255.0f), min(c[1], 255) * (1.0f / 255.0f), min(c[2], 255) * (1.0f / 255.0f), 1);
-                                       numvertices++;
-                               }
-                       }
-                       else
+                       if (rsurface.texture->deforms[i].deform == Q3DEFORM_AUTOSPRITE)
                        {
-                               for (j = 0;j < surfacenumvertices;j++)
-                               {
-                                       Vector4Set(rsurface.array_batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
-                                       numvertices++;
-                               }
+                               generatetangents = true;
+                               generatenormals = true;
                        }
-               }
-       }
-
+                       if (rsurface.texture->deforms[i].deform != Q3DEFORM_NONE)
+                               generatenormals = true;
+               }
+               if (generatenormals && !rsurface.modelnormal3f)
+               {
+                       rsurface.normal3f = rsurface.modelnormal3f = rsurface.array_modelnormal3f;
+                       rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject = 0;
+                       rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset = 0;
+                       Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
+               }
+               if (generatetangents && !rsurface.modelsvector3f)
+               {
+                       rsurface.svector3f = rsurface.modelsvector3f = rsurface.array_modelsvector3f;
+                       rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject = 0;
+                       rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset = 0;
+                       rsurface.tvector3f = rsurface.modeltvector3f = rsurface.array_modeltvector3f;
+                       rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject = 0;
+                       rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset = 0;
+                       Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
+               }
+       }
+       rsurface.vertex3f  = rsurface.modelvertex3f;
+       rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
+       rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
+       rsurface.svector3f = rsurface.modelsvector3f;
+       rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
+       rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
+       rsurface.tvector3f = rsurface.modeltvector3f;
+       rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
+       rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
+       rsurface.normal3f  = rsurface.modelnormal3f;
+       rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
+       rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
        // if vertices are deformed (sprite flares and things in maps, possibly
-       // water waves, bulges and other deformations), modify the copied vertices
-       // in place
+       // water waves, bulges and other deformations), generate them into
+       // rsurface.deform* arrays from whatever the rsurface.* arrays point to
+       // (may be static model data or generated data for an animated model, or
+       //  the previous deform pass)
        for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform;deformindex++, deform++)
        {
                switch (deform->deform)
@@ -10678,36 +10172,41 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                        VectorNormalize(newforward);
                        VectorNormalize(newright);
                        VectorNormalize(newup);
-                       // a single autosprite surface can contain multiple sprites...
-                       for (j = 0;j < rsurface.batchnumvertices - 3;j += 4)
+                       // make deformed versions of only the model vertices used by the specified surfaces
+                       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                        {
-                               VectorClear(center);
-                               for (i = 0;i < 4;i++)
-                                       VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
-                               VectorScale(center, 0.25f, center);
-                               VectorCopy(rsurface.batchnormal3f + 3*j, forward);
-                               VectorCopy(rsurface.batchsvector3f + 3*j, right);
-                               VectorCopy(rsurface.batchtvector3f + 3*j, up);
-                               for (i = 0;i < 4;i++)
+                               const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+                               // a single autosprite surface can contain multiple sprites...
+                               for (j = 0;j < surface->num_vertices - 3;j += 4)
                                {
-                                       VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
-                                       VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.array_batchvertex3f + 3*(j+i));
+                                       VectorClear(center);
+                                       for (i = 0;i < 4;i++)
+                                               VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
+                                       VectorScale(center, 0.25f, center);
+                                       VectorCopy((rsurface.normal3f  + 3 * surface->num_firstvertex) + j*3, forward);
+                                       VectorCopy((rsurface.svector3f + 3 * surface->num_firstvertex) + j*3, right);
+                                       VectorCopy((rsurface.tvector3f + 3 * surface->num_firstvertex) + j*3, up);
+                                       for (i = 0;i < 4;i++)
+                                       {
+                                               VectorSubtract((rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, center, v);
+                                               VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
+                                       }
                                }
+                               Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer != 0);
+                               Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0);
                        }
-                       Mod_BuildNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchnormal3f, true);
-                       Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, true);
-                       rsurface.batchvertex3f = rsurface.array_batchvertex3f;
-                       rsurface.batchvertex3f_vertexbuffer = NULL;
-                       rsurface.batchvertex3f_bufferoffset = 0;
-                       rsurface.batchsvector3f = rsurface.array_batchsvector3f;
-                       rsurface.batchsvector3f_vertexbuffer = NULL;
-                       rsurface.batchsvector3f_bufferoffset = 0;
-                       rsurface.batchtvector3f = rsurface.array_batchtvector3f;
-                       rsurface.batchtvector3f_vertexbuffer = NULL;
-                       rsurface.batchtvector3f_bufferoffset = 0;
-                       rsurface.batchnormal3f = rsurface.array_batchnormal3f;
-                       rsurface.batchnormal3f_vertexbuffer = NULL;
-                       rsurface.batchnormal3f_bufferoffset = 0;
+                       rsurface.vertex3f = rsurface.array_deformedvertex3f;
+                       rsurface.vertex3f_bufferobject = 0;
+                       rsurface.vertex3f_bufferoffset = 0;
+                       rsurface.svector3f = rsurface.array_deformedsvector3f;
+                       rsurface.svector3f_bufferobject = 0;
+                       rsurface.svector3f_bufferoffset = 0;
+                       rsurface.tvector3f = rsurface.array_deformedtvector3f;
+                       rsurface.tvector3f_bufferobject = 0;
+                       rsurface.tvector3f_bufferoffset = 0;
+                       rsurface.normal3f = rsurface.array_deformednormal3f;
+                       rsurface.normal3f_bufferobject = 0;
+                       rsurface.normal3f_bufferoffset = 0;
                        break;
                case Q3DEFORM_AUTOSPRITE2:
                        Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
@@ -10716,7 +10215,10 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                        VectorNormalize(newforward);
                        VectorNormalize(newright);
                        VectorNormalize(newup);
+                       // make deformed versions of only the model vertices used by the specified surfaces
+                       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                        {
+                               const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
                                const float *v1, *v2;
                                vec3_t start, end;
                                float f, l;
@@ -10729,18 +10231,25 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                                shortest[2];
                                memset(shortest, 0, sizeof(shortest));
                                // a single autosprite surface can contain multiple sprites...
-                               for (j = 0;j < rsurface.batchnumvertices - 3;j += 4)
+                               for (j = 0;j < surface->num_vertices - 3;j += 4)
                                {
                                        VectorClear(center);
                                        for (i = 0;i < 4;i++)
-                                               VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
+                                               VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
                                        VectorScale(center, 0.25f, center);
                                        // find the two shortest edges, then use them to define the
                                        // axis vectors for rotating around the central axis
                                        for (i = 0;i < 6;i++)
                                        {
-                                               v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
-                                               v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
+                                               v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][0]);
+                                               v2 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][1]);
+#if 0
+                                               Debug_PolygonBegin(NULL, 0);
+                                               Debug_PolygonVertex(v1[0], v1[1], v1[2], 0, 0, 1, 0, 0, 1);
+                                               Debug_PolygonVertex((v1[0] + v2[0]) * 0.5f + rsurface.normal3f[3 * (surface->num_firstvertex + j)+0] * 4, (v1[1] + v2[1]) * 0.5f + rsurface.normal3f[3 * (surface->num_firstvertex + j)+1], (v1[2] + v2[2]) * 0.5f + rsurface.normal3f[3 * (surface->num_firstvertex + j)+2], 0, 0, 1, 1, 0, 1);
+                                               Debug_PolygonVertex(v2[0], v2[1], v2[2], 0, 0, 1, 0, 0, 1);
+                                               Debug_PolygonEnd();
+#endif
                                                l = VectorDistance2(v1, v2);
                                                // this length bias tries to make sense of square polygons, assuming they are meant to be upright
                                                if (v1[2] != v2[2])
@@ -10761,6 +10270,13 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                                        }
                                        VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
                                        VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
+#if 0
+                                       Debug_PolygonBegin(NULL, 0);
+                                       Debug_PolygonVertex(start[0], start[1], start[2], 0, 0, 1, 1, 0, 1);
+                                       Debug_PolygonVertex(center[0] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+0] * 4, center[1] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+1] * 4, center[2] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+2] * 4, 0, 0, 0, 1, 0, 1);
+                                       Debug_PolygonVertex(end[0], end[1], end[2], 0, 0, 0, 1, 1, 1);
+                                       Debug_PolygonEnd();
+#endif
                                        // this calculates the right vector from the shortest edge
                                        // and the up vector from the edge midpoints
                                        VectorSubtract(shortest[0].v1, shortest[0].v2, right);
@@ -10775,6 +10291,20 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                                        VectorNormalize(forward);
                                        CrossProduct(up, forward, newright);
                                        VectorNormalize(newright);
+#if 0
+                                       Debug_PolygonBegin(NULL, 0);
+                                       Debug_PolygonVertex(center[0] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+0] * 8, center[1] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+1] * 8, center[2] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+2] * 8, 0, 0, 1, 0, 0, 1);
+                                       Debug_PolygonVertex(center[0] + right[0] * 8, center[1] + right[1] * 8, center[2] + right[2] * 8, 0, 0, 0, 1, 0, 1);
+                                       Debug_PolygonVertex(center[0] + up   [0] * 8, center[1] + up   [1] * 8, center[2] + up   [2] * 8, 0, 0, 0, 0, 1, 1);
+                                       Debug_PolygonEnd();
+#endif
+#if 0
+                                       Debug_PolygonBegin(NULL, 0);
+                                       Debug_PolygonVertex(center[0] + forward [0] * 8, center[1] + forward [1] * 8, center[2] + forward [2] * 8, 0, 0, 1, 0, 0, 1);
+                                       Debug_PolygonVertex(center[0] + newright[0] * 8, center[1] + newright[1] * 8, center[2] + newright[2] * 8, 0, 0, 0, 1, 0, 1);
+                                       Debug_PolygonVertex(center[0] + up      [0] * 8, center[1] + up      [1] * 8, center[2] + up      [2] * 8, 0, 0, 0, 0, 1, 1);
+                                       Debug_PolygonEnd();
+#endif
                                        // rotate the quad around the up axis vector, this is made
                                        // especially easy by the fact we know the quad is flat,
                                        // so we only have to subtract the center position and
@@ -10788,49 +10318,54 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                                        l = DotProduct(right, center);
                                        for (i = 0;i < 4;i++)
                                        {
-                                               v1 = rsurface.batchvertex3f + 3*(j+i);
+                                               v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + j + i);
                                                f = DotProduct(right, v1) - l;
-                                               VectorMAMAM(1, v1, -f, right, f, newright, rsurface.array_batchvertex3f + 3*(j+i));
+                                               VectorMAMAM(1, v1, -f, right, f, newright, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
                                        }
                                }
+                               Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer != 0);
+                               Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0);
                        }
-                       Mod_BuildNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchnormal3f, true);
-                       Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, true);
-                       rsurface.batchvertex3f = rsurface.array_batchvertex3f;
-                       rsurface.batchvertex3f_vertexbuffer = NULL;
-                       rsurface.batchvertex3f_bufferoffset = 0;
-                       rsurface.batchsvector3f = rsurface.array_batchsvector3f;
-                       rsurface.batchsvector3f_vertexbuffer = NULL;
-                       rsurface.batchsvector3f_bufferoffset = 0;
-                       rsurface.batchtvector3f = rsurface.array_batchtvector3f;
-                       rsurface.batchtvector3f_vertexbuffer = NULL;
-                       rsurface.batchtvector3f_bufferoffset = 0;
-                       rsurface.batchnormal3f = rsurface.array_batchnormal3f;
-                       rsurface.batchnormal3f_vertexbuffer = NULL;
-                       rsurface.batchnormal3f_bufferoffset = 0;
+                       rsurface.vertex3f = rsurface.array_deformedvertex3f;
+                       rsurface.vertex3f_bufferobject = 0;
+                       rsurface.vertex3f_bufferoffset = 0;
+                       rsurface.svector3f = rsurface.array_deformedsvector3f;
+                       rsurface.svector3f_bufferobject = 0;
+                       rsurface.svector3f_bufferoffset = 0;
+                       rsurface.tvector3f = rsurface.array_deformedtvector3f;
+                       rsurface.tvector3f_bufferobject = 0;
+                       rsurface.tvector3f_bufferoffset = 0;
+                       rsurface.normal3f = rsurface.array_deformednormal3f;
+                       rsurface.normal3f_bufferobject = 0;
+                       rsurface.normal3f_bufferoffset = 0;
                        break;
                case Q3DEFORM_NORMAL:
                        // deform the normals to make reflections wavey
-                       for (j = 0;j < rsurface.batchnumvertices;j++)
+                       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                        {
-                               float vertex[3];
-                               float *normal = rsurface.array_batchnormal3f + 3*j;
-                               VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
-                               normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]);
-                               normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]);
-                               normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]);
-                               VectorNormalize(normal);
+                               const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+                               for (j = 0;j < surface->num_vertices;j++)
+                               {
+                                       float vertex[3];
+                                       float *normal = (rsurface.array_deformednormal3f  + 3 * surface->num_firstvertex) + j*3;
+                                       VectorScale((rsurface.vertex3f  + 3 * surface->num_firstvertex) + j*3, 0.98f, vertex);
+                                       VectorCopy((rsurface.normal3f  + 3 * surface->num_firstvertex) + j*3, normal);
+                                       normal[0] += deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]);
+                                       normal[1] += deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]);
+                                       normal[2] += deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]);
+                                       VectorNormalize(normal);
+                               }
+                               Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0);
                        }
-                       Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, true);
-                       rsurface.batchsvector3f = rsurface.array_batchsvector3f;
-                       rsurface.batchsvector3f_vertexbuffer = NULL;
-                       rsurface.batchsvector3f_bufferoffset = 0;
-                       rsurface.batchtvector3f = rsurface.array_batchtvector3f;
-                       rsurface.batchtvector3f_vertexbuffer = NULL;
-                       rsurface.batchtvector3f_bufferoffset = 0;
-                       rsurface.batchnormal3f = rsurface.array_batchnormal3f;
-                       rsurface.batchnormal3f_vertexbuffer = NULL;
-                       rsurface.batchnormal3f_bufferoffset = 0;
+                       rsurface.svector3f = rsurface.array_deformedsvector3f;
+                       rsurface.svector3f_bufferobject = 0;
+                       rsurface.svector3f_bufferoffset = 0;
+                       rsurface.tvector3f = rsurface.array_deformedtvector3f;
+                       rsurface.tvector3f_bufferobject = 0;
+                       rsurface.tvector3f_bufferoffset = 0;
+                       rsurface.normal3f = rsurface.array_deformednormal3f;
+                       rsurface.normal3f_bufferobject = 0;
+                       rsurface.normal3f_bufferoffset = 0;
                        break;
                case Q3DEFORM_WAVE:
                        // deform vertex array to make wavey water and flags and such
@@ -10843,52 +10378,40 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                        // this is how a divisor of vertex influence on deformation
                        animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
                        scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
-                       for (j = 0;j < rsurface.batchnumvertices;j++)
+                       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                        {
-                               // if the wavefunc depends on time, evaluate it per-vertex
-                               if (waveparms[3])
+                               const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+                               for (j = 0;j < surface->num_vertices;j++)
                                {
-                                       waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
-                                       scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
+                                       float *vertex = (rsurface.array_deformedvertex3f  + 3 * surface->num_firstvertex) + j*3;
+                                       VectorCopy((rsurface.vertex3f  + 3 * surface->num_firstvertex) + j*3, vertex);
+                                       // if the wavefunc depends on time, evaluate it per-vertex
+                                       if (waveparms[3])
+                                       {
+                                               waveparms[2] = deform->waveparms[2] + (vertex[0] + vertex[1] + vertex[2]) * animpos;
+                                               scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
+                                       }
+                                       VectorMA(vertex, scale, (rsurface.normal3f  + 3 * surface->num_firstvertex) + j*3, vertex);
                                }
-                               VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.array_batchvertex3f + 3*j);
                        }
-                       Mod_BuildNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchnormal3f, true);
-                       Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, true);
-                       rsurface.batchvertex3f = rsurface.array_batchvertex3f;
-                       rsurface.batchvertex3f_vertexbuffer = NULL;
-                       rsurface.batchvertex3f_bufferoffset = 0;
-                       rsurface.batchsvector3f = rsurface.array_batchsvector3f;
-                       rsurface.batchsvector3f_vertexbuffer = NULL;
-                       rsurface.batchsvector3f_bufferoffset = 0;
-                       rsurface.batchtvector3f = rsurface.array_batchtvector3f;
-                       rsurface.batchtvector3f_vertexbuffer = NULL;
-                       rsurface.batchtvector3f_bufferoffset = 0;
-                       rsurface.batchnormal3f = rsurface.array_batchnormal3f;
-                       rsurface.batchnormal3f_vertexbuffer = NULL;
-                       rsurface.batchnormal3f_bufferoffset = 0;
+                       rsurface.vertex3f = rsurface.array_deformedvertex3f;
+                       rsurface.vertex3f_bufferobject = 0;
+                       rsurface.vertex3f_bufferoffset = 0;
                        break;
                case Q3DEFORM_BULGE:
                        // deform vertex array to make the surface have moving bulges
-                       for (j = 0;j < rsurface.batchnumvertices;j++)
+                       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                        {
-                               scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + r_refdef.scene.time * deform->parms[2]) * deform->parms[1];
-                               VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.array_batchvertex3f + 3*j);
+                               const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+                               for (j = 0;j < surface->num_vertices;j++)
+                               {
+                                       scale = sin((rsurface.modeltexcoordtexture2f[2 * (surface->num_firstvertex + j)] * deform->parms[0] + r_refdef.scene.time * deform->parms[2])) * deform->parms[1];
+                                       VectorMA(rsurface.vertex3f + 3 * (surface->num_firstvertex + j), scale, rsurface.normal3f + 3 * (surface->num_firstvertex + j), rsurface.array_deformedvertex3f + 3 * (surface->num_firstvertex + j));
+                               }
                        }
-                       Mod_BuildNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchnormal3f, true);
-                       Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, true);
-                       rsurface.batchvertex3f = rsurface.array_batchvertex3f;
-                       rsurface.batchvertex3f_vertexbuffer = NULL;
-                       rsurface.batchvertex3f_bufferoffset = 0;
-                       rsurface.batchsvector3f = rsurface.array_batchsvector3f;
-                       rsurface.batchsvector3f_vertexbuffer = NULL;
-                       rsurface.batchsvector3f_bufferoffset = 0;
-                       rsurface.batchtvector3f = rsurface.array_batchtvector3f;
-                       rsurface.batchtvector3f_vertexbuffer = NULL;
-                       rsurface.batchtvector3f_bufferoffset = 0;
-                       rsurface.batchnormal3f = rsurface.array_batchnormal3f;
-                       rsurface.batchnormal3f_vertexbuffer = NULL;
-                       rsurface.batchnormal3f_bufferoffset = 0;
+                       rsurface.vertex3f = rsurface.array_deformedvertex3f;
+                       rsurface.vertex3f_bufferobject = 0;
+                       rsurface.vertex3f_bufferoffset = 0;
                        break;
                case Q3DEFORM_MOVE:
                        // deform vertex array
@@ -10896,68 +10419,83 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                                break; // if wavefunc is a nop, don't make a dynamic vertex array
                        scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
                        VectorScale(deform->parms, scale, waveparms);
-                       for (j = 0;j < rsurface.batchnumvertices;j++)
-                               VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.array_batchvertex3f + 3*j);
-                       rsurface.batchvertex3f = rsurface.array_batchvertex3f;
-                       rsurface.batchvertex3f_vertexbuffer = NULL;
-                       rsurface.batchvertex3f_bufferoffset = 0;
+                       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+                       {
+                               const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+                               for (j = 0;j < surface->num_vertices;j++)
+                                       VectorAdd(rsurface.vertex3f + 3 * (surface->num_firstvertex + j), waveparms, rsurface.array_deformedvertex3f + 3 * (surface->num_firstvertex + j));
+                       }
+                       rsurface.vertex3f = rsurface.array_deformedvertex3f;
+                       rsurface.vertex3f_bufferobject = 0;
+                       rsurface.vertex3f_bufferoffset = 0;
                        break;
                }
        }
-
        // generate texcoords based on the chosen texcoord source
        switch(rsurface.texture->tcgen.tcgen)
        {
        default:
        case Q3TCGEN_TEXTURE:
+               rsurface.texcoordtexture2f               = rsurface.modeltexcoordtexture2f;
+               rsurface.texcoordtexture2f_bufferobject  = rsurface.modeltexcoordtexture2f_bufferobject;
+               rsurface.texcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
                break;
        case Q3TCGEN_LIGHTMAP:
-               if (rsurface.batchtexcoordlightmap2f)
-                       memcpy(rsurface.array_batchtexcoordlightmap2f, rsurface.batchtexcoordtexture2f, rsurface.batchnumvertices * sizeof(float[2]));
-               rsurface.batchtexcoordtexture2f = rsurface.array_batchtexcoordtexture2f;
-               rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-               rsurface.batchtexcoordtexture2f_bufferoffset = 0;
+               rsurface.texcoordtexture2f               = rsurface.modeltexcoordlightmap2f;
+               rsurface.texcoordtexture2f_bufferobject  = rsurface.modeltexcoordlightmap2f_bufferobject;
+               rsurface.texcoordtexture2f_bufferoffset  = rsurface.modeltexcoordlightmap2f_bufferoffset;
                break;
        case Q3TCGEN_VECTOR:
-               for (j = 0;j < rsurface.batchnumvertices;j++)
+               for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                {
-                       rsurface.array_batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->tcgen.parms);
-                       rsurface.array_batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->tcgen.parms + 3);
+                       const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+                       for (j = 0, v1 = rsurface.modelvertex3f + 3 * surface->num_firstvertex, out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;j < surface->num_vertices;j++, v1 += 3, out_tc += 2)
+                       {
+                               out_tc[0] = DotProduct(v1, rsurface.texture->tcgen.parms);
+                               out_tc[1] = DotProduct(v1, rsurface.texture->tcgen.parms + 3);
+                       }
                }
-               rsurface.batchtexcoordtexture2f = rsurface.array_batchtexcoordtexture2f;
-               rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-               rsurface.batchtexcoordtexture2f_bufferoffset = 0;
+               rsurface.texcoordtexture2f               = rsurface.array_generatedtexcoordtexture2f;
+               rsurface.texcoordtexture2f_bufferobject  = 0;
+               rsurface.texcoordtexture2f_bufferoffset  = 0;
                break;
        case Q3TCGEN_ENVIRONMENT:
                // make environment reflections using a spheremap
-               for (j = 0;j < rsurface.batchnumvertices;j++)
+               for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                {
-                       // identical to Q3A's method, but executed in worldspace so
-                       // carried models can be shiny too
+                       const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+                       const float *vertex = rsurface.modelvertex3f + 3 * surface->num_firstvertex;
+                       const float *normal = rsurface.modelnormal3f + 3 * surface->num_firstvertex;
+                       float *out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;
+                       for (j = 0;j < surface->num_vertices;j++, vertex += 3, normal += 3, out_tc += 2)
+                       {
+                               // identical to Q3A's method, but executed in worldspace so
+                               // carried models can be shiny too
 
-                       float viewer[3], d, reflected[3], worldreflected[3];
+                               float viewer[3], d, reflected[3], worldreflected[3];
 
-                       VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
-                       // VectorNormalize(viewer);
+                               VectorSubtract(rsurface.localvieworigin, vertex, viewer);
+                               // VectorNormalize(viewer);
 
-                       d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
+                               d = DotProduct(normal, viewer);
 
-                       reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
-                       reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
-                       reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
-                       // note: this is proportinal to viewer, so we can normalize later
+                               reflected[0] = normal[0]*2*d - viewer[0];
+                               reflected[1] = normal[1]*2*d - viewer[1];
+                               reflected[2] = normal[2]*2*d - viewer[2];
+                               // note: this is proportinal to viewer, so we can normalize later
 
-                       Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
-                       VectorNormalize(worldreflected);
+                               Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
+                               VectorNormalize(worldreflected);
 
-                       // note: this sphere map only uses world x and z!
-                       // so positive and negative y will LOOK THE SAME.
-                       rsurface.array_batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
-                       rsurface.array_batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
+                               // note: this sphere map only uses world x and z!
+                               // so positive and negative y will LOOK THE SAME.
+                               out_tc[0] = 0.5 + 0.5 * worldreflected[1];
+                               out_tc[1] = 0.5 - 0.5 * worldreflected[2];
+                       }
                }
-               rsurface.batchtexcoordtexture2f = rsurface.array_batchtexcoordtexture2f;
-               rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-               rsurface.batchtexcoordtexture2f_bufferoffset = 0;
+               rsurface.texcoordtexture2f               = rsurface.array_generatedtexcoordtexture2f;
+               rsurface.texcoordtexture2f_bufferobject  = 0;
+               rsurface.texcoordtexture2f_bufferoffset  = 0;
                break;
        }
        // the only tcmod that needs software vertex processing is turbulent, so
@@ -10969,86 +10507,116 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
        {
                amplitude = rsurface.texture->tcmods[0].parms[1];
                animpos = rsurface.texture->tcmods[0].parms[2] + r_refdef.scene.time * rsurface.texture->tcmods[0].parms[3];
-               for (j = 0;j < rsurface.batchnumvertices;j++)
+               for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                {
-                       rsurface.array_batchtexcoordtexture2f[j*2+0] += amplitude * sin(((rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+2]) * 1.0 / 1024.0f + animpos) * M_PI * 2);
-                       rsurface.array_batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
+                       const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+                       for (j = 0, v1 = rsurface.modelvertex3f + 3 * surface->num_firstvertex, in_tc = rsurface.texcoordtexture2f + 2 * surface->num_firstvertex, out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;j < surface->num_vertices;j++, v1 += 3, in_tc += 2, out_tc += 2)
+                       {
+                               out_tc[0] = in_tc[0] + amplitude * sin(((v1[0] + v1[2]) * 1.0 / 1024.0f + animpos) * M_PI * 2);
+                               out_tc[1] = in_tc[1] + amplitude * sin(((v1[1]        ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
+                       }
                }
-               rsurface.batchtexcoordtexture2f = rsurface.array_batchtexcoordtexture2f;
-               rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-               rsurface.batchtexcoordtexture2f_bufferoffset = 0;
+               rsurface.texcoordtexture2f               = rsurface.array_generatedtexcoordtexture2f;
+               rsurface.texcoordtexture2f_bufferobject  = 0;
+               rsurface.texcoordtexture2f_bufferoffset  = 0;
        }
+       rsurface.texcoordlightmap2f              = rsurface.modeltexcoordlightmap2f;
+       rsurface.texcoordlightmap2f_bufferobject = rsurface.modeltexcoordlightmap2f_bufferobject;
+       rsurface.texcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
+       R_Mesh_VertexPointer(rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
+}
 
-       if (needsupdate & batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
+void RSurf_DrawBatch_Simple(int texturenumsurfaces, const msurface_t **texturesurfacelist)
+{
+       int i, 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_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
+       else if (r_batchmode.integer == 2)
        {
-               // convert the modified arrays to vertex structs
-               rsurface.batchvertexmesh = rsurface.array_batchvertexmesh;
-               rsurface.batchvertexmeshbuffer = NULL;
-               if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)
-                       for (j = 0, vertexmesh = rsurface.array_batchvertexmesh;j < rsurface.batchnumvertices;j++, vertexmesh++)
-                               VectorCopy(rsurface.batchvertex3f + 3*j, vertexmesh->vertex3f);
-               if (batchneed & BATCHNEED_VERTEXMESH_NORMAL)
-                       for (j = 0, vertexmesh = rsurface.array_batchvertexmesh;j < rsurface.batchnumvertices;j++, vertexmesh++)
-                               VectorCopy(rsurface.batchnormal3f + 3*j, vertexmesh->normal3f);
-               if (batchneed & BATCHNEED_VERTEXMESH_VECTOR)
+               #define MAXBATCHTRIANGLES 65536
+               int batchtriangles = 0;
+               static int batchelements[MAXBATCHTRIANGLES*3];
+               for (i = 0;i < texturenumsurfaces;i = j)
                {
-                       for (j = 0, vertexmesh = rsurface.array_batchvertexmesh;j < rsurface.batchnumvertices;j++, vertexmesh++)
+                       surface = texturesurfacelist[i];
+                       j = i + 1;
+                       if (surface->num_triangles > MAXBATCHTRIANGLES)
                        {
-                               VectorCopy(rsurface.batchsvector3f + 3*j, vertexmesh->svector3f);
-                               VectorCopy(rsurface.batchtvector3f + 3*j, vertexmesh->tvector3f);
+                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
+                               continue;
+                       }
+                       memcpy(batchelements, rsurface.modelelement3i + 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++)
+                       {
+                               surface2 = texturesurfacelist[j];
+                               if (batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
+                                       break;
+                               memcpy(batchelements + batchtriangles * 3, rsurface.modelelement3i + 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);
                        }
+                       surface2 = texturesurfacelist[j-1];
+                       numvertices = endvertex - firstvertex;
+                       R_Mesh_Draw(firstvertex, numvertices, 0, batchtriangles, batchelements, NULL, 0, 0);
                }
-               if ((batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) && rsurface.batchlightmapcolor4f)
-                       for (j = 0, vertexmesh = rsurface.array_batchvertexmesh;j < rsurface.batchnumvertices;j++, vertexmesh++)
-                               Vector4Scale(rsurface.batchlightmapcolor4f + 4*j, 255.0f, vertexmesh->color4ub);
-               if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD)
-                       for (j = 0, vertexmesh = rsurface.array_batchvertexmesh;j < rsurface.batchnumvertices;j++, vertexmesh++)
-                               Vector2Copy(rsurface.batchtexcoordtexture2f + 2*j, vertexmesh->texcoordtexture2f);
-               if ((batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) && rsurface.batchtexcoordlightmap2f)
-                       for (j = 0, vertexmesh = rsurface.array_batchvertexmesh;j < rsurface.batchnumvertices;j++, vertexmesh++)
-                               Vector2Copy(rsurface.batchtexcoordlightmap2f + 2*j, vertexmesh->texcoordlightmap2f);
        }
-
-       if (needsupdate & batchneed & BATCHNEED_VERTEXPOSITION)
+       else if (r_batchmode.integer == 1)
        {
-               // convert the modified arrays to vertex structs
-               rsurface.batchvertexposition = rsurface.array_batchvertexposition;
-               rsurface.batchvertexpositionbuffer = NULL;
-               if (sizeof(r_vertexposition_t) == sizeof(float[3]))
-                       memcpy(rsurface.array_batchvertexposition, rsurface.batchvertex3f, rsurface.batchnumvertices * sizeof(r_vertexposition_t));
-               else
-                       for (j = 0, vertexposition = rsurface.array_batchvertexposition;j < rsurface.batchnumvertices;j++, vertexposition++)
-                               VectorCopy(rsurface.batchvertex3f + 3*j, vertexposition->vertex3f);
+               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;
+                       R_Mesh_Draw(surface->num_firstvertex, numvertices, surface->num_firsttriangle, numtriangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
+               }
+       }
+       else
+       {
+               for (i = 0;i < texturenumsurfaces;i++)
+               {
+                       surface = texturesurfacelist[i];
+                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
+               }
        }
 }
 
-void RSurf_DrawBatch(void)
-{
-       R_Mesh_Draw(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchfirsttriangle, rsurface.batchnumtriangles, rsurface.batchelement3i, rsurface.batchelement3i_indexbuffer, rsurface.batchelement3i_bufferoffset, rsurface.batchelement3s, rsurface.batchelement3s_indexbuffer, rsurface.batchelement3s_bufferoffset);
-}
-
-static void RSurf_BindLightmapForBatch(void)
+static void RSurf_BindLightmapForSurface(const msurface_t *surface)
 {
        switch(vid.renderpath)
        {
        case RENDERPATH_CGGL:
 #ifdef SUPPORTCG
-               if (r_cg_permutation->fp_Texture_Lightmap ) CG_BindTexture(r_cg_permutation->fp_Texture_Lightmap , rsurface.lightmaptexture );CHECKCGERROR
-               if (r_cg_permutation->fp_Texture_Deluxemap) CG_BindTexture(r_cg_permutation->fp_Texture_Deluxemap, rsurface.deluxemaptexture);CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Lightmap ) CG_BindTexture(r_cg_permutation->fp_Texture_Lightmap , surface->lightmaptexture );CHECKCGERROR
+               if (r_cg_permutation->fp_Texture_Deluxemap) CG_BindTexture(r_cg_permutation->fp_Texture_Deluxemap, surface->deluxemaptexture);CHECKCGERROR
 #endif
                break;
        case RENDERPATH_GL20:
-               if (r_glsl_permutation->loc_Texture_Lightmap  >= 0) R_Mesh_TexBind(GL20TU_LIGHTMAP , rsurface.lightmaptexture );
-               if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) R_Mesh_TexBind(GL20TU_DELUXEMAP, rsurface.deluxemaptexture);
+               if (r_glsl_permutation->loc_Texture_Lightmap  >= 0) R_Mesh_TexBind(GL20TU_LIGHTMAP , surface->lightmaptexture );
+               if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) R_Mesh_TexBind(GL20TU_DELUXEMAP, surface->deluxemaptexture);
                break;
        case RENDERPATH_GL13:
        case RENDERPATH_GL11:
-               R_Mesh_TexBind(0, rsurface.lightmaptexture);
+               R_Mesh_TexBind(0, surface->lightmaptexture);
                break;
        }
 }
 
-static void RSurf_BindReflectionForBatch(void)
+static void RSurf_BindReflectionForSurface(const msurface_t *surface)
 {
        // pick the closest matching water plane and bind textures
        int planeindex, vertexindex;
@@ -11063,7 +10631,7 @@ static void RSurf_BindReflectionForBatch(void)
                if(p->camera_entity != rsurface.texture->camera_entity)
                        continue;
                d = 0;
-               for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
+               for (vertexindex = 0, v = rsurface.modelvertex3f + surface->num_firstvertex * 3;vertexindex < surface->num_vertices;vertexindex++, v += 3)
                {
                        Matrix4x4_Transform(&rsurface.matrix, v, vert);
                        d += fabs(PlaneDiff(vert, &p->plane));
@@ -11094,170 +10662,376 @@ static void RSurf_BindReflectionForBatch(void)
        }
 }
 
-static void RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(void)
+static void RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(int texturenumsurfaces, const msurface_t **texturesurfacelist)
 {
        int i;
-       for (i = 0;i < rsurface.batchnumvertices;i++)
-               Vector4Set(rsurface.array_passcolor4f + 4*i, 0.5f, 0.5f, 0.5f, 1.0f);
-       rsurface.passcolor4f = rsurface.array_passcolor4f;
-       rsurface.passcolor4f_vertexbuffer = 0;
-       rsurface.passcolor4f_bufferoffset = 0;
+       const msurface_t *surface;
+       if (r_waterstate.renderingscene)
+               return;
+       for (i = 0;i < texturenumsurfaces;i++)
+       {
+               surface = texturesurfacelist[i];
+               RSurf_BindLightmapForSurface(surface);
+               RSurf_BindReflectionForSurface(surface);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
+       }
 }
 
-static void RSurf_DrawBatch_GL11_ApplyFog(void)
+static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, const msurface_t **texturesurfacelist)
 {
+       int i;
+       int j;
+       const msurface_t *surface = texturesurfacelist[0];
+       const msurface_t *surface2;
+       int firstvertex;
+       int endvertex;
+       int numvertices;
+       int numtriangles;
+       if (texturenumsurfaces == 1)
+       {
+               RSurf_BindLightmapForSurface(surface);
+               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
+       }
+       else if (r_batchmode.integer == 2)
+       {
+               int batchtriangles = 0;
+               static int batchelements[MAXBATCHTRIANGLES*3];
+               for (i = 0;i < texturenumsurfaces;i = j)
+               {
+                       surface = texturesurfacelist[i];
+                       RSurf_BindLightmapForSurface(surface);
+                       j = i + 1;
+                       if (surface->num_triangles > MAXBATCHTRIANGLES)
+                       {
+                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
+                               continue;
+                       }
+                       memcpy(batchelements, rsurface.modelelement3i + 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++)
+                       {
+                               surface2 = texturesurfacelist[j];
+                               if (surface2->lightmaptexture != surface->lightmaptexture || batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
+                                       break;
+                               memcpy(batchelements + batchtriangles * 3, rsurface.modelelement3i + 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);
+                       }
+                       surface2 = texturesurfacelist[j-1];
+                       numvertices = endvertex - firstvertex;
+                       R_Mesh_Draw(firstvertex, numvertices, 0, batchtriangles, batchelements, NULL, 0, 0);
+               }
+       }
+       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];
+                       RSurf_BindLightmapForSurface(surface);
+                       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;
+                       R_Mesh_Draw(surface->num_firstvertex, numvertices, surface->num_firsttriangle, numtriangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
+               }
+#if 0
+               Con_Printf("\n");
+#endif
+       }
+       else
+       {
+               for (i = 0;i < texturenumsurfaces;i++)
+               {
+                       surface = texturesurfacelist[i];
+                       RSurf_BindLightmapForSurface(surface);
+                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
+               }
+       }
+}
+
+static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist)
+{
+       int j;
+       int texturesurfaceindex;
+       if (r_showsurfaces.integer == 2)
+       {
+               for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+               {
+                       const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+                       for (j = 0;j < surface->num_triangles;j++)
+                       {
+                               float f = ((j + surface->num_firsttriangle) & 31) * (1.0f / 31.0f) * r_refdef.view.colorscale;
+                               GL_Color(f, f, f, 1);
+                               R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle + j, 1, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
+                       }
+               }
+       }
+       else
+       {
+               for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+               {
+                       const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+                       int k = (int)(((size_t)surface) / sizeof(msurface_t));
+                       GL_Color((k & 15) * (1.0f / 16.0f) * r_refdef.view.colorscale, ((k >> 4) & 15) * (1.0f / 16.0f) * r_refdef.view.colorscale, ((k >> 8) & 15) * (1.0f / 16.0f) * r_refdef.view.colorscale, 1);
+                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
+               }
+       }
+}
+
+static void RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(int texturenumsurfaces, const msurface_t **texturesurfacelist)
+{
+       int texturesurfaceindex;
+       int i;
+       const float *v;
+       float *c2;
+       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)
+               {
+                       c2[0] = 0.5;
+                       c2[1] = 0.5;
+                       c2[2] = 0.5;
+                       c2[3] = 1;
+               }
+       }
+       rsurface.lightmapcolor4f = rsurface.array_color4f;
+       rsurface.lightmapcolor4f_bufferobject = 0;
+       rsurface.lightmapcolor4f_bufferoffset = 0;
+}
+
+static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, const msurface_t **texturesurfacelist)
+{
+       int texturesurfaceindex;
        int i;
        float f;
        const float *v;
        const float *c;
        float *c2;
-       if (rsurface.passcolor4f)
+       if (rsurface.lightmapcolor4f)
        {
-               // generate color arrays
-               for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, c = rsurface.passcolor4f + rsurface.batchfirstvertex * 4, c2 = rsurface.array_passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, c += 4, c2 += 4)
+               // generate color arrays for the surfaces in this list
+               for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                {
-                       f = RSurf_FogVertex(v);
-                       c2[0] = c[0] * f;
-                       c2[1] = c[1] * f;
-                       c2[2] = c[2] * f;
-                       c2[3] = c[3];
+                       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 = RSurf_FogVertex(v);
+                               c2[0] = c[0] * f;
+                               c2[1] = c[1] * f;
+                               c2[2] = c[2] * f;
+                               c2[3] = c[3];
+                       }
                }
        }
        else
        {
-               for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, c2 = rsurface.array_passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, c2 += 4)
+               for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                {
-                       f = RSurf_FogVertex(v);
-                       c2[0] = f;
-                       c2[1] = f;
-                       c2[2] = f;
-                       c2[3] = 1;
+                       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 = RSurf_FogVertex(v);
+                               c2[0] = f;
+                               c2[1] = f;
+                               c2[2] = f;
+                               c2[3] = 1;
+                       }
                }
        }
-       rsurface.passcolor4f = rsurface.array_passcolor4f;
-       rsurface.passcolor4f_vertexbuffer = 0;
-       rsurface.passcolor4f_bufferoffset = 0;
+       rsurface.lightmapcolor4f = rsurface.array_color4f;
+       rsurface.lightmapcolor4f_bufferobject = 0;
+       rsurface.lightmapcolor4f_bufferoffset = 0;
 }
 
-static void RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(void)
+static void RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(int texturenumsurfaces, const msurface_t **texturesurfacelist)
 {
+       int texturesurfaceindex;
        int i;
        float f;
        const float *v;
        const float *c;
        float *c2;
-       if (!rsurface.passcolor4f)
+       if (!rsurface.lightmapcolor4f)
                return;
-       for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, c = rsurface.passcolor4f + rsurface.batchfirstvertex * 4, c2 = rsurface.array_passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, c += 4, c2 += 4)
+       // generate color arrays for the surfaces in this list
+       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
        {
-               f = RSurf_FogVertex(v);
-               c2[0] = c[0] * f + r_refdef.fogcolor[0] * (1 - f);
-               c2[1] = c[1] * f + r_refdef.fogcolor[1] * (1 - f);
-               c2[2] = c[2] * f + r_refdef.fogcolor[2] * (1 - f);
-               c2[3] = c[3];
+               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 = RSurf_FogVertex(v);
+                       c2[0] = c[0] * f + r_refdef.fogcolor[0] * (1 - f);
+                       c2[1] = c[1] * f + r_refdef.fogcolor[1] * (1 - f);
+                       c2[2] = c[2] * f + r_refdef.fogcolor[2] * (1 - f);
+                       c2[3] = c[3];
+               }
        }
-       rsurface.passcolor4f = rsurface.array_passcolor4f;
-       rsurface.passcolor4f_vertexbuffer = 0;
-       rsurface.passcolor4f_bufferoffset = 0;
+       rsurface.lightmapcolor4f = rsurface.array_color4f;
+       rsurface.lightmapcolor4f_bufferobject = 0;
+       rsurface.lightmapcolor4f_bufferoffset = 0;
 }
 
-static void RSurf_DrawBatch_GL11_ApplyColor(float r, float g, float b, float a)
+static void RSurf_DrawBatch_GL11_ApplyColor(int texturenumsurfaces, const msurface_t **texturesurfacelist, float r, float g, float b, float a)
 {
+       int texturesurfaceindex;
        int i;
        const float *c;
        float *c2;
-       if (!rsurface.passcolor4f)
+       if (!rsurface.lightmapcolor4f)
                return;
-       for (i = 0, c = rsurface.passcolor4f + rsurface.batchfirstvertex * 4, c2 = rsurface.array_passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, c += 4, c2 += 4)
+       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;
+               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)
+               {
+                       c2[0] = c[0] * r;
+                       c2[1] = c[1] * g;
+                       c2[2] = c[2] * b;
+                       c2[3] = c[3] * a;
+               }
        }
-       rsurface.passcolor4f = rsurface.array_passcolor4f;
-       rsurface.passcolor4f_vertexbuffer = 0;
-       rsurface.passcolor4f_bufferoffset = 0;
+       rsurface.lightmapcolor4f = rsurface.array_color4f;
+       rsurface.lightmapcolor4f_bufferobject = 0;
+       rsurface.lightmapcolor4f_bufferoffset = 0;
 }
 
-static void RSurf_DrawBatch_GL11_ApplyAmbient(void)
+static void RSurf_DrawBatch_GL11_ApplyAmbient(int texturenumsurfaces, const msurface_t **texturesurfacelist)
 {
+       int texturesurfaceindex;
        int i;
        const float *c;
        float *c2;
-       if (!rsurface.passcolor4f)
+       if (!rsurface.lightmapcolor4f)
                return;
-       for (i = 0, c = rsurface.passcolor4f + rsurface.batchfirstvertex * 4, c2 = rsurface.array_passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, c += 4, c2 += 4)
+       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
        {
-               c2[0] = c[0] + r_refdef.scene.ambient;
-               c2[1] = c[1] + r_refdef.scene.ambient;
-               c2[2] = c[2] + r_refdef.scene.ambient;
-               c2[3] = c[3];
+               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)
+               {
+                       c2[0] = c[0] + r_refdef.scene.ambient;
+                       c2[1] = c[1] + r_refdef.scene.ambient;
+                       c2[2] = c[2] + r_refdef.scene.ambient;
+                       c2[3] = c[3];
+               }
        }
-       rsurface.passcolor4f = rsurface.array_passcolor4f;
-       rsurface.passcolor4f_vertexbuffer = 0;
-       rsurface.passcolor4f_bufferoffset = 0;
+       rsurface.lightmapcolor4f = rsurface.array_color4f;
+       rsurface.lightmapcolor4f_bufferobject = 0;
+       rsurface.lightmapcolor4f_bufferoffset = 0;
 }
 
-static void RSurf_DrawBatch_GL11_Lightmap(float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
+static void RSurf_DrawBatch_GL11_Lightmap(int texturenumsurfaces, const msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
 {
        // TODO: optimize
-       rsurface.passcolor4f = NULL;
-       rsurface.passcolor4f_vertexbuffer = 0;
-       rsurface.passcolor4f_bufferoffset = 0;
-       if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog();
-       if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(r, g, b, a);
-       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset);
+       rsurface.lightmapcolor4f = NULL;
+       rsurface.lightmapcolor4f_bufferobject = 0;
+       rsurface.lightmapcolor4f_bufferoffset = 0;
+       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, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
        GL_Color(r, g, b, a);
-       RSurf_BindLightmapForBatch();
-       RSurf_DrawBatch();
+       RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist);
 }
 
-static void RSurf_DrawBatch_GL11_Unlit(float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
+static void RSurf_DrawBatch_GL11_Unlit(int texturenumsurfaces, const 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.passcolor4f = NULL;
-       rsurface.passcolor4f_vertexbuffer = 0;
-       rsurface.passcolor4f_bufferoffset = 0;
-       if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog();
-       if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(r, g, b, a);
-       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset);
+       rsurface.lightmapcolor4f = NULL;
+       rsurface.lightmapcolor4f_bufferobject = 0;
+       rsurface.lightmapcolor4f_bufferoffset = 0;
+       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, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
        GL_Color(r, g, b, a);
-       RSurf_DrawBatch();
+       RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
 }
 
-static void RSurf_DrawBatch_GL11_VertexColor(float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
-{
-       // TODO: optimize
-       rsurface.passcolor4f = rsurface.batchlightmapcolor4f;
-       rsurface.passcolor4f_vertexbuffer = rsurface.batchlightmapcolor4f_vertexbuffer;
-       rsurface.passcolor4f_bufferoffset = rsurface.batchlightmapcolor4f_bufferoffset;
-       if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog();
-       if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(r, g, b, a);
-       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset);
-       GL_Color(r, g, b, a);
-       RSurf_DrawBatch();
-}
-
-static void RSurf_DrawBatch_GL11_ClampColor(void)
+static void RSurf_DrawBatch_GL11_VertexColor(int texturenumsurfaces, const msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
 {
+       int texturesurfaceindex;
        int i;
-       const float *c1;
-       float *c2;
-       if (!rsurface.passcolor4f)
-               return;
-       for (i = 0, c1 = rsurface.passcolor4f + 4*rsurface.batchfirstvertex, c2 = rsurface.array_passcolor4f + 4*rsurface.batchfirstvertex;i < rsurface.batchnumvertices;i++, c1 += 4, c2 += 4)
+       float *c;
+       // TODO: optimize
+       if (texturesurfacelist[0]->lightmapinfo)
+       {
+               // 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)
+                       {
+                               if (surface->lightmapinfo->samples)
+                               {
+                                       const unsigned char *lm = surface->lightmapinfo->samples + (rsurface.modellightmapoffsets + surface->num_firstvertex)[i];
+                                       float scale = r_refdef.scene.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.scene.lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f);
+                                               VectorMA(c, scale, lm, c);
+                                               if (surface->lightmapinfo->styles[2] != 255)
+                                               {
+                                                       lm += size3;
+                                                       scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f);
+                                                       VectorMA(c, scale, lm, c);
+                                                       if (surface->lightmapinfo->styles[3] != 255)
+                                                       {
+                                                               lm += size3;
+                                                               scale = r_refdef.scene.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;
+               rsurface.lightmapcolor4f_bufferobject = 0;
+               rsurface.lightmapcolor4f_bufferoffset = 0;
+       }
+       else
        {
-               c2[0] = bound(0.0f, c1[0], 1.0f);
-               c2[1] = bound(0.0f, c1[1], 1.0f);
-               c2[2] = bound(0.0f, c1[2], 1.0f);
-               c2[3] = bound(0.0f, c1[3], 1.0f);
+               rsurface.lightmapcolor4f = rsurface.modellightmapcolor4f;
+               rsurface.lightmapcolor4f_bufferobject = rsurface.modellightmapcolor4f_bufferobject;
+               rsurface.lightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
        }
+       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, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
+       GL_Color(r, g, b, a);
+       RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
 }
 
-static void RSurf_DrawBatch_GL11_ApplyVertexShade(float *r, float *g, float *b, float *a, qboolean *applycolor)
+static void RSurf_DrawBatch_GL11_ApplyVertexShade(int texturenumsurfaces, const msurface_t **texturesurfacelist, float *r, float *g, float *b, float *a, qboolean *applycolor)
 {
+       int texturesurfaceindex;
        int i;
        float f;
        float alpha;
@@ -11278,24 +11052,33 @@ static void RSurf_DrawBatch_GL11_ApplyVertexShade(float *r, float *g, float *b,
        diffusecolor[1] = rsurface.modellight_diffuse[1] * *g * f;
        diffusecolor[2] = rsurface.modellight_diffuse[2] * *b * f;
        alpha = *a;
-       if (VectorLength2(diffusecolor) > 0)
+       if (VectorLength2(diffusecolor) > 0 && rsurface.normal3f)
        {
-               // q3-style directional shading
-               for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, n = rsurface.batchnormal3f + rsurface.batchfirstvertex * 3, c = rsurface.array_passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, n += 3, c += 4)
+               // generate color arrays for the surfaces in this list
+               for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                {
-                       if ((f = DotProduct(n, lightdir)) > 0)
-                               VectorMA(ambientcolor, f, diffusecolor, c);
-                       else
-                               VectorCopy(ambientcolor, c);
-                       c[3] = alpha;
+                       const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+                       int numverts = surface->num_vertices;
+                       v = rsurface.vertex3f + 3 * surface->num_firstvertex;
+                       n = 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, n += 3, c += 4)
+                       {
+                               if ((f = DotProduct(n, lightdir)) > 0)
+                                       VectorMA(ambientcolor, f, diffusecolor, c);
+                               else
+                                       VectorCopy(ambientcolor, c);
+                               c[3] = alpha;
+                       }
                }
                *r = 1;
                *g = 1;
                *b = 1;
                *a = 1;
-               rsurface.passcolor4f = rsurface.array_passcolor4f;
-               rsurface.passcolor4f_vertexbuffer = 0;
-               rsurface.passcolor4f_bufferoffset = 0;
+               rsurface.lightmapcolor4f = rsurface.array_color4f;
+               rsurface.lightmapcolor4f_bufferobject = 0;
+               rsurface.lightmapcolor4f_bufferoffset = 0;
                *applycolor = false;
        }
        else
@@ -11303,36 +11086,20 @@ static void RSurf_DrawBatch_GL11_ApplyVertexShade(float *r, float *g, float *b,
                *r = ambientcolor[0];
                *g = ambientcolor[1];
                *b = ambientcolor[2];
-               rsurface.passcolor4f = NULL;
-               rsurface.passcolor4f_vertexbuffer = 0;
-               rsurface.passcolor4f_bufferoffset = 0;
+               rsurface.lightmapcolor4f = NULL;
+               rsurface.lightmapcolor4f_bufferobject = 0;
+               rsurface.lightmapcolor4f_bufferoffset = 0;
        }
 }
 
-static void RSurf_DrawBatch_GL11_VertexShade(float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
+static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, const msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
 {
-       RSurf_DrawBatch_GL11_ApplyVertexShade(&r, &g, &b, &a, &applycolor);
-       if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog();
-       if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(r, g, b, a);
-       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset);
+       RSurf_DrawBatch_GL11_ApplyVertexShade(texturenumsurfaces, texturesurfacelist, &r, &g, &b, &a, &applycolor);
+       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, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
        GL_Color(r, g, b, a);
-       RSurf_DrawBatch();
-}
-
-static void RSurf_DrawBatch_GL11_MakeFogColor(float r, float g, float b, float a)
-{
-       int i;
-       float f;
-       const float *v;
-       float *c;
-       for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, c = rsurface.array_passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, c += 4)
-       {
-               f = 1 - RSurf_FogVertex(v);
-               c[0] = r;
-               c[1] = g;
-               c[2] = b;
-               c[3] = f * a;
-       }
+       RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
 }
 
 void RSurf_SetupDepthAndCulling(void)
@@ -11363,6 +11130,8 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_
        // level, so don't use it then either.
        if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_refdef.viewcache.world_novis)
        {
+               GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
+               R_Mesh_ColorPointer(NULL, 0, 0);
                R_Mesh_ResetTextureState();
                if (skyrendermasked)
                {
@@ -11372,19 +11141,15 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_
                        // just to make sure that braindead drivers don't draw
                        // anything despite that colormask...
                        GL_BlendFunc(GL_ZERO, GL_ONE);
-                       RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXPOSITION, texturenumsurfaces, texturesurfacelist);
-                       R_Mesh_PrepareVertices_Position(rsurface.batchnumvertices, rsurface.batchvertexposition, rsurface.batchvertexpositionbuffer);
                }
                else
                {
                        R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
                        // fog sky
                        GL_BlendFunc(GL_ONE, GL_ZERO);
-                       RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, texturenumsurfaces, texturesurfacelist);
-                       GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
-                       R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
                }
-               RSurf_DrawBatch();
+               RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
+               RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
                if (skyrendermasked)
                        GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
        }
@@ -11398,50 +11163,50 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface
 {
        if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
                return;
+       RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist);
        if (prepass)
        {
                // render screenspace normalmap to texture
                GL_DepthMask(true);
-               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist);
-               RSurf_DrawBatch();
+               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_DEFERREDGEOMETRY);
+               RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
        }
        else if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)) && !r_waterstate.renderingscene)
        {
                // render water or distortion background, then blend surface on top
                GL_DepthMask(true);
-               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND, texturenumsurfaces, texturesurfacelist);
-               RSurf_BindReflectionForBatch();
-               if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
-                       RSurf_BindLightmapForBatch();
-               RSurf_DrawBatch();
+               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND);
+               RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist);
                GL_DepthMask(false);
-               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist);
+               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE);
                if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
-                       RSurf_BindLightmapForBatch();
-               RSurf_DrawBatch();
+                       RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist);
+               else
+                       RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
        }
        else
        {
                // render surface normally
                GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
-               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist);
+               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE);
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
-                       RSurf_BindReflectionForBatch();
-               if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
-                       RSurf_BindLightmapForBatch();
-               RSurf_DrawBatch();
+                       RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist);
+               else if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
+                       RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist);
+               else
+                       RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
        }
 }
 
 static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
 {
        // OpenGL 1.3 path - anything not completely ancient
+       int texturesurfaceindex;
        qboolean applycolor;
        qboolean applyfog;
        int layerindex;
        const texturelayer_t *layer;
-       RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | ((!rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.modeltexcoordlightmap2f ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
-       R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
+       RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
 
        for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++)
        {
@@ -11476,7 +11241,7 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface
                }
                layercolor[3] = layer->color[3];
                applycolor = layercolor[0] != 1 || layercolor[1] != 1 || layercolor[2] != 1 || layercolor[3] != 1;
-               R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, 0, 0);
+               R_Mesh_ColorPointer(NULL, 0, 0);
                applyfog = r_refdef.fogenabled && (rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED);
                switch (layer->type)
                {
@@ -11485,27 +11250,27 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface
                        R_Mesh_TexBind(0, r_texture_white);
                        R_Mesh_TexMatrix(0, NULL);
                        R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
+                       R_Mesh_TexCoordPointer(0, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
                        R_Mesh_TexBind(1, layer->texture);
                        R_Mesh_TexMatrix(1, &layer->texmatrix);
                        R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, layertexrgbscale, 1);
-                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
+                       R_Mesh_TexCoordPointer(1, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                        if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
-                               RSurf_DrawBatch_GL11_VertexShade(layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
+                               RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
                        else if (rsurface.uselightmaptexture)
-                               RSurf_DrawBatch_GL11_Lightmap(layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
+                               RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
                        else
-                               RSurf_DrawBatch_GL11_VertexColor(layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
+                               RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
                        break;
                case TEXTURELAYERTYPE_TEXTURE:
                        // singletexture unlit texture with transparency support
                        R_Mesh_TexBind(0, layer->texture);
                        R_Mesh_TexMatrix(0, &layer->texmatrix);
                        R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, layertexrgbscale, 1);
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
+                       R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                        R_Mesh_TexBind(1, 0);
-                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, 0, 0);
-                       RSurf_DrawBatch_GL11_Unlit(layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
+                       R_Mesh_TexCoordPointer(1, 2, NULL, 0, 0);
+                       RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
                        break;
                case TEXTURELAYERTYPE_FOG:
                        // singletexture fogging
@@ -11514,19 +11279,34 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface
                                R_Mesh_TexBind(0, layer->texture);
                                R_Mesh_TexMatrix(0, &layer->texmatrix);
                                R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, layertexrgbscale, 1);
-                               R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
+                               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                        }
                        else
                        {
                                R_Mesh_TexBind(0, 0);
-                               R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, 0, 0);
+                               R_Mesh_TexCoordPointer(0, 2, NULL, 0, 0);
                        }
                        R_Mesh_TexBind(1, 0);
-                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, 0, 0);
+                       R_Mesh_TexCoordPointer(1, 2, NULL, 0, 0);
                        // generate a color array for the fog pass
-                       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
-                       RSurf_DrawBatch_GL11_MakeFogColor(layercolor[0], layercolor[1], layercolor[2], layercolor[3]);
-                       RSurf_DrawBatch();
+                       R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
+                       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+                       {
+                               int i;
+                               float f;
+                               const float *v;
+                               float *c;
+                               const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+                               for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4)
+                               {
+                                       f = 1 - RSurf_FogVertex(v);
+                                       c[0] = layercolor[0];
+                                       c[1] = layercolor[1];
+                                       c[2] = layercolor[2];
+                                       c[3] = f * layercolor[3];
+                               }
+                       }
+                       RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
                        break;
                default:
                        Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
@@ -11543,11 +11323,11 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface
 static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
 {
        // OpenGL 1.1 - crusty old voodoo path
+       int texturesurfaceindex;
        qboolean applyfog;
        int layerindex;
        const texturelayer_t *layer;
-       RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | ((!rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.modeltexcoordlightmap2f ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
-       R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
+       RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
 
        for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++)
        {
@@ -11563,7 +11343,7 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
                }
                GL_DepthMask(layer->depthmask && writedepth);
                GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
-               R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, 0, 0);
+               R_Mesh_ColorPointer(NULL, 0, 0);
                applyfog = r_refdef.fogenabled && (rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED);
                switch (layer->type)
                {
@@ -11575,20 +11355,20 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
                                R_Mesh_TexBind(0, r_texture_white);
                                R_Mesh_TexMatrix(0, NULL);
                                R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
-                               R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
+                               R_Mesh_TexCoordPointer(0, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
                                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
-                                       RSurf_DrawBatch_GL11_VertexShade(1, 1, 1, 1, false, false);
+                                       RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
                                else if (rsurface.uselightmaptexture)
-                                       RSurf_DrawBatch_GL11_Lightmap(1, 1, 1, 1, false, false);
+                                       RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
                                else
-                                       RSurf_DrawBatch_GL11_VertexColor(1, 1, 1, 1, false, false);
+                                       RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
                                // then apply the texture to it
                                GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
                                R_Mesh_TexBind(0, layer->texture);
                                R_Mesh_TexMatrix(0, &layer->texmatrix);
                                R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
-                               R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
-                               RSurf_DrawBatch_GL11_Unlit(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);
+                               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+                               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
                        {
@@ -11596,11 +11376,11 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
                                R_Mesh_TexBind(0, layer->texture);
                                R_Mesh_TexMatrix(0, &layer->texmatrix);
                                R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
-                               R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
+                               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
-                                       RSurf_DrawBatch_GL11_VertexShade(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);
+                                       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(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);
+                                       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:
@@ -11608,8 +11388,8 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
                        R_Mesh_TexBind(0, layer->texture);
                        R_Mesh_TexMatrix(0, &layer->texmatrix);
                        R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
-                       RSurf_DrawBatch_GL11_Unlit(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);
+                       R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+                       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
@@ -11618,17 +11398,32 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
                                R_Mesh_TexBind(0, layer->texture);
                                R_Mesh_TexMatrix(0, &layer->texmatrix);
                                R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
-                               R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
+                               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                        }
                        else
                        {
                                R_Mesh_TexBind(0, 0);
-                               R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, 0, 0);
+                               R_Mesh_TexCoordPointer(0, 2, NULL, 0, 0);
                        }
                        // generate a color array for the fog pass
-                       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
-                       RSurf_DrawBatch_GL11_MakeFogColor(layer->color[0], layer->color[1], layer->color[2], layer->color[3]);
-                       RSurf_DrawBatch();
+                       R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
+                       for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+                       {
+                               int i;
+                               float f;
+                               const float *v;
+                               float *c;
+                               const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+                               for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4)
+                               {
+                                       f = 1 - RSurf_FogVertex(v);
+                                       c[0] = layer->color[0];
+                                       c[1] = layer->color[1];
+                                       c[2] = layer->color[2];
+                                       c[3] = f * layer->color[3];
+                               }
+                       }
+                       RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
                        break;
                default:
                        Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
@@ -11642,14 +11437,12 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
        }
 }
 
-static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
+static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
 {
-       int vi;
-       int j;
-       r_vertexgeneric_t *batchvertex;
        float c[4];
 
        GL_AlphaTest(false);
+       R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
        R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
 
@@ -11707,127 +11500,55 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const
                GL_DepthMask(writedepth);
        }
 
-       if (r_showsurfaces.integer == 3)
-       {
-               rsurface.passcolor4f = NULL;
-
-               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
-               {
-                       RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
-
-                       rsurface.passcolor4f = NULL;
-                       rsurface.passcolor4f_vertexbuffer = 0;
-                       rsurface.passcolor4f_bufferoffset = 0;
-               }
-               else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
-               {
-                       qboolean applycolor = true;
-                       float one = 1.0;
+       rsurface.lightmapcolor4f = NULL;
 
-                       RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
-
-                       r_refdef.lightmapintensity = 1;
-                       RSurf_DrawBatch_GL11_ApplyVertexShade(&one, &one, &one, &one, &applycolor);
-                       r_refdef.lightmapintensity = 0; // we're in showsurfaces, after all
-               }
-               else
-               {
-                       RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
-
-                       rsurface.passcolor4f = rsurface.batchlightmapcolor4f;
-                       rsurface.passcolor4f_vertexbuffer = rsurface.batchlightmapcolor4f_vertexbuffer;
-                       rsurface.passcolor4f_bufferoffset = rsurface.batchlightmapcolor4f_bufferoffset;
-               }
-
-               if(!rsurface.passcolor4f)
-                       RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray();
-
-               RSurf_DrawBatch_GL11_ApplyAmbient();
-               RSurf_DrawBatch_GL11_ApplyColor(c[0], c[1], c[2], c[3]);
-               if(r_refdef.fogenabled)
-                       RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors();
-               RSurf_DrawBatch_GL11_ClampColor();
-
-               R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.passcolor4f, NULL);
-               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
-               RSurf_DrawBatch();
-       }
-       else if (!r_refdef.view.showdebug)
+       if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
        {
-               RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
-               batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
-               for (j = 0, vi = rsurface.batchfirstvertex;j < rsurface.batchnumvertices;j++, vi++)
-               {
-                       VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
-                       Vector4Set(batchvertex[vi].color4ub, 0, 0, 0, 255);
-               }
-               R_Mesh_PrepareVertices_Generic_Unlock();
-               RSurf_DrawBatch();
-       }
-       else if (r_showsurfaces.integer == 4)
-       {
-               RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
-               batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
-               for (j = 0, vi = rsurface.batchfirstvertex;j < rsurface.batchnumvertices;j++, vi++)
-               {
-                       unsigned char c = vi << 3;
-                       VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
-                       Vector4Set(batchvertex[vi].color4ub, c, c, c, 255);
-               }
-               R_Mesh_PrepareVertices_Generic_Unlock();
-               RSurf_DrawBatch();
+               RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
+
+               rsurface.lightmapcolor4f = NULL;
+               rsurface.lightmapcolor4f_bufferobject = 0;
+               rsurface.lightmapcolor4f_bufferoffset = 0;
        }
-       else if (r_showsurfaces.integer == 2)
+       else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
        {
-               const int *e;
-               RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
-               batchvertex = R_Mesh_PrepareVertices_Generic_Lock(3*rsurface.batchnumtriangles);
-               for (j = 0, e = rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle;j < rsurface.batchnumtriangles;j++, e += 3)
-               {
-                       unsigned char c = (j + rsurface.batchfirsttriangle) << 3;
-                       VectorCopy(rsurface.batchvertex3f + 3*e[0], batchvertex[j*3+0].vertex3f);
-                       VectorCopy(rsurface.batchvertex3f + 3*e[1], batchvertex[j*3+1].vertex3f);
-                       VectorCopy(rsurface.batchvertex3f + 3*e[2], batchvertex[j*3+2].vertex3f);
-                       Vector4Set(batchvertex[j*3+0].color4ub, c, c, c, 255);
-                       Vector4Set(batchvertex[j*3+1].color4ub, c, c, c, 255);
-                       Vector4Set(batchvertex[j*3+2].color4ub, c, c, c, 255);
-               }
-               R_Mesh_PrepareVertices_Generic_Unlock();
-               R_Mesh_Draw(0, rsurface.batchnumtriangles*3, 0, rsurface.batchnumtriangles, NULL, NULL, 0, NULL, NULL, 0);
+               qboolean applycolor = true;
+               float one = 1.0;
+
+               RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
+
+               r_refdef.lightmapintensity = 1;
+               RSurf_DrawBatch_GL11_ApplyVertexShade(texturenumsurfaces, texturesurfacelist, &one, &one, &one, &one, &applycolor);
+               r_refdef.lightmapintensity = 0; // we're in showsurfaces, after all
        }
        else
        {
-               int texturesurfaceindex;
-               int k;
-               const msurface_t *surface;
-               unsigned char surfacecolor4ub[4];
-               RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
-               batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchfirstvertex + rsurface.batchnumvertices);
-               vi = 0;
-               for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
-               {
-                       surface = texturesurfacelist[texturesurfaceindex];
-                       k = (int)(((size_t)surface) / sizeof(msurface_t));
-                       Vector4Set(surfacecolor4ub, (k & 0xF) << 4, (k & 0xF0), (k & 0xF00) >> 4, 255);
-                       for (j = 0;j < surface->num_vertices;j++)
-                       {
-                               VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
-                               Vector4Copy(surfacecolor4ub, batchvertex[vi].color4ub);
-                               vi++;
-                       }
-               }
-               R_Mesh_PrepareVertices_Generic_Unlock();
-               RSurf_DrawBatch();
+               RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
+
+               rsurface.lightmapcolor4f = rsurface.modellightmapcolor4f;
+               rsurface.lightmapcolor4f_bufferobject = rsurface.modellightmapcolor4f_bufferobject;
+               rsurface.lightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
        }
+
+       if(!rsurface.lightmapcolor4f)
+               RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(texturenumsurfaces, texturesurfacelist);
+
+       RSurf_DrawBatch_GL11_ApplyAmbient(texturenumsurfaces, texturesurfacelist);
+       RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, c[0], c[1], c[2], c[3]);
+       if(r_refdef.fogenabled)
+               RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(texturenumsurfaces, texturesurfacelist);
+
+       R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
+       RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
 }
 
 static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
 {
        CHECKGLERROR
        RSurf_SetupDepthAndCulling();
-       if (r_showsurfaces.integer)
+       if (r_showsurfaces.integer == 3 && !prepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY))
        {
-               R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
+               R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth);
                return;
        }
        switch (vid.renderpath)
@@ -11850,9 +11571,9 @@ static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface
 {
        CHECKGLERROR
        RSurf_SetupDepthAndCulling();
-       if (r_showsurfaces.integer)
+       if (r_showsurfaces.integer == 3 && !prepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY))
        {
-               R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
+               R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth);
                return;
        }
        switch (vid.renderpath)
@@ -11911,9 +11632,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
                        surface = rsurface.modelsurfaces + surfacelist[i];
                        texture = surface->texture;
                        rsurface.texture = R_GetCurrentTexture(texture);
-                       rsurface.lightmaptexture = NULL;
-                       rsurface.deluxemaptexture = NULL;
-                       rsurface.uselightmaptexture = false;
+                       rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
                        // scan ahead until we find a different texture
                        endsurface = min(i + 1024, numsurfaces);
                        texturenumsurfaces = 0;
@@ -11921,7 +11640,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
                        for (;j < endsurface;j++)
                        {
                                surface = rsurface.modelsurfaces + surfacelist[j];
-                               if (texture != surface->texture)
+                               if (texture != surface->texture || rsurface.uselightmaptexture != (surface->lightmaptexture != NULL))
                                        break;
                                texturesurfacelist[texturenumsurfaces++] = surface;
                        }
@@ -11937,13 +11656,13 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
                                GL_BlendFunc(GL_ONE, GL_ZERO);
                                GL_DepthMask(true);
                                GL_AlphaTest(false);
+                               R_Mesh_ColorPointer(NULL, 0, 0);
                                R_Mesh_ResetTextureState();
                                R_SetupShader_DepthOrShadow();
                        }
                        RSurf_SetupDepthAndCulling();
-                       RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXPOSITION, texturenumsurfaces, texturesurfacelist);
-                       R_Mesh_PrepareVertices_Position(rsurface.batchnumvertices, rsurface.batchvertexposition, rsurface.batchvertexpositionbuffer);
-                       RSurf_DrawBatch();
+                       RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
+                       RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
                }
                if (setup)
                        GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
@@ -11955,8 +11674,6 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
                surface = rsurface.modelsurfaces + surfacelist[i];
                texture = surface->texture;
                rsurface.texture = R_GetCurrentTexture(texture);
-               rsurface.lightmaptexture = surface->lightmaptexture;
-               rsurface.deluxemaptexture = surface->deluxemaptexture;
                rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
                // scan ahead until we find a different texture
                endsurface = min(i + MAXBATCH_TRANSPARENTSURFACES, numsurfaces);
@@ -11965,7 +11682,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
                for (;j < endsurface;j++)
                {
                        surface = rsurface.modelsurfaces + surfacelist[j];
-                       if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
+                       if (texture != surface->texture || rsurface.uselightmaptexture != (surface->lightmaptexture != NULL))
                                break;
                        texturesurfacelist[texturenumsurfaces++] = surface;
                }
@@ -12002,24 +11719,20 @@ static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const
        }
 }
 
-static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
-{
-       if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
-               return;
-       if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
-               return;
-       RSurf_SetupDepthAndCulling();
-       RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXPOSITION, texturenumsurfaces, texturesurfacelist);
-       R_Mesh_PrepareVertices_Position(rsurface.batchnumvertices, rsurface.batchvertexposition, rsurface.batchvertexpositionbuffer);
-       RSurf_DrawBatch();
-}
-
 static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
 {
        const entity_render_t *queueentity = r_refdef.scene.worldentity;
        CHECKGLERROR
        if (depthonly)
-               R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
+       {
+               if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
+                       return;
+               if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
+                       return;
+               RSurf_SetupDepthAndCulling();
+               RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
+               RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+       }
        else if (prepass)
        {
                if (!rsurface.texture->currentnumlayers)
@@ -12029,7 +11742,34 @@ static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurf
                else
                        R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
        }
-       else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && !r_showsurfaces.integer)
+       else if (r_showsurfaces.integer && !r_refdef.view.showdebug && !prepass)
+       {
+               RSurf_SetupDepthAndCulling();
+               GL_AlphaTest(false);
+               R_Mesh_ColorPointer(NULL, 0, 0);
+               R_Mesh_ResetTextureState();
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+               RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
+               GL_DepthMask(true);
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_Color(0, 0, 0, 1);
+               GL_DepthTest(writedepth);
+               RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+       }
+       else if (r_showsurfaces.integer && r_showsurfaces.integer != 3 && !prepass)
+       {
+               RSurf_SetupDepthAndCulling();
+               GL_AlphaTest(false);
+               R_Mesh_ColorPointer(NULL, 0, 0);
+               R_Mesh_ResetTextureState();
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+               RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
+               GL_DepthMask(true);
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_DepthTest(true);
+               RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
+       }
+       else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY)
                R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
        else if (!rsurface.texture->currentnumlayers)
                return;
@@ -12061,8 +11801,6 @@ void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, in
                // use skin 1 instead)
                texture = surfacelist[i]->texture;
                rsurface.texture = R_GetCurrentTexture(texture);
-               rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
-               rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
                rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL && !depthonly && !prepass;
                if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
                {
@@ -12072,7 +11810,7 @@ void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, in
                        continue;
                }
                // simply scan ahead until we find a different texture or lightmap state
-               for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
+               for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
                        ;
                // render the range of surfaces
                R_ProcessWorldTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
@@ -12083,7 +11821,15 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf
 {
        CHECKGLERROR
        if (depthonly)
-               R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
+       {
+               if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
+                       return;
+               if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
+                       return;
+               RSurf_SetupDepthAndCulling();
+               RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
+               RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+       }
        else if (prepass)
        {
                if (!rsurface.texture->currentnumlayers)
@@ -12093,7 +11839,34 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf
                else
                        R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
        }
-       else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && !r_showsurfaces.integer)
+       else if (r_showsurfaces.integer && !r_refdef.view.showdebug)
+       {
+               RSurf_SetupDepthAndCulling();
+               GL_AlphaTest(false);
+               R_Mesh_ColorPointer(NULL, 0, 0);
+               R_Mesh_ResetTextureState();
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+               RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
+               GL_DepthMask(true);
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_Color(0, 0, 0, 1);
+               GL_DepthTest(writedepth);
+               RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+       }
+       else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
+       {
+               RSurf_SetupDepthAndCulling();
+               GL_AlphaTest(false);
+               R_Mesh_ColorPointer(NULL, 0, 0);
+               R_Mesh_ResetTextureState();
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+               RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
+               GL_DepthMask(true);
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_DepthTest(true);
+               RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
+       }
+       else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY)
                R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
        else if (!rsurface.texture->currentnumlayers)
                return;
@@ -12125,8 +11898,6 @@ void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurfa
                // use skin 1 instead)
                texture = surfacelist[i]->texture;
                rsurface.texture = R_GetCurrentTexture(texture);
-               rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
-               rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
                rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL && !depthonly && !prepass;
                if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
                {
@@ -12136,7 +11907,7 @@ void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurfa
                        continue;
                }
                // simply scan ahead until we find a different texture or lightmap state
-               for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
+               for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
                        ;
                // render the range of surfaces
                R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent, prepass);
@@ -12178,7 +11949,10 @@ void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, in
        GL_CullFace(GL_NONE);
        R_EntityMatrix(&identitymatrix);
 
+       R_Mesh_VertexPointer(vertex3f, 0, 0);
+       R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
 
        i = surfacelist[0];
        GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
@@ -12201,9 +11975,7 @@ void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, in
                for (j = 0;j < 3;j++, i++)
                        vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
 
-       R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
-       R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
+       R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, locboxelements, 0, 0);
 }
 
 void R_DrawLocs(void)
@@ -12766,12 +12538,12 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
                t2f[5] = decal->texcoord2f[2][1];
 
                // update vertex positions for animated models
-               if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
+               if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnum_triangles)
                {
                        e = rsurface.modelelement3i + 3*decal->triangleindex;
-                       VectorCopy(rsurface.modelvertexposition[e[0]].vertex3f, v3f);
-                       VectorCopy(rsurface.modelvertexposition[e[1]].vertex3f, v3f + 3);
-                       VectorCopy(rsurface.modelvertexposition[e[2]].vertex3f, v3f + 6);
+                       VectorCopy(rsurface.vertex3f + 3*e[0], v3f);
+                       VectorCopy(rsurface.vertex3f + 3*e[1], v3f + 3);
+                       VectorCopy(rsurface.vertex3f + 3*e[2], v3f + 6);
                }
                else
                {
@@ -12804,7 +12576,9 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
                // (this assumes they all use one particle font texture!)
                RSurf_ActiveCustomEntity(&rsurface.matrix, &rsurface.inversematrix, rsurface.ent_flags, rsurface.ent_shadertime, 1, 1, 1, 1, numdecals*3, decalsystem->vertex3f, decalsystem->texcoord2f, NULL, NULL, NULL, decalsystem->color4f, numtris, decalsystem->element3i, decalsystem->element3s, false, false);
                R_Mesh_ResetTextureState();
-               R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
+               R_Mesh_VertexPointer(decalsystem->vertex3f, 0, 0);
+               R_Mesh_TexCoordPointer(0, 2, decalsystem->texcoord2f, 0, 0);
+               R_Mesh_ColorPointer(decalsystem->color4f, 0, 0);
                GL_DepthMask(false);
                GL_DepthRange(0, 1);
                GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
@@ -12812,7 +12586,7 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
                GL_CullFace(GL_NONE);
                GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
                R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1);
-               R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
+               R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, decalsystem->element3s, 0, 0);
        }
 }
 
@@ -12863,6 +12637,7 @@ void R_DrawDebugModel(void)
 
        flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
 
+       R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
        R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
        GL_DepthRange(0, 1);
@@ -12891,9 +12666,9 @@ void R_DrawDebugModel(void)
                                brush = model->brush.data_brushes + bihleaf->itemindex;
                                if (brush->colbrushf && brush->colbrushf->numtriangles)
                                {
+                                       R_Mesh_VertexPointer(brush->colbrushf->points->v, 0, 0);
                                        GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
-                                       R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
-                                       R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
+                                       R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, 0);
                                }
                                break;
                        case BIH_COLLISIONTRIANGLE:
@@ -12901,18 +12676,18 @@ void R_DrawDebugModel(void)
                                VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
                                VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
                                VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
+                               R_Mesh_VertexPointer(vertex3f[0], 0, 0);
                                GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
-                               R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
-                               R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+                               R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);
                                break;
                        case BIH_RENDERTRIANGLE:
                                triangleindex = bihleaf->itemindex;
                                VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
                                VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
                                VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
+                               R_Mesh_VertexPointer(vertex3f[0], 0, 0);
                                GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
-                               R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
-                               R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+                               R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0);
                                break;
                        }
                }
@@ -12939,7 +12714,7 @@ void R_DrawDebugModel(void)
                        rsurface.texture = R_GetCurrentTexture(surface->texture);
                        if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
                        {
-                               RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
+                               RSurf_PrepareVerticesForBatch(true, true, 1, &surface);
                                if (r_showtris.value > 0)
                                {
                                        if (!rsurface.texture->currentlayers->depthmask)
@@ -12948,9 +12723,12 @@ void R_DrawDebugModel(void)
                                                GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
                                        else
                                                GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
-                                       R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
+                                       R_Mesh_VertexPointer(rsurface.vertex3f, 0, 0);
+                                       R_Mesh_ColorPointer(NULL, 0, 0);
+                                       R_Mesh_TexCoordPointer(0, 0, NULL, 0, 0);
                                        qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-                                       RSurf_DrawBatch();
+                                       //R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, model->surfmesh.data_element3i, NULL, 0, 0);
+                                       R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
                                        qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                                        CHECKGLERROR
                                }
@@ -12959,25 +12737,25 @@ void R_DrawDebugModel(void)
                                        qglBegin(GL_LINES);
                                        for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
                                        {
-                                               VectorCopy(rsurface.batchvertex3f + l * 3, v);
+                                               VectorCopy(rsurface.vertex3f + l * 3, v);
                                                GL_Color(r_refdef.view.colorscale, 0, 0, 1);
                                                qglVertex3f(v[0], v[1], v[2]);
-                                               VectorMA(v, -r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
+                                               VectorMA(v, -r_shownormals.value, rsurface.svector3f + l * 3, v);
                                                GL_Color(r_refdef.view.colorscale, 1, 1, 1);
                                                qglVertex3f(v[0], v[1], v[2]);
                                        }
                                        qglEnd();
                                        CHECKGLERROR
                                }
-                               if (r_shownormals.value > 0 && rsurface.batchsvector3f)
+                               if (r_shownormals.value > 0)
                                {
                                        qglBegin(GL_LINES);
                                        for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
                                        {
-                                               VectorCopy(rsurface.batchvertex3f + l * 3, v);
+                                               VectorCopy(rsurface.vertex3f + l * 3, v);
                                                GL_Color(r_refdef.view.colorscale, 0, 0, 1);
                                                qglVertex3f(v[0], v[1], v[2]);
-                                               VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
+                                               VectorMA(v, r_shownormals.value, rsurface.svector3f + l * 3, v);
                                                GL_Color(r_refdef.view.colorscale, 1, 1, 1);
                                                qglVertex3f(v[0], v[1], v[2]);
                                        }
@@ -12986,10 +12764,10 @@ void R_DrawDebugModel(void)
                                        qglBegin(GL_LINES);
                                        for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
                                        {
-                                               VectorCopy(rsurface.batchvertex3f + l * 3, v);
+                                               VectorCopy(rsurface.vertex3f + l * 3, v);
                                                GL_Color(0, r_refdef.view.colorscale, 0, 1);
                                                qglVertex3f(v[0], v[1], v[2]);
-                                               VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
+                                               VectorMA(v, r_shownormals.value, rsurface.tvector3f + l * 3, v);
                                                GL_Color(r_refdef.view.colorscale, 1, 1, 1);
                                                qglVertex3f(v[0], v[1], v[2]);
                                        }
@@ -12998,10 +12776,10 @@ void R_DrawDebugModel(void)
                                        qglBegin(GL_LINES);
                                        for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
                                        {
-                                               VectorCopy(rsurface.batchvertex3f + l * 3, v);
+                                               VectorCopy(rsurface.vertex3f + l * 3, v);
                                                GL_Color(0, 0, r_refdef.view.colorscale, 1);
                                                qglVertex3f(v[0], v[1], v[2]);
-                                               VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
+                                               VectorMA(v, r_shownormals.value, rsurface.normal3f + l * 3, v);
                                                GL_Color(r_refdef.view.colorscale, 1, 1, 1);
                                                qglVertex3f(v[0], v[1], v[2]);
                                        }
@@ -13065,8 +12843,6 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep
                return;
        }
 
-       rsurface.lightmaptexture = NULL;
-       rsurface.deluxemaptexture = NULL;
        rsurface.uselightmaptexture = false;
        rsurface.texture = NULL;
        rsurface.rtlight = NULL;
@@ -13197,8 +12973,6 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
                return;
        }
 
-       rsurface.lightmaptexture = NULL;
-       rsurface.deluxemaptexture = NULL;
        rsurface.uselightmaptexture = false;
        rsurface.texture = NULL;
        rsurface.rtlight = NULL;
@@ -13268,8 +13042,6 @@ void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, i
 
        // now render it
        rsurface.texture = R_GetCurrentTexture(surface.texture);
-       rsurface.lightmaptexture = NULL;
-       rsurface.deluxemaptexture = NULL;
        rsurface.uselightmaptexture = false;
        R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
 }
@@ -13289,8 +13061,6 @@ void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatri
 
        // now render it
        rsurface.texture = R_GetCurrentTexture(surface.texture);
-       rsurface.lightmaptexture = NULL;
-       rsurface.deluxemaptexture = NULL;
        rsurface.uselightmaptexture = false;
        R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
 }
index 615119baf09c8db359bd2db01c2849d58ad3ddbb..d3b941aa04d2d98246487e4b5371bdb3fc166686 100644 (file)
@@ -349,7 +349,10 @@ static void R_DrawPortal_Callback(const entity_render_t *ent, const rtlight_t *r
 
        numpoints = min(portal->numpoints, POLYGONELEMENTS_MAXPOINTS);
 
+       R_Mesh_VertexPointer(vertex3f, 0, 0);
+       R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
 
        isvis = (portal->here->clusterindex >= 0 && portal->past->clusterindex >= 0 && portal->here->clusterindex != portal->past->clusterindex);
 
@@ -360,9 +363,7 @@ static void R_DrawPortal_Callback(const entity_render_t *ent, const rtlight_t *r
                         isvis ? 0.125f : 0.03125f);
        for (i = 0, v = vertex3f;i < numpoints;i++, v += 3)
                VectorCopy(portal->points[i].position, v);
-       R_Mesh_PrepareVertices_Generic_Arrays(numpoints, vertex3f, NULL, NULL);
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
-       R_Mesh_Draw(0, numpoints, 0, numpoints - 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+       R_Mesh_Draw(0, numpoints, 0, numpoints - 2, polygonelement3i, polygonelement3s, 0, 0);
 }
 
 // LordHavoc: this is just a nice debugging tool, very slow
@@ -610,6 +611,7 @@ void R_Q1BSP_DrawDepth(entity_render_t *ent)
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthMask(true);
        GL_AlphaTest(false);
+       R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
        R_SetupShader_DepthOrShadow();
        if (ent == r_refdef.scene.worldentity)
@@ -1084,10 +1086,10 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, const vec3_t relativelightor
                        rsurface.texture = R_GetCurrentTexture(surface->texture);
                        if (rsurface.texture->currentmaterialflags & MATERIALFLAG_NOSHADOW)
                                continue;
-                       RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
-                       R_Shadow_MarkVolumeFromBox(surface->num_firsttriangle, surface->num_triangles, rsurface.batchvertex3f, rsurface.modelelement3i, relativelightorigin, relativelightdirection, lightmins, lightmaxs, surface->mins, surface->maxs);
+                       RSurf_PrepareVerticesForBatch(false, false, 1, &surface);
+                       R_Shadow_MarkVolumeFromBox(surface->num_firsttriangle, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i, relativelightorigin, relativelightdirection, lightmins, lightmaxs, surface->mins, surface->maxs);
                }
-               R_Shadow_VolumeFromList(model->surfmesh.num_vertices, model->surfmesh.num_triangles, rsurface.batchvertex3f, model->surfmesh.data_element3i, model->surfmesh.data_neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist, ent->mins, ent->maxs);
+               R_Shadow_VolumeFromList(model->surfmesh.num_vertices, model->surfmesh.num_triangles, rsurface.vertex3f, model->surfmesh.data_element3i, model->surfmesh.data_neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist, ent->mins, ent->maxs);
        }
        if (ent->model->brush.submodel)
                GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);
@@ -1157,9 +1159,8 @@ void R_Q1BSP_DrawShadowMap(int side, entity_render_t *ent, const vec3_t relative
                }
                --modelsurfacelistindex;
                GL_CullFace(rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE ? GL_NONE : r_refdef.view.cullface_back);
-               RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXPOSITION, batchnumsurfaces, batchsurfacelist);
-               R_Mesh_PrepareVertices_Position(rsurface.batchnumvertices, rsurface.batchvertexposition, rsurface.batchvertexpositionbuffer);
-               RSurf_DrawBatch();
+               RSurf_PrepareVerticesForBatch(false, false, batchnumsurfaces, batchsurfacelist);
+               RSurf_DrawBatch_Simple(batchnumsurfaces, batchsurfacelist);
        }
 }
 
@@ -1170,7 +1171,7 @@ static void R_Q1BSP_DrawLight_TransparentCallback(const entity_render_t *ent, co
        int i, j, endsurface;
        texture_t *t;
        const msurface_t *surface;
-       // note: in practice this never actually receives batches
+       // note: in practice this never actually receives batches), oh well
        R_Shadow_RenderMode_Begin();
        R_Shadow_RenderMode_ActiveLight(rtlight);
        R_Shadow_RenderMode_Lighting(false, true, false);
@@ -1187,7 +1188,8 @@ static void R_Q1BSP_DrawLight_TransparentCallback(const entity_render_t *ent, co
                        surface = rsurface.modelsurfaces + surfacelist[j];
                        if (t != surface->texture)
                                break;
-                       R_Shadow_RenderLighting(1, &surface);
+                       RSurf_PrepareVerticesForBatch(true, true, 1, &surface);
+                       R_Shadow_RenderLighting(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, ent->model->surfmesh.data_element3i, ent->model->surfmesh.data_element3s, ent->model->surfmesh.ebo3i, ent->model->surfmesh.ebo3s);
                }
        }
        R_Shadow_RenderMode_End();
@@ -1198,9 +1200,9 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface
 {
        dp_model_t *model = ent->model;
        const msurface_t *surface;
-       int i, k, kend, l, endsurface, batchnumsurfaces, texturenumsurfaces;
-       const msurface_t **texturesurfacelist;
+       int i, k, kend, l, m, mend, endsurface, batchnumsurfaces, batchnumtriangles, batchfirstvertex, batchlastvertex, batchfirsttriangle;
        const int *element3i;
+       static int batchelements[BATCHSIZE*3];
        texture_t *tex;
        CHECKGLERROR
        element3i = rsurface.modelelement3i;
@@ -1254,9 +1256,45 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface
                        }
                        if (r_shadow_usingdeferredprepass)
                                continue;
-                       texturenumsurfaces = kend - k;
-                       texturesurfacelist = batchsurfacelist + k;
-                       R_Shadow_RenderLighting(texturenumsurfaces, texturesurfacelist);
+                       batchnumtriangles = 0;
+                       batchfirsttriangle = surface->num_firsttriangle;
+                       m = 0; // hush warning
+                       for (l = k;l < kend;l++)
+                       {
+                               surface = batchsurfacelist[l];
+                               RSurf_PrepareVerticesForBatch(true, true, 1, &surface);
+                               for (m = surface->num_firsttriangle, mend = m + surface->num_triangles;m < mend;m++)
+                               {
+                                       if (lighttrispvs && r_test.integer && !CHECKPVSBIT(lighttrispvs, m))
+                                               continue;
+                                       if (batchnumtriangles >= BATCHSIZE)
+                                       {
+                                               r_refdef.stats.lights_lighttriangles += batchnumtriangles;
+                                               Mod_VertexRangeFromElements(batchnumtriangles*3, batchelements, &batchfirstvertex, &batchlastvertex);
+                                               // use the element buffer if all triangles are consecutive
+                                               if (m == batchfirsttriangle + batchnumtriangles)
+                                                       R_Shadow_RenderLighting(batchfirstvertex, batchlastvertex + 1 - batchfirstvertex, batchfirsttriangle, batchnumtriangles, ent->model->surfmesh.data_element3i, ent->model->surfmesh.data_element3s, ent->model->surfmesh.ebo3i, ent->model->surfmesh.ebo3s);
+                                               else
+                                                       R_Shadow_RenderLighting(batchfirstvertex, batchlastvertex + 1 - batchfirstvertex, 0, batchnumtriangles, batchelements, NULL, 0, 0);
+                                               batchnumtriangles = 0;
+                                               batchfirsttriangle = m;
+                                       }
+                                       batchelements[batchnumtriangles*3+0] = element3i[m*3+0];
+                                       batchelements[batchnumtriangles*3+1] = element3i[m*3+1];
+                                       batchelements[batchnumtriangles*3+2] = element3i[m*3+2];
+                                       batchnumtriangles++;
+                               }
+                       }
+                       if (batchnumtriangles > 0)
+                       {
+                               r_refdef.stats.lights_lighttriangles += batchnumtriangles;
+                               Mod_VertexRangeFromElements(batchnumtriangles*3, batchelements, &batchfirstvertex, &batchlastvertex);
+                               // use the element buffer if all triangles are consecutive
+                               if (m == batchfirsttriangle + batchnumtriangles)
+                                       R_Shadow_RenderLighting(batchfirstvertex, batchlastvertex + 1 - batchfirstvertex, batchfirsttriangle, batchnumtriangles, ent->model->surfmesh.data_element3i, ent->model->surfmesh.data_element3s, ent->model->surfmesh.ebo3i, ent->model->surfmesh.ebo3s);
+                               else
+                                       R_Shadow_RenderLighting(batchfirstvertex, batchlastvertex + 1 - batchfirstvertex, 0, batchnumtriangles, batchelements, NULL, 0, 0);
+                       }
                }
        }
 }
index 4e7ceb8aa6074453c19917321ffc50ea8c98f071..bd3e133cf9366697509cfd0d470b0d9a4d341e59 100644 (file)
--- a/glquake.h
+++ b/glquake.h
@@ -636,14 +636,12 @@ extern void (GLAPIENTRY *qglColorMask)(GLboolean red, GLboolean green, GLboolean
 
 extern void (GLAPIENTRY *qglDrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
 extern void (GLAPIENTRY *qglDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
-extern void (GLAPIENTRY *qglDrawArrays)(GLenum mode, GLint first, GLsizei count);
 extern void (GLAPIENTRY *qglVertexPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr);
 extern void (GLAPIENTRY *qglNormalPointer)(GLenum type, GLsizei stride, const GLvoid *ptr);
 extern void (GLAPIENTRY *qglColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr);
 extern void (GLAPIENTRY *qglTexCoordPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr);
 extern void (GLAPIENTRY *qglArrayElement)(GLint i);
 
-extern void (GLAPIENTRY *qglColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
 extern void (GLAPIENTRY *qglColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
 extern void (GLAPIENTRY *qglTexCoord1f)(GLfloat s);
 extern void (GLAPIENTRY *qglTexCoord2f)(GLfloat s, GLfloat t);
@@ -651,7 +649,6 @@ extern void (GLAPIENTRY *qglTexCoord3f)(GLfloat s, GLfloat t, GLfloat r);
 extern void (GLAPIENTRY *qglTexCoord4f)(GLfloat s, GLfloat t, GLfloat r, GLfloat q);
 extern void (GLAPIENTRY *qglVertex2f)(GLfloat x, GLfloat y);
 extern void (GLAPIENTRY *qglVertex3f)(GLfloat x, GLfloat y, GLfloat z);
-extern void (GLAPIENTRY *qglVertex4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
 extern void (GLAPIENTRY *qglBegin)(GLenum mode);
 extern void (GLAPIENTRY *qglEnd)(void);
 
index d8a902d4508746c93efdd6bab94cab85f83af8f8..8832e062737694d5f441e3fab079c9b4b4b64f7a 100644 (file)
--- a/mathlib.h
+++ b/mathlib.h
@@ -83,7 +83,6 @@ unsigned int CeilPowerOf2(unsigned int value);
 #define Vector2Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1])
 #define Vector2Negate(a,b) ((b)[0]=-((a)[0]),(b)[1]=-((a)[1]))
 #define Vector2Set(a,b,c,d,e) ((a)[0]=(b),(a)[1]=(c))
-#define Vector2Scale(in, scale, out) ((out)[0] = (in)[0] * (scale),(out)[1] = (in)[1] * (scale))
 #define Vector2Normalize2(v,dest) {float ilength = (float) sqrt(DotProduct2((v),(v)));if (ilength) ilength = 1.0f / ilength;dest[0] = (v)[0] * ilength;dest[1] = (v)[1] * ilength;}
 
 #define DotProduct4(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]+(a)[3]*(b)[3])
@@ -95,7 +94,6 @@ unsigned int CeilPowerOf2(unsigned int value);
 #define Vector4Normalize2(v,dest) {float ilength = (float) sqrt(DotProduct4((v),(v)));if (ilength) ilength = 1.0f / ilength;dest[0] = (v)[0] * ilength;dest[1] = (v)[1] * ilength;dest[2] = (v)[2] * ilength;dest[3] = (v)[3] * ilength;}
 #define Vector4Subtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2],(c)[3]=(a)[3]-(b)[3])
 #define Vector4Add(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2],(c)[3]=(a)[3]+(b)[3])
-#define Vector4Scale(in, scale, out) ((out)[0] = (in)[0] * (scale),(out)[1] = (in)[1] * (scale),(out)[2] = (in)[2] * (scale),(out)[3] = (in)[3] * (scale))
 #define Vector4Multiply(a,b,c) ((c)[0]=(a)[0]*(b)[0],(c)[1]=(a)[1]*(b)[1],(c)[2]=(a)[2]*(b)[2],(c)[3]=(a)[3]*(b)[3])
 #define Vector4MA(a, scale, b, c) ((c)[0] = (a)[0] + (scale) * (b)[0],(c)[1] = (a)[1] + (scale) * (b)[1],(c)[2] = (a)[2] + (scale) * (b)[2],(c)[3] = (a)[3] + (scale) * (b)[3])
 #define Vector4Lerp(v1,lerp,v2,c) ((c)[0] = (v1)[0] + (lerp) * ((v2)[0] - (v1)[0]), (c)[1] = (v1)[1] + (lerp) * ((v2)[1] - (v1)[1]), (c)[2] = (v1)[2] + (lerp) * ((v2)[2] - (v1)[2]), (c)[3] = (v1)[3] + (lerp) * ((v2)[3] - (v1)[3]))
index 5cd6890da5ad6ca7847d28f4db9a9a8df968aed0..9374b6691ae4746f35353584aeb19e608a852bfb 100644 (file)
@@ -196,24 +196,12 @@ void Mod_UnloadModel (dp_model_t *mod)
        strlcpy(name, mod->name, sizeof(name));
        parentmodel = mod->brush.parentmodel;
        used = mod->used;
-       if (mod->mempool)
-       {
-               if (mod->surfmesh.vertexpositionbuffer)
-                       R_Mesh_DestroyMeshBuffer(mod->surfmesh.vertexpositionbuffer);
-               mod->surfmesh.vertexpositionbuffer = NULL;
-               if (mod->surfmesh.vertexmeshbuffer)
-                       R_Mesh_DestroyMeshBuffer(mod->surfmesh.vertexmeshbuffer);
-               mod->surfmesh.vertexmeshbuffer = NULL;
-               if (mod->surfmesh.data_element3i_indexbuffer)
-                       R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3i_indexbuffer);
-               mod->surfmesh.data_element3i_indexbuffer = NULL;
-               if (mod->surfmesh.data_element3s_indexbuffer)
-                       R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3s_indexbuffer);
-               mod->surfmesh.data_element3s_indexbuffer = NULL;
-               if (mod->surfmesh.vbo_vertexbuffer)
-                       R_Mesh_DestroyMeshBuffer(mod->surfmesh.vbo_vertexbuffer);
-               mod->surfmesh.vbo_vertexbuffer = NULL;
-       }
+       if (mod->surfmesh.ebo3i)
+               R_Mesh_DestroyBufferObject(mod->surfmesh.ebo3i);
+       if (mod->surfmesh.ebo3s)
+               R_Mesh_DestroyBufferObject(mod->surfmesh.ebo3s);
+       if (mod->surfmesh.vbo)
+               R_Mesh_DestroyBufferObject(mod->surfmesh.vbo);
        // free textures/memory attached to the model
        R_FreeTexturePool(&mod->texturepool);
        Mem_FreePool(&mod->mempool);
@@ -1189,60 +1177,26 @@ shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtria
 
 static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh)
 {
-       if (!mesh->numverts)
+       if (!vid.support.arb_vertex_buffer_object)
+               return;
+       if (mesh->vbo)
                return;
 
-       // build r_vertexmesh_t array
-       // (compressed interleaved array for faster rendering)
-       if (!mesh->vertexmesh && mesh->texcoord2f)
-       {
-               int vertexindex;
-               int numvertices = mesh->numverts;
-               r_vertexmesh_t *vertexmesh;
-               mesh->vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(*mesh->vertexmesh));
-               for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++)
-               {
-                       VectorCopy(mesh->vertex3f + 3*vertexindex, vertexmesh->vertex3f);
-                       VectorScale(mesh->svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f);
-                       VectorScale(mesh->tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f);
-                       VectorScale(mesh->normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f);
-                       Vector2Copy(mesh->texcoord2f + 2*vertexindex, vertexmesh->texcoordtexture2f);
-               }
-       }
-
-       // build r_vertexposition_t array
-       if (!mesh->vertexposition)
+       // element buffer is easy because it's just one array
+       if (mesh->numtriangles)
        {
-               int vertexindex;
-               int numvertices = mesh->numverts;
-               r_vertexposition_t *vertexposition;
-               mesh->vertexposition = vertexposition = (r_vertexposition_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(*mesh->vertexposition));
-               for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexposition++)
-                       VectorCopy(mesh->vertex3f + 3*vertexindex, vertexposition->vertex3f);
+               if (mesh->element3s)
+                       mesh->ebo3s = R_Mesh_CreateStaticBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, mesh->element3s, mesh->numtriangles * sizeof(unsigned short[3]), "shadowmesh");
+               else
+                       mesh->ebo3i = R_Mesh_CreateStaticBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, mesh->element3i, mesh->numtriangles * sizeof(unsigned int[3]), "shadowmesh");
        }
 
-       // upload r_vertexmesh_t array as a buffer
-       if (mesh->vertexmesh && !mesh->vertexmeshbuffer)
-               mesh->vertexmeshbuffer = R_Mesh_CreateMeshBuffer(mesh->vertexmesh, mesh->numverts * sizeof(*mesh->vertexmesh), loadmodel->name, false, false);
-
-       // upload r_vertexposition_t array as a buffer
-       if (mesh->vertexposition && !mesh->vertexpositionbuffer)
-               mesh->vertexpositionbuffer = R_Mesh_CreateMeshBuffer(mesh->vertexposition, mesh->numverts * sizeof(*mesh->vertexposition), loadmodel->name, false, false);
-
-       // upload short indices as a buffer
-       if (mesh->element3s && !mesh->element3s_indexbuffer)
-               mesh->element3s_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3s, mesh->numtriangles * sizeof(short[3]), loadmodel->name, true, false);
-
-       // upload int indices as a buffer
-       if (mesh->element3i && !mesh->element3i_indexbuffer && !mesh->element3s)
-               mesh->element3i_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3i, mesh->numtriangles * sizeof(int[3]), loadmodel->name, true, false);
-
        // vertex buffer is several arrays and we put them in the same buffer
        //
        // is this wise?  the texcoordtexture2f array is used with dynamic
        // vertex/svector/tvector/normal when rendering animated models, on the
        // other hand animated models don't use a lot of vertices anyway...
-       if (!mesh->vbo_vertexbuffer)
+       if (mesh->numverts)
        {
                size_t size;
                unsigned char *mem;
@@ -1258,7 +1212,7 @@ static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh)
                if (mesh->tvector3f         ) memcpy(mem + mesh->vbooffset_tvector3f         , mesh->tvector3f         , mesh->numverts * sizeof(float[3]));
                if (mesh->normal3f          ) memcpy(mem + mesh->vbooffset_normal3f          , mesh->normal3f          , mesh->numverts * sizeof(float[3]));
                if (mesh->texcoord2f        ) memcpy(mem + mesh->vbooffset_texcoord2f        , mesh->texcoord2f        , mesh->numverts * sizeof(float[2]));
-               mesh->vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, "shadowmesh", false, false);
+               mesh->vbo = R_Mesh_CreateStaticBufferObject(GL_ARRAY_BUFFER_ARB, mem, size, "shadowmesh");
                Mem_Free(mem);
        }
 }
@@ -1347,16 +1301,12 @@ void Mod_ShadowMesh_Free(shadowmesh_t *mesh)
        shadowmesh_t *nextmesh;
        for (;mesh;mesh = nextmesh)
        {
-               if (mesh->vertexpositionbuffer)
-                       R_Mesh_DestroyMeshBuffer(mesh->vertexpositionbuffer);
-               if (mesh->vertexmeshbuffer)
-                       R_Mesh_DestroyMeshBuffer(mesh->vertexmeshbuffer);
-               if (mesh->element3i_indexbuffer)
-                       R_Mesh_DestroyMeshBuffer(mesh->element3i_indexbuffer);
-               if (mesh->element3s_indexbuffer)
-                       R_Mesh_DestroyMeshBuffer(mesh->element3s_indexbuffer);
-               if (mesh->vbo_vertexbuffer)
-                       R_Mesh_DestroyMeshBuffer(mesh->vbo_vertexbuffer);
+               if (mesh->ebo3i)
+                       R_Mesh_DestroyBufferObject(mesh->ebo3i);
+               if (mesh->ebo3s)
+                       R_Mesh_DestroyBufferObject(mesh->ebo3s);
+               if (mesh->vbo)
+                       R_Mesh_DestroyBufferObject(mesh->vbo);
                nextmesh = mesh->next;
                Mem_Free(mesh);
        }
@@ -2738,9 +2688,6 @@ void Mod_MakeSortedSurfaces(dp_model_t *mod)
 
 void Mod_BuildVBOs(void)
 {
-       if (!loadmodel->surfmesh.num_vertices)
-               return;
-
        if (gl_paranoid.integer && loadmodel->surfmesh.data_element3s && loadmodel->surfmesh.data_element3i)
        {
                int i;
@@ -2754,62 +2701,27 @@ void Mod_BuildVBOs(void)
                }
        }
 
-       // build r_vertexmesh_t array
-       // (compressed interleaved array for faster rendering)
-       if (!loadmodel->surfmesh.vertexmesh)
-       {
-               int vertexindex;
-               int numvertices = loadmodel->surfmesh.num_vertices;
-               r_vertexmesh_t *vertexmesh;
-               loadmodel->surfmesh.vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(*loadmodel->surfmesh.vertexmesh));
-               for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++)
-               {
-                       VectorCopy(loadmodel->surfmesh.data_vertex3f + 3*vertexindex, vertexmesh->vertex3f);
-                       VectorScale(loadmodel->surfmesh.data_svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f);
-                       VectorScale(loadmodel->surfmesh.data_tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f);
-                       VectorScale(loadmodel->surfmesh.data_normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f);
-                       if (loadmodel->surfmesh.data_lightmapcolor4f)
-                               Vector4Scale(loadmodel->surfmesh.data_lightmapcolor4f + 4*vertexindex, 255.0f, vertexmesh->color4ub);
-                       Vector2Copy(loadmodel->surfmesh.data_texcoordtexture2f + 2*vertexindex, vertexmesh->texcoordtexture2f);
-                       if (loadmodel->surfmesh.data_texcoordlightmap2f)
-                               Vector2Scale(loadmodel->surfmesh.data_texcoordlightmap2f + 2*vertexindex, 1.0f, vertexmesh->texcoordlightmap2f);
-               }
-       }
+       if (!vid.support.arb_vertex_buffer_object)
+               return;
+       // only build a vbo if one has not already been created (this is important for brush models which load specially)
+       if (loadmodel->surfmesh.vbo)
+               return;
 
-       // build r_vertexposition_t array
-       if (!loadmodel->surfmesh.vertexposition)
+       // element buffer is easy because it's just one array
+       if (loadmodel->surfmesh.num_triangles)
        {
-               int vertexindex;
-               int numvertices = loadmodel->surfmesh.num_vertices;
-               r_vertexposition_t *vertexposition;
-               loadmodel->surfmesh.vertexposition = vertexposition = (r_vertexposition_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(*loadmodel->surfmesh.vertexposition));
-               for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexposition++)
-                       VectorCopy(loadmodel->surfmesh.data_vertex3f + 3*vertexindex, vertexposition->vertex3f);
+               if (loadmodel->surfmesh.data_element3s)
+                       loadmodel->surfmesh.ebo3s = R_Mesh_CreateStaticBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]), loadmodel->name);
+               else
+                       loadmodel->surfmesh.ebo3i = R_Mesh_CreateStaticBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles * sizeof(unsigned int[3]), loadmodel->name);
        }
 
-       // upload r_vertexmesh_t array as a buffer
-       if (loadmodel->surfmesh.vertexmesh && !loadmodel->surfmesh.vertexmeshbuffer)
-               loadmodel->surfmesh.vertexmeshbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.vertexmesh, loadmodel->surfmesh.num_vertices * sizeof(*loadmodel->surfmesh.vertexmesh), loadmodel->name, false, false);
-
-       // upload r_vertexposition_t array as a buffer
-       if (loadmodel->surfmesh.vertexposition && !loadmodel->surfmesh.vertexpositionbuffer)
-               loadmodel->surfmesh.vertexpositionbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.vertexposition, loadmodel->surfmesh.num_vertices * sizeof(*loadmodel->surfmesh.vertexposition), loadmodel->name, false, false);
-
-       // upload short indices as a buffer
-       if (loadmodel->surfmesh.data_element3s && !loadmodel->surfmesh.data_element3s_indexbuffer)
-               loadmodel->surfmesh.data_element3s_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles * sizeof(short[3]), loadmodel->name, true, false);
-
-       // upload int indices as a buffer
-       if (loadmodel->surfmesh.data_element3i && !loadmodel->surfmesh.data_element3i_indexbuffer && !loadmodel->surfmesh.data_element3s)
-               loadmodel->surfmesh.data_element3i_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles * sizeof(int[3]), loadmodel->name, true, false);
-
-       // only build a vbo if one has not already been created (this is important for brush models which load specially)
        // vertex buffer is several arrays and we put them in the same buffer
        //
        // is this wise?  the texcoordtexture2f array is used with dynamic
        // vertex/svector/tvector/normal when rendering animated models, on the
        // other hand animated models don't use a lot of vertices anyway...
-       if (!loadmodel->surfmesh.vbo_vertexbuffer)
+       if (loadmodel->surfmesh.num_vertices)
        {
                size_t size;
                unsigned char *mem;
@@ -2829,7 +2741,7 @@ void Mod_BuildVBOs(void)
                if (loadmodel->surfmesh.data_texcoordtexture2f ) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordtexture2f , loadmodel->surfmesh.data_texcoordtexture2f , loadmodel->surfmesh.num_vertices * sizeof(float[2]));
                if (loadmodel->surfmesh.data_texcoordlightmap2f) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordlightmap2f, loadmodel->surfmesh.data_texcoordlightmap2f, loadmodel->surfmesh.num_vertices * sizeof(float[2]));
                if (loadmodel->surfmesh.data_lightmapcolor4f   ) memcpy(mem + loadmodel->surfmesh.vbooffset_lightmapcolor4f   , loadmodel->surfmesh.data_lightmapcolor4f   , loadmodel->surfmesh.num_vertices * sizeof(float[4]));
-               loadmodel->surfmesh.vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false);
+               loadmodel->surfmesh.vbo = R_Mesh_CreateStaticBufferObject(GL_ARRAY_BUFFER_ARB, mem, size, loadmodel->name);
                Mem_Free(mem);
        }
 }
@@ -3796,27 +3708,15 @@ static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model)
        if (model->surfmesh.num_vertices > 65536)
                model->surfmesh.data_element3s = NULL;
 
-       if (model->surfmesh.vertexposition)
-               Mem_Free(model->surfmesh.vertexposition);
-       model->surfmesh.vertexposition = NULL;
-       if (model->surfmesh.vertexmesh)
-               Mem_Free(model->surfmesh.vertexmesh);
-       model->surfmesh.vertexmesh = NULL;
-       if (model->surfmesh.vertexpositionbuffer)
-               R_Mesh_DestroyMeshBuffer(model->surfmesh.vertexpositionbuffer);
-       model->surfmesh.vertexpositionbuffer = NULL;
-       if (model->surfmesh.vertexmeshbuffer)
-               R_Mesh_DestroyMeshBuffer(model->surfmesh.vertexmeshbuffer);
-       model->surfmesh.vertexmeshbuffer = NULL;
-       if (model->surfmesh.data_element3i_indexbuffer)
-               R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3i_indexbuffer);
-       model->surfmesh.data_element3i_indexbuffer = NULL;
-       if (model->surfmesh.data_element3s_indexbuffer)
-               R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3s_indexbuffer);
-       model->surfmesh.data_element3s_indexbuffer = NULL;
-       if (model->surfmesh.vbo_vertexbuffer)
-               R_Mesh_DestroyMeshBuffer(model->surfmesh.vbo_vertexbuffer);
-       model->surfmesh.vbo_vertexbuffer = 0;
+       if (model->surfmesh.vbo)
+               R_Mesh_DestroyBufferObject(model->surfmesh.vbo);
+       model->surfmesh.vbo = 0;
+       if (model->surfmesh.ebo3i)
+               R_Mesh_DestroyBufferObject(model->surfmesh.ebo3i);
+       model->surfmesh.ebo3i = 0;
+       if (model->surfmesh.ebo3s)
+               R_Mesh_DestroyBufferObject(model->surfmesh.ebo3s);
+       model->surfmesh.ebo3s = 0;
 
        // convert all triangles to unique vertex data
        outvertexindex = 0;
index e6f0ed53a1f9c2c9524d9291208bcd6b7699c4f9..56e20ce68b2bfafa5be59e7f68761b66855f8a05 100644 (file)
@@ -101,46 +101,6 @@ typedef struct blendweights_s
 }
 blendweights_t;
 
-typedef struct r_vertexposition_s
-{
-       // 12 bytes
-       float vertex3f[3];
-}
-r_vertexposition_t;
-
-typedef struct r_vertexgeneric_s
-{
-       // 24 bytes
-       float vertex3f[3];
-       unsigned char color4ub[4];
-       float texcoord2f[2];
-}
-r_vertexgeneric_t;
-
-typedef struct r_vertexmesh_s
-{
-       // 68 bytes
-       float vertex3f[3];
-       unsigned char color4ub[4];
-       float texcoordtexture2f[2];
-       float texcoordlightmap2f[2];
-       float svector3f[3];
-       float tvector3f[3];
-       float normal3f[3];
-}
-r_vertexmesh_t;
-
-typedef struct r_meshbuffer_s
-{
-       int bufferobject; // OpenGL
-       void *devicebuffer; // Direct3D
-       size_t size;
-       qboolean isindexbuffer;
-       qboolean isdynamic;
-       char name[MAX_QPATH];
-}
-r_meshbuffer_t;
-
 // used for mesh lists in q1bsp/q3bsp map models
 // (the surfaces reference portions of these meshes)
 typedef struct surfmesh_s
@@ -148,12 +108,11 @@ typedef struct surfmesh_s
        // triangle data in system memory
        int num_triangles; // number of triangles in the mesh
        int *data_element3i; // int[tris*3] triangles of the mesh, 3 indices into vertex arrays for each
-       r_meshbuffer_t *data_element3i_indexbuffer;
-       size_t data_element3i_bufferoffset;
        unsigned short *data_element3s; // unsigned short[tris*3] triangles of the mesh in unsigned short format (NULL if num_vertices > 65536)
-       r_meshbuffer_t *data_element3s_indexbuffer;
-       size_t data_element3s_bufferoffset;
        int *data_neighbor3i; // int[tris*3] neighboring triangle on each edge (-1 if none)
+       // element buffer object (stores triangles in video memory)
+       int ebo3i; // unsigned int format (only allocated if num_vertices > 65536)
+       int ebo3s; // unsigned short format (only allocated if num_vertices <= 65536)
        // vertex data in system memory
        int num_vertices; // number of vertices in the mesh
        float *data_vertex3f; // float[verts*3] vertex locations
@@ -165,7 +124,7 @@ typedef struct surfmesh_s
        float *data_lightmapcolor4f;
        int *data_lightmapoffsets; // index into surface's lightmap samples for vertex lighting
        // vertex buffer object (stores geometry in video memory)
-       r_meshbuffer_t *vbo_vertexbuffer;
+       int vbo;
        size_t vbooffset_vertex3f;
        size_t vbooffset_svector3f;
        size_t vbooffset_tvector3f;
@@ -187,12 +146,6 @@ typedef struct surfmesh_s
        unsigned short *blends;
        // set if there is some kind of animation on this model
        qboolean isanimated;
-
-       // vertex and index buffers for rendering
-       r_vertexposition_t *vertexposition;
-       r_vertexmesh_t *vertexmesh;
-       r_meshbuffer_t *vertexpositionbuffer;
-       r_meshbuffer_t *vertexmeshbuffer;
 }
 surfmesh_t;
 
@@ -223,11 +176,7 @@ typedef struct shadowmesh_s
        float *texcoord2f;
        // used always
        int *element3i;
-       r_meshbuffer_t *element3i_indexbuffer;
-       size_t element3i_bufferoffset;
        unsigned short *element3s;
-       r_meshbuffer_t *element3s_indexbuffer;
-       size_t element3s_bufferoffset;
        // used for shadow mapping cubemap side partitioning
        int sideoffsets[6], sidetotals[6];
        // used for shadow mesh (NULL on light mesh)
@@ -235,18 +184,18 @@ typedef struct shadowmesh_s
        // these are NULL after Mod_ShadowMesh_Finish is performed, only used
        // while building meshes
        shadowmeshvertexhash_t **vertexhashtable, *vertexhashentries;
-       r_meshbuffer_t *vbo_vertexbuffer;
+       // element buffer object (stores triangles in video memory)
+       // (created by Mod_ShadowMesh_Finish if possible)
+       int ebo3i;
+       int ebo3s;
+       // vertex buffer object (stores vertices in video memory)
+       // (created by Mod_ShadowMesh_Finish if possible)
+       int vbo;
        size_t vbooffset_vertex3f;
        size_t vbooffset_svector3f;
        size_t vbooffset_tvector3f;
        size_t vbooffset_normal3f;
        size_t vbooffset_texcoord2f;
-       // vertex/index buffers for rendering
-       // (created by Mod_ShadowMesh_Finish if possible)
-       r_vertexposition_t *vertexposition;
-       r_vertexmesh_t *vertexmesh; // usually NULL
-       r_meshbuffer_t *vertexpositionbuffer;
-       r_meshbuffer_t *vertexmeshbuffer; // usually NULL
 }
 shadowmesh_t;
 
index 3519fd940044dd983f9fb935f377e3f30bb9c976..1c12a07b134d44df3990ba04150818f0e8260a09 100644 (file)
@@ -212,15 +212,17 @@ static void R_DrawExplosion_TransparentCallback(const entity_render_t *ent, cons
        GL_CullFace(r_refdef.view.cullface_back);
        R_EntityMatrix(&identitymatrix);
 
+       R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
        R_SetupShader_Generic(explosiontexture, NULL, GL_MODULATE, 1);
+       R_Mesh_TexCoordPointer(0, 2, explosiontexcoord2f[0], 0, 0);
        for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
        {
                const explosion_t *e = explosion + surfacelist[surfacelistindex];
-               // FIXME: this can't properly handle r_refdef.view.colorscale > 1
+               R_Mesh_VertexPointer(e->vert[0], 0, 0);
+               // FIXME: fixed function path can't properly handle r_refdef.view.colorscale > 1
                GL_Color(e->alpha * r_refdef.view.colorscale, e->alpha * r_refdef.view.colorscale, e->alpha * r_refdef.view.colorscale, 1);
-               R_Mesh_PrepareVertices_Generic_Arrays(numverts, e->vert[0], NULL, explosiontexcoord2f[0]);
-               R_Mesh_Draw(0, numverts, 0, numtriangles, NULL, NULL, 0, explosiontris[0], NULL, 0);
+               R_Mesh_Draw(0, numverts, 0, numtriangles, NULL, explosiontris[0], 0, 0);
        }
 }
 
index 9f0ee258ee132d278ae6b241aba74ba402b00f72..2aed02fce0ed513eac26c33da2883abd1422d8bc 100644 (file)
@@ -1324,8 +1324,8 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f,
        else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
        {
                tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
-               R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
-               R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
+               R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
+               R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
        }
        else
        {
@@ -1339,12 +1339,13 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f,
                r_refdef.stats.lights_dynamicshadowtriangles += tris;
                r_refdef.stats.lights_shadowtriangles += tris;
                CHECKGLERROR
+               R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
                if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
                {
                        // increment stencil if frontface is infront of depthbuffer
                        GL_CullFace(r_refdef.view.cullface_front);
                        qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
-                       R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
+                       R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
                        // decrement stencil if backface is infront of depthbuffer
                        GL_CullFace(r_refdef.view.cullface_back);
                        qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
@@ -1354,13 +1355,12 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f,
                        // decrement stencil if backface is behind depthbuffer
                        GL_CullFace(r_refdef.view.cullface_front);
                        qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
-                       R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
+                       R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
                        // increment stencil if frontface is behind depthbuffer
                        GL_CullFace(r_refdef.view.cullface_back);
                        qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
                }
-               R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
-               R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
+               R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
                CHECKGLERROR
        }
 }
@@ -1896,8 +1896,6 @@ void R_Shadow_ValidateCvars(void)
                Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
 }
 
-static const r_vertexposition_t resetvertexposition[3];
-
 void R_Shadow_RenderMode_Begin(void)
 {
 #if 0
@@ -1913,8 +1911,8 @@ void R_Shadow_RenderMode_Begin(void)
                R_Shadow_MakeTextures();
 
        CHECKGLERROR
+       R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
-       R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthRange(0, 1);
        GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
@@ -1993,8 +1991,8 @@ void R_Shadow_RenderMode_Reset(void)
 #endif
        R_SetViewport(&r_refdef.view.viewport);
        GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
+       R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
-       R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
        GL_DepthRange(0, 1);
        GL_DepthTest(true);
        GL_DepthMask(false);
@@ -2304,7 +2302,7 @@ void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qb
                        break;
                }
        }
-       //R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
+       R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
        CHECKGLERROR
 }
 
@@ -2373,6 +2371,8 @@ void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadow
                for (i = 0;i < 8;i++)
                        Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
                CHECKGLERROR
+               R_Mesh_VertexPointer(vertex3f, 0, 0);
+               R_Mesh_ColorPointer(NULL, 0, 0);
                GL_ColorMask(1,1,1,1);
                GL_DepthMask(false);
                GL_DepthRange(0, 1);
@@ -2380,8 +2380,7 @@ void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadow
                GL_DepthTest(true);
                qglDepthFunc(GL_GREATER);CHECKGLERROR
                GL_CullFace(r_refdef.view.cullface_back);
-               R_Mesh_PrepareVertices_Position_Arrays(8, vertex3f);
-               R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
+               R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
        }
 }
 
@@ -2562,12 +2561,11 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
        return false;
 }
 
-static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
+static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
 {
-       int i;
-       const float *vertex3f;
-       const float *normal3f;
-       float *color4f;
+       const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
+       const float *normal3f = rsurface.normal3f + 3 * firstvertex;
+       float *color4f = rsurface.array_color4f + 4 * firstvertex;
        float dist, dot, distintensity, shadeintensity, v[3], n[3];
        switch (r_shadow_rendermode)
        {
@@ -2575,7 +2573,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
        case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
                if (VectorLength2(diffusecolor) > 0)
                {
-                       for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
+                       for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
                        {
                                Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
                                Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
@@ -2597,7 +2595,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
                }
                else
                {
-                       for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
+                       for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
                        {
                                VectorCopy(ambientcolor, color4f);
                                if (r_refdef.fogenabled)
@@ -2605,7 +2603,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
                                        float f;
                                        Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
                                        f = RSurf_FogVertex(vertex3f);
-                                       VectorScale(color4f + 4*i, f, color4f);
+                                       VectorScale(color4f, f, color4f);
                                }
                                color4f[3] = 1;
                        }
@@ -2614,7 +2612,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
        case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
                if (VectorLength2(diffusecolor) > 0)
                {
-                       for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
+                       for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
                        {
                                Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
                                if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
@@ -2647,7 +2645,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
                }
                else
                {
-                       for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
+                       for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
                        {
                                Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
                                if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
@@ -2671,7 +2669,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
        case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
                if (VectorLength2(diffusecolor) > 0)
                {
-                       for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
+                       for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
                        {
                                Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
                                if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
@@ -2705,7 +2703,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
                }
                else
                {
-                       for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
+                       for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
                        {
                                Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
                                if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
@@ -2732,23 +2730,21 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
        }
 }
 
-static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
+static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject)
 {
        // used to display how many times a surface is lit for level design purposes
-       RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
-       R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
-       RSurf_DrawBatch();
+       R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
 }
 
-static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
+static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
 {
        // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
-       R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist);
+       R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
        if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
        {
                qglDepthFunc(GL_EQUAL);CHECKGLERROR
        }
-       RSurf_DrawBatch();
+       R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
        if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
        {
                qglDepthFunc(GL_LEQUAL);CHECKGLERROR
@@ -2768,7 +2764,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numve
        float *c;
        int maxtriangles = 4096;
        static int newelements[4096*3];
-       R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
+       R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
        for (renders = 0;renders < 4;renders++)
        {
                stop = true;
@@ -2783,7 +2779,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numve
                // renders them at once
                for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
                {
-                       if (VectorLength2(rsurface.array_passcolor4f + e[0] * 4) + VectorLength2(rsurface.array_passcolor4f + e[1] * 4) + VectorLength2(rsurface.array_passcolor4f + e[2] * 4) >= 0.01)
+                       if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
                        {
                                if (newnumtriangles)
                                {
@@ -2806,7 +2802,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numve
                                newe += 3;
                                if (newnumtriangles >= maxtriangles)
                                {
-                                       R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
+                                       R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
                                        newnumtriangles = 0;
                                        newe = newelements;
                                        stop = false;
@@ -2815,7 +2811,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numve
                }
                if (newnumtriangles >= 1)
                {
-                       R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
+                       R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
                        stop = false;
                }
                // if we couldn't find any lit triangles, exit early
@@ -2826,7 +2822,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numve
                // handling of negative colors
                // (some old drivers even have improper handling of >1 color)
                stop = true;
-               for (i = 0, c = rsurface.array_passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
+               for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
                {
                        if (c[0] > 1 || c[1] > 1 || c[2] > 1)
                        {
@@ -2844,7 +2840,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numve
        }
 }
 
-static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
+static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolor, float ambientscale, float diffusescale)
 {
        // OpenGL 1.1 path (anything)
        float ambientcolorbase[3], diffusecolorbase[3];
@@ -2866,32 +2862,29 @@ static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const m
        diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
        ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
        diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
-       RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD, texturenumsurfaces, texturesurfacelist);
-       R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
-       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
-       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
        R_Mesh_TexBind(0, basetexture);
        R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
        R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+       R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
        switch(r_shadow_rendermode)
        {
        case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
                R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
                R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
                R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
-               R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
+               R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
                break;
        case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
                R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
                R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
                R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
-               R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
+               R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
                // fall through
        case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
                R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
                R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
                R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
-               R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
+               R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
                break;
        case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
                break;
@@ -2899,21 +2892,21 @@ static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const m
                break;
        }
        //R_Mesh_TexBind(0, basetexture);
-       R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
+       R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
        if (dopants)
        {
                R_Mesh_TexBind(0, pantstexture);
-               R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
+               R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
        }
        if (doshirt)
        {
                R_Mesh_TexBind(0, shirttexture);
-               R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
+               R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
        }
 }
 
 extern cvar_t gl_lightmaps;
-void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
+void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject)
 {
        float ambientscale, diffusescale, specularscale;
        qboolean negated;
@@ -2941,16 +2934,16 @@ void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **textures
        {
        case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
                GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
-               R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
+               R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
                break;
        case R_SHADOW_RENDERMODE_LIGHT_GLSL:
-               R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
+               R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolor, ambientscale, diffusescale, specularscale);
                break;
        case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
        case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
        case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
        case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
-               R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
+               R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolor, ambientscale, diffusescale);
                break;
        default:
                Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
@@ -3334,8 +3327,8 @@ void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const
                        if (!mesh->sidetotals[r_shadow_shadowmapside])
                                continue;
             r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
-            R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
-            R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
+            R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
+            R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
         }
         CHECKGLERROR
     }
@@ -3367,13 +3360,13 @@ void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, co
                for (;mesh;mesh = mesh->next)
                {
                        r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
-                       R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
+                       R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
                        if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
                        {
                                // increment stencil if frontface is infront of depthbuffer
                                GL_CullFace(r_refdef.view.cullface_back);
                                qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
-                               R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
+                               R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
                                // decrement stencil if backface is infront of depthbuffer
                                GL_CullFace(r_refdef.view.cullface_front);
                                qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
@@ -3383,12 +3376,12 @@ void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, co
                                // decrement stencil if backface is behind depthbuffer
                                GL_CullFace(r_refdef.view.cullface_front);
                                qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
-                               R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
+                               R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
                                // increment stencil if frontface is behind depthbuffer
                                GL_CullFace(r_refdef.view.cullface_back);
                                qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
                        }
-                       R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
+                       R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
                }
                CHECKGLERROR
        }
@@ -3998,6 +3991,7 @@ void R_Shadow_DrawPrepass(void)
        entity_render_t *ent;
 
        GL_AlphaTest(false);
+       R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
        GL_DepthMask(true);
        GL_ColorMask(1,1,1,1);
@@ -4585,6 +4579,9 @@ void R_DrawModelShadows(void)
        //R_EntityMatrix(&identitymatrix);
        //R_Mesh_ResetTextureState();
        R_ResetViewRendering2D();
+       R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
+       R_Mesh_ColorPointer(NULL, 0, 0);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
 
        // set up a darkening blend on shadowed areas
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -4601,9 +4598,7 @@ void R_DrawModelShadows(void)
        qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR
 
        // apply the blend to the shadowed areas
-       R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
-       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+       R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
 
        // restore the viewport
        R_SetViewport(&r_refdef.view.viewport);
@@ -4635,14 +4630,14 @@ void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
                qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
                qglDepthFunc(GL_ALWAYS);
                R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
-               R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
-               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+               R_Mesh_VertexPointer(vertex3f, 0, 0);
+               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
                qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
                qglDepthFunc(GL_LEQUAL);
                qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
                R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
-               R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
-               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+               R_Mesh_VertexPointer(vertex3f, 0, 0);
+               R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
                qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
                CHECKGLERROR
        }
@@ -4734,6 +4729,7 @@ void R_Shadow_DrawCoronas(void)
                GL_DepthRange(0, 1);
                GL_PolygonOffset(0, 0);
                GL_DepthTest(true);
+               R_Mesh_ColorPointer(NULL, 0, 0);
                R_Mesh_ResetTextureState();
                R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
        }
index cf74e268bfcb6ee1a79c6cce946c0df122c256a3..5997605e45d771d346d58c5247a59cf8f0377081 100644 (file)
@@ -45,7 +45,7 @@ void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *inv
 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias);
 int R_Shadow_CalcSphereSideMask(const vec3_t p1, float radius, float bias);
 int R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals);
-void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist);
+void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject);
 void R_Shadow_RenderMode_Begin(void);
 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight);
 void R_Shadow_RenderMode_Reset(void);
index d81cc5656b55ed56716f7d8106a8b975728b00dc..ea72d28229f7ca99577271d64a87505c6a158435 100644 (file)
--- a/render.h
+++ b/render.h
@@ -232,27 +232,19 @@ extern mempool_t *r_main_mempool;
 
 typedef struct rsurfacestate_s
 {
-       // software processing buffers
-       int                         array_size;
-       unsigned char              *array_base;
-       r_vertexmesh_t             *array_modelvertexmesh;
-       r_vertexmesh_t             *array_batchvertexmesh;
-       r_vertexposition_t         *array_modelvertexposition;
-       r_vertexposition_t         *array_batchvertexposition;
-       float                      *array_modelvertex3f;
-       float                      *array_modelsvector3f;
-       float                      *array_modeltvector3f;
-       float                      *array_modelnormal3f;
-       float                      *array_batchvertex3f;
-       float                      *array_batchsvector3f;
-       float                      *array_batchtvector3f;
-       float                      *array_batchnormal3f;
-       float                      *array_batchlightmapcolor4f;
-       float                      *array_batchtexcoordtexture2f;
-       float                      *array_batchtexcoordlightmap2f;
-       float                      *array_passcolor4f;
-       int                        *array_batchelement3i;
-       unsigned short             *array_batchelement3s;
+       // processing buffers
+       int array_size;
+       float *array_modelvertex3f;
+       float *array_modelsvector3f;
+       float *array_modeltvector3f;
+       float *array_modelnormal3f;
+       float *array_deformedvertex3f;
+       float *array_deformedsvector3f;
+       float *array_deformedtvector3f;
+       float *array_deformednormal3f;
+       float *array_generatedtexcoordtexture2f;
+       float *array_color4f;
+       float *array_texcoord3f;
 
        // current model array pointers
        // these may point to processing buffers if model is animated,
@@ -268,89 +260,67 @@ typedef struct rsurfacestate_s
        //
        // this indicates the model* arrays are pointed at array_model* buffers
        // (in other words, the model has been animated in software)
-       qboolean                    modelgeneratedvertex;
-       const float                *modelvertex3f;
-       const r_meshbuffer_t       *modelvertex3f_vertexbuffer;
-       size_t                      modelvertex3f_bufferoffset;
-       const float                *modelsvector3f;
-       const r_meshbuffer_t       *modelsvector3f_vertexbuffer;
-       size_t                      modelsvector3f_bufferoffset;
-       const float                *modeltvector3f;
-       const r_meshbuffer_t       *modeltvector3f_vertexbuffer;
-       size_t                      modeltvector3f_bufferoffset;
-       const float                *modelnormal3f;
-       const r_meshbuffer_t       *modelnormal3f_vertexbuffer;
-       size_t                      modelnormal3f_bufferoffset;
-       const float                *modellightmapcolor4f;
-       const r_meshbuffer_t       *modellightmapcolor4f_vertexbuffer;
-       size_t                      modellightmapcolor4f_bufferoffset;
-       const float                *modeltexcoordtexture2f;
-       const r_meshbuffer_t       *modeltexcoordtexture2f_vertexbuffer;
-       size_t                      modeltexcoordtexture2f_bufferoffset;
-       const float                *modeltexcoordlightmap2f;
-       const r_meshbuffer_t       *modeltexcoordlightmap2f_vertexbuffer;
-       size_t                      modeltexcoordlightmap2f_bufferoffset;
-       const r_vertexmesh_t       *modelvertexmesh;
-       const r_meshbuffer_t       *modelvertexmeshbuffer;
-       const r_vertexposition_t   *modelvertexposition;
-       const r_meshbuffer_t       *modelvertexpositionbuffer;
-       const int                  *modelelement3i;
-       const r_meshbuffer_t       *modelelement3i_indexbuffer;
-       size_t                      modelelement3i_bufferoffset;
-       const unsigned short       *modelelement3s;
-       const r_meshbuffer_t       *modelelement3s_indexbuffer;
-       size_t                      modelelement3s_bufferoffset;
-       const int                  *modellightmapoffsets;
-       int                         modelnumvertices;
-       int                         modelnumtriangles;
-       const msurface_t           *modelsurfaces;
+       qboolean generatedvertex;
+       const float *modelvertex3f;
+       int modelvertex3f_bufferobject;
+       size_t modelvertex3f_bufferoffset;
+       const float *modelsvector3f;
+       int modelsvector3f_bufferobject;
+       size_t modelsvector3f_bufferoffset;
+       const float *modeltvector3f;
+       int modeltvector3f_bufferobject;
+       size_t modeltvector3f_bufferoffset;
+       const float *modelnormal3f;
+       int modelnormal3f_bufferobject;
+       size_t modelnormal3f_bufferoffset;
+       const float *modellightmapcolor4f;
+       int modellightmapcolor4f_bufferobject;
+       size_t modellightmapcolor4f_bufferoffset;
+       const float *modeltexcoordtexture2f;
+       int modeltexcoordtexture2f_bufferobject;
+       size_t modeltexcoordtexture2f_bufferoffset;
+       const float *modeltexcoordlightmap2f;
+       int modeltexcoordlightmap2f_bufferobject;
+       size_t modeltexcoordlightmap2f_bufferoffset;
+       const int *modelelement3i;
+       const unsigned short *modelelement3s;
+       int modelelement3i_bufferobject;
+       int modelelement3s_bufferobject;
+       const int *modellightmapoffsets;
+       int modelnum_vertices;
+       int modelnum_triangles;
+       const msurface_t *modelsurfaces;
        // current rendering array pointers
        // these may point to any of several different buffers depending on how
        // much processing was needed to prepare this model for rendering
        // these usually equal the model* pointers, they only differ if
        // deformvertexes is used in a q3 shader, and consequently these can
        // change on a per-surface basis (according to rsurface.texture)
-       qboolean                    batchgeneratedvertex;
-       int                         batchfirstvertex;
-       int                         batchnumvertices;
-       int                         batchfirsttriangle;
-       int                         batchnumtriangles;
-       const r_vertexmesh_t       *batchvertexmesh;
-       const r_meshbuffer_t       *batchvertexmeshbuffer;
-       const r_vertexposition_t   *batchvertexposition;
-       const r_meshbuffer_t       *batchvertexpositionbuffer;
-       const float                *batchvertex3f;
-       const r_meshbuffer_t       *batchvertex3f_vertexbuffer;
-       size_t                      batchvertex3f_bufferoffset;
-       const float                *batchsvector3f;
-       const r_meshbuffer_t       *batchsvector3f_vertexbuffer;
-       size_t                      batchsvector3f_bufferoffset;
-       const float                *batchtvector3f;
-       const r_meshbuffer_t       *batchtvector3f_vertexbuffer;
-       size_t                      batchtvector3f_bufferoffset;
-       const float                *batchnormal3f;
-       const r_meshbuffer_t       *batchnormal3f_vertexbuffer;
-       size_t                      batchnormal3f_bufferoffset;
-       const float                *batchlightmapcolor4f;
-       const r_meshbuffer_t       *batchlightmapcolor4f_vertexbuffer;
-       size_t                      batchlightmapcolor4f_bufferoffset;
-       const float                *batchtexcoordtexture2f;
-       const r_meshbuffer_t       *batchtexcoordtexture2f_vertexbuffer;
-       size_t                      batchtexcoordtexture2f_bufferoffset;
-       const float                *batchtexcoordlightmap2f;
-       const r_meshbuffer_t       *batchtexcoordlightmap2f_vertexbuffer;
-       size_t                      batchtexcoordlightmap2f_bufferoffset;
-       const int                  *batchelement3i;
-       const r_meshbuffer_t       *batchelement3i_indexbuffer;
-       size_t                      batchelement3i_bufferoffset;
-       const unsigned short       *batchelement3s;
-       const r_meshbuffer_t       *batchelement3s_indexbuffer;
-       size_t                      batchelement3s_bufferoffset;
-       // rendering pass processing arrays in GL11 and GL13 paths
-       const float                *passcolor4f;
-       const r_meshbuffer_t       *passcolor4f_vertexbuffer;
-       size_t                      passcolor4f_bufferoffset;
-
+       //
+       // the exception is the color array which is often generated based on
+       // colormod, alpha fading, and fogging, it may also come from q3bsp vertex
+       // lighting of certain surfaces
+       const float *vertex3f;
+       int vertex3f_bufferobject;
+       size_t vertex3f_bufferoffset;
+       const float *svector3f;
+       int svector3f_bufferobject;
+       size_t svector3f_bufferoffset;
+       const float *tvector3f;
+       int tvector3f_bufferobject;
+       size_t tvector3f_bufferoffset;
+       const float *normal3f;
+       int normal3f_bufferobject;
+       size_t normal3f_bufferoffset;
+       const float *lightmapcolor4f;
+       int lightmapcolor4f_bufferobject;
+       size_t lightmapcolor4f_bufferoffset;
+       const float *texcoordtexture2f;
+       int texcoordtexture2f_bufferobject;
+       size_t texcoordtexture2f_bufferoffset;
+       const float *texcoordlightmap2f;
+       int texcoordlightmap2f_bufferobject;
+       size_t texcoordlightmap2f_bufferoffset;
        // some important fields from the entity
        int ent_skinnum;
        int ent_qwskin;
@@ -383,10 +353,8 @@ typedef struct rsurfacestate_s
        // polygon offset data for submodels
        float basepolygonfactor;
        float basepolygonoffset;
-       // current textures in batching code
+       // current texture in batching code
        texture_t *texture;
-       rtexture_t *lightmaptexture;
-       rtexture_t *deluxemaptexture;
        // whether lightmapping is active on this batch
        // (otherwise vertex colored)
        qboolean uselightmaptexture;
@@ -438,22 +406,8 @@ void R_AddWaterPlanes(entity_render_t *ent);
 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass);
 void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass);
 
-#define BATCHNEED_VERTEXPOSITION         (1<< 0) // set up rsurface.batchvertexposition
-#define BATCHNEED_VERTEXMESH_VERTEX      (1<< 1) // set up rsurface.batchvertexmesh
-#define BATCHNEED_VERTEXMESH_NORMAL      (1<< 2) // set up normals in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchnormal3f if BATCHNEED_ARRAYS
-#define BATCHNEED_VERTEXMESH_VECTOR      (1<< 3) // set up vectors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchsvector3f and rsurface.batchtvector3f if BATCHNEED_ARRAYS
-#define BATCHNEED_VERTEXMESH_VERTEXCOLOR (1<< 4) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS
-#define BATCHNEED_VERTEXMESH_TEXCOORD    (1<< 5) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS
-#define BATCHNEED_VERTEXMESH_LIGHTMAP    (1<< 6) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS
-#define BATCHNEED_ARRAY_VERTEX           (1<< 7) // set up rsurface.batchvertex3f and optionally others
-#define BATCHNEED_ARRAY_NORMAL           (1<< 8) // set up normals in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchnormal3f if BATCHNEED_ARRAYS
-#define BATCHNEED_ARRAY_VECTOR           (1<< 9) // set up vectors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchsvector3f and rsurface.batchtvector3f if BATCHNEED_ARRAYS
-#define BATCHNEED_ARRAY_VERTEXCOLOR      (1<<10) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS
-#define BATCHNEED_ARRAY_TEXCOORD         (1<<11) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS
-#define BATCHNEED_ARRAY_LIGHTMAP         (1<<12) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS
-#define BATCHNEED_NOGAPS                 (1<<13) // force vertex copying (no gaps)
-void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist);
-void RSurf_DrawBatch(void);
+void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, const msurface_t **texturesurfacelist);
+void RSurf_DrawBatch_Simple(int texturenumsurfaces, const msurface_t **texturesurfacelist);
 
 void R_DecalSystem_SplatEntities(const vec3_t org, const vec3_t normal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float size);
 
@@ -523,7 +477,7 @@ gl20_texunit;
 void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale);
 void R_SetupShader_DepthOrShadow(void);
 void R_SetupShader_ShowDepth(void);
-void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist);
+void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass);
 void R_SetupShader_DeferredLight(const rtlight_t *rtlight);
 
 typedef struct r_waterstate_waterplane_s
diff --git a/vid.h b/vid.h
index b5ffc050a953e86c32ce67b9edb100bb97041868..52331ae4acf59fd45a5f54537c55d143a3b485fa 100644 (file)
--- a/vid.h
+++ b/vid.h
@@ -100,7 +100,6 @@ typedef struct viddef_s
        void *cgcontext;
 
        renderpath_t renderpath;
-       qboolean forcevbo; // some renderpaths can not operate without it
 
        unsigned int texunits;
        unsigned int teximageunits;
index eb6c56d47acbd0aa5d099c70a1a2cbb268f92e57..4579c1434a32aaf5d853be81326c10d5ab84cae7 100644 (file)
@@ -147,14 +147,12 @@ void (GLAPIENTRY *qglColorMask)(GLboolean red, GLboolean green, GLboolean blue,
 
 void (GLAPIENTRY *qglDrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
 void (GLAPIENTRY *qglDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
-void (GLAPIENTRY *qglDrawArrays)(GLenum mode, GLint first, GLsizei count);
 void (GLAPIENTRY *qglVertexPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr);
 void (GLAPIENTRY *qglNormalPointer)(GLenum type, GLsizei stride, const GLvoid *ptr);
 void (GLAPIENTRY *qglColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr);
 void (GLAPIENTRY *qglTexCoordPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr);
 void (GLAPIENTRY *qglArrayElement)(GLint i);
 
-void (GLAPIENTRY *qglColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
 void (GLAPIENTRY *qglColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
 void (GLAPIENTRY *qglTexCoord1f)(GLfloat s);
 void (GLAPIENTRY *qglTexCoord2f)(GLfloat s, GLfloat t);
@@ -162,7 +160,6 @@ void (GLAPIENTRY *qglTexCoord3f)(GLfloat s, GLfloat t, GLfloat r);
 void (GLAPIENTRY *qglTexCoord4f)(GLfloat s, GLfloat t, GLfloat r, GLfloat q);
 void (GLAPIENTRY *qglVertex2f)(GLfloat x, GLfloat y);
 void (GLAPIENTRY *qglVertex3f)(GLfloat x, GLfloat y, GLfloat z);
-void (GLAPIENTRY *qglVertex4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
 void (GLAPIENTRY *qglBegin)(GLenum mode);
 void (GLAPIENTRY *qglEnd)(void);
 
@@ -491,14 +488,12 @@ static dllfunction_t opengl110funcs[] =
        {"glDepthMask", (void **) &qglDepthMask},
        {"glDepthRange", (void **) &qglDepthRange},
        {"glDrawElements", (void **) &qglDrawElements},
-       {"glDrawArrays", (void **) &qglDrawArrays},
        {"glColorMask", (void **) &qglColorMask},
        {"glVertexPointer", (void **) &qglVertexPointer},
        {"glNormalPointer", (void **) &qglNormalPointer},
        {"glColorPointer", (void **) &qglColorPointer},
        {"glTexCoordPointer", (void **) &qglTexCoordPointer},
        {"glArrayElement", (void **) &qglArrayElement},
-       {"glColor4ub", (void **) &qglColor4ub},
        {"glColor4f", (void **) &qglColor4f},
        {"glTexCoord1f", (void **) &qglTexCoord1f},
        {"glTexCoord2f", (void **) &qglTexCoord2f},
@@ -506,7 +501,6 @@ static dllfunction_t opengl110funcs[] =
        {"glTexCoord4f", (void **) &qglTexCoord4f},
        {"glVertex2f", (void **) &qglVertex2f},
        {"glVertex3f", (void **) &qglVertex3f},
-       {"glVertex4f", (void **) &qglVertex4f},
        {"glBegin", (void **) &qglBegin},
        {"glEnd", (void **) &qglEnd},
 //[515]: added on 29.07.2005
@@ -804,7 +798,6 @@ void VID_CheckExtensions(void)
 
        Con_DPrint("Checking OpenGL extensions...\n");
 
-       vid.forcevbo = false;
        vid.support.amd_texture_texture4 = GL_CheckExtension("GL_AMD_texture_texture4", NULL, "-notexture4", false);
        vid.support.arb_depth_texture = GL_CheckExtension("GL_ARB_depth_texture", NULL, "-nodepthtexture", false);
        vid.support.arb_draw_buffers = GL_CheckExtension("GL_ARB_draw_buffers", drawbuffersfuncs, "-nodrawbuffers", false);