redesigned how the renderer handles much of it's state (R_Mesh_State turned into...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 1 Jul 2003 18:43:42 +0000 (18:43 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 1 Jul 2003 18:43:42 +0000 (18:43 +0000)
batching is gone
VAR support is gone (but may make a return someday)
dynamic shadow volumes are now more optimized (removal of unused verts)
added a glossary of terminology to the start of r_shadow.c
added gl_mesh_testarrayelement and gl_mesh_testmanualfeeding cvars for testing/debugging purposes in the backend (incase vertex array state is a mess)
added gl_paranoid cvar (enables CHECKGLERROR and verifies geometry before rendering it)
added gl_printcheckerror cvar (prints location of every CHECKGLERROR statement as it executes, for tracking code flow)

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3119 d7cf8633-e32d-0410-b094-e92efae38249

21 files changed:
cl_main.c
cl_particles.c
gl_backend.c
gl_backend.h
gl_draw.c
gl_models.c
gl_rmain.c
gl_rsurf.c
gl_textures.c
glquake.h
model_shared.c
model_shared.h
r_crosshairs.c
r_explosion.c
r_light.c
r_shadow.c
r_shadow.h
r_sky.c
r_sprites.c
render.h
vid_shared.c

index d1b514c..2fe8e73 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -1251,18 +1251,7 @@ void R_DrawLightningBeamCallback(const void *calldata1, int calldata2)
        rmeshstate_t m;
        vec3_t beamdir, right, up, offset;
        float length, t1, t2;
-       memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_SRC_ALPHA;
-       m.blendfunc2 = GL_ONE;
-       if (r_lightningbeam_qmbtexture.integer && r_lightningbeamqmbtexture == NULL)
-               r_lightningbeams_setupqmbtexture();
-       if (!r_lightningbeam_qmbtexture.integer && r_lightningbeamtexture == NULL)
-               r_lightningbeams_setuptexture();
-       if (r_lightningbeam_qmbtexture.integer)
-               m.tex[0] = R_GetTexture(r_lightningbeamqmbtexture);
-       else
-               m.tex[0] = R_GetTexture(r_lightningbeamtexture);
-       R_Mesh_State(&m);
+
        R_Mesh_Matrix(&r_identitymatrix);
 
        // calculate beam direction (beamdir) vector and beam length
@@ -1304,29 +1293,42 @@ void R_DrawLightningBeamCallback(const void *calldata1, int calldata2)
        // (and realize that the whole polygon assembly orients itself to face
        //  the viewer)
 
-       R_Mesh_GetSpace(12);
+       memset(&m, 0, sizeof(m));
+       if (r_lightningbeam_qmbtexture.integer)
+               m.tex[0] = R_GetTexture(r_lightningbeamqmbtexture);
+       else
+               m.tex[0] = R_GetTexture(r_lightningbeamtexture);
+       m.pointer_texcoord[0] = varray_texcoord2f[0];
+       R_Mesh_State_Texture(&m);
+
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
+       if (r_lightningbeam_qmbtexture.integer && r_lightningbeamqmbtexture == NULL)
+               r_lightningbeams_setupqmbtexture();
+       if (!r_lightningbeam_qmbtexture.integer && r_lightningbeamtexture == NULL)
+               r_lightningbeams_setuptexture();
 
        // polygon 1, verts 0-3
        VectorScale(right, r_lightningbeam_thickness.value, offset);
-       R_CalcLightningBeamPolygonVertex3f(varray_vertex3f, b->start, b->end, offset);
-       R_CalcLightningBeamPolygonTexCoord2f(varray_texcoord2f[0], t1, t2);
-
+       R_CalcLightningBeamPolygonVertex3f(varray_vertex3f + 0, b->start, b->end, offset);
        // polygon 2, verts 4-7
        VectorAdd(right, up, offset);
        VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset);
        R_CalcLightningBeamPolygonVertex3f(varray_vertex3f + 12, b->start, b->end, offset);
-       R_CalcLightningBeamPolygonTexCoord2f(varray_texcoord2f[0] + 8, t1 + 0.33, t2 + 0.33);
-
        // polygon 3, verts 8-11
        VectorSubtract(right, up, offset);
        VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset);
        R_CalcLightningBeamPolygonVertex3f(varray_vertex3f + 24, b->start, b->end, offset);
+       R_CalcLightningBeamPolygonTexCoord2f(varray_texcoord2f[0] + 0, t1, t2);
+       R_CalcLightningBeamPolygonTexCoord2f(varray_texcoord2f[0] + 8, t1 + 0.33, t2 + 0.33);
        R_CalcLightningBeamPolygonTexCoord2f(varray_texcoord2f[0] + 16, t1 + 0.66, t2 + 0.66);
+       GL_VertexPointer(varray_vertex3f);
 
        if (fogenabled)
        {
                // per vertex colors if fog is used
-               GL_UseColorArray();
+               GL_ColorPointer(varray_color4f);
                R_FogLightningBeam_Vertex3f_Color4f(varray_vertex3f, varray_color4f, 12, r_lightningbeam_color_red.value, r_lightningbeam_color_green.value, r_lightningbeam_color_blue.value, 1);
        }
        else
index fae3e46..339bdd7 100644 (file)
@@ -1663,10 +1663,10 @@ void R_InitParticles(void)
        CL_Particles_Init();
        R_Particles_Init();
 }
-
-float varray_vertex3f[12], varray_texcoord2f[1][8];
 #endif
 
+float particle_vertex3f[12], particle_texcoord2f[8];
+
 #ifdef WORKINGLQUAKE
 void R_DrawParticle(particle_t *p)
 {
@@ -1698,26 +1698,6 @@ void R_DrawParticleCallback(const void *calldata1, int calldata2)
        }
 
 #ifndef WORKINGLQUAKE
-       memset(&m, 0, sizeof(m));
-       if (p->blendmode == 0)
-       {
-               m.blendfunc1 = GL_SRC_ALPHA;
-               m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
-       }
-       else if (p->blendmode == 1)
-       {
-               m.blendfunc1 = GL_SRC_ALPHA;
-               m.blendfunc2 = GL_ONE;
-       }
-       else
-       {
-               m.blendfunc1 = GL_ZERO;
-               m.blendfunc2 = GL_ONE_MINUS_SRC_COLOR;
-       }
-       m.tex[0] = R_GetTexture(tex->texture);
-       R_Mesh_Matrix(&r_identitymatrix);
-       R_Mesh_State(&m);
-
        if (fogenabled && p->blendmode != PBLEND_MOD)
        {
                VectorSubtract(org, r_origin, fogvec);
@@ -1739,7 +1719,22 @@ void R_DrawParticleCallback(const void *calldata1, int calldata2)
 
        GL_Color(cr, cg, cb, ca);
 
-       R_Mesh_GetSpace(4);
+       R_Mesh_Matrix(&r_identitymatrix);
+
+       memset(&m, 0, sizeof(m));
+       m.tex[0] = R_GetTexture(tex->texture);
+       m.pointer_texcoord[0] = particle_texcoord2f;
+       R_Mesh_State_Texture(&m);
+
+       if (p->blendmode == 0)
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       else if (p->blendmode == 1)
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+       else
+               GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
+       GL_VertexPointer(particle_vertex3f);
 #endif
        if (p->orientation == PARTICLE_BILLBOARD || p->orientation == PARTICLE_ORIENTED_DOUBLESIDED)
        {
@@ -1761,44 +1756,44 @@ void R_DrawParticleCallback(const void *calldata1, int calldata2)
                        VectorScale(vright, p->scalex, right);
                        VectorScale(vup, p->scaley, up);
                }
-               varray_vertex3f[ 0] = org[0] - right[0] - up[0];
-               varray_vertex3f[ 1] = org[1] - right[1] - up[1];
-               varray_vertex3f[ 2] = org[2] - right[2] - up[2];
-               varray_vertex3f[ 3] = org[0] - right[0] + up[0];
-               varray_vertex3f[ 4] = org[1] - right[1] + up[1];
-               varray_vertex3f[ 5] = org[2] - right[2] + up[2];
-               varray_vertex3f[ 6] = org[0] + right[0] + up[0];
-               varray_vertex3f[ 7] = org[1] + right[1] + up[1];
-               varray_vertex3f[ 8] = org[2] + right[2] + up[2];
-               varray_vertex3f[ 9] = org[0] + right[0] - up[0];
-               varray_vertex3f[10] = org[1] + right[1] - up[1];
-               varray_vertex3f[11] = org[2] + right[2] - up[2];
-               varray_texcoord2f[0][0] = tex->s1;varray_texcoord2f[0][1] = tex->t2;
-               varray_texcoord2f[0][2] = tex->s1;varray_texcoord2f[0][3] = tex->t1;
-               varray_texcoord2f[0][4] = tex->s2;varray_texcoord2f[0][5] = tex->t1;
-               varray_texcoord2f[0][6] = tex->s2;varray_texcoord2f[0][7] = tex->t2;
+               particle_vertex3f[ 0] = org[0] - right[0] - up[0];
+               particle_vertex3f[ 1] = org[1] - right[1] - up[1];
+               particle_vertex3f[ 2] = org[2] - right[2] - up[2];
+               particle_vertex3f[ 3] = org[0] - right[0] + up[0];
+               particle_vertex3f[ 4] = org[1] - right[1] + up[1];
+               particle_vertex3f[ 5] = org[2] - right[2] + up[2];
+               particle_vertex3f[ 6] = org[0] + right[0] + up[0];
+               particle_vertex3f[ 7] = org[1] + right[1] + up[1];
+               particle_vertex3f[ 8] = org[2] + right[2] + up[2];
+               particle_vertex3f[ 9] = org[0] + right[0] - up[0];
+               particle_vertex3f[10] = org[1] + right[1] - up[1];
+               particle_vertex3f[11] = org[2] + right[2] - up[2];
+               particle_texcoord2f[0] = tex->s1;particle_texcoord2f[1] = tex->t2;
+               particle_texcoord2f[2] = tex->s1;particle_texcoord2f[3] = tex->t1;
+               particle_texcoord2f[4] = tex->s2;particle_texcoord2f[5] = tex->t1;
+               particle_texcoord2f[6] = tex->s2;particle_texcoord2f[7] = tex->t2;
        }
        else if (p->orientation == PARTICLE_SPARK)
        {
                VectorMA(p->org, -p->scaley, p->vel, v);
                VectorMA(p->org, p->scaley, p->vel, up2);
-               R_CalcBeam_Vertex3f(varray_vertex3f, v, up2, p->scalex);
-               varray_texcoord2f[0][0] = tex->s1;varray_texcoord2f[0][1] = tex->t2;
-               varray_texcoord2f[0][2] = tex->s1;varray_texcoord2f[0][3] = tex->t1;
-               varray_texcoord2f[0][4] = tex->s2;varray_texcoord2f[0][5] = tex->t1;
-               varray_texcoord2f[0][6] = tex->s2;varray_texcoord2f[0][7] = tex->t2;
+               R_CalcBeam_Vertex3f(particle_vertex3f, v, up2, p->scalex);
+               particle_texcoord2f[0] = tex->s1;particle_texcoord2f[1] = tex->t2;
+               particle_texcoord2f[2] = tex->s1;particle_texcoord2f[3] = tex->t1;
+               particle_texcoord2f[4] = tex->s2;particle_texcoord2f[5] = tex->t1;
+               particle_texcoord2f[6] = tex->s2;particle_texcoord2f[7] = tex->t2;
        }
        else if (p->orientation == PARTICLE_BEAM)
        {
-               R_CalcBeam_Vertex3f(varray_vertex3f, p->org, p->vel2, p->scalex);
+               R_CalcBeam_Vertex3f(particle_vertex3f, p->org, p->vel2, p->scalex);
                VectorSubtract(p->vel2, p->org, up);
                VectorNormalizeFast(up);
                v[0] = DotProduct(p->org, up) * (1.0f / 64.0f) - cl.time * 0.25;
                v[1] = DotProduct(p->vel2, up) * (1.0f / 64.0f) - cl.time * 0.25;
-               varray_texcoord2f[0][0] = 1;varray_texcoord2f[0][1] = v[0];
-               varray_texcoord2f[0][2] = 0;varray_texcoord2f[0][3] = v[0];
-               varray_texcoord2f[0][4] = 0;varray_texcoord2f[0][5] = v[1];
-               varray_texcoord2f[0][6] = 1;varray_texcoord2f[0][7] = v[1];
+               particle_texcoord2f[0] = 1;particle_texcoord2f[1] = v[0];
+               particle_texcoord2f[2] = 0;particle_texcoord2f[3] = v[0];
+               particle_texcoord2f[4] = 0;particle_texcoord2f[5] = v[1];
+               particle_texcoord2f[6] = 1;particle_texcoord2f[7] = v[1];
        }
        else
                Host_Error("R_DrawParticles: unknown particle orientation %i\n", p->orientation);
@@ -1812,10 +1807,10 @@ void R_DrawParticleCallback(const void *calldata1, int calldata2)
                glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
        glColor4f(cr, cg, cb, ca);
        glBegin(GL_QUADS);
-       glTexCoord2f(varray_texcoord2f[0][0], varray_texcoord2f[0][1]);glVertex3f(varray_vertex3f[ 0], varray_vertex3f[ 1], varray_vertex3f[ 2]);
-       glTexCoord2f(varray_texcoord2f[0][2], varray_texcoord2f[0][3]);glVertex3f(varray_vertex3f[ 3], varray_vertex3f[ 4], varray_vertex3f[ 5]);
-       glTexCoord2f(varray_texcoord2f[0][4], varray_texcoord2f[0][5]);glVertex3f(varray_vertex3f[ 6], varray_vertex3f[ 7], varray_vertex3f[ 8]);
-       glTexCoord2f(varray_texcoord2f[0][6], varray_texcoord2f[0][7]);glVertex3f(varray_vertex3f[ 9], varray_vertex3f[10], varray_vertex3f[11]);
+       glTexCoord2f(particle_texcoord2f[0], particle_texcoord2f[1]);glVertex3f(particle_vertex3f[ 0], particle_vertex3f[ 1], particle_vertex3f[ 2]);
+       glTexCoord2f(particle_texcoord2f[2], particle_texcoord2f[3]);glVertex3f(particle_vertex3f[ 3], particle_vertex3f[ 4], particle_vertex3f[ 5]);
+       glTexCoord2f(particle_texcoord2f[4], particle_texcoord2f[5]);glVertex3f(particle_vertex3f[ 6], particle_vertex3f[ 7], particle_vertex3f[ 8]);
+       glTexCoord2f(particle_texcoord2f[6], particle_texcoord2f[7]);glVertex3f(particle_vertex3f[ 9], particle_vertex3f[10], particle_vertex3f[11]);
        glEnd();
 #else
        R_Mesh_Draw(4, 2, polygonelements);
index cc88e36..3a15f7a 100644 (file)
@@ -3,25 +3,12 @@
 #include "image.h"
 #include "jpeg.h"
 
-//#define MESH_VAR
-#define MESH_BATCH
-
-// 65536 is the max addressable on a Geforce 256 up until Geforce3
-// (excluding MX), seems a reasonable number...
-cvar_t gl_mesh_maxverts = {0, "gl_mesh_maxverts", "65536"};
-cvar_t gl_mesh_floatcolors = {0, "gl_mesh_floatcolors", "1"};
 cvar_t gl_mesh_drawrangeelements = {0, "gl_mesh_drawrangeelements", "1"};
-#ifdef MESH_VAR
-cvar_t gl_mesh_vertex_array_range = {0, "gl_mesh_vertex_array_range", "0"};
-cvar_t gl_mesh_vertex_array_range_readfrequency = {0, "gl_mesh_vertex_array_range_readfrequency", "0.2"};
-cvar_t gl_mesh_vertex_array_range_writefrequency = {0, "gl_mesh_vertex_array_range_writefrequency", "0.2"};
-cvar_t gl_mesh_vertex_array_range_priority = {0, "gl_mesh_vertex_array_range_priority", "0.7"};
-#endif
-#ifdef MESH_BATCH
-cvar_t gl_mesh_batching = {0, "gl_mesh_batching", "1"};
-#endif
-cvar_t gl_mesh_copyarrays = {0, "gl_mesh_copyarrays", "1"};
+cvar_t gl_mesh_testarrayelement = {0, "gl_mesh_testarrayelement", "0"};
+cvar_t gl_mesh_testmanualfeeding = {0, "gl_mesh_testmanualfeeding", "0"};
 cvar_t gl_delayfinish = {CVAR_SAVE, "gl_delayfinish", "0"};
+cvar_t gl_paranoid = {0, "gl_paranoid", "0"};
+cvar_t gl_printcheckerror = {0, "gl_printcheckerror", "0"};
 
 cvar_t r_render = {0, "r_render", "1"};
 cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1"}; // whether or not to use dithering
@@ -88,26 +75,6 @@ void SCR_ScreenShot_f (void);
 // these are externally accessible
 int r_lightmapscalebit;
 float r_colorscale;
-GLfloat *varray_vertex3f, *varray_buf_vertex3f;
-GLfloat *varray_color4f, *varray_buf_color4f;
-GLfloat *varray_texcoord3f[MAX_TEXTUREUNITS], *varray_buf_texcoord3f[MAX_TEXTUREUNITS];
-GLfloat *varray_texcoord2f[MAX_TEXTUREUNITS], *varray_buf_texcoord2f[MAX_TEXTUREUNITS];
-static qbyte *varray_buf_color4b;
-int mesh_maxverts;
-#ifdef MESH_VAR
-int mesh_var;
-float mesh_var_readfrequency;
-float mesh_var_writefrequency;
-float mesh_var_priority;
-#endif
-int varray_offset = 0, varray_offsetnext = 0;
-GLuint *varray_buf_elements3i;
-int mesh_maxelements = 32768;
-#ifdef MESH_BATCH
-int gl_batchvertexfirst = 0;
-int gl_batchvertexcount = 0;
-int gl_batchelementcount = 0;
-#endif
 
 static matrix4x4_t backend_viewmatrix;
 static matrix4x4_t backend_modelmatrix;
@@ -135,149 +102,26 @@ A0B, 01B, B1C, 12C, C2D, 23D, D3E, 34E
 *elements++ = i + row + 1;
 */
 
-void GL_Backend_AllocElementsArray(void)
-{
-       if (varray_buf_elements3i)
-               Mem_Free(varray_buf_elements3i);
-       varray_buf_elements3i = Mem_Alloc(gl_backend_mempool, mesh_maxelements * sizeof(GLuint));
-}
-
-void GL_Backend_FreeElementArray(void)
-{
-       if (varray_buf_elements3i)
-               Mem_Free(varray_buf_elements3i);
-       varray_buf_elements3i = NULL;
-}
-
-void GL_Backend_CheckCvars(void)
-{
-       if (gl_mesh_maxverts.integer < 1024)
-               Cvar_SetValueQuick(&gl_mesh_maxverts, 1024);
-       if (gl_mesh_maxverts.integer > 65536)
-               Cvar_SetValueQuick(&gl_mesh_maxverts, 65536);
-#ifdef MESH_VAR
-       if (gl_mesh_vertex_array_range.integer && !gl_support_var)
-               Cvar_SetValueQuick(&gl_mesh_vertex_array_range, 0);
-       if (gl_mesh_vertex_array_range_readfrequency.value < 0)
-               Cvar_SetValueQuick(&gl_mesh_vertex_array_range_readfrequency, 0);
-       if (gl_mesh_vertex_array_range_readfrequency.value > 1)
-               Cvar_SetValueQuick(&gl_mesh_vertex_array_range_readfrequency, 1);
-       if (gl_mesh_vertex_array_range_writefrequency.value < 0)
-               Cvar_SetValueQuick(&gl_mesh_vertex_array_range_writefrequency, 0);
-       if (gl_mesh_vertex_array_range_writefrequency.value > 1)
-               Cvar_SetValueQuick(&gl_mesh_vertex_array_range_writefrequency, 1);
-       if (gl_mesh_vertex_array_range_priority.value < 0)
-               Cvar_SetValueQuick(&gl_mesh_vertex_array_range_priority, 0);
-       if (gl_mesh_vertex_array_range_priority.value > 1)
-               Cvar_SetValueQuick(&gl_mesh_vertex_array_range_priority, 1);
-#endif
-}
-
 int polygonelements[768];
 
 static void R_Mesh_CacheArray_Startup(void);
 static void R_Mesh_CacheArray_Shutdown(void);
 void GL_Backend_AllocArrays(void)
 {
-       int i, size;
-       qbyte *data;
-
        if (!gl_backend_mempool)
-       {
                gl_backend_mempool = Mem_AllocPool("GL_Backend");
-               varray_buf_vertex3f = NULL;
-               varray_buf_color4f = NULL;
-               varray_buf_color4b = NULL;
-               varray_buf_elements3i = NULL;
-               for (i = 0;i < MAX_TEXTUREUNITS;i++)
-                       varray_buf_texcoord3f[i] = varray_buf_texcoord2f[i] = NULL;
-       }
-
-       if (varray_buf_vertex3f)
-#ifdef MESH_VAR
-               VID_FreeVertexArrays(varray_buf_vertex3f);
-#else
-               Mem_Free(varray_buf_vertex3f);
-#endif
-       varray_buf_vertex3f = NULL;
-       varray_buf_color4f = NULL;
-       varray_buf_color4b = NULL;
-       for (i = 0;i < MAX_TEXTUREUNITS;i++)
-               varray_buf_texcoord3f[i] = varray_buf_texcoord2f[i] = NULL;
-
-       mesh_maxverts = gl_mesh_maxverts.integer;
-       size = mesh_maxverts * (sizeof(float[3]) + sizeof(float[4]) + sizeof(qbyte[4]) + (sizeof(float[3]) + sizeof(float[2])) * backendunits);
-#ifdef MESH_VAR
-       mesh_var = gl_mesh_vertex_array_range.integer && gl_support_var;
-       mesh_var_readfrequency = gl_mesh_vertex_array_range_readfrequency.value;
-       mesh_var_writefrequency = gl_mesh_vertex_array_range_writefrequency.value;
-       mesh_var_priority = gl_mesh_vertex_array_range_priority.value;
-       data = VID_AllocVertexArrays(gl_backend_mempool, size, gl_mesh_vertex_array_range.integer, gl_mesh_vertex_array_range_readfrequency.value, gl_mesh_vertex_array_range_writefrequency.value, gl_mesh_vertex_array_range_priority.value);
-#else
-       data = Mem_Alloc(gl_backend_mempool, size);
-#endif
-
-       varray_buf_vertex3f = (void *)data;data += sizeof(float[3]) * mesh_maxverts;
-       varray_buf_color4f = (void *)data;data += sizeof(float[4]) * mesh_maxverts;
-       for (i = 0;i < backendunits;i++)
-       {
-               varray_buf_texcoord3f[i] = (void *)data;data += sizeof(float[3]) * mesh_maxverts;
-               varray_buf_texcoord2f[i] = (void *)data;data += sizeof(float[2]) * mesh_maxverts;
-       }
-       for (;i < MAX_TEXTUREUNITS;i++)
-               varray_buf_texcoord3f[i] = varray_buf_texcoord2f[i] = NULL;
-       varray_buf_color4b = (void *)data;data += sizeof(qbyte[4]) * mesh_maxverts;
-
-       GL_Backend_AllocElementsArray();
-
-#ifdef MESH_VAR
-       if (mesh_var)
-       {
-               CHECKGLERROR
-               qglVertexArrayRangeNV(size, varray_buf_vertex3f);
-               CHECKGLERROR
-       }
-#endif
-
        R_Mesh_CacheArray_Startup();
 }
 
 void GL_Backend_FreeArrays(void)
 {
-       int i;
-
        R_Mesh_CacheArray_Shutdown();
-
-#ifdef MESH_VAR
-       if (mesh_var)
-       {
-               CHECKGLERROR
-               qglDisableClientState(GL_VERTEX_ARRAY_RANGE_NV);
-               CHECKGLERROR
-       }
-#endif
-
-       if (varray_buf_vertex3f)
-#ifdef MESH_VAR
-               VID_FreeVertexArrays(varray_buf_vertex3f);
-#else
-               Mem_Free(varray_buf_vertex3f);
-#endif
-       varray_buf_vertex3f = NULL;
-       varray_buf_color4f = NULL;
-       varray_buf_color4b = NULL;
-       for (i = 0;i < MAX_TEXTUREUNITS;i++)
-               varray_buf_texcoord3f[i] = varray_buf_texcoord2f[i] = NULL;
-       varray_buf_elements3i = NULL;
-
        Mem_FreePool(&gl_backend_mempool);
 }
 
 static void gl_backend_start(void)
 {
-       GL_Backend_CheckCvars();
-
-       Con_Printf("OpenGL Backend started with gl_mesh_maxverts %i\n", gl_mesh_maxverts.integer);
+       Con_Printf("OpenGL Backend started\n");
        if (qglDrawRangeElements != NULL)
        {
                CHECKGLERROR
@@ -287,31 +131,11 @@ static void gl_backend_start(void)
                CHECKGLERROR
                Con_Printf("glDrawRangeElements detected (max vertices %i, max indices %i)\n", gl_maxdrawrangeelementsvertices, gl_maxdrawrangeelementsindices);
        }
-       if (strstr(gl_renderer, "3Dfx"))
-       {
-               Con_Printf("3Dfx driver detected, forcing gl_mesh_floatcolors to 0 to prevent crashs\n");
-               Cvar_SetValueQuick(&gl_mesh_floatcolors, 0);
-       }
 
        backendunits = min(MAX_TEXTUREUNITS, gl_textureunits);
 
        GL_Backend_AllocArrays();
 
-#ifdef MESH_VAR
-       if (mesh_var)
-       {
-               CHECKGLERROR
-               qglEnableClientState(GL_VERTEX_ARRAY_RANGE_NV);
-               CHECKGLERROR
-       }
-#endif
-       varray_offset = varray_offsetnext = 0;
-#ifdef MESH_BATCH
-       gl_batchvertexfirst = 0;
-       gl_batchvertexcount = 0;
-       gl_batchelementcount = 0;
-#endif
-
        backendactive = true;
 }
 
@@ -322,26 +146,9 @@ static void gl_backend_shutdown(void)
 
        Con_Printf("OpenGL Backend shutting down\n");
 
-#ifdef MESH_VAR
-       if (mesh_var)
-       {
-               CHECKGLERROR
-               qglDisableClientState(GL_VERTEX_ARRAY_RANGE_NV);
-               CHECKGLERROR
-       }
-#endif
-
        GL_Backend_FreeArrays();
 }
 
-void GL_Backend_ResizeArrays(int numvertices)
-{
-       Cvar_SetValueQuick(&gl_mesh_maxverts, numvertices);
-       GL_Backend_CheckCvars();
-       mesh_maxverts = gl_mesh_maxverts.integer;
-       GL_Backend_AllocArrays();
-}
-
 static void gl_backend_newmap(void)
 {
 }
@@ -361,23 +168,15 @@ void gl_backend_init(void)
        Cvar_RegisterVariable(&gl_dither);
        Cvar_RegisterVariable(&gl_lockarrays);
        Cvar_RegisterVariable(&gl_delayfinish);
+       Cvar_RegisterVariable(&gl_paranoid);
+       Cvar_RegisterVariable(&gl_printcheckerror);
 #ifdef NORENDER
        Cvar_SetValue("r_render", 0);
 #endif
 
-       Cvar_RegisterVariable(&gl_mesh_maxverts);
-       Cvar_RegisterVariable(&gl_mesh_floatcolors);
        Cvar_RegisterVariable(&gl_mesh_drawrangeelements);
-#ifdef MESH_VAR
-       Cvar_RegisterVariable(&gl_mesh_vertex_array_range);
-       Cvar_RegisterVariable(&gl_mesh_vertex_array_range_readfrequency);
-       Cvar_RegisterVariable(&gl_mesh_vertex_array_range_writefrequency);
-       Cvar_RegisterVariable(&gl_mesh_vertex_array_range_priority);
-#endif
-#ifdef MESH_BATCH
-       Cvar_RegisterVariable(&gl_mesh_batching);
-#endif
-       Cvar_RegisterVariable(&gl_mesh_copyarrays);
+       Cvar_RegisterVariable(&gl_mesh_testarrayelement);
+       Cvar_RegisterVariable(&gl_mesh_testmanualfeeding);
        R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
 }
 
@@ -492,11 +291,13 @@ void GL_SetupView_Mode_Ortho (double x1, double y1, double x2, double y2, double
 typedef struct gltextureunit_s
 {
        int t1d, t2d, t3d, tcubemap;
-       int arrayenabled, arrayis3d;
+       int arrayenabled;
+       int arrayis3d;
        const void *pointer_texcoord;
        float rgbscale, alphascale;
        int combinergb, combinealpha;
        // FIXME: add more combine stuff
+       matrix4x4_t matrix;
 }
 gltextureunit_t;
 
@@ -506,15 +307,13 @@ static struct
        int blendfunc2;
        int blend;
        GLboolean depthmask;
-       int depthdisable;
+       int depthtest;
        int unit;
        int clientunit;
        gltextureunit_t units[MAX_TEXTUREUNITS];
-       int colorarray;
        float color4f[4];
        int lockrange_first;
        int lockrange_count;
-       int pointervertexcount;
        const void *pointer_vertex;
        const void *pointer_color;
 }
@@ -524,26 +323,26 @@ void GL_SetupTextureState(void)
 {
        int i;
        gltextureunit_t *unit;
+       gl_state.unit = -1;
+       gl_state.clientunit = -1;
        for (i = 0;i < backendunits;i++)
        {
-               if (qglActiveTexture)
-                       qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
-               if (qglClientActiveTexture)
-                       qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
+               GL_ActiveTexture(i);
+               GL_ClientActiveTexture(i);
                unit = gl_state.units + i;
                unit->t1d = 0;
                unit->t2d = 0;
                unit->t3d = 0;
                unit->tcubemap = 0;
-               unit->arrayenabled = false;
-               unit->arrayis3d = false;
                unit->pointer_texcoord = NULL;
                unit->rgbscale = 1;
                unit->alphascale = 1;
                unit->combinergb = GL_MODULATE;
                unit->combinealpha = GL_MODULATE;
+
+               qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), NULL);CHECKGLERROR
                qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
-               qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), varray_buf_texcoord2f[i]);CHECKGLERROR
+
                qglDisable(GL_TEXTURE_1D);CHECKGLERROR
                qglDisable(GL_TEXTURE_2D);CHECKGLERROR
                if (gl_texture3d)
@@ -584,22 +383,18 @@ void GL_SetupTextureState(void)
 void GL_Backend_ResetState(void)
 {
        memset(&gl_state, 0, sizeof(gl_state));
-       gl_state.depthdisable = false;
+       gl_state.depthtest = true;
        gl_state.blendfunc1 = GL_ONE;
        gl_state.blendfunc2 = GL_ZERO;
        gl_state.blend = false;
        gl_state.depthmask = GL_TRUE;
-       gl_state.colorarray = false;
        gl_state.color4f[0] = gl_state.color4f[1] = gl_state.color4f[2] = gl_state.color4f[3] = 1;
        gl_state.lockrange_first = 0;
        gl_state.lockrange_count = 0;
-       gl_state.pointervertexcount = 0;
        gl_state.pointer_vertex = NULL;
        gl_state.pointer_color = NULL;
 
        CHECKGLERROR
-       qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
-       qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
 
        qglEnable(GL_CULL_FACE);CHECKGLERROR
        qglCullFace(GL_FRONT);CHECKGLERROR
@@ -607,65 +402,148 @@ void GL_Backend_ResetState(void)
        qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
        qglDisable(GL_BLEND);CHECKGLERROR
        qglDepthMask(gl_state.depthmask);CHECKGLERROR
-       qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), varray_buf_vertex3f);CHECKGLERROR
+
+       qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), NULL);CHECKGLERROR
        qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
-       if (gl_mesh_floatcolors.integer)
+
+       qglColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL);CHECKGLERROR
+       qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
+
+       GL_Color(0, 0, 0, 0);
+       GL_Color(1, 1, 1, 1);
+
+       GL_SetupTextureState();
+}
+
+void GL_ActiveTexture(int num)
+{
+       if (gl_state.unit != num)
        {
-               qglColorPointer(4, GL_FLOAT, sizeof(float[4]), varray_buf_color4f);CHECKGLERROR
+               gl_state.unit = num;
+               if (qglActiveTexture)
+               {
+                       qglActiveTexture(GL_TEXTURE0_ARB + gl_state.unit);
+                       CHECKGLERROR
+               }
        }
-       else
+}
+
+void GL_ClientActiveTexture(int num)
+{
+       if (gl_state.clientunit != num)
        {
-               qglColorPointer(4, GL_UNSIGNED_BYTE, sizeof(qbyte[4]), varray_buf_color4b);CHECKGLERROR
+               gl_state.clientunit = num;
+               if (qglActiveTexture)
+               {
+                       qglClientActiveTexture(GL_TEXTURE0_ARB + gl_state.clientunit);
+                       CHECKGLERROR
+               }
        }
-       GL_Color(0, 0, 0, 0);
-       GL_Color(1, 1, 1, 1);
+}
 
-       GL_SetupTextureState();
+void GL_BlendFunc(int blendfunc1, int blendfunc2)
+{
+       if (gl_state.blendfunc1 != blendfunc1 || gl_state.blendfunc2 != blendfunc2)
+       {
+               qglBlendFunc(gl_state.blendfunc1 = blendfunc1, gl_state.blendfunc2 = blendfunc2);CHECKGLERROR
+               if (gl_state.blendfunc2 == GL_ZERO)
+               {
+                       if (gl_state.blendfunc1 == GL_ONE)
+                       {
+                               if (gl_state.blend)
+                               {
+                                       gl_state.blend = 0;
+                                       qglDisable(GL_BLEND);CHECKGLERROR
+                               }
+                       }
+                       else
+                       {
+                               if (!gl_state.blend)
+                               {
+                                       gl_state.blend = 1;
+                                       qglEnable(GL_BLEND);CHECKGLERROR
+                               }
+                       }
+               }
+               else
+               {
+                       if (!gl_state.blend)
+                       {
+                               gl_state.blend = 1;
+                               qglEnable(GL_BLEND);CHECKGLERROR
+                       }
+               }
+       }
 }
 
-void GL_UseColorArray(void)
+void GL_DepthMask(int state)
 {
-       if (!gl_state.colorarray)
+       if (gl_state.depthmask != state)
        {
-#ifdef MESH_BATCH
-               if (gl_batchelementcount)
-                       R_Mesh_EndBatch();
-#endif
-               gl_state.colorarray = true;
-               qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
+               qglDepthMask(gl_state.depthmask = state);CHECKGLERROR
+       }
+}
+
+void GL_DepthTest(int state)
+{
+       if (gl_state.depthtest != state)
+       {
+               gl_state.depthtest = state;
+               if (gl_state.depthtest)
+               {
+                       qglEnable(GL_DEPTH_TEST);CHECKGLERROR
+               }
+               else
+               {
+                       qglDisable(GL_DEPTH_TEST);CHECKGLERROR
+               }
+       }
+}
+
+void GL_VertexPointer(const float *p)
+{
+       if (gl_state.pointer_vertex != p)
+       {
+               gl_state.pointer_vertex = p;
+               CHECKGLERROR
+               qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), gl_state.pointer_vertex);
+               CHECKGLERROR
+       }
+}
+
+void GL_ColorPointer(const float *p)
+{
+       if (gl_state.pointer_color != p)
+       {
+               CHECKGLERROR
+               if (!gl_state.pointer_color)
+               {
+                       qglEnableClientState(GL_COLOR_ARRAY);
+                       CHECKGLERROR
+               }
+               else if (!p)
+               {
+                       qglDisableClientState(GL_COLOR_ARRAY);
+                       CHECKGLERROR
+               }
+               gl_state.pointer_color = p;
+               qglColorPointer(4, GL_FLOAT, sizeof(float[4]), gl_state.pointer_color);
+               CHECKGLERROR
        }
 }
 
 void GL_Color(float cr, float cg, float cb, float ca)
 {
-       if (gl_state.colorarray)
+       if (gl_state.pointer_color || gl_state.color4f[0] != cr || gl_state.color4f[1] != cg || gl_state.color4f[2] != cb || gl_state.color4f[3] != ca)
        {
-#ifdef MESH_BATCH
-               if (gl_batchelementcount)
-                       R_Mesh_EndBatch();
-#endif
-               gl_state.colorarray = false;
-               qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
+               GL_ColorPointer(NULL);
                gl_state.color4f[0] = cr;
                gl_state.color4f[1] = cg;
                gl_state.color4f[2] = cb;
                gl_state.color4f[3] = ca;
+               CHECKGLERROR
                qglColor4f(cr, cg, cb, ca);
-       }
-       else
-       {
-               if (gl_state.color4f[0] != cr || gl_state.color4f[1] != cg || gl_state.color4f[2] != cb || gl_state.color4f[3] != ca)
-               {
-#ifdef MESH_BATCH
-                       if (gl_batchelementcount)
-                               R_Mesh_EndBatch();
-#endif
-                       gl_state.color4f[0] = cr;
-                       gl_state.color4f[1] = cg;
-                       gl_state.color4f[2] = cb;
-                       gl_state.color4f[3] = ca;
-                       qglColor4f(cr, cg, cb, ca);
-               }
+               CHECKGLERROR
        }
 }
 
@@ -707,168 +585,30 @@ void GL_TransformToScreen(const vec4_t in, vec4_t out)
 void R_Mesh_Start(void)
 {
        BACKENDACTIVECHECK
-
        CHECKGLERROR
-
-       GL_Backend_CheckCvars();
-       if (mesh_maxverts != gl_mesh_maxverts.integer
-#ifdef MESH_VAR
-        || mesh_var != (gl_mesh_vertex_array_range.integer && gl_support_var)
-        || mesh_var_readfrequency != gl_mesh_vertex_array_range_readfrequency.value
-        || mesh_var_writefrequency != gl_mesh_vertex_array_range_writefrequency.value
-        || mesh_var_priority != gl_mesh_vertex_array_range_priority.value
-#endif
-               )
-               GL_Backend_ResizeArrays(gl_mesh_maxverts.integer);
-
        GL_Backend_ResetState();
-#ifdef MESH_VAR
-       if (!mesh_var)
-       {
-               gl_batchvertexfirst = gl_batchvertexcount = gl_batchelementcount = 0;
-               varray_offset = varray_offsetnext = 0;
-       }
-#else
-       varray_offset = varray_offsetnext = 0;
-#endif
 }
 
 int gl_backend_rebindtextures;
 
-void GL_ConvertColorsFloatToByte(int first, int count)
-{
-       int i, k;
-       union {float f[4];int i[4];} *color4fi;
-       struct {GLubyte c[4];} *color4b;
-
-       // shift float to have 8bit fraction at base of number
-       color4fi = (void *)(varray_buf_color4f + first * 4);
-       for (i = 0;i < count;i++, color4fi++)
-       {
-               color4fi->f[0] += 32768.0f;
-               color4fi->f[1] += 32768.0f;
-               color4fi->f[2] += 32768.0f;
-               color4fi->f[3] += 32768.0f;
-       }
-
-       // then read as integer and kill float bits...
-       color4fi = (void *)(varray_buf_color4f + first * 4);
-       color4b = (void *)(varray_buf_color4b + first * 4);
-       for (i = 0;i < count;i++, color4fi++, color4b++)
-       {
-               k = color4fi->i[0] & 0x7FFFFF;color4b->c[0] = (GLubyte) min(k, 255);
-               k = color4fi->i[1] & 0x7FFFFF;color4b->c[1] = (GLubyte) min(k, 255);
-               k = color4fi->i[2] & 0x7FFFFF;color4b->c[2] = (GLubyte) min(k, 255);
-               k = color4fi->i[3] & 0x7FFFFF;color4b->c[3] = (GLubyte) min(k, 255);
-       }
-}
-
-/*
-// enlarges geometry buffers if they are too small
-void _R_Mesh_ResizeCheck(int numverts)
-{
-       if (numverts > mesh_maxverts)
-       {
-               BACKENDACTIVECHECK
-               GL_Backend_ResizeArrays(numverts + 100);
-               GL_Backend_ResetState();
-       }
-}
-*/
-
-void R_Mesh_EndBatch(void)
-{
-#ifdef MESH_BATCH
-       if (gl_batchelementcount)
-       {
-               if (gl_state.pointervertexcount)
-                       Host_Error("R_Mesh_EndBatch: called with pointers enabled\n");
-
-               if (gl_state.colorarray && !gl_mesh_floatcolors.integer && gl_state.pointer_color == NULL)
-                       GL_ConvertColorsFloatToByte(gl_batchvertexfirst, gl_batchvertexcount);
-               if (r_render.integer)
-               {
-                       //int i;for (i = 0;i < gl_batchelementcount;i++) if (varray_buf_elements3i[i] < gl_batchvertexfirst || varray_buf_elements3i[i] >= (gl_batchvertexfirst + gl_batchvertexcount)) Host_Error("R_Mesh_EndBatch: invalid element #%i (value %i) outside range %i-%i\n", i, varray_buf_elements3i[i], gl_batchvertexfirst, gl_batchvertexfirst + gl_batchvertexcount);
-                       CHECKGLERROR
-                       GL_LockArrays(gl_batchvertexfirst, gl_batchvertexcount);
-                       if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
-                       {
-                               qglDrawRangeElements(GL_TRIANGLES, gl_batchvertexfirst, gl_batchvertexfirst + gl_batchvertexcount, gl_batchelementcount, GL_UNSIGNED_INT, (const GLuint *) varray_buf_elements3i);CHECKGLERROR
-                       }
-                       else
-                       {
-                               qglDrawElements(GL_TRIANGLES, gl_batchelementcount, GL_UNSIGNED_INT, (const GLuint *) varray_buf_elements3i);CHECKGLERROR
-                       }
-                       GL_LockArrays(0, 0);
-               }
-               gl_batchelementcount = 0;
-               gl_batchvertexcount = 0;
-       }
-#endif
-}
-
 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
 {
        int i;
-       //if (offset)
+       if (offset)
+       {
                for (i = 0;i < count;i++)
                        *out++ = *in++ + offset;
-       //else
-       //      memcpy(out, in, sizeof(*out) * count);
-}
-
-// gets vertex buffer space for use with a following R_Mesh_Draw
-// (can be multiple Draw calls per GetSpace)
-void R_Mesh_GetSpace(int numverts)
-{
-       int i;
-
-       if (gl_state.pointervertexcount)
-               Host_Error("R_Mesh_GetSpace: called with pointers enabled\n");
-       if (gl_state.lockrange_count)
-               Host_Error("R_Mesh_GetSpace: called with arrays locked\n");
-
-       varray_offset = varray_offsetnext;
-       if (varray_offset + numverts > mesh_maxverts)
-       {
-               //Con_Printf("R_Mesh_GetSpace: vertex buffer wrap\n");
-#ifdef MESH_BATCH
-               if (gl_batchelementcount)
-                       R_Mesh_EndBatch();
-#endif
-               varray_offset = 0;
-#ifdef MESH_VAR
-               if (mesh_var)
-               {
-                       CHECKGLERROR
-                       qglFlushVertexArrayRangeNV();
-                       CHECKGLERROR
-               }
-#endif
-               if (numverts > mesh_maxverts)
-               {
-                       GL_Backend_ResizeArrays(numverts + 100);
-                       GL_Backend_ResetState();
-               }
-       }
-
-       varray_vertex3f = varray_buf_vertex3f + varray_offset * 3;
-       varray_color4f = varray_buf_color4f + varray_offset * 4;
-       for (i = 0;i < backendunits;i++)
-       {
-               varray_texcoord3f[i] = varray_buf_texcoord3f[i] + varray_offset * 3;
-               varray_texcoord2f[i] = varray_buf_texcoord2f[i] + varray_offset * 2;
        }
-
-       varray_offsetnext = varray_offset + numverts;
+       else
+               memcpy(out, in, sizeof(*out) * count);
 }
 
-// renders triangles using vertices from the most recent GetSpace call
-// (can be multiple Draw calls per GetSpace)
+// renders triangles using vertices from the active arrays
+int paranoidblah = 0;
 void R_Mesh_Draw(int numverts, int numtriangles, const int *elements)
 {
        int numelements = numtriangles * 3;
-       if (numtriangles == 0 || numverts == 0)
+       if (numverts == 0 || numtriangles == 0)
        {
                Con_Printf("R_Mesh_Draw(%d, %d, %08p);\n", numverts, numtriangles, elements);
                return;
@@ -876,117 +616,120 @@ void R_Mesh_Draw(int numverts, int numtriangles, const int *elements)
        c_meshs++;
        c_meshelements += numelements;
        CHECKGLERROR
-       if (gl_state.pointervertexcount)
+       if (r_render.integer)
        {
-#ifdef MESH_BATCH
-               if (gl_batchelementcount)
-                       R_Mesh_EndBatch();
-#endif
-               if (r_render.integer)
+               if (gl_paranoid.integer)
                {
-                       GL_LockArrays(0, gl_state.pointervertexcount);
-                       if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
+                       int i, j, size;
+                       const int *p;
+                       if (!qglIsEnabled(GL_VERTEX_ARRAY))
+                               Con_Printf("R_Mesh_Draw: vertex array not enabled\n");
+                       for (j = 0, size = numverts * (int)sizeof(float[3]), p = gl_state.pointer_vertex;j < size;j += sizeof(int), p++)
+                               paranoidblah += *p;
+                       if (gl_state.pointer_color)
                        {
-                               qglDrawRangeElements(GL_TRIANGLES, 0, gl_state.pointervertexcount, numelements, GL_UNSIGNED_INT, elements);CHECKGLERROR
+                               if (!qglIsEnabled(GL_COLOR_ARRAY))
+                                       Con_Printf("R_Mesh_Draw: color array set but not enabled\n");
+                               for (j = 0, size = numverts * (int)sizeof(float[4]), p = gl_state.pointer_color;j < size;j += sizeof(int), p++)
+                                       paranoidblah += *p;
                        }
-                       else
-                       {
-                               qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, elements);CHECKGLERROR
-                       }
-                       GL_LockArrays(0, 0);
-               }
-       }
-#ifdef MESH_BATCH
-       else if (gl_mesh_batching.integer)
-       {
-               if (mesh_maxelements < gl_batchelementcount + numelements)
-               {
-                       //Con_Printf("R_Mesh_Draw: enlarging elements array\n");
-                       if (gl_batchelementcount)
-                               R_Mesh_EndBatch();
-                       // round up to a multiple of 1024 and add another 1024 just for good measure
-                       mesh_maxelements = (gl_batchelementcount + numelements + 1024 + 1023) & ~1023;
-                       GL_Backend_AllocElementsArray();
-               }
-               if (varray_offset < gl_batchvertexfirst && gl_batchelementcount)
-                       R_Mesh_EndBatch();
-               if (gl_batchelementcount == 0)
-               {
-                       gl_batchvertexfirst = varray_offset;
-                       gl_batchvertexcount = 0;
-               }
-               if (gl_batchvertexcount < varray_offsetnext - gl_batchvertexfirst)
-                       gl_batchvertexcount = varray_offsetnext - gl_batchvertexfirst;
-               GL_Backend_RenumberElements(varray_buf_elements3i + gl_batchelementcount, numelements, elements, varray_offset);
-               //Con_Printf("off %i:%i, vertex %i:%i, element %i:%i\n", varray_offset, varray_offsetnext, gl_batchvertexfirst, gl_batchvertexfirst + gl_batchvertexcount, gl_batchelementcount, gl_batchelementcount + numelements);
-               gl_batchelementcount += numelements;
-               //{int i;for (i = 0;i < gl_batchelementcount;i++) if (varray_buf_elements3i[i] < gl_batchvertexfirst || varray_buf_elements3i[i] >= (gl_batchvertexfirst + gl_batchvertexcount)) Host_Error("R_Mesh_EndBatch: invalid element #%i (value %i) outside range %i-%i, there were previously %i elements and there are now %i elements, varray_offset is %i\n", i, varray_buf_elements3i[i], gl_batchvertexfirst, gl_batchvertexfirst + gl_batchvertexcount, gl_batchelementcount - numelements, gl_batchelementcount, varray_offset);}
-       }
-#endif
-       else
-       {
-               GL_Backend_RenumberElements(varray_buf_elements3i, numelements, elements, varray_offset);
-               if (r_render.integer)
-               {
-                       GL_LockArrays(varray_offset, numverts);
-                       if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
+                       for (i = 0;i < backendunits;i++)
                        {
-                               qglDrawRangeElements(GL_TRIANGLES, varray_offset, varray_offset + numverts, numelements, GL_UNSIGNED_INT, varray_buf_elements3i);CHECKGLERROR
+                               if (gl_state.units[i].t1d || gl_state.units[i].t2d || gl_state.units[i].t3d || gl_state.units[i].tcubemap || gl_state.units[i].arrayenabled)
+                               {
+                                       if (gl_state.units[i].arrayenabled && !(gl_state.units[i].t1d || gl_state.units[i].t2d || gl_state.units[i].t3d || gl_state.units[i].tcubemap))
+                                               Con_Printf("R_Mesh_Draw: array enabled but no texture bound\n");
+                                       GL_ActiveTexture(i);
+                                       if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
+                                               Con_Printf("R_Mesh_Draw: texcoord array set but not enabled\n");
+                                       for (j = 0, size = numverts * ((gl_state.units[i].t3d || gl_state.units[i].tcubemap) ? (int)sizeof(float[3]) : (int)sizeof(float[2])), p = gl_state.units[i].pointer_texcoord;j < size;j += sizeof(int), p++)
+                                               paranoidblah += *p;
+                               }
                        }
-                       else
+                       for (i = 0;i < numtriangles * 3;i++)
                        {
-                               qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, varray_buf_elements3i);CHECKGLERROR
+                               if (elements[i] < 0 || elements[i] >= numverts)
+                               {
+                                       Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range 0 - %i) in elements list\n", elements[i], numverts);
+                                       return;
+                               }
                        }
-                       GL_LockArrays(0, 0);
                }
-       }
-}
-
-// renders triangles using vertices from the most recent GetSpace call
-// (can be multiple Draw calls per GetSpace)
-void R_Mesh_Draw_NoBatching(int numverts, int numtriangles, const int *elements)
-{
-       int numelements = numtriangles * 3;
-       if (numtriangles == 0 || numverts == 0)
-       {
-               Con_Printf("R_Mesh_Draw_NoBatching(%d, %d, %08p);\n", numverts, numtriangles, elements);
-               return;
-       }
-       c_meshs++;
-       c_meshelements += numelements;
-       CHECKGLERROR
-       if (gl_state.pointervertexcount)
-       {
-               if (r_render.integer)
+               CHECKGLERROR
+               GL_LockArrays(0, numverts);
+               CHECKGLERROR
+               if (gl_mesh_testmanualfeeding.integer)
                {
-                       GL_LockArrays(0, gl_state.pointervertexcount);
-                       if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
-                       {
-                               qglDrawRangeElements(GL_TRIANGLES, 0, gl_state.pointervertexcount, numelements, GL_UNSIGNED_INT, elements);CHECKGLERROR
-                       }
-                       else
+                       int i, j;
+                       const GLfloat *p;
+                       qglBegin(GL_TRIANGLES);
+                       for (i = 0;i < numtriangles * 3;i++)
                        {
-                               qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, elements);CHECKGLERROR
+                               for (j = 0;j < backendunits;j++)
+                               {
+                                       if (gl_state.units[j].pointer_texcoord)
+                                       {
+                                               if (backendunits > 1)
+                                               {
+                                                       if (gl_state.units[j].t3d || gl_state.units[j].tcubemap)
+                                                       {
+                                                               p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
+                                                               qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
+                                                       }
+                                                       else
+                                                       {
+                                                               p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
+                                                               qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       if (gl_state.units[j].t3d || gl_state.units[j].tcubemap)
+                                                       {
+                                                               p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
+                                                               qglTexCoord3f(p[0], p[1], p[2]);
+                                                       }
+                                                       else
+                                                       {
+                                                               p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
+                                                               qglTexCoord2f(p[0], p[1]);
+                                                       }
+                                               }
+                                       }
+                               }
+                               if (gl_state.pointer_color)
+                               {
+                                       p = ((const GLfloat *)(gl_state.pointer_color)) + elements[i] * 4;
+                                       qglColor4f(p[0], p[1], p[2], p[3]);
+                               }
+                               p = ((const GLfloat *)(gl_state.pointer_vertex)) + elements[i] * 3;
+                               qglVertex3f(p[0], p[1], p[2]);
                        }
-                       GL_LockArrays(0, 0);
+                       qglEnd();
+                       CHECKGLERROR
                }
-       }
-       else
-       {
-               GL_Backend_RenumberElements(varray_buf_elements3i, numelements, elements, varray_offset);
-               if (r_render.integer)
+               else if (gl_mesh_testarrayelement.integer)
                {
-                       GL_LockArrays(varray_offset, numverts);
-                       if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
+                       int i;
+                       qglBegin(GL_TRIANGLES);
+                       for (i = 0;i < numtriangles * 3;i++)
                        {
-                               qglDrawRangeElements(GL_TRIANGLES, varray_offset, varray_offset + numverts, numelements, GL_UNSIGNED_INT, varray_buf_elements3i);CHECKGLERROR
+                               qglArrayElement(elements[i]);
                        }
-                       else
-                       {
-                               qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, varray_buf_elements3i);CHECKGLERROR
-                       }
-                       GL_LockArrays(0, 0);
+                       qglEnd();
+                       CHECKGLERROR
+               }
+               else if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
+               {
+                       qglDrawRangeElements(GL_TRIANGLES, 0, numverts, numelements, GL_UNSIGNED_INT, elements);CHECKGLERROR
+               }
+               else
+               {
+                       qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, elements);CHECKGLERROR
                }
+               CHECKGLERROR
+               GL_LockArrays(0, 0);
+               CHECKGLERROR
        }
 }
 
@@ -995,11 +738,9 @@ void R_Mesh_Finish(void)
 {
        int i;
        BACKENDACTIVECHECK
-#ifdef MESH_BATCH
-       if (gl_batchelementcount)
-               R_Mesh_EndBatch();
-#endif
+               CHECKGLERROR
        GL_LockArrays(0, 0);
+               CHECKGLERROR
 
        for (i = backendunits - 1;i >= 0;i--)
        {
@@ -1038,10 +779,6 @@ void R_Mesh_Matrix(const matrix4x4_t *matrix)
 {
        if (memcmp(matrix, &backend_modelmatrix, sizeof(matrix4x4_t)))
        {
-#ifdef MESH_BATCH
-               if (gl_batchelementcount)
-                       R_Mesh_EndBatch();
-#endif
                backend_modelmatrix = *matrix;
                Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewmatrix, matrix);
                Matrix4x4_Transpose(&backend_glmodelviewmatrix, &backend_modelviewmatrix);
@@ -1049,110 +786,24 @@ void R_Mesh_Matrix(const matrix4x4_t *matrix)
        }
 }
 
-// sets up the requested state
-void R_Mesh_MainState(const rmeshstate_t *m)
+void R_Mesh_TextureMatrix(int unitnumber, const matrix4x4_t *matrix)
 {
-       const void *p;
-       BACKENDACTIVECHECK
-
-       if (gl_state.blendfunc1 != m->blendfunc1 || gl_state.blendfunc2 != m->blendfunc2)
-       {
-#ifdef MESH_BATCH
-               if (gl_batchelementcount)
-                       R_Mesh_EndBatch();
-#endif
-               qglBlendFunc(gl_state.blendfunc1 = m->blendfunc1, gl_state.blendfunc2 = m->blendfunc2);CHECKGLERROR
-               if (gl_state.blendfunc2 == GL_ZERO)
-               {
-                       if (gl_state.blendfunc1 == GL_ONE)
-                       {
-                               if (gl_state.blend)
-                               {
-                                       gl_state.blend = 0;
-                                       qglDisable(GL_BLEND);CHECKGLERROR
-                               }
-                       }
-                       else
-                       {
-                               if (!gl_state.blend)
-                               {
-                                       gl_state.blend = 1;
-                                       qglEnable(GL_BLEND);CHECKGLERROR
-                               }
-                       }
-               }
-               else
-               {
-                       if (!gl_state.blend)
-                       {
-                               gl_state.blend = 1;
-                               qglEnable(GL_BLEND);CHECKGLERROR
-                       }
-               }
-       }
-       if (gl_state.depthdisable != m->depthdisable)
+       if (memcmp(&gl_state.units[unitnumber].matrix, matrix, sizeof(matrix4x4_t)))
        {
-#ifdef MESH_BATCH
-               if (gl_batchelementcount)
-                       R_Mesh_EndBatch();
-#endif
-               gl_state.depthdisable = m->depthdisable;
-               if (gl_state.depthdisable)
-                       qglDisable(GL_DEPTH_TEST);
-               else
-                       qglEnable(GL_DEPTH_TEST);
-       }
-       if (gl_state.depthmask != (m->blendfunc2 == GL_ZERO || m->depthwrite))
-       {
-#ifdef MESH_BATCH
-               if (gl_batchelementcount)
-                       R_Mesh_EndBatch();
-#endif
-               qglDepthMask(gl_state.depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite));CHECKGLERROR
-       }
-
-       if (gl_state.pointervertexcount != m->pointervertexcount)
-       {
-#ifdef MESH_BATCH
-               if (gl_batchelementcount)
-                       R_Mesh_EndBatch();
-#endif
-               gl_state.pointervertexcount = m->pointervertexcount;
-       }
-
-       p = gl_state.pointervertexcount ? m->pointer_vertex : NULL;
-       if (gl_state.pointer_vertex != p)
-       {
-#ifdef MESH_BATCH
-               if (gl_batchelementcount)
-                       R_Mesh_EndBatch();
-#endif
-               gl_state.pointer_vertex = p;
-               qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), p ? p : varray_buf_vertex3f);CHECKGLERROR
-       }
-
-       p = gl_state.pointervertexcount ? m->pointer_color : NULL;
-       if (gl_state.pointer_color != p)
-       {
-#ifdef MESH_BATCH
-               if (gl_batchelementcount)
-                       R_Mesh_EndBatch();
-#endif
-               gl_state.pointer_color = p;
-               if (p || gl_mesh_floatcolors.integer)
-                       qglColorPointer(4, GL_FLOAT, sizeof(float[4]), p ? p : varray_buf_color4f);
-               else
-                       qglColorPointer(4, GL_UNSIGNED_BYTE, sizeof(GLubyte[4]), p ? p : varray_buf_color4b);
-               CHECKGLERROR
+               matrix4x4_t tempmatrix;
+               gl_state.units[unitnumber].matrix = *matrix;
+               Matrix4x4_Transpose(&tempmatrix, &gl_state.units[unitnumber].matrix);
+               qglMatrixMode(GL_TEXTURE);
+               GL_ActiveTexture(unitnumber);
+               qglLoadMatrixf(&tempmatrix.m[0][0]);
+               qglMatrixMode(GL_MODELVIEW);
        }
 }
 
-void R_Mesh_TextureState(const rmeshstate_t *m)
+void R_Mesh_State_Texture(const rmeshstate_t *m)
 {
-       int i, combinergb, combinealpha;
-       float scale;
+       int i, combinergb, combinealpha, scale, arrayis3d;
        gltextureunit_t *unit;
-       const void *p;
 
        BACKENDACTIVECHECK
 
@@ -1162,187 +813,74 @@ void R_Mesh_TextureState(const rmeshstate_t *m)
                GL_SetupTextureState();
        }
 
-       for (i = 0;i < backendunits;i++)
+       for (i = 0, unit = gl_state.units;i < backendunits;i++, unit++)
        {
-               unit = gl_state.units + i;
-               if (unit->t1d != m->tex1d[i] || unit->t2d != m->tex[i] || unit->t3d != m->tex3d[i] || unit->tcubemap != m->texcubemap[i])
+               if (unit->t1d != m->tex1d[i])
                {
-                       if (m->tex3d[i] || m->texcubemap[i])
+                       GL_ActiveTexture(i);
+                       if (m->tex1d[i])
                        {
-                               if (!unit->arrayis3d)
-                               {
-#ifdef MESH_BATCH
-                                       if (gl_batchelementcount)
-                                               R_Mesh_EndBatch();
-#endif
-                                       unit->arrayis3d = true;
-                                       if (gl_state.clientunit != i)
-                                       {
-                                               qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
-                                       }
-                                       qglTexCoordPointer(3, GL_FLOAT, sizeof(float[3]), varray_buf_texcoord3f[i]);
-                               }
-                               if (!unit->arrayenabled)
-                               {
-#ifdef MESH_BATCH
-                                       if (gl_batchelementcount)
-                                               R_Mesh_EndBatch();
-#endif
-                                       unit->arrayenabled = true;
-                                       if (gl_state.clientunit != i)
-                                       {
-                                               qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
-                                       }
-                                       qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
-                               }
+                               if (unit->t1d == 0)
+                                       qglEnable(GL_TEXTURE_1D);CHECKGLERROR
                        }
-                       else if (m->tex1d[i] || m->tex[i])
+                       else
                        {
-                               if (unit->arrayis3d)
-                               {
-#ifdef MESH_BATCH
-                                       if (gl_batchelementcount)
-                                               R_Mesh_EndBatch();
-#endif
-                                       unit->arrayis3d = false;
-                                       if (gl_state.clientunit != i)
-                                       {
-                                               qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
-                                       }
-                                       qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), varray_buf_texcoord2f[i]);
-                               }
-                               if (!unit->arrayenabled)
-                               {
-#ifdef MESH_BATCH
-                                       if (gl_batchelementcount)
-                                               R_Mesh_EndBatch();
-#endif
-                                       unit->arrayenabled = true;
-                                       if (gl_state.clientunit != i)
-                                       {
-                                               qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
-                                       }
-                                       qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
-                               }
+                               if (unit->t1d)
+                                       qglDisable(GL_TEXTURE_1D);CHECKGLERROR
+                       }
+                       qglBindTexture(GL_TEXTURE_1D, (unit->t1d = m->tex1d[i]));CHECKGLERROR
+               }
+               if (unit->t2d != m->tex[i])
+               {
+                       GL_ActiveTexture(i);
+                       if (m->tex[i])
+                       {
+                               if (unit->t2d == 0)
+                                       qglEnable(GL_TEXTURE_2D);CHECKGLERROR
                        }
                        else
                        {
-                               if (unit->arrayenabled)
-                               {
-#ifdef MESH_BATCH
-                                       if (gl_batchelementcount)
-                                               R_Mesh_EndBatch();
-#endif
-                                       unit->arrayenabled = false;
-                                       if (gl_state.clientunit != i)
-                                       {
-                                               qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
-                                       }
-                                       qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
-                               }
+                               if (unit->t2d)
+                                       qglDisable(GL_TEXTURE_2D);CHECKGLERROR
                        }
-                       if (unit->t1d != m->tex1d[i])
+                       qglBindTexture(GL_TEXTURE_2D, (unit->t2d = m->tex[i]));CHECKGLERROR
+               }
+               if (unit->t3d != m->tex3d[i])
+               {
+                       GL_ActiveTexture(i);
+                       if (m->tex3d[i])
                        {
-#ifdef MESH_BATCH
-                               if (gl_batchelementcount)
-                                       R_Mesh_EndBatch();
-#endif
-                               if (gl_state.unit != i)
-                               {
-                                       qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
-                               }
-                               if (m->tex1d[i])
-                               {
-                                       if (unit->t1d == 0)
-                                               qglEnable(GL_TEXTURE_1D);CHECKGLERROR
-                               }
-                               else
-                               {
-                                       if (unit->t1d)
-                                               qglDisable(GL_TEXTURE_1D);CHECKGLERROR
-                               }
-                               qglBindTexture(GL_TEXTURE_1D, (unit->t1d = m->tex1d[i]));CHECKGLERROR
+                               if (unit->t3d == 0)
+                                       qglEnable(GL_TEXTURE_3D);CHECKGLERROR
                        }
-                       if (unit->t2d != m->tex[i])
+                       else
                        {
-#ifdef MESH_BATCH
-                               if (gl_batchelementcount)
-                                       R_Mesh_EndBatch();
-#endif
-                               if (gl_state.unit != i)
-                               {
-                                       qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
-                               }
-                               if (m->tex[i])
-                               {
-                                       if (unit->t2d == 0)
-                                               qglEnable(GL_TEXTURE_2D);CHECKGLERROR
-                               }
-                               else
-                               {
-                                       if (unit->t2d)
-                                               qglDisable(GL_TEXTURE_2D);CHECKGLERROR
-                               }
-                               qglBindTexture(GL_TEXTURE_2D, (unit->t2d = m->tex[i]));CHECKGLERROR
+                               if (unit->t3d)
+                                       qglDisable(GL_TEXTURE_3D);CHECKGLERROR
                        }
-                       if (unit->t3d != m->tex3d[i])
+                       qglBindTexture(GL_TEXTURE_3D, (unit->t3d = m->tex3d[i]));CHECKGLERROR
+               }
+               if (unit->tcubemap != m->texcubemap[i])
+               {
+                       GL_ActiveTexture(i);
+                       if (m->texcubemap[i])
                        {
-#ifdef MESH_BATCH
-                               if (gl_batchelementcount)
-                                       R_Mesh_EndBatch();
-#endif
-                               if (gl_state.unit != i)
-                               {
-                                       qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
-                               }
-                               if (m->tex3d[i])
-                               {
-                                       if (unit->t3d == 0)
-                                               qglEnable(GL_TEXTURE_3D);CHECKGLERROR
-                               }
-                               else
-                               {
-                                       if (unit->t3d)
-                                               qglDisable(GL_TEXTURE_3D);CHECKGLERROR
-                               }
-                               qglBindTexture(GL_TEXTURE_3D, (unit->t3d = m->tex3d[i]));CHECKGLERROR
+                               if (unit->tcubemap == 0)
+                                       qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
                        }
-                       if (unit->tcubemap != m->texcubemap[i])
+                       else
                        {
-#ifdef MESH_BATCH
-                               if (gl_batchelementcount)
-                                       R_Mesh_EndBatch();
-#endif
-                               if (gl_state.unit != i)
-                               {
-                                       qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
-                               }
-                               if (m->texcubemap[i])
-                               {
-                                       if (unit->tcubemap == 0)
-                                               qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
-                               }
-                               else
-                               {
-                                       if (unit->tcubemap)
-                                               qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
-                               }
-                               qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, (unit->tcubemap = m->texcubemap[i]));CHECKGLERROR
+                               if (unit->tcubemap)
+                                       qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
                        }
+                       qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, (unit->tcubemap = m->texcubemap[i]));CHECKGLERROR
                }
                combinergb = m->texcombinergb[i];
                if (!combinergb)
                        combinergb = GL_MODULATE;
                if (unit->combinergb != combinergb)
                {
-#ifdef MESH_BATCH
-                       if (gl_batchelementcount)
-                               R_Mesh_EndBatch();
-#endif
-                       if (gl_state.unit != i)
-                       {
-                               qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
-                       }
+                       GL_ActiveTexture(i);
                        unit->combinergb = combinergb;
                        if (gl_combine.integer)
                        {
@@ -1358,14 +896,7 @@ void R_Mesh_TextureState(const rmeshstate_t *m)
                        combinealpha = GL_MODULATE;
                if (unit->combinealpha != combinealpha)
                {
-#ifdef MESH_BATCH
-                       if (gl_batchelementcount)
-                               R_Mesh_EndBatch();
-#endif
-                       if (gl_state.unit != i)
-                       {
-                               qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
-                       }
+                       GL_ActiveTexture(i);
                        unit->combinealpha = combinealpha;
                        if (gl_combine.integer)
                        {
@@ -1373,61 +904,48 @@ void R_Mesh_TextureState(const rmeshstate_t *m)
                        }
                }
                scale = max(m->texrgbscale[i], 1);
-               if (gl_state.units[i].rgbscale != scale)
+               if (unit->rgbscale != scale)
                {
-#ifdef MESH_BATCH
-                       if (gl_batchelementcount)
-                               R_Mesh_EndBatch();
-#endif
-                       if (gl_state.unit != i)
-                       {
-                               qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
-                       }
-                       qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (gl_state.units[i].rgbscale = scale));CHECKGLERROR
+                       GL_ActiveTexture(i);
+                       qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = scale));CHECKGLERROR
                }
                scale = max(m->texalphascale[i], 1);
-               if (gl_state.units[i].alphascale != scale)
+               if (unit->alphascale != scale)
                {
-#ifdef MESH_BATCH
-                       if (gl_batchelementcount)
-                               R_Mesh_EndBatch();
-#endif
-                       if (gl_state.unit != i)
-                       {
-                               qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
-                       }
-                       qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (gl_state.units[i].alphascale = scale));CHECKGLERROR
+                       GL_ActiveTexture(i);
+                       qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = scale));CHECKGLERROR
                }
-               if (unit->arrayenabled)
+               arrayis3d = unit->t3d || unit->tcubemap;
+               if (unit->pointer_texcoord != m->pointer_texcoord[i] || unit->arrayis3d != arrayis3d)
                {
-                       p = gl_state.pointervertexcount ? m->pointer_texcoord[i] : NULL;
-                       if (unit->pointer_texcoord != p)
+                       GL_ClientActiveTexture(i);
+                       if (m->pointer_texcoord[i])
                        {
-#ifdef MESH_BATCH
-                               if (gl_batchelementcount)
-                                       R_Mesh_EndBatch();
-#endif
-                               unit->pointer_texcoord = p;
-                               if (gl_state.clientunit != i)
+                               if (!unit->arrayenabled)
                                {
-                                       qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
+                                       unit->arrayenabled = true;
+                                       qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
                                }
-                               if (unit->arrayis3d)
-                                       qglTexCoordPointer(3, GL_FLOAT, sizeof(float[3]), p ? p : varray_buf_texcoord3f[i]);
-                               else
-                                       qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), p ? p : varray_buf_texcoord2f[i]);
-                               CHECKGLERROR
                        }
+                       else
+                       {
+                               if (unit->arrayenabled)
+                               {
+                                       unit->arrayenabled = false;
+                                       qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
+                               }
+                       }
+                       unit->pointer_texcoord = m->pointer_texcoord[i];
+                       unit->arrayis3d = arrayis3d;
+                       if (unit->arrayis3d)
+                               qglTexCoordPointer(3, GL_FLOAT, sizeof(float[3]), unit->pointer_texcoord);
+                       else
+                               qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), unit->pointer_texcoord);
+                       CHECKGLERROR
                }
        }
 }
 
-void R_Mesh_State(const rmeshstate_t *m)
-{
-       R_Mesh_MainState(m);
-       R_Mesh_TextureState(m);
-}
-
 /*
 ==============================================================================
 
@@ -1557,70 +1075,16 @@ void SCR_UpdateScreen (void)
        }
 }
 
-// utility functions
 
-void R_Mesh_CopyVertex3f(const float *vertex3f, int numverts)
-{
-#ifdef MESH_VAR
-       if (mesh_var)
-       {
-               float *out = varray_vertex3f;
-               while (--numverts)
-               {
-                       *out++ = *vertex3f++;
-                       *out++ = *vertex3f++;
-                       *out++ = *vertex3f++;
-               }
-       }
-       else
-#endif
-               memcpy(varray_vertex3f, vertex3f, numverts * sizeof(float[3]));
-}
-
-void R_Mesh_CopyTexCoord2f(int tmu, const float *texcoord2f, int numverts)
-{
-#ifdef MESH_VAR
-       if (mesh_var)
-       {
-               float *out = varray_texcoord2f[tmu];
-               while (numverts--)
-               {
-                       *out++ = *texcoord2f++;
-                       *out++ = *texcoord2f++;
-               }
-       }
-       else
-#endif
-               memcpy(varray_texcoord2f[tmu], texcoord2f, numverts * sizeof(float[2]));
-}
-
-void R_Mesh_CopyColor4f(const float *color4f, int numverts)
-{
-#ifdef MESH_VAR
-       if (mesh_var)
-       {
-               float *out = varray_color4f;
-               while (numverts--)
-               {
-                       *out++ = *color4f++;
-                       *out++ = *color4f++;
-                       *out++ = *color4f++;
-                       *out++ = *color4f++;
-               }
-       }
-       else
-#endif
-               memcpy(varray_color4f, color4f, numverts * sizeof(float[4]));
-}
+//===========================================================================
+// dynamic vertex array buffer subsystem
+//===========================================================================
 
-void R_ScrollTexCoord2f (float *out2f, const float *in2f, int numverts, float s, float t)
-{
-       while (numverts--)
-       {
-               *out2f++ = *in2f++ + s;
-               *out2f++ = *in2f++ + t;
-       }
-}
+float varray_vertex3f[65536*3];
+float varray_color4f[65536*4];
+float varray_texcoord2f[4][65536*2];
+float varray_texcoord3f[4][65536*3];
+float varray_normal3f[65536*3];
 
 //===========================================================================
 // vertex array caching subsystem
index 1206168..e8918dc 100644 (file)
@@ -7,41 +7,44 @@
 #define POLYGONELEMENTS_MAXPOINTS 258
 extern int polygonelements[768];
 
-void GL_SetupView_ViewPort (int x, int y, int width, int height);
-void GL_SetupView_Orientation_Identity (void);
-void GL_SetupView_Orientation_FromEntity (vec3_t origin, vec3_t angles);
-void GL_SetupView_Mode_Perspective (double fovx, double fovy, double zNear, double zFar);
-void GL_SetupView_Mode_PerspectiveInfiniteFarClip (double fovx, double fovy, double zNear);
-void GL_SetupView_Mode_Ortho (double x1, double y1, double x2, double y2, double zNear, double zFar);
-void GL_UseColorArray(void);
+void GL_SetupView_ViewPort(int x, int y, int width, int height);
+void GL_SetupView_Orientation_Identity(void);
+void GL_SetupView_Orientation_FromEntity(vec3_t origin, vec3_t angles);
+void GL_SetupView_Mode_Perspective(double fovx, double fovy, double zNear, double zFar);
+void GL_SetupView_Mode_PerspectiveInfiniteFarClip(double fovx, double fovy, double zNear);
+void GL_SetupView_Mode_Ortho(double x1, double y1, double x2, double y2, double zNear, double zFar);
+void GL_BlendFunc(int blendfunc1, int blendfunc2);
+void GL_DepthMask(int state);
+void GL_DepthTest(int state);
+void GL_VertexPointer(const float *p);
+void GL_ColorPointer(const float *p);
 void GL_Color(float cr, float cg, float cb, float ca);
 void GL_TransformToScreen(const vec4_t in, vec4_t out);
 void GL_LockArrays(int first, int count);
+void GL_ActiveTexture(int num);
+void GL_ClientActiveTexture(int num);
 
 extern cvar_t gl_lockarrays;
 extern cvar_t gl_mesh_copyarrays;
+extern cvar_t gl_paranoid;
+extern cvar_t gl_printcheckerror;
 
 extern int c_meshelements, c_meshs;
 
 //input to R_Mesh_State
 typedef struct
 {
-       int depthwrite; // force depth writing enabled even if polygon is not opaque
-       int depthdisable; // disable depth read/write entirely
-       int blendfunc1;
-       int blendfunc2;
-       //int wantoverbright;
+       // textures
        int tex1d[MAX_TEXTUREUNITS];
        int tex[MAX_TEXTUREUNITS];
        int tex3d[MAX_TEXTUREUNITS];
        int texcubemap[MAX_TEXTUREUNITS];
+       // texture combine settings
        int texrgbscale[MAX_TEXTUREUNITS]; // used only if COMBINE is present
        int texalphascale[MAX_TEXTUREUNITS]; // used only if COMBINE is present
        int texcombinergb[MAX_TEXTUREUNITS]; // works with or without combine for some operations
        int texcombinealpha[MAX_TEXTUREUNITS]; // does nothing without combine
-       int pointervertexcount;
-       const float *pointer_vertex;
-       const float *pointer_color;
+       // pointers
        const float *pointer_texcoord[MAX_TEXTUREUNITS];
 }
 rmeshstate_t;
@@ -49,11 +52,6 @@ rmeshstate_t;
 // overbright rendering scale for the current state
 extern int r_lightmapscalebit;
 extern float r_colorscale;
-extern float *varray_vertex3f;
-extern float *varray_color4f;
-extern float *varray_texcoord3f[MAX_TEXTUREUNITS];
-extern float *varray_texcoord2f[MAX_TEXTUREUNITS];
-extern int mesh_maxverts;
 
 // adds console variables and registers the render module (only call from GL_Init)
 void gl_backend_init(void);
@@ -68,39 +66,21 @@ void R_Mesh_Finish(void);
 // sets up the requested transform matrix
 void R_Mesh_Matrix(const matrix4x4_t *matrix);
 
-// sets up the requested state
-void R_Mesh_State(const rmeshstate_t *m);
-
-// sets up the requested main state
-void R_Mesh_MainState(const rmeshstate_t *m);
+// sets up the requested transform matrix
+void R_Mesh_TextureMatrix(int unitnumber, const matrix4x4_t *matrix);
 
-// sets up the requested texture state
-void R_Mesh_TextureState(const rmeshstate_t *m);
+// set up the requested state
+void R_Mesh_State_Texture(const rmeshstate_t *m);
 
-// forcefully ends a batch (do this before calling any gl functions directly)
-void R_Mesh_EndBatch(void);
-// prepares varray_* buffers for rendering a mesh
-void R_Mesh_GetSpace(int numverts);
-// renders a mesh (optionally with batching)
+// renders a mesh
 void R_Mesh_Draw(int numverts, int numtriangles, const int *elements);
-// renders a mesh without affecting batching
-void R_Mesh_Draw_NoBatching(int numverts, int numtriangles, const int *elements);
-
-// copies a vertex3f array into varray_vertex3f
-void R_Mesh_CopyVertex3f(const float *vertex3f, int numverts);
-// copies a texcoord2f array into varray_texcoord[tmu]
-void R_Mesh_CopyTexCoord2f(int tmu, const float *texcoord2f, int numverts);
-// copies a color4f array into varray_color4f
-void R_Mesh_CopyColor4f(const float *color4f, int numverts);
-// copies a texcoord2f array into another array, with scrolling
-void R_ScrollTexCoord2f (float *out2f, const float *in2f, int numverts, float s, float t);
 
 // saves a section of the rendered frame to a .tga or .jpg file
 qboolean SCR_ScreenShot(char *filename, int x, int y, int width, int height, qboolean jpeg);
 // used by R_Envmap_f and internally in backend, clears the frame
 void R_ClearScreen(void);
 // invoke refresh of frame
-void SCR_UpdateScreen (void);
+void SCR_UpdateScreen(void);
 
 // public structure
 typedef struct rcachearrayrequest_s
@@ -123,5 +103,11 @@ rcachearrayrequest_t;
 
 int R_Mesh_CacheArray(rcachearrayrequest_t *r);
 
+extern float varray_vertex3f[65536*3];
+extern float varray_color4f[65536*4];
+extern float varray_texcoord2f[4][65536*2];
+extern float varray_texcoord3f[4][65536*3];
+extern float varray_normal3f[65536*3];
+
 #endif
 
index 8830e06..88b9f19 100644 (file)
--- a/gl_draw.c
+++ b/gl_draw.c
@@ -380,8 +380,6 @@ void GL_Draw_Init (void)
 float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10};
 
 int quadelements[768];
-float textverts[128*4*3];
-float texttexcoords[128*4*2];
 void R_DrawQueue(void)
 {
        int pos, num, chartexnum, overbright, texnum, additive, batch;
@@ -420,7 +418,7 @@ void R_DrawQueue(void)
 
        memset(&m, 0, sizeof(m));
        m.tex[0] = 0;
-       R_Mesh_TextureState(&m);
+       R_Mesh_State_Texture(&m);
 
        currentpic = "";
        pic = NULL;
@@ -435,12 +433,9 @@ void R_DrawQueue(void)
                dq = (drawqueue_t *)(r_refdef.drawqueue + pos);
                additive = (dq->flags & DRAWFLAG_ADDITIVE) != 0;
                color = dq->color;
-               m.blendfunc1 = GL_SRC_ALPHA;
-               if (additive)
-                       m.blendfunc2 = GL_ONE;
-               else
-                       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
-               m.depthdisable = true;
+               GL_BlendFunc(GL_SRC_ALPHA, additive ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA);
+               GL_DepthMask(true);
+               GL_DepthTest(false);
 
                c[0] = (float) ((color >> 24) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
                c[1] = (float) ((color >> 16) & 0xFF) * (1.0f / 255.0f) * r_colorscale;
@@ -454,6 +449,7 @@ void R_DrawQueue(void)
                switch(dq->command)
                {
                case DRAWQUEUE_STRING:
+                       GL_Color(c[0], c[1], c[2], c[3]);
                        str = (char *)(dq + 1);
                        if (strcmp("gfx/conchars", currentpic))
                        {
@@ -461,9 +457,11 @@ void R_DrawQueue(void)
                                m.tex[0] = chartexnum;
                        }
                        batchcount = 0;
-                       at = texttexcoords;
-                       av = textverts;
-                       GL_Color(c[0], c[1], c[2], c[3]);
+                       GL_VertexPointer(varray_vertex3f);
+                       m.pointer_texcoord[0] = varray_texcoord2f[0];
+                       R_Mesh_State_Texture(&m);
+                       at = varray_texcoord2f[0];
+                       av = varray_vertex3f;
                        while ((num = *str++) && x < vid.conwidth)
                        {
                                if (num != ' ')
@@ -485,81 +483,24 @@ void R_DrawQueue(void)
                                        batchcount++;
                                        if (batchcount >= 128)
                                        {
-                                               if (gl_mesh_copyarrays.integer)
-                                               {
-                                                       m.pointervertexcount = 0;
-                                                       m.pointer_vertex = NULL;
-                                                       m.pointer_texcoord[0] = NULL;
-                                                       m.pointer_color = NULL;
-                                                       R_Mesh_State(&m);
-                                                       R_Mesh_GetSpace(batchcount * 4);
-                                                       R_Mesh_CopyVertex3f(textverts, batchcount * 4);
-                                                       R_Mesh_CopyTexCoord2f(0, texttexcoords, batchcount * 4);
-                                               }
-                                               else
-                                               {
-                                                       m.pointervertexcount = batchcount * 4;
-                                                       m.pointer_vertex = textverts;
-                                                       m.pointer_texcoord[0] = texttexcoords;
-                                                       m.pointer_color = NULL;
-                                                       R_Mesh_State(&m);
-                                               }
                                                R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
                                                batchcount = 0;
-                                               at = texttexcoords;
-                                               av = textverts;
+                                               at = varray_texcoord2f[0];
+                                               av = varray_vertex3f;
                                        }
                                }
                                x += w;
                        }
                        if (batchcount > 0)
-                       {
-                               if (gl_mesh_copyarrays.integer)
-                               {
-                                       m.pointervertexcount = 0;
-                                       m.pointer_vertex = NULL;
-                                       m.pointer_texcoord[0] = NULL;
-                                       m.pointer_color = NULL;
-                                       R_Mesh_State(&m);
-                                       R_Mesh_GetSpace(batchcount * 4);
-                                       R_Mesh_CopyVertex3f(textverts, batchcount * 4);
-                                       R_Mesh_CopyTexCoord2f(0, texttexcoords, batchcount * 4);
-                               }
-                               else
-                               {
-                                       m.pointervertexcount = batchcount * 4;
-                                       m.pointer_vertex = textverts;
-                                       m.pointer_texcoord[0] = texttexcoords;
-                                       m.pointer_color = NULL;
-                                       R_Mesh_State(&m);
-                               }
                                R_Mesh_Draw(batchcount * 4, batchcount * 2, quadelements);
-                       }
                        break;
                case DRAWQUEUE_MESH:
                        mesh = (void *)(dq + 1);
+                       GL_VertexPointer(mesh->vertex3f);
+                       GL_ColorPointer(mesh->color4f);
                        m.tex[0] = R_GetTexture(mesh->texture);
-                       GL_UseColorArray();
-                       if (gl_mesh_copyarrays.integer)
-                       {
-                               m.pointervertexcount = 0;
-                               m.pointer_vertex = NULL;
-                               m.pointer_texcoord[0] = NULL;
-                               m.pointer_color = NULL;
-                               R_Mesh_State(&m);
-                               R_Mesh_GetSpace(mesh->numvertices);
-                               R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numvertices);
-                               R_Mesh_CopyTexCoord2f(0, mesh->texcoord2f, mesh->numvertices);
-                               R_Mesh_CopyColor4f(mesh->color4f, mesh->numvertices);
-                       }
-                       else
-                       {
-                               m.pointervertexcount = mesh->numvertices;
-                               m.pointer_vertex = mesh->vertex3f;
-                               m.pointer_texcoord[0] = mesh->texcoord2f;
-                               m.pointer_color = mesh->color4f;
-                               R_Mesh_State(&m);
-                       }
+                       m.pointer_texcoord[0] = mesh->texcoord2f;
+                       R_Mesh_State_Texture(&m);
                        R_Mesh_Draw(mesh->numvertices, mesh->numtriangles, mesh->element3i);
                        currentpic = "\0";
                        break;
@@ -570,7 +511,9 @@ void R_DrawQueue(void)
        {
                // all the blends ignore depth
                memset(&m, 0, sizeof(m));
-               m.depthdisable = true;
+               R_Mesh_State_Texture(&m);
+               GL_DepthMask(true);
+               GL_DepthTest(false);
                if (v_color_enable.integer)
                {
                        c[0] = v_color_white_r.value;
@@ -582,20 +525,8 @@ void R_DrawQueue(void)
                VectorScale(c, (float) (1 << v_overbrightbits.integer), c);
                if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
                {
-                       m.blendfunc1 = GL_DST_COLOR;
-                       m.blendfunc2 = GL_ONE;
-                       if (gl_mesh_copyarrays.integer)
-                       {
-                               R_Mesh_State(&m);
-                               R_Mesh_GetSpace(3);
-                               R_Mesh_CopyVertex3f(blendvertex3f, 3);
-                       }
-                       else
-                       {
-                               m.pointervertexcount = 3;
-                               m.pointer_vertex = blendvertex3f;
-                               R_Mesh_State(&m);
-                       }
+                       GL_BlendFunc(GL_DST_COLOR, GL_ONE);
+                       GL_VertexPointer(blendvertex3f);
                        while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
                        {
                                GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1);
@@ -613,22 +544,8 @@ void R_DrawQueue(void)
                        c[0] = c[1] = c[2] = v_brightness.value;
                if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
                {
-                       m.blendfunc1 = GL_ONE;
-                       m.blendfunc2 = GL_ONE;
-                       if (gl_mesh_copyarrays.integer)
-                       {
-                               m.pointervertexcount = 0;
-                               m.pointer_vertex = NULL;
-                               R_Mesh_State(&m);
-                               R_Mesh_GetSpace(3);
-                               R_Mesh_CopyVertex3f(blendvertex3f, 3);
-                       }
-                       else
-                       {
-                               m.pointervertexcount = 3;
-                               m.pointer_vertex = blendvertex3f;
-                               R_Mesh_State(&m);
-                       }
+                       GL_BlendFunc(GL_ONE, GL_ONE);
+                       GL_VertexPointer(blendvertex3f);
                        GL_Color(c[0], c[1], c[2], 1);
                        R_Mesh_Draw(3, 1, polygonelements);
                }
index 3cbd420..ec9ed00 100644 (file)
@@ -86,7 +86,7 @@ void GL_Models_Init(void)
 #define MODELARRAY_TVECTOR 2
 #define MODELARRAY_NORMAL 3
 
-void R_Model_Alias_GetMesh_Array3f(const entity_render_t *ent, aliasmesh_t *mesh, int whicharray, float *out3f)
+void R_Model_Alias_GetMesh_Array3f(const entity_render_t *ent, const aliasmesh_t *mesh, int whicharray, float *out3f)
 {
        int i, vertcount;
        float lerp1, lerp2, lerp3, lerp4;
@@ -161,7 +161,7 @@ aliasskin_t *R_FetchAliasSkin(const entity_render_t *ent, const aliasmesh_t *mes
 void R_DrawAliasModelCallback (const void *calldata1, int calldata2)
 {
        int c, fullbright, layernum, firstpass;
-       float tint[3], fog, ifog, colorscale, ambientcolor4f[4], *fcolor;
+       float tint[3], fog, ifog, colorscale, ambientcolor4f[4];
        vec3_t diff;
        qbyte *bcolor;
        rmeshstate_t m;
@@ -169,7 +169,6 @@ void R_DrawAliasModelCallback (const void *calldata1, int calldata2)
        aliasmesh_t *mesh = ent->model->aliasdata_meshes + calldata2;
        aliaslayer_t *layer;
        aliasskin_t *skin;
-       rcachearrayrequest_t request;
 
        R_Mesh_Matrix(&ent->matrix);
 
@@ -204,55 +203,42 @@ void R_DrawAliasModelCallback (const void *calldata1, int calldata2)
                         || ((layer->flags & ALIASLAYER_DIFFUSE) && (r_shadow_realtime_world.integer && r_ambient.integer <= 0 && r_fullbright.integer == 0 && !(ent->effects & EF_FULLBRIGHT))))
                                continue;
                }
-               memset(&m, 0, sizeof(m));
                if (!firstpass || (ent->effects & EF_ADDITIVE))
                {
-                       m.blendfunc1 = GL_SRC_ALPHA;
-                       m.blendfunc2 = GL_ONE;
+                       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+                       GL_DepthMask(false);
                }
                else if ((skin->flags & ALIASSKIN_TRANSPARENT) || ent->alpha != 1.0)
                {
-                       m.blendfunc1 = GL_SRC_ALPHA;
-                       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+                       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+                       GL_DepthMask(false);
                }
                else
                {
-                       m.blendfunc1 = GL_ONE;
-                       m.blendfunc2 = GL_ZERO;
+                       GL_BlendFunc(GL_ONE, GL_ZERO);
+                       GL_DepthMask(true);
                }
+               GL_DepthTest(true);
                firstpass = false;
                expandaliasvert(mesh->num_vertices);
                colorscale = r_colorscale;
-               m.texrgbscale[0] = 1;
-               m.tex[0] = R_GetTexture(layer->texture);
-               if (gl_combine.integer && layer->flags & (ALIASLAYER_DIFFUSE | ALIASLAYER_SPECULAR))
+
+               memset(&m, 0, sizeof(m));
+               if (layer->texture != NULL)
                {
-                       colorscale *= 0.25f;
-                       m.texrgbscale[0] = 4;
+                       m.tex[0] = R_GetTexture(layer->texture);
+                       m.pointer_texcoord[0] = mesh->data_texcoord2f;
+                       if (gl_combine.integer && layer->flags & (ALIASLAYER_DIFFUSE | ALIASLAYER_SPECULAR))
+                       {
+                               colorscale *= 0.25f;
+                               m.texrgbscale[0] = 4;
+                       }
                }
+               R_Mesh_State_Texture(&m);
+
                c_alias_polys += mesh->num_triangles;
-               if (gl_mesh_copyarrays.integer)
-               {
-                       R_Mesh_State(&m);
-                       R_Mesh_GetSpace(mesh->num_vertices);
-                       if (layer->texture != NULL)
-                               R_Mesh_CopyTexCoord2f(0, mesh->data_texcoord2f, mesh->num_vertices);
-                       R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_VERTEX, varray_vertex3f);
-               }
-               else
-               {
-                       m.pointervertexcount = mesh->num_vertices;
-                       memset(&request, 0, sizeof(request));
-                       request.data_size = mesh->num_vertices * sizeof(float[3]);
-                       request.id_pointer2 = mesh->data_aliasvertex3f;
-                       request.id_number1 = layernum;
-                       request.id_number2 = 0;
-                       request.id_number3 = CRC_Block((void *)ent->frameblend, sizeof(ent->frameblend));
-                       if (R_Mesh_CacheArray(&request))
-                               R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_VERTEX, request.data);
-                       m.pointer_vertex = request.data;
-                       m.pointer_texcoord[0] = layer->texture != NULL ? mesh->data_texcoord2f : NULL;
-               }
+               GL_VertexPointer(varray_vertex3f);
+               R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_VERTEX, varray_vertex3f);
                if (layer->flags & ALIASLAYER_FOG)
                {
                        colorscale *= fog;
@@ -260,6 +246,12 @@ void R_DrawAliasModelCallback (const void *calldata1, int calldata2)
                }
                else
                {
+                       fullbright = !(layer->flags & ALIASLAYER_DIFFUSE) || r_fullbright.integer || (ent->effects & EF_FULLBRIGHT);
+                       if (r_shadow_realtime_world.integer && !fullbright)
+                       {
+                               colorscale *= r_ambient.value * (2.0f / 128.0f);
+                               fullbright = true;
+                       }
                        if (layer->flags & (ALIASLAYER_COLORMAP_PANTS | ALIASLAYER_COLORMAP_SHIRT))
                        {
                                // 128-224 are backwards ranges
@@ -269,63 +261,26 @@ void R_DrawAliasModelCallback (const void *calldata1, int calldata2)
                                        c = (ent->colormap & 0xF0);
                                c += (c >= 128 && c < 224) ? 4 : 12;
                                bcolor = (qbyte *) (&palette_complete[c]);
-                               fullbright = c >= 224;
+                               fullbright = fullbright || c >= 224;
                                VectorScale(bcolor, (1.0f / 255.0f), tint);
                        }
                        else
-                       {
                                tint[0] = tint[1] = tint[2] = 1;
-                               fullbright = false;
-                       }
                        colorscale *= ifog;
-                       if (fullbright || !(layer->flags & ALIASLAYER_DIFFUSE) || r_fullbright.integer || (ent->effects & EF_FULLBRIGHT))
-                               GL_Color(tint[0] * colorscale, tint[1] * colorscale, tint[2] * colorscale, ent->alpha);
-                       else if (r_shadow_realtime_world.integer)
-                       {
-                               colorscale *= r_ambient.value * (2.0f / 128.0f);
+                       if (fullbright)
                                GL_Color(tint[0] * colorscale, tint[1] * colorscale, tint[2] * colorscale, ent->alpha);
-                       }
                        else
                        {
                                if (R_LightModel(ambientcolor4f, ent, tint[0] * colorscale, tint[1] * colorscale, tint[2] * colorscale, ent->alpha, false))
                                {
-                                       GL_UseColorArray();
-                                       if (gl_mesh_copyarrays.integer)
-                                       {
-                                               R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_NORMAL, aliasvert_normal3f);
-                                               R_LightModel_CalcVertexColors(ambientcolor4f, mesh->num_vertices, varray_vertex3f, aliasvert_normal3f, varray_color4f);
-                                       }
-                                       else
-                                       {
-                                               // request color4f cache
-                                               request.data_size = mesh->num_vertices * sizeof(float[4]);
-                                               request.id_pointer1 = ent;
-                                               request.id_number2 = 2;
-                                               request.id_number3 = CRC_Block((void *)ent->frameblend, sizeof(ent->frameblend)) + CRC_Block((void *)&ent->entlightstime, sizeof(ent->entlightstime));
-                                               if (R_Mesh_CacheArray(&request))
-                                               {
-                                                       // save off the color pointer before we blow away the request
-                                                       fcolor = request.data;
-                                                       m.pointer_color = fcolor;
-                                                       // request normal3f cache
-                                                       request.data_size = mesh->num_vertices * sizeof(float[3]);
-                                                       request.id_pointer1 = NULL;
-                                                       request.id_number2 = 3;
-                                                       request.id_number3 = CRC_Block((void *)ent->frameblend, sizeof(ent->frameblend));
-                                                       if (R_Mesh_CacheArray(&request))
-                                                               R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_NORMAL, request.data);
-                                                       R_LightModel_CalcVertexColors(ambientcolor4f, mesh->num_vertices, m.pointer_vertex, request.data, fcolor);
-                                               }
-                                               else
-                                                       m.pointer_color = request.data;
-                                       }
+                                       GL_ColorPointer(varray_color4f);
+                                       R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_NORMAL, varray_normal3f);
+                                       R_LightModel_CalcVertexColors(ambientcolor4f, mesh->num_vertices, varray_vertex3f, varray_normal3f, varray_color4f);
                                }
                                else
                                        GL_Color(ambientcolor4f[0], ambientcolor4f[1], ambientcolor4f[2], ambientcolor4f[3]);
                        }
                }
-               if (!gl_mesh_copyarrays.integer)
-                       R_Mesh_State(&m);
                R_Mesh_Draw(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
        }
 }
@@ -355,7 +310,6 @@ void R_Model_Alias_DrawFakeShadow (entity_render_t *ent)
        aliasskin_t *skin;
        rmeshstate_t m;
        float *v, plane[4], dist, projection[3], floororigin[3], surfnormal[3], lightdirection[3], v2[3];
-       rcachearrayrequest_t request;
 
        if ((ent->effects & EF_ADDITIVE) || ent->alpha < 1)
                return;
@@ -372,10 +326,12 @@ void R_Model_Alias_DrawFakeShadow (entity_render_t *ent)
        R_Mesh_Matrix(&ent->matrix);
 
        memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_SRC_ALPHA;
-       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
-       if (gl_mesh_copyarrays.integer)
-               R_Mesh_State(&m);
+       R_Mesh_State_Texture(&m);
+
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
+       GL_VertexPointer(varray_vertex3f);
        GL_Color(0, 0, 0, 0.5);
 
        // put a light direction in the entity's coordinate space
@@ -392,43 +348,17 @@ void R_Model_Alias_DrawFakeShadow (entity_render_t *ent)
 
        dist = -1.0f / DotProduct(projection, plane);
        VectorScale(projection, dist, projection);
-       memset(&request, 0, sizeof(request));
        for (meshnum = 0, mesh = ent->model->aliasdata_meshes;meshnum < ent->model->aliasnum_meshes;meshnum++)
        {
                skin = R_FetchAliasSkin(ent, mesh);
                if (skin->flags & ALIASSKIN_TRANSPARENT)
                        continue;
-               if (gl_mesh_copyarrays.integer)
+               R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_VERTEX, varray_vertex3f);
+               for (i = 0, v = varray_vertex3f;i < mesh->num_vertices;i++, v += 3)
                {
-                       R_Mesh_GetSpace(mesh->num_vertices);
-                       R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_VERTEX, varray_vertex3f);
-                       for (i = 0, v = varray_vertex3f;i < mesh->num_vertices;i++, v += 3)
-                       {
-                               dist = DotProduct(v, plane) - plane[3];
-                               if (dist > 0)
-                                       VectorMA(v, dist, projection, v);
-                       }
-               }
-               else
-               {
-                       request.data_size = mesh->num_vertices * sizeof(float[3]);
-                       request.id_pointer1 = mesh;
-                       request.id_number1 = CRC_Block((void *)&ent->matrix, sizeof(ent->matrix));
-                       request.id_number2 = CRC_Block((void *)&plane, sizeof(plane));
-                       request.id_number3 = CRC_Block((void *)&ent->frameblend, sizeof(ent->frameblend));
-                       m.pointervertexcount = mesh->num_vertices;
-                       if (R_Mesh_CacheArray(&request))
-                       {
-                               R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_VERTEX, request.data);
-                               for (i = 0, v = request.data;i < mesh->num_vertices;i++, v += 3)
-                               {
-                                       dist = DotProduct(v, plane) - plane[3];
-                                       if (dist > 0)
-                                               VectorMA(v, dist, projection, v);
-                               }
-                       }
-                       m.pointer_vertex = request.data;
-                       R_Mesh_State(&m);
+                       dist = DotProduct(v, plane) - plane[3];
+                       if (dist > 0)
+                               VectorMA(v, dist, projection, v);
                }
                c_alias_polys += mesh->num_triangles;
                R_Mesh_Draw(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
@@ -452,9 +382,8 @@ void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightor
                        skin = R_FetchAliasSkin(ent, mesh);
                        if (skin->flags & ALIASSKIN_TRANSPARENT)
                                continue;
-                       R_Mesh_GetSpace(mesh->num_vertices * 2);
                        R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_VERTEX, varray_vertex3f);
-                       R_Shadow_Volume(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, mesh->data_neighbor3i, relativelightorigin, lightradius, projectdistance);
+                       R_Shadow_Volume(mesh->num_vertices, mesh->num_triangles, varray_vertex3f, mesh->data_element3i, mesh->data_neighbor3i, relativelightorigin, lightradius, projectdistance);
                }
        }
 }
@@ -852,22 +781,25 @@ void R_DrawZymoticModelMeshCallback (const void *calldata1, int calldata2)
        }
        ifog = 1 - fog;
 
-       memset(&mstate, 0, sizeof(mstate));
        if (ent->effects & EF_ADDITIVE)
        {
-               mstate.blendfunc1 = GL_SRC_ALPHA;
-               mstate.blendfunc2 = GL_ONE;
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+               GL_DepthMask(false);
        }
        else if (ent->alpha != 1.0 || R_TextureHasAlpha(texture))
        {
-               mstate.blendfunc1 = GL_SRC_ALPHA;
-               mstate.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               GL_DepthMask(false);
        }
        else
        {
-               mstate.blendfunc1 = GL_ONE;
-               mstate.blendfunc2 = GL_ZERO;
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_DepthMask(true);
        }
+       GL_DepthTest(true);
+       GL_VertexPointer(varray_vertex3f);
+
+       memset(&mstate, 0, sizeof(mstate));
        colorscale = r_colorscale;
        if (gl_combine.integer)
        {
@@ -875,16 +807,16 @@ void R_DrawZymoticModelMeshCallback (const void *calldata1, int calldata2)
                colorscale *= 0.25f;
        }
        mstate.tex[0] = R_GetTexture(texture);
-       R_Mesh_State(&mstate);
+       mstate.pointer_texcoord[0] = ent->model->zymdata_texcoords;
+       R_Mesh_State_Texture(&mstate);
+
        ZymoticLerpBones(ent->model->zymnum_bones, (zymbonematrix *) ent->model->zymdata_poses, ent->frameblend, ent->model->zymdata_bones);
 
-       R_Mesh_GetSpace(numverts);
        ZymoticTransformVerts(numverts, varray_vertex3f, ent->model->zymdata_vertbonecounts, ent->model->zymdata_verts);
-       R_Mesh_CopyTexCoord2f(0, ent->model->zymdata_texcoords, ent->model->zymnum_verts);
        ZymoticCalcNormal3f(numverts, varray_vertex3f, aliasvert_normal3f, ent->model->zymnum_shaders, ent->model->zymdata_renderlist);
        if (R_LightModel(ambientcolor4f, ent, ifog * colorscale, ifog * colorscale, ifog * colorscale, ent->alpha, false))
        {
-               GL_UseColorArray();
+               GL_ColorPointer(varray_color4f);
                R_LightModel_CalcVertexColors(ambientcolor4f, numverts, varray_vertex3f, aliasvert_normal3f, varray_color4f);
        }
        else
@@ -894,14 +826,18 @@ void R_DrawZymoticModelMeshCallback (const void *calldata1, int calldata2)
 
        if (fog)
        {
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               GL_DepthMask(false);
+               GL_DepthTest(true);
+               GL_VertexPointer(varray_vertex3f);
+
                memset(&mstate, 0, sizeof(mstate));
-               mstate.blendfunc1 = GL_SRC_ALPHA;
-               mstate.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
                // FIXME: need alpha mask for fogging...
                //mstate.tex[0] = R_GetTexture(texture);
-               R_Mesh_State(&mstate);
+               //mstate.pointer_texcoord = ent->model->zymdata_texcoords;
+               R_Mesh_State_Texture(&mstate);
+
                GL_Color(fogcolor[0] * r_colorscale, fogcolor[1] * r_colorscale, fogcolor[2] * r_colorscale, ent->alpha * fog);
-               R_Mesh_GetSpace(numverts);
                ZymoticTransformVerts(numverts, varray_vertex3f, ent->model->zymdata_vertbonecounts, ent->model->zymdata_verts);
                R_Mesh_Draw(numverts, numtriangles, elements);
                c_alias_polys += numtriangles;
index f353812..efe64d9 100644 (file)
@@ -817,11 +817,11 @@ void R_ShadowVolumeLighting (int visiblevolumes)
        if (visiblevolumes)
        {
                memset(&m, 0, sizeof(m));
-               m.blendfunc1 = GL_ONE;
-               m.blendfunc2 = GL_ONE;
-               if (r_shadow_visiblevolumes.integer >= 2)
-                       m.depthdisable = true;
-               R_Mesh_State(&m);
+               R_Mesh_State_Texture(&m);
+
+               GL_BlendFunc(GL_ONE, GL_ONE);
+               GL_DepthMask(false);
+               GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
                qglDisable(GL_CULL_FACE);
                GL_Color(0.0 * r_colorscale, 0.0125 * r_colorscale, 0.1 * r_colorscale, 1);
        }
@@ -1055,9 +1055,10 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                }
        }
 
-       if (!visiblevolumes)
+       if (visiblevolumes)
+               qglEnable(GL_CULL_FACE);
+       else
                R_Shadow_Stage_End();
-       qglEnable(GL_CULL_FACE);
        qglDisable(GL_SCISSOR_TEST);
 }
 
@@ -1119,29 +1120,31 @@ static void R_BlendView(void)
 {
        rmeshstate_t m;
        float r;
+       float vertex3f[3*3];
 
        if (r_refdef.viewblend[3] < 0.01f)
                return;
 
-       memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_SRC_ALPHA;
-       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
-       m.depthdisable = true; // magic
        R_Mesh_Matrix(&r_identitymatrix);
-       R_Mesh_State(&m);
 
-       R_Mesh_GetSpace(3);
-       r = 64000;
-       varray_vertex3f[0] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r - vup[0] * r;
-       varray_vertex3f[1] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r - vup[1] * r;
-       varray_vertex3f[2] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r - vup[2] * r;
-       varray_vertex3f[3] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r + vup[0] * r * 3;
-       varray_vertex3f[4] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r + vup[1] * r * 3;
-       varray_vertex3f[5] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r + vup[2] * r * 3;
-       varray_vertex3f[6] = r_origin[0] + vpn[0] * 1.5 + vright[0] * r * 3 - vup[0] * r;
-       varray_vertex3f[7] = r_origin[1] + vpn[1] * 1.5 + vright[1] * r * 3 - vup[1] * r;
-       varray_vertex3f[8] = r_origin[2] + vpn[2] * 1.5 + vright[2] * r * 3 - vup[2] * r;
+       memset(&m, 0, sizeof(m));
+       R_Mesh_State_Texture(&m);
+
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       GL_DepthMask(true);
+       GL_DepthTest(false); // magic
+       GL_VertexPointer(vertex3f);
        GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
+       r = 64000;
+       vertex3f[0] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r - vup[0] * r;
+       vertex3f[1] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r - vup[1] * r;
+       vertex3f[2] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r - vup[2] * r;
+       vertex3f[3] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r + vup[0] * r * 3;
+       vertex3f[4] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r + vup[1] * r * 3;
+       vertex3f[5] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r + vup[2] * r * 3;
+       vertex3f[6] = r_origin[0] + vpn[0] * 1.5 + vright[0] * r * 3 - vup[0] * r;
+       vertex3f[7] = r_origin[1] + vpn[1] * 1.5 + vright[1] * r * 3 - vup[1] * r;
+       vertex3f[8] = r_origin[2] + vpn[2] * 1.5 + vright[2] * r * 3 - vup[2] * r;
        R_Mesh_Draw(3, 1, polygonelements);
 }
 
@@ -1267,26 +1270,30 @@ void R_RenderView (void)
 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
 {
        int i;
-       float *v, *c, f1, f2, diff[3];
+       float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
        rmeshstate_t m;
-       m.blendfunc1 = GL_SRC_ALPHA;
-       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
        R_Mesh_Matrix(&r_identitymatrix);
-       R_Mesh_State(&m);
+
+       memset(&m, 0, sizeof(m));
+       R_Mesh_State_Texture(&m);
 
        R_Mesh_GetSpace(8);
-       varray_vertex[ 0] = mins[0];varray_vertex[ 1] = mins[1];varray_vertex[ 2] = mins[2];
-       varray_vertex[ 4] = maxs[0];varray_vertex[ 5] = mins[1];varray_vertex[ 6] = mins[2];
-       varray_vertex[ 8] = mins[0];varray_vertex[ 9] = maxs[1];varray_vertex[10] = mins[2];
-       varray_vertex[12] = maxs[0];varray_vertex[13] = maxs[1];varray_vertex[14] = mins[2];
-       varray_vertex[16] = mins[0];varray_vertex[17] = mins[1];varray_vertex[18] = maxs[2];
-       varray_vertex[20] = maxs[0];varray_vertex[21] = mins[1];varray_vertex[22] = maxs[2];
-       varray_vertex[24] = mins[0];varray_vertex[25] = maxs[1];varray_vertex[26] = maxs[2];
-       varray_vertex[28] = maxs[0];varray_vertex[29] = maxs[1];varray_vertex[30] = maxs[2];
-       R_FillColors(varray_color, 8, cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
+       vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
+       vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
+       vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
+       vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
+       vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
+       vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
+       vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
+       vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
+       GL_ColorPointer(color);
+       R_FillColors(color, 8, cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
        if (fogenabled)
        {
-               for (i = 0, v = varray_vertex, c = varray_color;i < 8;i++, v += 4, c += 4)
+               for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
                {
                        VectorSubtract(v, r_origin, diff);
                        f2 = exp(fogdensity/DotProduct(diff, diff));
@@ -1297,7 +1304,6 @@ void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, floa
                        c[2] = c[2] * f1 + fogcolor[2] * f2;
                }
        }
-       GL_UseColorArray();
        R_Mesh_Draw(8, 12);
 }
 */
@@ -1314,66 +1320,84 @@ int nomodelelements[24] =
        1, 3, 4
 };
 
+float nomodelvertex3f[6*3] =
+{
+       -16,   0,   0,
+        16,   0,   0,
+         0, -16,   0,
+         0,  16,   0,
+         0,   0, -16,
+         0,   0,  16
+};
+
+float nomodelcolor4f[6*4] =
+{
+       0.0f, 0.0f, 0.5f, 1.0f,
+       0.0f, 0.0f, 0.5f, 1.0f,
+       0.0f, 0.5f, 0.0f, 1.0f,
+       0.0f, 0.5f, 0.0f, 1.0f,
+       0.5f, 0.0f, 0.0f, 1.0f,
+       0.5f, 0.0f, 0.0f, 1.0f
+};
+
 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
 {
        const entity_render_t *ent = calldata1;
        int i;
        float f1, f2, *c, diff[3];
+       float color4f[6*4];
        rmeshstate_t m;
+       R_Mesh_Matrix(&ent->matrix);
+
        memset(&m, 0, sizeof(m));
+       R_Mesh_State_Texture(&m);
+
        if (ent->flags & EF_ADDITIVE)
        {
-               m.blendfunc1 = GL_SRC_ALPHA;
-               m.blendfunc2 = GL_ONE;
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+               GL_DepthMask(false);
        }
        else if (ent->alpha < 1)
        {
-               m.blendfunc1 = GL_SRC_ALPHA;
-               m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               GL_DepthMask(false);
        }
        else
        {
-               m.blendfunc1 = GL_ONE;
-               m.blendfunc2 = GL_ZERO;
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_DepthMask(true);
        }
-       R_Mesh_Matrix(&ent->matrix);
-       R_Mesh_State(&m);
-
-       GL_UseColorArray();
-       R_Mesh_GetSpace(6);
-       varray_vertex3f[ 0] = -16;varray_vertex3f[ 1] =   0;varray_vertex3f[ 2] =   0;
-       varray_vertex3f[ 3] =  16;varray_vertex3f[ 4] =   0;varray_vertex3f[ 5] =   0;
-       varray_vertex3f[ 6] =   0;varray_vertex3f[ 7] = -16;varray_vertex3f[ 8] =   0;
-       varray_vertex3f[ 9] =   0;varray_vertex3f[10] =  16;varray_vertex3f[11] =   0;
-       varray_vertex3f[12] =   0;varray_vertex3f[13] =   0;varray_vertex3f[14] = -16;
-       varray_vertex3f[15] =   0;varray_vertex3f[16] =   0;varray_vertex3f[17] =  16;
-       varray_color4f[ 0] = 0.00f * r_colorscale;varray_color4f[ 1] = 0.00f * r_colorscale;varray_color4f[ 2] = 0.50f * r_colorscale;varray_color4f[ 3] = ent->alpha;
-       varray_color4f[ 4] = 0.00f * r_colorscale;varray_color4f[ 5] = 0.00f * r_colorscale;varray_color4f[ 6] = 0.50f * r_colorscale;varray_color4f[ 7] = ent->alpha;
-       varray_color4f[ 8] = 0.00f * r_colorscale;varray_color4f[ 9] = 0.50f * r_colorscale;varray_color4f[10] = 0.00f * r_colorscale;varray_color4f[11] = ent->alpha;
-       varray_color4f[12] = 0.00f * r_colorscale;varray_color4f[13] = 0.50f * r_colorscale;varray_color4f[14] = 0.00f * r_colorscale;varray_color4f[15] = ent->alpha;
-       varray_color4f[16] = 0.50f * r_colorscale;varray_color4f[17] = 0.00f * r_colorscale;varray_color4f[18] = 0.00f * r_colorscale;varray_color4f[19] = ent->alpha;
-       varray_color4f[20] = 0.50f * r_colorscale;varray_color4f[21] = 0.00f * r_colorscale;varray_color4f[22] = 0.00f * r_colorscale;varray_color4f[23] = ent->alpha;
+       GL_DepthTest(true);
+       GL_VertexPointer(nomodelvertex3f);
        if (fogenabled)
        {
+               memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
+               GL_ColorPointer(color4f);
                VectorSubtract(ent->origin, r_origin, diff);
                f2 = exp(fogdensity/DotProduct(diff, diff));
                f1 = 1 - f2;
-               for (i = 0, c = varray_color4f;i < 6;i++, c += 4)
+               for (i = 0, c = color4f;i < 6;i++, c += 4)
                {
                        c[0] = (c[0] * f1 + fogcolor[0] * f2) * r_colorscale;
                        c[1] = (c[1] * f1 + fogcolor[1] * f2) * r_colorscale;
                        c[2] = (c[2] * f1 + fogcolor[2] * f2) * r_colorscale;
+                       c[3] *= ent->alpha;
                }
        }
-       else
+       else if (r_colorscale != 1 || ent->alpha != 1)
        {
-               for (i = 0, c = varray_color4f;i < 6;i++, c += 4)
+               memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
+               GL_ColorPointer(color4f);
+               for (i = 0, c = color4f;i < 6;i++, c += 4)
                {
                        c[0] *= r_colorscale;
                        c[1] *= r_colorscale;
                        c[2] *= r_colorscale;
+                       c[3] *= ent->alpha;
                }
        }
+       else
+               GL_ColorPointer(nomodelcolor4f);
        R_Mesh_Draw(6, 8, nomodelelements);
 }
 
@@ -1416,13 +1440,31 @@ void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, flo
        vert[11] = org2[2] + width * right2[2];
 }
 
-void R_DrawSpriteMesh(const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2)
+float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
+
+void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, int depthdisable, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2, float cr, float cg, float cb, float ca)
 {
-       R_Mesh_GetSpace(4);
-       varray_texcoord2f[0][0] = 0;varray_texcoord2f[0][1] = 1;
-       varray_texcoord2f[0][2] = 0;varray_texcoord2f[0][3] = 0;
-       varray_texcoord2f[0][4] = 1;varray_texcoord2f[0][5] = 0;
-       varray_texcoord2f[0][6] = 1;varray_texcoord2f[0][7] = 1;
+       float diff[3];
+       rmeshstate_t m;
+
+       if (fogenabled)
+       {
+               VectorSubtract(origin, r_origin, diff);
+               ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
+       }
+
+       R_Mesh_Matrix(&r_identitymatrix);
+       GL_Color(cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
+       GL_VertexPointer(varray_vertex3f);
+       GL_BlendFunc(blendfunc1, blendfunc2);
+       GL_DepthMask(false);
+       GL_DepthTest(!depthdisable);
+
+       memset(&m, 0, sizeof(m));
+       m.tex[0] = R_GetTexture(texture);
+       m.pointer_texcoord[0] = spritetexcoord2f;
+       R_Mesh_State_Texture(&m);
+
        varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
        varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
        varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
index f35c425..252d7e2 100644 (file)
@@ -741,33 +741,33 @@ static void RSurfShader_Sky(const entity_render_t *ent, const texture_t *texture
 
        R_Mesh_Matrix(&ent->matrix);
 
-       // draw depth-only polys
-       memset(&m, 0, sizeof(m));
+       GL_Color(fogcolor[0] * r_colorscale, fogcolor[1] * r_colorscale, fogcolor[2] * r_colorscale, 1);
        if (skyrendermasked)
        {
+               // depth-only (masking)
                qglColorMask(0,0,0,0);
                // just to make sure that braindead drivers don't draw anything
                // despite that colormask...
-               m.blendfunc1 = GL_ZERO;
-               m.blendfunc2 = GL_ONE;
+               GL_BlendFunc(GL_ZERO, GL_ONE);
        }
        else
        {
                // fog sky
-               m.blendfunc1 = GL_ONE;
-               m.blendfunc2 = GL_ZERO;
+               GL_BlendFunc(GL_ONE, GL_ZERO);
        }
-       m.depthwrite = true;
-       R_Mesh_State(&m);
+       GL_DepthMask(true);
+       GL_DepthTest(true);
+
+       memset(&m, 0, sizeof(m));
+       R_Mesh_State_Texture(&m);
+
        while((surf = *surfchain++) != NULL)
        {
                if (surf->visframe == r_framecount)
                {
                        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                        {
-                               GL_Color(fogcolor[0] * r_colorscale, fogcolor[1] * r_colorscale, fogcolor[2] * r_colorscale, 1);
-                               R_Mesh_GetSpace(mesh->numverts);
-                               R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
+                               GL_VertexPointer(mesh->vertex3f);
                                R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
                        }
                }
@@ -785,27 +785,32 @@ static void RSurfShader_Water_Callback(const void *calldata1, int calldata2)
        float alpha;
        float modelorg[3];
        texture_t *texture;
-       Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
+       matrix4x4_t tempmatrix;
+
+       // scrolling in texture matrix
+       Matrix4x4_CreateTranslate(&tempmatrix, sin(cl.time) * 0.125, sin(cl.time * 0.8f) * 0.125, 0);
+       R_Mesh_TextureMatrix(0, &tempmatrix);
 
        R_Mesh_Matrix(&ent->matrix);
+       Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
 
        memset(&m, 0, sizeof(m));
        texture = surf->texinfo->texture->currentframe;
        alpha = texture->currentalpha;
        if (texture->rendertype == SURFRENDER_ADD)
        {
-               m.blendfunc1 = GL_SRC_ALPHA;
-               m.blendfunc2 = GL_ONE;
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+               GL_DepthMask(false);
        }
        else if (texture->rendertype == SURFRENDER_ALPHA)
        {
-               m.blendfunc1 = GL_SRC_ALPHA;
-               m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               GL_DepthMask(false);
        }
        else
        {
-               m.blendfunc1 = GL_ONE;
-               m.blendfunc2 = GL_ZERO;
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_DepthMask(true);
        }
        m.tex[0] = R_GetTexture(texture->skin.base);
        colorscale = r_colorscale;
@@ -814,13 +819,13 @@ static void RSurfShader_Water_Callback(const void *calldata1, int calldata2)
                m.texrgbscale[0] = 4;
                colorscale *= 0.25f;
        }
-       R_Mesh_State(&m);
-       GL_UseColorArray();
+       GL_DepthTest(true);
+       GL_ColorPointer(varray_color4f);
        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
        {
-               R_Mesh_GetSpace(mesh->numverts);
-               R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-               R_ScrollTexCoord2f(varray_texcoord2f[0], mesh->texcoordtexture2f, mesh->numverts, sin(cl.time) * 0.125f, sin(cl.time * 0.8f) * 0.125f);
+               GL_VertexPointer(mesh->vertex3f);
+               m.pointer_texcoord[0] = mesh->texcoordtexture2f;
+               R_Mesh_State_Texture(&m);
                f = surf->flags & SURF_DRAWFULLBRIGHT ? 1.0f : ((surf->flags & SURF_LIGHTMAP) ? 0 : 0.5f);
                R_FillColors(varray_color4f, mesh->numverts, f, f, f, alpha);
                if (!(surf->flags & SURF_DRAWFULLBRIGHT || ent->effects & EF_FULLBRIGHT))
@@ -837,20 +842,23 @@ static void RSurfShader_Water_Callback(const void *calldata1, int calldata2)
        if (fogenabled)
        {
                memset(&m, 0, sizeof(m));
-               m.blendfunc1 = GL_SRC_ALPHA;
-               m.blendfunc2 = GL_ONE;
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+               GL_DepthMask(false);
+               GL_DepthTest(true);
                m.tex[0] = R_GetTexture(texture->skin.fog);
-               R_Mesh_State(&m);
                for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                {
-                       R_Mesh_GetSpace(mesh->numverts);
-                       R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-                       if (m.tex[0])
-                               R_Mesh_CopyTexCoord2f(0, mesh->texcoordtexture2f, mesh->numverts);
+                       GL_VertexPointer(mesh->vertex3f);
+                       m.pointer_texcoord[0] = mesh->texcoordtexture2f;
+                       GL_ColorPointer(varray_color4f);
+                       R_Mesh_State_Texture(&m);
                        RSurf_FogPassColors_Vertex3f_Color4f(mesh->vertex3f, varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], alpha, r_colorscale, mesh->numverts, modelorg);
                        R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
                }
        }
+
+       Matrix4x4_CreateIdentity(&tempmatrix);
+       R_Mesh_TextureMatrix(0, &tempmatrix);
 }
 
 static void RSurfShader_Water(const entity_render_t *ent, const texture_t *texture, msurface_t **surfchain)
@@ -880,25 +888,23 @@ static void RSurfShader_Wall_Pass_BaseVertex(const entity_render_t *ent, const m
        float base, colorscale;
        const surfmesh_t *mesh;
        rmeshstate_t m;
-       rcachearrayrequest_t request;
        float modelorg[3];
        Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
-       memset(&request, 0, sizeof(request));
        memset(&m, 0, sizeof(m));
        if (rendertype == SURFRENDER_ADD)
        {
-               m.blendfunc1 = GL_SRC_ALPHA;
-               m.blendfunc2 = GL_ONE;
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+               GL_DepthMask(false);
        }
        else if (rendertype == SURFRENDER_ALPHA)
        {
-               m.blendfunc1 = GL_SRC_ALPHA;
-               m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               GL_DepthMask(false);
        }
        else
        {
-               m.blendfunc1 = GL_ONE;
-               m.blendfunc2 = GL_ZERO;
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_DepthMask(true);
        }
        m.tex[0] = R_GetTexture(texture->skin.base);
        colorscale = r_colorscale;
@@ -908,53 +914,23 @@ static void RSurfShader_Wall_Pass_BaseVertex(const entity_render_t *ent, const m
                colorscale *= 0.25f;
        }
        base = ent->effects & EF_FULLBRIGHT ? 2.0f : r_ambient.value * (1.0f / 64.0f);
-       R_Mesh_State(&m);
-       GL_UseColorArray();
+       GL_DepthTest(true);
+       GL_ColorPointer(varray_color4f);
        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
        {
-               if (gl_mesh_copyarrays.integer)
-               {
-                       R_Mesh_GetSpace(mesh->numverts);
-                       R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-                       R_Mesh_CopyTexCoord2f(0, mesh->texcoordtexture2f, mesh->numverts);
-                       R_FillColors(varray_color4f, mesh->numverts, base, base, base, currentalpha);
-                       if (!(ent->effects & EF_FULLBRIGHT))
-                       {
-                               if (surf->dlightframe == r_framecount)
-                                       RSurf_LightSeparate_Vertex3f_Color4f(&ent->inversematrix, surf->dlightbits, mesh->numverts, mesh->vertex3f, varray_color4f, 1);
-                               if (surf->flags & SURF_LIGHTMAP)
-                                       RSurf_AddLightmapToVertexColors_Color4f(mesh->lightmapoffsets, varray_color4f, mesh->numverts, surf->samples, ((surf->extents[0]>>4)+1)*((surf->extents[1]>>4)+1)*3, surf->styles);
-                       }
-                       RSurf_FogColors_Vertex3f_Color4f(mesh->vertex3f, varray_color4f, colorscale, mesh->numverts, modelorg);
-                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
-               }
-               else
+               GL_VertexPointer(mesh->vertex3f);
+               m.pointer_texcoord[0] = mesh->texcoordtexture2f;
+               R_Mesh_State_Texture(&m);
+               R_FillColors(varray_color4f, mesh->numverts, base, base, base, currentalpha);
+               if (!(ent->effects & EF_FULLBRIGHT))
                {
-                       m.pointervertexcount = mesh->numverts;
-                       m.pointer_vertex = mesh->vertex3f;
-                       m.pointer_texcoord[0] = mesh->texcoordtexture2f;
-                       // LordHavoc: this is not caching at all (difficult to
-                       // cache fogging information), it's just (ab)using the
-                       // cache system to get some memory
-                       request.data_size = mesh->numverts * sizeof(float[4]);
-                       request.id_pointer1 = ent;
-                       request.id_pointer2 = mesh;
-                       request.id_number1 = r_framecount;
-                       if (R_Mesh_CacheArray(&request))
-                       {
-                               R_FillColors(request.data, mesh->numverts, base, base, base, currentalpha);
-                               if (!(ent->effects & EF_FULLBRIGHT))
-                               {
-                                       if (surf->dlightframe == r_framecount)
-                                               RSurf_LightSeparate_Vertex3f_Color4f(&ent->inversematrix, surf->dlightbits, mesh->numverts, mesh->vertex3f, request.data, 1);
-                                       if (surf->flags & SURF_LIGHTMAP)
-                                               RSurf_AddLightmapToVertexColors_Color4f(mesh->lightmapoffsets, request.data, mesh->numverts, surf->samples, ((surf->extents[0]>>4)+1)*((surf->extents[1]>>4)+1)*3, surf->styles);
-                               }
-                               RSurf_FogColors_Vertex3f_Color4f(mesh->vertex3f, request.data, colorscale, mesh->numverts, modelorg);
-                       }
-                       m.pointer_color = request.data;
-                       R_Mesh_State(&m);
+                       if (surf->dlightframe == r_framecount)
+                               RSurf_LightSeparate_Vertex3f_Color4f(&ent->inversematrix, surf->dlightbits, mesh->numverts, mesh->vertex3f, varray_color4f, 1);
+                       if (surf->flags & SURF_LIGHTMAP)
+                               RSurf_AddLightmapToVertexColors_Color4f(mesh->lightmapoffsets, varray_color4f, mesh->numverts, surf->samples, ((surf->extents[0]>>4)+1)*((surf->extents[1]>>4)+1)*3, surf->styles);
                }
+               RSurf_FogColors_Vertex3f_Color4f(mesh->vertex3f, varray_color4f, colorscale, mesh->numverts, modelorg);
+               R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
        }
 }
 
@@ -962,43 +938,21 @@ static void RSurfShader_Wall_Pass_Glow(const entity_render_t *ent, const msurfac
 {
        const surfmesh_t *mesh;
        rmeshstate_t m;
-       rcachearrayrequest_t request;
        float modelorg[3];
        Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
-       memset(&request, 0, sizeof(request));
        memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_SRC_ALPHA;
-       m.blendfunc2 = GL_ONE;
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
        m.tex[0] = R_GetTexture(texture->skin.glow);
-       R_Mesh_State(&m);
-       GL_UseColorArray();
+       GL_ColorPointer(varray_color4f);
        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
        {
-               if (gl_mesh_copyarrays.integer)
-               {
-                       R_Mesh_GetSpace(mesh->numverts);
-                       R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-                       R_Mesh_CopyTexCoord2f(0, mesh->texcoordtexture2f, mesh->numverts);
-                       RSurf_FoggedColors_Vertex3f_Color4f(mesh->vertex3f, varray_color4f, 1, 1, 1, currentalpha, r_colorscale, mesh->numverts, modelorg);
-               }
-               else
-               {
-                       m.pointervertexcount = mesh->numverts;
-                       m.pointer_vertex = mesh->vertex3f;
-                       if (m.tex[0])
-                               m.pointer_texcoord[0] = mesh->texcoordtexture2f;
-                       // LordHavoc: this is not caching at all (difficult to
-                       // cache fogging information), it's just (ab)using the
-                       // cache system to get some memory
-                       request.data_size = mesh->numverts * sizeof(float[4]);
-                       request.id_pointer1 = ent;
-                       request.id_pointer2 = mesh;
-                       request.id_number1 = r_framecount;
-                       if (R_Mesh_CacheArray(&request))
-                               RSurf_FoggedColors_Vertex3f_Color4f(mesh->vertex3f, request.data, 1, 1, 1, currentalpha, r_colorscale, mesh->numverts, modelorg);
-                       m.pointer_color = request.data;
-                       R_Mesh_State(&m);
-               }
+               GL_VertexPointer(mesh->vertex3f);
+               if (m.tex[0])
+                       m.pointer_texcoord[0] = mesh->texcoordtexture2f;
+               R_Mesh_State_Texture(&m);
+               RSurf_FoggedColors_Vertex3f_Color4f(mesh->vertex3f, varray_color4f, 1, 1, 1, currentalpha, r_colorscale, mesh->numverts, modelorg);
                R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
        }
 }
@@ -1007,44 +961,21 @@ static void RSurfShader_Wall_Pass_Fog(const entity_render_t *ent, const msurface
 {
        const surfmesh_t *mesh;
        rmeshstate_t m;
-       rcachearrayrequest_t request;
        float modelorg[3];
        Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
-       memset(&request, 0, sizeof(request));
        memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_SRC_ALPHA;
-       m.blendfunc2 = GL_ONE;
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
        m.tex[0] = R_GetTexture(texture->skin.fog);
-       R_Mesh_State(&m);
-       GL_UseColorArray();
+       GL_ColorPointer(varray_color4f);
        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
        {
-               if (gl_mesh_copyarrays.integer)
-               {
-                       R_Mesh_GetSpace(mesh->numverts);
-                       R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-                       if (m.tex[0])
-                               R_Mesh_CopyTexCoord2f(0, mesh->texcoordtexture2f, mesh->numverts);
-                       RSurf_FogPassColors_Vertex3f_Color4f(mesh->vertex3f, varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], currentalpha, r_colorscale, mesh->numverts, modelorg);
-               }
-               else
-               {
-                       m.pointervertexcount = mesh->numverts;
-                       m.pointer_vertex = mesh->vertex3f;
-                       if (m.tex[0])
-                               m.pointer_texcoord[0] = mesh->texcoordtexture2f;
-                       // LordHavoc: this is not caching at all (difficult to
-                       // cache fogging information), it's just (ab)using the
-                       // cache system to get some memory
-                       request.data_size = mesh->numverts * sizeof(float[4]);
-                       request.id_pointer1 = ent;
-                       request.id_pointer2 = mesh;
-                       request.id_number1 = r_framecount;
-                       if (R_Mesh_CacheArray(&request))
-                               RSurf_FogPassColors_Vertex3f_Color4f(mesh->vertex3f, request.data, fogcolor[0], fogcolor[1], fogcolor[2], currentalpha, r_colorscale, mesh->numverts, modelorg);
-                       m.pointer_color = request.data;
-                       R_Mesh_State(&m);
-               }
+               GL_VertexPointer(mesh->vertex3f);
+               if (m.tex[0])
+                       m.pointer_texcoord[0] = mesh->texcoordtexture2f;
+               R_Mesh_State_Texture(&m);
+               RSurf_FogPassColors_Vertex3f_Color4f(mesh->vertex3f, varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], currentalpha, r_colorscale, mesh->numverts, modelorg);
                R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
        }
 }
@@ -1057,15 +988,15 @@ static void RSurfShader_OpaqueWall_Pass_BaseTripleTexCombine(const entity_render
        int lightmaptexturenum;
        float cl;
        memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_ONE;
-       m.blendfunc2 = GL_ZERO;
+       GL_BlendFunc(GL_ONE, GL_ZERO);
+       GL_DepthMask(true);
+       GL_DepthTest(true);
        m.tex[0] = R_GetTexture(texture->skin.base);
        m.tex[1] = R_GetTexture((**surfchain).lightmaptexture);
        m.tex[2] = R_GetTexture(texture->skin.detail);
        m.texrgbscale[0] = 1;
        m.texrgbscale[1] = 4;
        m.texrgbscale[2] = 2;
-       R_Mesh_State(&m);
        cl = (float) (1 << r_lightmapscalebit) * r_colorscale;
        GL_Color(cl, cl, cl, 1);
 
@@ -1074,31 +1005,18 @@ static void RSurfShader_OpaqueWall_Pass_BaseTripleTexCombine(const entity_render
                if (surf->visframe == r_framecount)
                {
                        lightmaptexturenum = R_GetTexture(surf->lightmaptexture);
-                       if (m.tex[1] != lightmaptexturenum)
-                       {
+                       //if (m.tex[1] != lightmaptexturenum)
+                       //{
                                m.tex[1] = lightmaptexturenum;
-                               if (gl_mesh_copyarrays.integer)
-                                       R_Mesh_State(&m);
-                       }
+                       //      R_Mesh_State_Texture(&m);
+                       //}
                        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                        {
-                               if (gl_mesh_copyarrays.integer)
-                               {
-                                       R_Mesh_GetSpace(mesh->numverts);
-                                       R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-                                       R_Mesh_CopyTexCoord2f(0, mesh->texcoordtexture2f, mesh->numverts);
-                                       R_Mesh_CopyTexCoord2f(1, mesh->texcoordlightmap2f, mesh->numverts);
-                                       R_Mesh_CopyTexCoord2f(2, mesh->texcoorddetail2f, mesh->numverts);
-                               }
-                               else
-                               {
-                                       m.pointervertexcount = mesh->numverts;
-                                       m.pointer_vertex = mesh->vertex3f;
-                                       m.pointer_texcoord[0] = mesh->texcoordtexture2f;
-                                       m.pointer_texcoord[1] = mesh->texcoordlightmap2f;
-                                       m.pointer_texcoord[2] = mesh->texcoorddetail2f;
-                                       R_Mesh_State(&m);
-                               }
+                               GL_VertexPointer(mesh->vertex3f);
+                               m.pointer_texcoord[0] = mesh->texcoordtexture2f;
+                               m.pointer_texcoord[1] = mesh->texcoordlightmap2f;
+                               m.pointer_texcoord[2] = mesh->texcoorddetail2f;
+                               R_Mesh_State_Texture(&m);
                                R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
                        }
                }
@@ -1112,41 +1030,30 @@ static void RSurfShader_OpaqueWall_Pass_BaseDoubleTex(const entity_render_t *ent
        rmeshstate_t m;
        int lightmaptexturenum;
        memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_ONE;
-       m.blendfunc2 = GL_ZERO;
+       GL_BlendFunc(GL_ONE, GL_ZERO);
+       GL_DepthMask(true);
+       GL_DepthTest(true);
        m.tex[0] = R_GetTexture(texture->skin.base);
        m.tex[1] = R_GetTexture((**surfchain).lightmaptexture);
        if (gl_combine.integer)
                m.texrgbscale[1] = 4;
-       R_Mesh_State(&m);
        GL_Color(r_colorscale, r_colorscale, r_colorscale, 1);
        while((surf = *surfchain++) != NULL)
        {
                if (surf->visframe == r_framecount)
                {
                        lightmaptexturenum = R_GetTexture(surf->lightmaptexture);
-                       if (m.tex[1] != lightmaptexturenum)
-                       {
+                       //if (m.tex[1] != lightmaptexturenum)
+                       //{
                                m.tex[1] = lightmaptexturenum;
-                               R_Mesh_State(&m);
-                       }
+                       //      R_Mesh_State_Texture(&m);
+                       //}
                        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                        {
-                               if (gl_mesh_copyarrays.integer)
-                               {
-                                       R_Mesh_GetSpace(mesh->numverts);
-                                       R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-                                       R_Mesh_CopyTexCoord2f(0, mesh->texcoordtexture2f, mesh->numverts);
-                                       R_Mesh_CopyTexCoord2f(1, mesh->texcoordlightmap2f, mesh->numverts);
-                               }
-                               else
-                               {
-                                       m.pointervertexcount = mesh->numverts;
-                                       m.pointer_vertex = mesh->vertex3f;
-                                       m.pointer_texcoord[0] = mesh->texcoordtexture2f;
-                                       m.pointer_texcoord[1] = mesh->texcoordlightmap2f;
-                                       R_Mesh_State(&m);
-                               }
+                               GL_VertexPointer(mesh->vertex3f);
+                               m.pointer_texcoord[0] = mesh->texcoordtexture2f;
+                               m.pointer_texcoord[1] = mesh->texcoordlightmap2f;
+                               R_Mesh_State_Texture(&m);
                                R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
                        }
                }
@@ -1159,10 +1066,10 @@ static void RSurfShader_OpaqueWall_Pass_BaseTexture(const entity_render_t *ent,
        const surfmesh_t *mesh;
        rmeshstate_t m;
        memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_ONE;
-       m.blendfunc2 = GL_ZERO;
+       GL_DepthMask(true);
+       GL_DepthTest(true);
+       GL_BlendFunc(GL_ONE, GL_ZERO);
        m.tex[0] = R_GetTexture(texture->skin.base);
-       R_Mesh_State(&m);
        GL_Color(1, 1, 1, 1);
        while((surf = *surfchain++) != NULL)
        {
@@ -1170,19 +1077,9 @@ static void RSurfShader_OpaqueWall_Pass_BaseTexture(const entity_render_t *ent,
                {
                        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                        {
-                               if (gl_mesh_copyarrays.integer)
-                               {
-                                       R_Mesh_GetSpace(mesh->numverts);
-                                       R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-                                       R_Mesh_CopyTexCoord2f(0, mesh->texcoordtexture2f, mesh->numverts);
-                               }
-                               else
-                               {
-                                       m.pointervertexcount = mesh->numverts;
-                                       m.pointer_vertex = mesh->vertex3f;
-                                       m.pointer_texcoord[0] = mesh->texcoordtexture2f;
-                                       R_Mesh_State(&m);
-                               }
+                               GL_VertexPointer(mesh->vertex3f);
+                               m.pointer_texcoord[0] = mesh->texcoordtexture2f;
+                               R_Mesh_State_Texture(&m);
                                R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
                        }
                }
@@ -1196,38 +1093,28 @@ static void RSurfShader_OpaqueWall_Pass_BaseLightmap(const entity_render_t *ent,
        rmeshstate_t m;
        int lightmaptexturenum;
        memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_ZERO;
-       m.blendfunc2 = GL_SRC_COLOR;
+       GL_BlendFunc(GL_ZERO, GL_SRC_COLOR);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
        m.tex[0] = R_GetTexture((**surfchain).lightmaptexture);
        if (gl_combine.integer)
                m.texrgbscale[0] = 4;
-       R_Mesh_State(&m);
        GL_Color(r_colorscale, r_colorscale, r_colorscale, 1);
        while((surf = *surfchain++) != NULL)
        {
                if (surf->visframe == r_framecount)
                {
                        lightmaptexturenum = R_GetTexture(surf->lightmaptexture);
-                       if (m.tex[0] != lightmaptexturenum)
-                       {
+                       //if (m.tex[0] != lightmaptexturenum)
+                       //{
                                m.tex[0] = lightmaptexturenum;
-                               R_Mesh_State(&m);
-                       }
+                       //      R_Mesh_State_Texture(&m);
+                       //}
                        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                        {
-                               if (gl_mesh_copyarrays.integer)
-                               {
-                                       R_Mesh_GetSpace(mesh->numverts);
-                                       R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-                                       R_Mesh_CopyTexCoord2f(0, mesh->texcoordlightmap2f, mesh->numverts);
-                               }
-                               else
-                               {
-                                       m.pointervertexcount = mesh->numverts;
-                                       m.pointer_vertex = mesh->vertex3f;
-                                       m.pointer_texcoord[0] = mesh->texcoordlightmap2f;
-                                       R_Mesh_State(&m);
-                               }
+                               GL_VertexPointer(mesh->vertex3f);
+                               m.pointer_texcoord[0] = mesh->texcoordlightmap2f;
+                               R_Mesh_State_Texture(&m);
                                R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
                        }
                }
@@ -1239,13 +1126,12 @@ static void RSurfShader_OpaqueWall_Pass_Light(const entity_render_t *ent, const
        const msurface_t *surf;
        const surfmesh_t *mesh;
        float colorscale;
-       rcachearrayrequest_t request;
        rmeshstate_t m;
 
-       memset(&request, 0, sizeof(request));
        memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_SRC_ALPHA;
-       m.blendfunc2 = GL_ONE;
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
        m.tex[0] = R_GetTexture(texture->skin.base);
        colorscale = r_colorscale;
        if (gl_combine.integer)
@@ -1253,8 +1139,7 @@ static void RSurfShader_OpaqueWall_Pass_Light(const entity_render_t *ent, const
                m.texrgbscale[0] = 4;
                colorscale *= 0.25f;
        }
-       R_Mesh_State(&m);
-       GL_UseColorArray();
+       GL_ColorPointer(varray_color4f);
        while((surf = *surfchain++) != NULL)
        {
                if (surf->visframe == r_framecount && surf->dlightframe == r_framecount)
@@ -1263,34 +1148,11 @@ static void RSurfShader_OpaqueWall_Pass_Light(const entity_render_t *ent, const
                        {
                                if (RSurf_LightCheck(&ent->inversematrix, surf->dlightbits, mesh))
                                {
-                                       if (gl_mesh_copyarrays.integer)
-                                       {
-                                               R_Mesh_GetSpace(mesh->numverts);
-                                               R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-                                               R_Mesh_CopyTexCoord2f(0, mesh->texcoordtexture2f, mesh->numverts);
-                                               R_FillColors(varray_color4f, mesh->numverts, 0, 0, 0, 1);
-                                               RSurf_LightSeparate_Vertex3f_Color4f(&ent->inversematrix, surf->dlightbits, mesh->numverts, mesh->vertex3f, varray_color4f, colorscale);
-                                       }
-                                       else
-                                       {
-                                               m.pointervertexcount = mesh->numverts;
-                                               m.pointer_vertex = mesh->vertex3f;
-                                               m.pointer_texcoord[0] = mesh->texcoordtexture2f;
-                                               // LordHavoc: this is not caching at all (difficult to
-                                               // cache lighting information), it's just (ab)using the
-                                               // cache system to get some memory
-                                               request.data_size = mesh->numverts * sizeof(float[4]);
-                                               request.id_pointer1 = ent;
-                                               request.id_pointer2 = mesh;
-                                               request.id_number1 = r_framecount;
-                                               if (R_Mesh_CacheArray(&request))
-                                               {
-                                                       R_FillColors(request.data, mesh->numverts, 0, 0, 0, 1);
-                                                       RSurf_LightSeparate_Vertex3f_Color4f(&ent->inversematrix, surf->dlightbits, mesh->numverts, mesh->vertex3f, request.data, colorscale);
-                                               }
-                                               m.pointer_color = request.data;
-                                               R_Mesh_State(&m);
-                                       }
+                                       GL_VertexPointer(mesh->vertex3f);
+                                       m.pointer_texcoord[0] = mesh->texcoordtexture2f;
+                                       R_FillColors(varray_color4f, mesh->numverts, 0, 0, 0, 1);
+                                       R_Mesh_State_Texture(&m);
+                                       RSurf_LightSeparate_Vertex3f_Color4f(&ent->inversematrix, surf->dlightbits, mesh->numverts, mesh->vertex3f, varray_color4f, colorscale);
                                        R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
                                }
                        }
@@ -1302,48 +1164,25 @@ static void RSurfShader_OpaqueWall_Pass_Fog(const entity_render_t *ent, const te
 {
        const msurface_t *surf;
        const surfmesh_t *mesh;
-       rcachearrayrequest_t request;
        rmeshstate_t m;
        float modelorg[3];
        Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
-       memset(&request, 0, sizeof(request));
        memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_SRC_ALPHA;
-       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
-       R_Mesh_State(&m);
-       GL_UseColorArray();
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
+       GL_ColorPointer(varray_color4f);
        while((surf = *surfchain++) != NULL)
        {
                if (surf->visframe == r_framecount)
                {
                        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                        {
-                               if (gl_mesh_copyarrays.integer)
-                               {
-                                       R_Mesh_GetSpace(mesh->numverts);
-                                       R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-                                       if (m.tex[0])
-                                               R_Mesh_CopyTexCoord2f(0, mesh->texcoordtexture2f, mesh->numverts);
-                                       RSurf_FogPassColors_Vertex3f_Color4f(mesh->vertex3f, varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], 1, r_colorscale, mesh->numverts, modelorg);
-                               }
-                               else
-                               {
-                                       m.pointervertexcount = mesh->numverts;
-                                       m.pointer_vertex = mesh->vertex3f;
-                                       if (m.tex[0])
-                                               m.pointer_texcoord[0] = mesh->texcoordtexture2f;
-                                       // LordHavoc: this is not caching at all (difficult to
-                                       // cache fogging information), it's just (ab)using the
-                                       // cache system to get some memory
-                                       request.data_size = mesh->numverts * sizeof(float[4]);
-                                       request.id_pointer1 = ent;
-                                       request.id_pointer2 = mesh;
-                                       request.id_number1 = r_framecount;
-                                       if (R_Mesh_CacheArray(&request))
-                                               RSurf_FogPassColors_Vertex3f_Color4f(mesh->vertex3f, request.data, fogcolor[0], fogcolor[1], fogcolor[2], 1, r_colorscale, mesh->numverts, modelorg);
-                                       m.pointer_color = request.data;
-                                       R_Mesh_State(&m);
-                               }
+                               GL_VertexPointer(mesh->vertex3f);
+                               if (m.tex[0])
+                                       m.pointer_texcoord[0] = mesh->texcoordtexture2f;
+                               R_Mesh_State_Texture(&m);
+                               RSurf_FogPassColors_Vertex3f_Color4f(mesh->vertex3f, varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], 1, r_colorscale, mesh->numverts, modelorg);
                                R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
                        }
                }
@@ -1356,10 +1195,10 @@ static void RSurfShader_OpaqueWall_Pass_BaseDetail(const entity_render_t *ent, c
        const surfmesh_t *mesh;
        rmeshstate_t m;
        memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_DST_COLOR;
-       m.blendfunc2 = GL_SRC_COLOR;
+       GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
        m.tex[0] = R_GetTexture(texture->skin.detail);
-       R_Mesh_State(&m);
        GL_Color(1, 1, 1, 1);
        while((surf = *surfchain++) != NULL)
        {
@@ -1367,19 +1206,9 @@ static void RSurfShader_OpaqueWall_Pass_BaseDetail(const entity_render_t *ent, c
                {
                        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                        {
-                               if (gl_mesh_copyarrays.integer)
-                               {
-                                       R_Mesh_GetSpace(mesh->numverts);
-                                       R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-                                       R_Mesh_CopyTexCoord2f(0, mesh->texcoorddetail2f, mesh->numverts);
-                               }
-                               else
-                               {
-                                       m.pointervertexcount = mesh->numverts;
-                                       m.pointer_vertex = mesh->vertex3f;
-                                       m.pointer_texcoord[0] = mesh->texcoorddetail2f;
-                                       R_Mesh_State(&m);
-                               }
+                               GL_VertexPointer(mesh->vertex3f);
+                               m.pointer_texcoord[0] = mesh->texcoorddetail2f;
+                               R_Mesh_State_Texture(&m);
                                R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
                        }
                }
@@ -1392,10 +1221,10 @@ static void RSurfShader_OpaqueWall_Pass_Glow(const entity_render_t *ent, const t
        const surfmesh_t *mesh;
        rmeshstate_t m;
        memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_SRC_ALPHA;
-       m.blendfunc2 = GL_ONE;
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
        m.tex[0] = R_GetTexture(texture->skin.glow);
-       R_Mesh_State(&m);
        GL_Color(r_colorscale, r_colorscale, r_colorscale, 1);
        while((surf = *surfchain++) != NULL)
        {
@@ -1403,19 +1232,9 @@ static void RSurfShader_OpaqueWall_Pass_Glow(const entity_render_t *ent, const t
                {
                        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                        {
-                               if (gl_mesh_copyarrays.integer)
-                               {
-                                       R_Mesh_GetSpace(mesh->numverts);
-                                       R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-                                       R_Mesh_CopyTexCoord2f(0, mesh->texcoordtexture2f, mesh->numverts);
-                               }
-                               else
-                               {
-                                       m.pointervertexcount = mesh->numverts;
-                                       m.pointer_vertex = mesh->vertex3f;
-                                       m.pointer_texcoord[0] = mesh->texcoordtexture2f;
-                                       R_Mesh_State(&m);
-                               }
+                               GL_VertexPointer(mesh->vertex3f);
+                               m.pointer_texcoord[0] = mesh->texcoordtexture2f;
+                               R_Mesh_State_Texture(&m);
                                R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
                        }
                }
@@ -1428,10 +1247,9 @@ static void RSurfShader_OpaqueWall_Pass_OpaqueGlow(const entity_render_t *ent, c
        const surfmesh_t *mesh;
        rmeshstate_t m;
        memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_SRC_ALPHA;
-       m.blendfunc2 = GL_ZERO;
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
+       GL_DepthMask(true);
        m.tex[0] = R_GetTexture(texture->skin.glow);
-       R_Mesh_State(&m);
        if (m.tex[0])
                GL_Color(r_colorscale, r_colorscale, r_colorscale, 1);
        else
@@ -1442,19 +1260,9 @@ static void RSurfShader_OpaqueWall_Pass_OpaqueGlow(const entity_render_t *ent, c
                {
                        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                        {
-                               if (gl_mesh_copyarrays.integer)
-                               {
-                                       R_Mesh_GetSpace(mesh->numverts);
-                                       R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-                                       R_Mesh_CopyTexCoord2f(0, mesh->texcoordtexture2f, mesh->numverts);
-                               }
-                               else
-                               {
-                                       m.pointervertexcount = mesh->numverts;
-                                       m.pointer_vertex = mesh->vertex3f;
-                                       m.pointer_texcoord[0] = mesh->texcoordtexture2f;
-                                       R_Mesh_State(&m);
-                               }
+                               GL_VertexPointer(mesh->vertex3f);
+                               m.pointer_texcoord[0] = mesh->texcoordtexture2f;
+                               R_Mesh_State_Texture(&m);
                                R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
                        }
                }
@@ -1689,12 +1497,15 @@ static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
        rmeshstate_t m;
        const entity_render_t *ent = calldata1;
        const mportal_t *portal = ent->model->portals + calldata2;
-       memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_SRC_ALPHA;
-       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
        R_Mesh_Matrix(&ent->matrix);
-       R_Mesh_State(&m);
-       R_Mesh_GetSpace(portal->numpoints);
+       GL_VertexPointer(varray_vertex3f);
+
+       memset(&m, 0, sizeof(m));
+       R_Mesh_State_Texture(&m);
+
        i = portal - ent->model->portals;
        GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_colorscale,
                         ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_colorscale,
@@ -2015,14 +1826,8 @@ void R_Model_Brush_DrawShadowVolume (entity_render_t *ent, vec3_t relativelighto
                                temp[1] = bound(surf->poly_mins[1], relativelightorigin[1], surf->poly_maxs[1]) - relativelightorigin[1];
                                temp[2] = bound(surf->poly_mins[2], relativelightorigin[2], surf->poly_maxs[2]) - relativelightorigin[2];
                                if (DotProduct(temp, temp) < lightradius2)
-                               {
                                        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
-                                       {
-                                               R_Mesh_GetSpace(mesh->numverts);
-                                               R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-                                               R_Shadow_Volume(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->neighbor3i, relativelightorigin, lightradius, projectdistance);
-                                       }
-                               }
+                                               R_Shadow_Volume(mesh->numverts, mesh->numtriangles, mesh->vertex3f, mesh->element3i, mesh->neighbor3i, relativelightorigin, lightradius, projectdistance);
                        }
                }
        }
@@ -2073,57 +1878,22 @@ void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v
        lightmaxs[1] = relativelightorigin[1] + lightradius;
        lightmaxs[2] = relativelightorigin[2] + lightradius;
        R_UpdateTextureInfo(ent);
-       if (ent != &cl_entities[0].render)
+       for (surfnum = 0, surf = ent->model->surfaces + ent->model->firstmodelsurface;surfnum < ent->model->nummodelsurfaces;surfnum++, surf++)
        {
-               // bmodel, cull crudely to view and light
-               for (surfnum = 0, surf = ent->model->surfaces + ent->model->firstmodelsurface;surfnum < ent->model->nummodelsurfaces;surfnum++, surf++)
+               if ((ent != &cl_entities[0].render || surf->visframe == r_framecount) && BoxesOverlap(surf->poly_mins, surf->poly_maxs, lightmins, lightmaxs))
                {
-                       if (BoxesOverlap(surf->poly_mins, surf->poly_maxs, lightmins, lightmaxs))
-                       {
-                               f = PlaneDiff(relativelightorigin, surf->plane);
-                               if (surf->flags & SURF_PLANEBACK)
-                                       f = -f;
-                               if (f >= -0.1 && f < lightradius)
-                               {
-                                       f = PlaneDiff(relativeeyeorigin, surf->plane);
-                                       if (surf->flags & SURF_PLANEBACK)
-                                               f = -f;
-                                       if (f > 0)
-                                       {
-                                               t = surf->texinfo->texture->currentframe;
-                                               if (t->rendertype == SURFRENDER_OPAQUE && t->flags & SURF_SHADOWLIGHT)
-                                               {
-                                                       for (mesh = surf->mesh;mesh;mesh = mesh->chain)
-                                                       {
-                                                               R_Shadow_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoordtexture2f, relativelightorigin, lightradius, lightcolor, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, t->skin.nmap, NULL);
-                                                               R_Shadow_SpecularLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.gloss, t->skin.nmap, NULL);
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-       else
-       {
-               // world, already culled to view, just cull to light
-               for (surfnum = 0, surf = ent->model->surfaces + ent->model->firstmodelsurface;surfnum < ent->model->nummodelsurfaces;surfnum++, surf++)
-               {
-                       if (surf->visframe == r_framecount && BoxesOverlap(surf->poly_mins, surf->poly_maxs, lightmins, lightmaxs))
+                       f = PlaneDiff(relativelightorigin, surf->plane);
+                       if (surf->flags & SURF_PLANEBACK)
+                               f = -f;
+                       if (f >= -0.1 && f < lightradius)
                        {
-                               f = PlaneDiff(relativelightorigin, surf->plane);
-                               if (surf->flags & SURF_PLANEBACK)
-                                       f = -f;
-                               if (f >= -0.1 && f < lightradius)
+                               t = surf->texinfo->texture->currentframe;
+                               if (t->rendertype == SURFRENDER_OPAQUE && t->flags & SURF_SHADOWLIGHT)
                                {
-                                       t = surf->texinfo->texture->currentframe;
-                                       if (t->rendertype == SURFRENDER_OPAQUE && t->flags & SURF_SHADOWLIGHT)
+                                       for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                                        {
-                                               for (mesh = surf->mesh;mesh;mesh = mesh->chain)
-                                               {
-                                                       R_Shadow_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoordtexture2f, relativelightorigin, lightradius, lightcolor, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, t->skin.nmap, NULL);
-                                                       R_Shadow_SpecularLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.gloss, t->skin.nmap, NULL);
-                                               }
+                                               R_Shadow_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoordtexture2f, relativelightorigin, lightradius, lightcolor, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, t->skin.nmap, NULL);
+                                               R_Shadow_SpecularLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.gloss, t->skin.nmap, NULL);
                                        }
                                }
                        }
index 8ed0cca..e1ccf15 100644 (file)
@@ -55,6 +55,7 @@ static textypeinfo_t textype_rgba_alpha    = {TEXTYPE_RGBA   , 4, 4, GL_RGBA, 4}
 #define GLTEXTURETYPE_CUBEMAP 3
 
 static int gltexturetypeenums[4] = {GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
+static int gltexturetypebindingenums[4] = {GL_TEXTURE_BINDING_1D, GL_TEXTURE_BINDING_2D, GL_TEXTURE_BINDING_3D, GL_TEXTURE_BINDING_CUBE_MAP_ARB};
 static int gltexturetypedimensions[4] = {1, 2, 3, 2};
 static int cubemapside[6] =
 {
@@ -320,11 +321,10 @@ static glmode_t modes[] =
        {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
 };
 
-extern int gl_backend_rebindtextures;
-
 static void GL_TextureMode_f (void)
 {
        int i;
+       GLint oldbindtexnum;
        gltextureimage_t *image;
        gltexturepool_t *pool;
 
@@ -363,12 +363,14 @@ static void GL_TextureMode_f (void)
                        // only update already uploaded images
                        if (!(image->flags & GLTEXF_UPLOAD))
                        {
-                               qglBindTexture(GL_TEXTURE_2D, image->texnum);
+                               qglGetIntegerv(gltexturetypebindingenums[image->texturetype], &oldbindtexnum);
+                               qglBindTexture(gltexturetypeenums[image->texturetype], image->texnum);
                                if (image->flags & TEXF_MIPMAP)
-                                       qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+                                       qglTexParameteri(gltexturetypeenums[image->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);
                                else
-                                       qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_mag);
-                               qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_mag);
+                                       qglTexParameteri(gltexturetypeenums[image->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);
+                               qglTexParameteri(gltexturetypeenums[image->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);
+                               qglBindTexture(gltexturetypeenums[image->texturetype], oldbindtexnum);
                        }
                }
        }
@@ -603,19 +605,19 @@ static void GL_SetupTextureParameters(int flags, int texturetype)
 
 static void R_Upload(gltexture_t *glt, qbyte *data)
 {
-       int i, mip, width, height, depth, internalformat;
+       int i, mip, width, height, depth;
+       GLint oldbindtexnum;
        qbyte *prevbuffer;
        prevbuffer = data;
 
-       R_Mesh_EndBatch();
-
        CHECKGLERROR
 
        glt->texnum = glt->image->texnum;
+       // we need to restore the texture binding after finishing the upload
+       qglGetIntegerv(gltexturetypebindingenums[glt->image->texturetype], &oldbindtexnum);
        qglBindTexture(gltexturetypeenums[glt->image->texturetype], glt->image->texnum);
        CHECKGLERROR
        glt->flags &= ~GLTEXF_UPLOAD;
-       gl_backend_rebindtextures = true;
 
        if (glt->flags & TEXF_FRAGMENT)
        {
@@ -679,124 +681,85 @@ static void R_Upload(gltexture_t *glt, qbyte *data)
                        Host_Error("R_Upload: fragment texture of type other than 1D, 2D, or 3D\n");
                        break;
                }
-               glt->texnum = glt->image->texnum;
-               return;
-       }
-
-       glt->image->flags &= ~GLTEXF_UPLOAD;
-
-       // these are rounded up versions of the size to do better resampling
-       for (width  = 1;width  < glt->width ;width  <<= 1);
-       for (height = 1;height < glt->height;height <<= 1);
-       for (depth  = 1;depth  < glt->depth ;depth  <<= 1);
-
-       R_MakeResizeBufferBigger(width * height * depth * glt->image->sides * glt->image->bytesperpixel);
-
-       if (prevbuffer == NULL)
-       {
-               width = glt->image->width;
-               height = glt->image->height;
-               depth = glt->image->depth;
-               memset(resizebuffer, 255, width * height * depth * glt->image->bytesperpixel);
-               prevbuffer = resizebuffer;
        }
        else
        {
-               if (glt->textype->textype == TEXTYPE_PALETTE)
-               {
-                       // promote paletted to RGBA, so we only have to worry about RGB and
-                       // RGBA in the rest of this code
-                       Image_Copy8bitRGBA(prevbuffer, colorconvertbuffer, glt->width * glt->height * glt->depth * glt->image->sides, glt->palette);
-                       prevbuffer = colorconvertbuffer;
-               }
-       }
+               glt->image->flags &= ~GLTEXF_UPLOAD;
 
-       // 3 and 4 are converted by the driver to it's preferred format for the current display mode
-       internalformat = 3;
-       if (glt->flags & TEXF_ALPHA)
-               internalformat = 4;
+               // these are rounded up versions of the size to do better resampling
+               for (width  = 1;width  < glt->width ;width  <<= 1);
+               for (height = 1;height < glt->height;height <<= 1);
+               for (depth  = 1;depth  < glt->depth ;depth  <<= 1);
 
-       // cubemaps contain multiple images and thus get processed a bit differently
-       if (glt->image->texturetype != GLTEXTURETYPE_CUBEMAP)
-       {
-               if (glt->width != width || glt->height != height || glt->depth != depth)
-               {
-                       Image_Resample(prevbuffer, glt->width, glt->height, glt->depth, resizebuffer, width, height, depth, glt->image->bytesperpixel, r_lerpimages.integer);
-                       prevbuffer = resizebuffer;
-               }
-               // picmip/max_size
-               while (width > glt->image->width || height > glt->image->height || depth > glt->image->depth)
+               R_MakeResizeBufferBigger(width * height * depth * glt->image->sides * glt->image->bytesperpixel);
+
+               if (prevbuffer == NULL)
                {
-                       Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, glt->image->width, glt->image->height, glt->image->depth, glt->image->bytesperpixel);
+                       width = glt->image->width;
+                       height = glt->image->height;
+                       depth = glt->image->depth;
+                       memset(resizebuffer, 255, width * height * depth * glt->image->bytesperpixel);
                        prevbuffer = resizebuffer;
                }
-       }
-       mip = 0;
-       switch(glt->image->texturetype)
-       {
-       case GLTEXTURETYPE_1D:
-               qglTexImage1D(GL_TEXTURE_1D, mip++, internalformat, width, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
-               CHECKGLERROR
-               if (glt->flags & TEXF_MIPMAP)
+               else
                {
-                       while (width > 1 || height > 1 || depth > 1)
+                       if (glt->textype->textype == TEXTYPE_PALETTE)
                        {
-                               Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1, glt->image->bytesperpixel);
-                               prevbuffer = resizebuffer;
-                               qglTexImage1D(GL_TEXTURE_1D, mip++, internalformat, width, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
-                               CHECKGLERROR
+                               // promote paletted to RGBA, so we only have to worry about RGB and
+                               // RGBA in the rest of this code
+                               Image_Copy8bitRGBA(prevbuffer, colorconvertbuffer, glt->width * glt->height * glt->depth * glt->image->sides, glt->palette);
+                               prevbuffer = colorconvertbuffer;
                        }
                }
-               break;
-       case GLTEXTURETYPE_2D:
-               qglTexImage2D(GL_TEXTURE_2D, mip++, internalformat, width, height, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
-               CHECKGLERROR
-               if (glt->flags & TEXF_MIPMAP)
+
+               // cubemaps contain multiple images and thus get processed a bit differently
+               if (glt->image->texturetype != GLTEXTURETYPE_CUBEMAP)
                {
-                       while (width > 1 || height > 1 || depth > 1)
+                       if (glt->width != width || glt->height != height || glt->depth != depth)
                        {
-                               Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1, glt->image->bytesperpixel);
+                               Image_Resample(prevbuffer, glt->width, glt->height, glt->depth, resizebuffer, width, height, depth, glt->image->bytesperpixel, r_lerpimages.integer);
                                prevbuffer = resizebuffer;
-                               qglTexImage2D(GL_TEXTURE_2D, mip++, internalformat, width, height, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
-                               CHECKGLERROR
                        }
-               }
-               break;
-       case GLTEXTURETYPE_3D:
-               qglTexImage3D(GL_TEXTURE_3D, mip++, internalformat, width, height, depth, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
-               CHECKGLERROR
-               if (glt->flags & TEXF_MIPMAP)
-               {
-                       while (width > 1 || height > 1 || depth > 1)
+                       // picmip/max_size
+                       while (width > glt->image->width || height > glt->image->height || depth > glt->image->depth)
                        {
-                               Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1, glt->image->bytesperpixel);
+                               Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, glt->image->width, glt->image->height, glt->image->depth, glt->image->bytesperpixel);
                                prevbuffer = resizebuffer;
-                               qglTexImage3D(GL_TEXTURE_3D, mip++, internalformat, width, height, depth, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
-                               CHECKGLERROR
                        }
                }
-               break;
-       case GLTEXTURETYPE_CUBEMAP:
-               // convert and upload each side in turn,
-               // from a continuous block of input texels
-               texturebuffer = prevbuffer;
-               for (i = 0;i < 6;i++)
+               mip = 0;
+               switch(glt->image->texturetype)
                {
-                       prevbuffer = texturebuffer;
-                       texturebuffer += width * height * depth * glt->textype->inputbytesperpixel;
-                       if (glt->width != width || glt->height != height || glt->depth != depth)
+               case GLTEXTURETYPE_1D:
+                       qglTexImage1D(GL_TEXTURE_1D, mip++, glt->image->glinternalformat, width, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
+                       CHECKGLERROR
+                       if (glt->flags & TEXF_MIPMAP)
                        {
-                               Image_Resample(prevbuffer, glt->width, glt->height, glt->depth, resizebuffer, width, height, depth, glt->image->bytesperpixel, r_lerpimages.integer);
-                               prevbuffer = resizebuffer;
+                               while (width > 1 || height > 1 || depth > 1)
+                               {
+                                       Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1, glt->image->bytesperpixel);
+                                       prevbuffer = resizebuffer;
+                                       qglTexImage1D(GL_TEXTURE_1D, mip++, glt->image->glinternalformat, width, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
+                                       CHECKGLERROR
+                               }
                        }
-                       // picmip/max_size
-                       while (width > glt->image->width || height > glt->image->height || depth > glt->image->depth)
+                       break;
+               case GLTEXTURETYPE_2D:
+                       qglTexImage2D(GL_TEXTURE_2D, mip++, glt->image->glinternalformat, width, height, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
+                       CHECKGLERROR
+                       if (glt->flags & TEXF_MIPMAP)
                        {
-                               Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, glt->image->width, glt->image->height, glt->image->depth, glt->image->bytesperpixel);
-                               prevbuffer = resizebuffer;
+                               while (width > 1 || height > 1 || depth > 1)
+                               {
+                                       Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1, glt->image->bytesperpixel);
+                                       prevbuffer = resizebuffer;
+                                       qglTexImage2D(GL_TEXTURE_2D, mip++, glt->image->glinternalformat, width, height, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
+                                       CHECKGLERROR
+                               }
                        }
-                       mip = 0;
-                       qglTexImage2D(cubemapside[i], mip++, internalformat, width, height, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
+                       break;
+               case GLTEXTURETYPE_3D:
+                       qglTexImage3D(GL_TEXTURE_3D, mip++, glt->image->glinternalformat, width, height, depth, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
                        CHECKGLERROR
                        if (glt->flags & TEXF_MIPMAP)
                        {
@@ -804,14 +767,49 @@ static void R_Upload(gltexture_t *glt, qbyte *data)
                                {
                                        Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1, glt->image->bytesperpixel);
                                        prevbuffer = resizebuffer;
-                                       qglTexImage2D(cubemapside[i], mip++, internalformat, width, height, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
+                                       qglTexImage3D(GL_TEXTURE_3D, mip++, glt->image->glinternalformat, width, height, depth, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
                                        CHECKGLERROR
                                }
                        }
+                       break;
+               case GLTEXTURETYPE_CUBEMAP:
+                       // convert and upload each side in turn,
+                       // from a continuous block of input texels
+                       texturebuffer = prevbuffer;
+                       for (i = 0;i < 6;i++)
+                       {
+                               prevbuffer = texturebuffer;
+                               texturebuffer += width * height * depth * glt->textype->inputbytesperpixel;
+                               if (glt->width != width || glt->height != height || glt->depth != depth)
+                               {
+                                       Image_Resample(prevbuffer, glt->width, glt->height, glt->depth, resizebuffer, width, height, depth, glt->image->bytesperpixel, r_lerpimages.integer);
+                                       prevbuffer = resizebuffer;
+                               }
+                               // picmip/max_size
+                               while (width > glt->image->width || height > glt->image->height || depth > glt->image->depth)
+                               {
+                                       Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, glt->image->width, glt->image->height, glt->image->depth, glt->image->bytesperpixel);
+                                       prevbuffer = resizebuffer;
+                               }
+                               mip = 0;
+                               qglTexImage2D(cubemapside[i], mip++, glt->image->glinternalformat, width, height, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
+                               CHECKGLERROR
+                               if (glt->flags & TEXF_MIPMAP)
+                               {
+                                       while (width > 1 || height > 1 || depth > 1)
+                                       {
+                                               Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1, glt->image->bytesperpixel);
+                                               prevbuffer = resizebuffer;
+                                               qglTexImage2D(cubemapside[i], mip++, glt->image->glinternalformat, width, height, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
+                                               CHECKGLERROR
+                                       }
+                               }
+                       }
+                       break;
                }
-               break;
+               GL_SetupTextureParameters(glt->image->flags, glt->image->texturetype);
        }
-       GL_SetupTextureParameters(glt->image->flags, glt->image->texturetype);
+       qglBindTexture(gltexturetypeenums[glt->image->texturetype], oldbindtexnum);
 }
 
 static void R_FindImageForTexture(gltexture_t *glt)
index 4e9e3a2..69542c0 100644 (file)
--- a/glquake.h
+++ b/glquake.h
@@ -111,6 +111,8 @@ typedef double GLclampd;
 #define GL_TEXTURE_MAG_FILTER                  0x2800
 #define GL_TEXTURE_MIN_FILTER                  0x2801
 #define GL_UNPACK_ALIGNMENT                    0x0CF5
+#define GL_TEXTURE_BINDING_1D                   0x8068
+#define GL_TEXTURE_BINDING_2D                   0x8069
 
 #define GL_NEAREST                             0x2600
 #define GL_LINEAR                              0x2601
@@ -207,6 +209,7 @@ typedef double GLclampd;
 // GL_ARB_multitexture
 extern int gl_textureunits;
 extern void (GLAPIENTRY *qglMultiTexCoord2f) (GLenum, GLfloat, GLfloat);
+extern void (GLAPIENTRY *qglMultiTexCoord3f) (GLenum, GLfloat, GLfloat, GLfloat);
 extern void (GLAPIENTRY *qglActiveTexture) (GLenum);
 extern void (GLAPIENTRY *qglClientActiveTexture) (GLenum);
 #ifndef GL_ACTIVE_TEXTURE_ARB
@@ -377,7 +380,7 @@ extern void (GLAPIENTRY *qglCullFace)(GLenum mode);
 //extern void (GLAPIENTRY *qglReadBuffer)(GLenum mode);
 extern void (GLAPIENTRY *qglEnable)(GLenum cap);
 extern void (GLAPIENTRY *qglDisable)(GLenum cap);
-//extern GLboolean GLAPIENTRY *qglIsEnabled)(GLenum cap);
+extern GLboolean (GLAPIENTRY *qglIsEnabled)(GLenum cap);
 
 extern void (GLAPIENTRY *qglEnableClientState)(GLenum cap);
 extern void (GLAPIENTRY *qglDisableClientState)(GLenum cap);
@@ -395,23 +398,24 @@ extern void (GLAPIENTRY *qglFlush)(void);
 extern void (GLAPIENTRY *qglClearDepth)(GLclampd depth);
 extern void (GLAPIENTRY *qglDepthFunc)(GLenum func);
 extern void (GLAPIENTRY *qglDepthMask)(GLboolean flag);
-//extern void (GLAPIENTRY *qglDepthRange)(GLclampd near_val, GLclampd far_val);
+extern void (GLAPIENTRY *qglDepthRange)(GLclampd near_val, GLclampd far_val);
 extern void (GLAPIENTRY *qglColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
 
 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 *qglVertexPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr);
-//extern void (GLAPIENTRY *qglNormalPointer)(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 *qglArrayElement)(GLint i);
 
 extern void (GLAPIENTRY *qglColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
-//extern void (GLAPIENTRY *qglTexCoord2f)(GLfloat s, GLfloat t);
-//extern void (GLAPIENTRY *qglVertex2f)(GLfloat x, GLfloat y);
-//extern void (GLAPIENTRY *qglVertex3f)(GLfloat x, GLfloat y, GLfloat z);
-//extern void (GLAPIENTRY *qglBegin)(GLenum mode);
-//extern void (GLAPIENTRY *qglEnd)(void);
+extern void (GLAPIENTRY *qglTexCoord2f)(GLfloat s, GLfloat t);
+extern void (GLAPIENTRY *qglTexCoord3f)(GLfloat s, GLfloat t, GLfloat r);
+extern void (GLAPIENTRY *qglVertex2f)(GLfloat x, GLfloat y);
+extern void (GLAPIENTRY *qglVertex3f)(GLfloat x, GLfloat y, GLfloat z);
+extern void (GLAPIENTRY *qglBegin)(GLenum mode);
+extern void (GLAPIENTRY *qglEnd)(void);
 
 extern void (GLAPIENTRY *qglMatrixMode)(GLenum mode);
 extern void (GLAPIENTRY *qglOrtho)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val);
@@ -480,7 +484,7 @@ extern BOOL (WINAPI *qwglSwapIntervalEXT)(int interval);
 #define DEBUGGL
 
 #ifdef DEBUGGL
-#define CHECKGLERROR if ((errornumber = qglGetError())) GL_PrintError(errornumber, __FILE__, __LINE__);
+#define CHECKGLERROR {if (gl_printcheckerror.integer) Con_Printf("CHECKGLERROR at %s:%d\n", __FILE__, __LINE__);if (gl_paranoid.integer && (errornumber = qglGetError())) GL_PrintError(errornumber, __FILE__, __LINE__);}
 extern int errornumber;
 void GL_PrintError(int errornumber, char *filename, int linenumber);
 #else
index 5703e61..d882c02 100644 (file)
@@ -676,7 +676,7 @@ void Mod_ShadowMesh_AddPolygon(mempool_t *mempool, shadowmesh_t *mesh, int numve
        */
 }
 
-void Mod_ShadowMesh_AddMesh(mempool_t *mempool, shadowmesh_t *mesh, int numverts, float *verts, int numtris, int *elements)
+void Mod_ShadowMesh_AddMesh(mempool_t *mempool, shadowmesh_t *mesh, float *verts, int numtris, int *elements)
 {
        int i;
        for (i = 0;i < numtris;i++, elements += 3)
index dd09ee6..762f4a9 100644 (file)
@@ -315,7 +315,7 @@ shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh);
 int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, float *v);
 void Mod_ShadowMesh_AddTriangle(mempool_t *mempool, shadowmesh_t *mesh, float *vert0, float *vert1, float *vert2);
 void Mod_ShadowMesh_AddPolygon(mempool_t *mempool, shadowmesh_t *mesh, int numverts, float *verts);
-void Mod_ShadowMesh_AddMesh(mempool_t *mempool, shadowmesh_t *mesh, int numverts, float *verts, int numtris, int *elements);
+void Mod_ShadowMesh_AddMesh(mempool_t *mempool, shadowmesh_t *mesh, float *verts, int numtris, int *elements);
 shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int initialnumtriangles);
 shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh);
 void Mod_ShadowMesh_CalcBBox(shadowmesh_t *firstmesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius);
index ba08ed9..4ed1ca6 100644 (file)
@@ -22,29 +22,6 @@ void R_Crosshairs_Init(void)
        Cvar_RegisterVariable(&crosshair_static);
 }
 
-void R_DrawCrosshairSprite(rtexture_t *texture, vec3_t origin, vec_t scale, float cr, float cg, float cb, float ca)
-{
-       rmeshstate_t m;
-       float diff[3];
-
-       if (fogenabled)
-       {
-               VectorSubtract(origin, r_origin, diff);
-               ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
-       }
-
-       memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_SRC_ALPHA;
-       m.blendfunc2 = GL_ONE;
-       m.depthdisable = true;
-       m.tex[0] = R_GetTexture(texture);
-       R_Mesh_Matrix(&r_identitymatrix);
-       R_Mesh_State(&m);
-
-       GL_Color(cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
-       R_DrawSpriteMesh(origin, vright, vup, scale, -scale, -scale, scale);
-}
-
 void R_GetCrosshairColor(float *out)
 {
        int i;
@@ -108,7 +85,7 @@ void R_DrawWorldCrosshair(void)
        spritescale = CL_TraceLine(v1, v2, spriteorigin, NULL, 0, true, NULL) * (8192.0f / 40.0f) * crosshair_size.value;
 
        // draw the sprite
-       R_DrawCrosshairSprite(pic->tex, spriteorigin, spritescale, color[0], color[1], color[2], color[3]);
+       R_DrawSprite(GL_SRC_ALPHA, GL_ONE, pic->tex, true, spriteorigin, vright, vup, spritescale, -spritescale, -spritescale, spritescale, color[0], color[1], color[2], color[3]);
 }
 
 void R_Draw2DCrosshair(void)
index 80f4909..b8eeb84 100644 (file)
@@ -181,30 +181,22 @@ void R_DrawExplosionCallback(const void *calldata1, int calldata2)
        const explosion_t *e;
        e = calldata1;
 
-       memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_SRC_ALPHA;
-       m.blendfunc2 = GL_ONE;
-       m.tex[0] = R_GetTexture(explosiontexture);
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
        R_Mesh_Matrix(&r_identitymatrix);
 
        numtriangles = EXPLOSIONTRIS;
        numverts = EXPLOSIONVERTS;
        alpha = e->alpha * r_colorscale;
        GL_Color(alpha, alpha, alpha, 1);
-       if (gl_mesh_copyarrays.integer)
-       {
-               R_Mesh_State(&m);
-               R_Mesh_GetSpace(numverts);
-               R_Mesh_CopyVertex3f(e->vert[0], numverts);
-               R_Mesh_CopyTexCoord2f(0, explosiontexcoord2f[0], numverts);
-       }
-       else
-       {
-               m.pointervertexcount = numverts;
-               m.pointer_vertex = e->vert[0];
-               m.pointer_texcoord[0] = explosiontexcoord2f[0];
-               R_Mesh_State(&m);
-       }
+       GL_VertexPointer(e->vert[0]);
+
+       memset(&m, 0, sizeof(m));
+       m.tex[0] = R_GetTexture(explosiontexture);
+       m.pointer_texcoord[0] = explosiontexcoord2f[0];
+       R_Mesh_State_Texture(&m);
+
        R_Mesh_Draw(numverts, numtriangles, explosiontris[0]);
 }
 
index d870813..c032679 100644 (file)
--- a/r_light.c
+++ b/r_light.c
@@ -141,18 +141,11 @@ void R_BuildLightList(void)
 void R_DrawCoronas(void)
 {
        int i;
-       rmeshstate_t m;
-       float scale, viewdist, diff[3], dist;
+       float cscale, scale, viewdist, dist;
        rdlight_t *rd;
        if (!r_coronas.integer)
                return;
-       memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_ONE;
-       m.blendfunc2 = GL_ONE;
-       m.depthdisable = true; // magic
-       m.tex[0] = R_GetTexture(lightcorona);
        R_Mesh_Matrix(&r_identitymatrix);
-       R_Mesh_State(&m);
        viewdist = DotProduct(r_origin, vpn);
        for (i = 0;i < r_numdlights;i++)
        {
@@ -160,19 +153,14 @@ void R_DrawCoronas(void)
                dist = (DotProduct(rd->origin, vpn) - viewdist);
                if (dist >= 24.0f && CL_TraceLine(rd->origin, r_origin, NULL, NULL, 0, true, NULL) == 1)
                {
-                       scale = r_colorscale * (1.0f / 131072.0f);
-                       if (gl_flashblend.integer)
-                               scale *= 4.0f;
-                       if (fogenabled)
-                       {
-                               VectorSubtract(rd->origin, r_origin, diff);
-                               scale *= 1 - exp(fogdensity/DotProduct(diff,diff));
-                       }
-                       GL_Color(rd->light[0] * scale, rd->light[1] * scale, rd->light[2] * scale, 1);
+                       cscale = (1.0f / 131072.0f);
                        scale = rd->cullradius * 0.25f;
                        if (gl_flashblend.integer)
+                       {
+                               cscale *= 4.0f;
                                scale *= 2.0f;
-                       R_DrawSpriteMesh(rd->origin, vright, vup, scale, -scale, -scale, scale);
+                       }
+                       R_DrawSprite(GL_ONE, GL_ONE, lightcorona, true, rd->origin, vright, vup, scale, -scale, -scale, scale, rd->light[0] * cscale, rd->light[1] * cscale, rd->light[2] * cscale, 1);
                }
        }
 }
index 16cb6ed..dcb2b3a 100644 (file)
@@ -1,4 +1,107 @@
 
+/*
+Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
+An extrusion of the lit faces, beginning at the original geometry and ending
+further from the light source than the original geometry (presumably at least
+as far as the light's radius, if the light has a radius at all), capped at
+both front and back to avoid any problems (extrusion from dark faces also
+works but has a different set of problems)
+
+This is rendered using Carmack's Reverse technique, in which backfaces behind
+zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
+decrement the stencil, the result is a stencil value of zero where shadows
+did not intersect the visible geometry, suitable as a stencil mask for
+rendering lighting everywhere but shadow.
+
+In our case we use a biased stencil clear of 128 to avoid requiring the
+stencil wrap extension (but probably should support it).
+
+
+
+Terminology: Stencil Light Volume (sometimes called Light Volumes)
+Similar to a Stencil Shadow Volume, but inverted; rather than containing the
+areas in shadow it contanis the areas in light, this can only be built
+quickly for certain limited cases (such as portal visibility from a point),
+but is quite useful for some effects (sunlight coming from sky polygons is
+one possible example, translucent occluders is another example).
+
+
+
+Terminology: Optimized Stencil Shadow Volume
+A Stencil Shadow Volume that has been processed sufficiently to ensure it has
+no duplicate coverage of areas (no need to shadow an area twice), often this
+greatly improves performance but is an operation too costly to use on moving
+lights (however completely optimal Stencil Light Volumes can be constructed
+in some ideal cases).
+
+
+
+Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
+Per pixel evaluation of lighting equations, at a bare minimum this involves
+DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
+vector and surface normal, using a texture of the surface bumps, called a
+NormalMap) if supported by hardware; in our case there is support for cards
+which are incapable of DOT3, the quality is quite poor however.  Additionally
+it is desirable to have specular evaluation per pixel, per vertex
+normalization of specular halfangle vectors causes noticable distortion but
+is unavoidable on hardware without GL_ARB_fragment_program.
+
+
+
+Terminology: Normalization CubeMap
+A cubemap containing normalized dot3-encoded (vectors of length 1 or less
+encoded as RGB colors) for any possible direction, this technique allows per
+pixel calculation of incidence vector for per pixel lighting purposes, which
+would not otherwise be possible per pixel without GL_ARB_fragment_program.
+
+
+
+Terminology: 2D Attenuation Texturing
+A very crude approximation of light attenuation with distance which results
+in cylindrical light shapes which fade vertically as a streak (some games
+such as Doom3 allow this to be rotated to be less noticable in specific
+cases), the technique is simply modulating lighting by two 2D textures (which
+can be the same) on different axes of projection (XY and Z, typically), this
+is the best technique available without 3D Attenuation Texturing or
+GL_ARB_fragment_program technology.
+
+
+
+Terminology: 3D Attenuation Texturing
+A slightly crude approximation of light attenuation with distance, its flaws
+are limited radius and resolution (performance tradeoffs).
+
+
+
+Terminology: 3D Attenuation-Normalization Texturing
+A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
+vectors shorter the lighting becomes darker, a very effective optimization of
+diffuse lighting if 3D Attenuation Textures are already used.
+
+
+
+Terminology: Light Cubemap Filtering
+A technique for modeling non-uniform light distribution according to
+direction, for example projecting a stained glass window image onto a wall,
+this is done by texturing the lighting with a cubemap.
+
+
+
+Terminology: Light Projection Filtering
+A technique for modeling shadowing of light passing through translucent
+surfaces, allowing stained glass windows and other effects to be done more
+elegantly than possible with Light Cubemap Filtering by applying an occluder
+texture to the lighting combined with a stencil light volume to limit the lit
+area (this allows evaluating multiple translucent occluders in a scene).
+
+
+
+Terminology: Doom3 Lighting
+A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
+CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
+the (currently upcoming) game Doom3.
+*/
+
 #include "quakedef.h"
 #include "r_shadow.h"
 #include "cl_collision.h"
@@ -24,6 +127,7 @@ int *trianglefacinglightlist;
 
 int maxvertexupdate;
 int *vertexupdate;
+int *vertexremap;
 int vertexupdatenum;
 
 rtexturepool_t *r_shadow_texturepool;
@@ -45,10 +149,11 @@ cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
-cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "-1"};
+cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "0"};
 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
-cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "100000"};
+cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "10000"};
 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
+cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
 
 int c_rt_lights, c_rt_clears, c_rt_scissored;
 int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
@@ -68,6 +173,7 @@ void r_shadow_start(void)
        shadowelements = NULL;
        maxvertexupdate = 0;
        vertexupdate = NULL;
+       vertexremap = NULL;
        vertexupdatenum = 0;
        maxtrianglefacinglight = 0;
        trianglefacinglight = NULL;
@@ -98,6 +204,7 @@ void r_shadow_shutdown(void)
        shadowelements = NULL;
        maxvertexupdate = 0;
        vertexupdate = NULL;
+       vertexremap = NULL;
        vertexupdatenum = 0;
        maxtrianglefacinglight = 0;
        trianglefacinglight = NULL;
@@ -128,126 +235,11 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_portallight);
        Cvar_RegisterVariable(&r_shadow_projectdistance);
        Cvar_RegisterVariable(&r_shadow_texture3d);
+       Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
        R_Shadow_EditLights_Init();
        R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
 }
 
-int R_Shadow_MakeTriangleShadowFlags_Vertex3f(const int *elements, const float *vertex, int numtris, qbyte *facing, int *list, const float *relativelightorigin)
-{
-       int i, tris = 0;
-       const float *v0, *v1, *v2;
-       for (i = 0;i < numtris;i++, elements += 3)
-       {
-               // calculate triangle facing flag
-               v0 = vertex + elements[0] * 3;
-               v1 = vertex + elements[1] * 3;
-               v2 = vertex + elements[2] * 3;
-               if(PointInfrontOfTriangle(relativelightorigin, v0, v1, v2))
-               {
-                       facing[i] = true;
-                       list[tris++] = i;
-               }
-               else
-                       facing[i] = false;
-       }
-       return tris;
-}
-
-int R_Shadow_BuildShadowVolume(const int *elements, const int *neighbors, int numverts, const qbyte *facing, const int *facinglist, int numfacing, int *out, float *vertices, const float *relativelightorigin, float projectdistance)
-{
-       int i, j, tris, vertexpointeradjust = numverts * 3;
-       const int *e, *n;
-       float *vin, *vout;
-
-       if (maxvertexupdate < numverts)
-       {
-               maxvertexupdate = numverts;
-               if (vertexupdate)
-                       Mem_Free(vertexupdate);
-               vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
-       }
-       vertexupdatenum++;
-
-       // check each frontface for bordering backfaces,
-       // and cast shadow polygons from those edges,
-       // also create front and back caps for shadow volume
-       tris = numfacing * 2;
-       // output front caps
-       for (i = 0;i < numfacing;i++)
-       {
-               e = elements + facinglist[i] * 3;
-               out[0] = e[0];
-               out[1] = e[1];
-               out[2] = e[2];
-               out += 3;
-       }
-       // output back caps
-       for (i = 0;i < numfacing;i++)
-       {
-               e = elements + facinglist[i] * 3;
-               // generate vertices if needed
-               for (j = 0;j < 3;j++)
-               {
-                       if (vertexupdate[e[j]] != vertexupdatenum)
-                       {
-                               vertexupdate[e[j]] = vertexupdatenum;
-                               vin = vertices + e[j] * 3;
-                               vout = vin + vertexpointeradjust;
-                               vout[0] = relativelightorigin[0] + projectdistance * (vin[0] - relativelightorigin[0]);
-                               vout[1] = relativelightorigin[1] + projectdistance * (vin[1] - relativelightorigin[1]);
-                               vout[2] = relativelightorigin[2] + projectdistance * (vin[2] - relativelightorigin[2]);
-                       }
-               }
-               out[0] = e[2] + numverts;
-               out[1] = e[1] + numverts;
-               out[2] = e[0] + numverts;
-               out += 3;
-       }
-       // output sides around frontfaces
-       for (i = 0;i < numfacing;i++)
-       {
-               n = neighbors + facinglist[i] * 3;
-               // check the edges
-               if (n[0] < 0 || !facing[n[0]])
-               {
-                       e = elements + facinglist[i] * 3;
-                       out[0] = e[1];
-                       out[1] = e[0];
-                       out[2] = e[0] + numverts;
-                       out[3] = e[1];
-                       out[4] = e[0] + numverts;
-                       out[5] = e[1] + numverts;
-                       out += 6;
-                       tris += 2;
-               }
-               if (n[1] < 0 || !facing[n[1]])
-               {
-                       e = elements + facinglist[i] * 3;
-                       out[0] = e[2];
-                       out[1] = e[1];
-                       out[2] = e[1] + numverts;
-                       out[3] = e[2];
-                       out[4] = e[1] + numverts;
-                       out[5] = e[2] + numverts;
-                       out += 6;
-                       tris += 2;
-               }
-               if (n[2] < 0 || !facing[n[2]])
-               {
-                       e = elements + facinglist[i] * 3;
-                       out[0] = e[0];
-                       out[1] = e[2];
-                       out[2] = e[2] + numverts;
-                       out[3] = e[0];
-                       out[4] = e[2] + numverts;
-                       out[5] = e[0] + numverts;
-                       out += 6;
-                       tris += 2;
-               }
-       }
-       return tris;
-}
-
 void R_Shadow_ResizeTriangleFacingLight(int numtris)
 {
        // make sure trianglefacinglight is big enough for this volume
@@ -278,9 +270,252 @@ int *R_Shadow_ResizeShadowElements(int numtris)
        return shadowelements;
 }
 
-void R_Shadow_Volume(int numverts, int numtris, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance)
+int R_Shadow_ConstructShadowVolume(int innumvertices, int trianglerange_start, int trianglerange_end, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *relativelightorigin, float projectdistance)
+{
+       int i, j, tris = 0, numfacing = 0, vr[3], t, outvertices = 0;
+       const float *v[3];
+       const int *e, *n, *te;
+       float f, temp[3];
+
+       // make sure trianglefacinglight is big enough for this volume
+       if (maxtrianglefacinglight < trianglerange_end)
+               R_Shadow_ResizeTriangleFacingLight(trianglerange_end);
+
+       if (maxvertexupdate < innumvertices)
+       {
+               maxvertexupdate = innumvertices;
+               if (vertexupdate)
+                       Mem_Free(vertexupdate);
+               if (vertexremap)
+                       Mem_Free(vertexremap);
+               vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
+               vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
+       }
+       vertexupdatenum++;
+
+       if (r_shadow_singlepassvolumegeneration.integer)
+       {
+               // one pass approach (identify lit/dark faces and generate sides while doing so)
+               for (i = trianglerange_start, e = inelement3i + i * 3, n = inneighbor3i + i * 3;i < trianglerange_end;i++, e += 3, n += 3)
+               {
+                       // calculate triangle facing flag
+                       v[0] = invertex3f + e[0] * 3;
+                       v[1] = invertex3f + e[1] * 3;
+                       v[2] = invertex3f + e[2] * 3;
+                       if((trianglefacinglight[i] = PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2])))
+                       {
+                               // make sure the vertices are created
+                               for (j = 0;j < 3;j++)
+                               {
+                                       if (vertexupdate[e[j]] != vertexupdatenum)
+                                       {
+                                               vertexupdate[e[j]] = vertexupdatenum;
+                                               vertexremap[e[j]] = outvertices;
+                                               VectorCopy(v[j], outvertex3f);
+                                               VectorSubtract(v[j], relativelightorigin, temp);
+                                               f = projectdistance / VectorLength(temp);
+                                               VectorMA(relativelightorigin, f, temp, (outvertex3f + 3));
+                                               outvertex3f += 6;
+                                               outvertices += 2;
+                                       }
+                               }
+                               // output the front and back triangles
+                               vr[0] = vertexremap[e[0]];
+                               vr[1] = vertexremap[e[1]];
+                               vr[2] = vertexremap[e[2]];
+                               outelement3i[0] = vr[0];
+                               outelement3i[1] = vr[1];
+                               outelement3i[2] = vr[2];
+                               outelement3i[3] = vr[2] + 1;
+                               outelement3i[4] = vr[1] + 1;
+                               outelement3i[5] = vr[0] + 1;
+                               outelement3i += 6;
+                               tris += 2;
+                               // output the sides (facing outward from this triangle)
+                               t = n[0];
+                               if ((t >= trianglerange_start && t < trianglerange_end) ? (t < i && !trianglefacinglight[t]) : (t < 0 || (te = inelement3i + t * 3, v[0] = invertex3f + te[0] * 3, v[1] = invertex3f + te[1] * 3, v[2] = invertex3f + te[2] * 3, !PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2]))))
+                               {
+                                       outelement3i[0] = vr[1];
+                                       outelement3i[1] = vr[0];
+                                       outelement3i[2] = vr[0] + 1;
+                                       outelement3i[3] = vr[1];
+                                       outelement3i[4] = vr[0] + 1;
+                                       outelement3i[5] = vr[1] + 1;
+                                       outelement3i += 6;
+                                       tris += 2;
+                               }
+                               t = n[1];
+                               if ((t >= trianglerange_start && t < trianglerange_end) ? (t < i && !trianglefacinglight[t]) : (t < 0 || (te = inelement3i + t * 3, v[0] = invertex3f + te[0] * 3, v[1] = invertex3f + te[1] * 3, v[2] = invertex3f + te[2] * 3, !PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2]))))
+                               {
+                                       outelement3i[0] = vr[2];
+                                       outelement3i[1] = vr[1];
+                                       outelement3i[2] = vr[1] + 1;
+                                       outelement3i[3] = vr[2];
+                                       outelement3i[4] = vr[1] + 1;
+                                       outelement3i[5] = vr[2] + 1;
+                                       outelement3i += 6;
+                                       tris += 2;
+                               }
+                               t = n[2];
+                               if ((t >= trianglerange_start && t < trianglerange_end) ? (t < i && !trianglefacinglight[t]) : (t < 0 || (te = inelement3i + t * 3, v[0] = invertex3f + te[0] * 3, v[1] = invertex3f + te[1] * 3, v[2] = invertex3f + te[2] * 3, !PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2]))))
+                               {
+                                       outelement3i[0] = vr[0];
+                                       outelement3i[1] = vr[2];
+                                       outelement3i[2] = vr[2] + 1;
+                                       outelement3i[3] = vr[0];
+                                       outelement3i[4] = vr[2] + 1;
+                                       outelement3i[5] = vr[0] + 1;
+                                       outelement3i += 6;
+                                       tris += 2;
+                               }
+                       }
+                       else
+                       {
+                               // this triangle is not facing the light
+                               // output the sides (facing inward to this triangle)
+                               t = n[0];
+                               if (t < i && t >= trianglerange_start && t < trianglerange_end && trianglefacinglight[t])
+                               {
+                                       vr[0] = vertexremap[e[0]];
+                                       vr[1] = vertexremap[e[1]];
+                                       outelement3i[0] = vr[1];
+                                       outelement3i[1] = vr[0] + 1;
+                                       outelement3i[2] = vr[0];
+                                       outelement3i[3] = vr[1];
+                                       outelement3i[4] = vr[1] + 1;
+                                       outelement3i[5] = vr[0] + 1;
+                                       outelement3i += 6;
+                                       tris += 2;
+                               }
+                               t = n[1];
+                               if (t < i && t >= trianglerange_start && t < trianglerange_end && trianglefacinglight[t])
+                               {
+                                       vr[1] = vertexremap[e[1]];
+                                       vr[2] = vertexremap[e[2]];
+                                       outelement3i[0] = vr[2];
+                                       outelement3i[1] = vr[1] + 1;
+                                       outelement3i[2] = vr[1];
+                                       outelement3i[3] = vr[2];
+                                       outelement3i[4] = vr[2] + 1;
+                                       outelement3i[5] = vr[1] + 1;
+                                       outelement3i += 6;
+                                       tris += 2;
+                               }
+                               t = n[2];
+                               if (t < i && t >= trianglerange_start && t < trianglerange_end && trianglefacinglight[t])
+                               {
+                                       vr[0] = vertexremap[e[0]];
+                                       vr[2] = vertexremap[e[2]];
+                                       outelement3i[0] = vr[0];
+                                       outelement3i[1] = vr[2] + 1;
+                                       outelement3i[2] = vr[2];
+                                       outelement3i[3] = vr[0];
+                                       outelement3i[4] = vr[0] + 1;
+                                       outelement3i[5] = vr[2] + 1;
+                                       outelement3i += 6;
+                                       tris += 2;
+                               }
+                       }
+               }
+       }
+       else
+       {
+               // two pass approach (identify lit/dark faces and then generate sides)
+               for (i = trianglerange_start, e = inelement3i + i * 3, numfacing = 0;i < trianglerange_end;i++, e += 3)
+               {
+                       // calculate triangle facing flag
+                       v[0] = invertex3f + e[0] * 3;
+                       v[1] = invertex3f + e[1] * 3;
+                       v[2] = invertex3f + e[2] * 3;
+                       if((trianglefacinglight[i] = PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2])))
+                       {
+                               trianglefacinglightlist[numfacing++] = i;
+                               // make sure the vertices are created
+                               for (j = 0;j < 3;j++)
+                               {
+                                       if (vertexupdate[e[j]] != vertexupdatenum)
+                                       {
+                                               vertexupdate[e[j]] = vertexupdatenum;
+                                               vertexremap[e[j]] = outvertices;
+                                               VectorSubtract(v[j], relativelightorigin, temp);
+                                               f = projectdistance / VectorLength(temp);
+                                               VectorCopy(v[j], outvertex3f);
+                                               VectorMA(relativelightorigin, f, temp, (outvertex3f + 3));
+                                               outvertex3f += 6;
+                                               outvertices += 2;
+                                       }
+                               }
+                               // output the front and back triangles
+                               outelement3i[3] = vertexremap[e[0]];
+                               outelement3i[4] = vertexremap[e[1]];
+                               outelement3i[5] = vertexremap[e[2]];
+                               outelement3i[0] = vertexremap[e[2]] + 1;
+                               outelement3i[1] = vertexremap[e[1]] + 1;
+                               outelement3i[2] = vertexremap[e[0]] + 1;
+                               outelement3i += 6;
+                               tris += 2;
+                       }
+               }
+               for (i = 0;i < numfacing;i++)
+               {
+                       t = trianglefacinglightlist[i];
+                       e = inelement3i + t * 3;
+                       n = inneighbor3i + t * 3;
+                       // output the sides (facing outward from this triangle)
+                       t = n[0];
+                       if ((t >= trianglerange_start && t < trianglerange_end) ? (!trianglefacinglight[t]) : (t < 0 || (te = inelement3i + t * 3, v[0] = invertex3f + te[0] * 3, v[1] = invertex3f + te[1] * 3, v[2] = invertex3f + te[2] * 3, !PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2]))))
+                       {
+                               vr[0] = vertexremap[e[0]];
+                               vr[1] = vertexremap[e[1]];
+                               outelement3i[0] = vr[1];
+                               outelement3i[1] = vr[0];
+                               outelement3i[2] = vr[0] + 1;
+                               outelement3i[3] = vr[1];
+                               outelement3i[4] = vr[0] + 1;
+                               outelement3i[5] = vr[1] + 1;
+                               outelement3i += 6;
+                               tris += 2;
+                       }
+                       t = n[1];
+                       if ((t >= trianglerange_start && t < trianglerange_end) ? (!trianglefacinglight[t]) : (t < 0 || (te = inelement3i + t * 3, v[0] = invertex3f + te[0] * 3, v[1] = invertex3f + te[1] * 3, v[2] = invertex3f + te[2] * 3, !PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2]))))
+                       {
+                               vr[1] = vertexremap[e[1]];
+                               vr[2] = vertexremap[e[2]];
+                               outelement3i[0] = vr[2];
+                               outelement3i[1] = vr[1];
+                               outelement3i[2] = vr[1] + 1;
+                               outelement3i[3] = vr[2];
+                               outelement3i[4] = vr[1] + 1;
+                               outelement3i[5] = vr[2] + 1;
+                               outelement3i += 6;
+                               tris += 2;
+                       }
+                       t = n[2];
+                       if ((t >= trianglerange_start && t < trianglerange_end) ? (!trianglefacinglight[t]) : (t < 0 || (te = inelement3i + t * 3, v[0] = invertex3f + te[0] * 3, v[1] = invertex3f + te[1] * 3, v[2] = invertex3f + te[2] * 3, !PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2]))))
+                       {
+                               vr[0] = vertexremap[e[0]];
+                               vr[2] = vertexremap[e[2]];
+                               outelement3i[0] = vr[0];
+                               outelement3i[1] = vr[2];
+                               outelement3i[2] = vr[2] + 1;
+                               outelement3i[3] = vr[0];
+                               outelement3i[4] = vr[2] + 1;
+                               outelement3i[5] = vr[0] + 1;
+                               outelement3i += 6;
+                               tris += 2;
+                       }
+               }
+       }
+       if (outnumvertices)
+               *outnumvertices = outvertices;
+       return tris;
+}
+
+float varray_vertex3f2[65536*3];
+
+void R_Shadow_Volume(int numverts, int numtris, const float *invertex3f, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance)
 {
-       int tris;
+       int tris, outverts;
        if (projectdistance < 0.1)
        {
                Con_Printf("R_Shadow_Volume: projectdistance %f\n");
@@ -288,93 +523,61 @@ void R_Shadow_Volume(int numverts, int numtris, int *elements, int *neighbors, v
        }
        if (!numverts)
                return;
-// terminology:
-//
-// frontface:
-// a triangle facing the light source
-//
-// backface:
-// a triangle not facing the light source
-//
-// shadow volume:
-// an extrusion of the frontfaces, beginning at the original geometry and
-// ending further from the light source than the original geometry
-// (presumably at least as far as the light's radius, if the light has a
-// radius at all), capped at both front and back to avoid any problems
-//
-// description:
-// draws the shadow volumes of the model.
-// requirements:
-// vertex locations must already be in varray_vertex3f before use.
-// varray_vertex3f must have capacity for numverts * 2.
-
-       // make sure trianglefacinglight is big enough for this volume
-       if (maxtrianglefacinglight < numtris)
-               R_Shadow_ResizeTriangleFacingLight(numtris);
 
        // make sure shadowelements is big enough for this volume
        if (maxshadowelements < numtris * 24)
                R_Shadow_ResizeShadowElements(numtris);
 
-       // check which triangles are facing the light
-       tris = R_Shadow_MakeTriangleShadowFlags_Vertex3f(elements, varray_vertex3f, numtris, trianglefacinglight, trianglefacinglightlist, relativelightorigin);
-       if (!tris)
-               return;
-
-       // by clever use of elements we can construct the whole shadow from
-       // the unprojected vertices and the projected vertices
-
-       // output triangle elements and vertices
-       tris = R_Shadow_BuildShadowVolume(elements, neighbors, numverts, trianglefacinglight, trianglefacinglightlist, tris, shadowelements, varray_vertex3f, relativelightorigin, projectdistance);
-       if (!tris)
-               return;
-
-       if (r_shadowstage == SHADOWSTAGE_STENCIL)
+       // check which triangles are facing the light, and then output
+       // triangle elements and vertices...  by clever use of elements we
+       // can construct the whole shadow from the unprojected vertices and
+       // the projected vertices
+       if ((tris = R_Shadow_ConstructShadowVolume(numverts, 0, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, relativelightorigin, projectdistance)))
        {
-               // increment stencil if backface is behind depthbuffer
-               //R_Mesh_EndBatch();
-               qglCullFace(GL_BACK); // quake is backwards, this culls front faces
-               qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
-               R_Mesh_Draw_NoBatching(numverts * 2, tris, shadowelements);
+               GL_VertexPointer(varray_vertex3f2);
+               if (r_shadowstage == SHADOWSTAGE_STENCIL)
+               {
+                       // increment stencil if backface is behind depthbuffer
+                       qglCullFace(GL_BACK); // quake is backwards, this culls front faces
+                       qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
+                       R_Mesh_Draw(outverts, tris, shadowelements);
+                       c_rt_shadowmeshes++;
+                       c_rt_shadowtris += numtris;
+                       // decrement stencil if frontface is behind depthbuffer
+                       qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
+                       qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
+               }
+               R_Mesh_Draw(outverts, tris, shadowelements);
                c_rt_shadowmeshes++;
                c_rt_shadowtris += numtris;
-               // decrement stencil if frontface is behind depthbuffer
-               //R_Mesh_EndBatch();
-               qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
-               qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
        }
-       R_Mesh_Draw_NoBatching(numverts * 2, tris, shadowelements);
-       c_rt_shadowmeshes++;
-       c_rt_shadowtris += numtris;
 }
 
 void R_Shadow_RenderShadowMeshVolume(shadowmesh_t *firstmesh)
 {
        shadowmesh_t *mesh;
+       rmeshstate_t m;
+       memset(&m, 0, sizeof(m));
        if (r_shadowstage == SHADOWSTAGE_STENCIL)
        {
                // increment stencil if backface is behind depthbuffer
-               //R_Mesh_EndBatch();
                qglCullFace(GL_BACK); // quake is backwards, this culls front faces
                qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
                for (mesh = firstmesh;mesh;mesh = mesh->next)
                {
-                       R_Mesh_GetSpace(mesh->numverts);
-                       R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-                       R_Mesh_Draw_NoBatching(mesh->numverts, mesh->numtriangles, mesh->element3i);
+                       GL_VertexPointer(mesh->vertex3f);
+                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
                        c_rtcached_shadowmeshes++;
                        c_rtcached_shadowtris += mesh->numtriangles;
                }
                // decrement stencil if frontface is behind depthbuffer
-               //R_Mesh_EndBatch();
                qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
                qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
        }
        for (mesh = firstmesh;mesh;mesh = mesh->next)
        {
-               R_Mesh_GetSpace(mesh->numverts);
-               R_Mesh_CopyVertex3f(mesh->vertex3f, mesh->numverts);
-               R_Mesh_Draw_NoBatching(mesh->numverts, mesh->numtriangles, mesh->element3i);
+               GL_VertexPointer(mesh->vertex3f);
+               R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
                c_rtcached_shadowmeshes++;
                c_rtcached_shadowtris += mesh->numtriangles;
        }
@@ -523,12 +726,14 @@ void R_Shadow_Stage_Begin(void)
         || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
                R_Shadow_MakeTextures();
 
-       R_Mesh_EndBatch();
-       memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_ONE;
-       m.blendfunc2 = GL_ZERO;
-       R_Mesh_State(&m);
+       GL_BlendFunc(GL_ONE, GL_ZERO);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
        GL_Color(0, 0, 0, 1);
+
+       memset(&m, 0, sizeof(m));
+       R_Mesh_State_Texture(&m);
+
        qglDisable(GL_SCISSOR_TEST);
        r_shadowstage = SHADOWSTAGE_NONE;
 
@@ -556,20 +761,29 @@ void R_Shadow_LoadWorldLightsIfNeeded(void)
 void R_Shadow_Stage_ShadowVolumes(void)
 {
        rmeshstate_t m;
-       //R_Mesh_EndBatch();
+
        memset(&m, 0, sizeof(m));
-       R_Mesh_TextureState(&m);
+       R_Mesh_State_Texture(&m);
+
        GL_Color(1, 1, 1, 1);
+       GL_BlendFunc(GL_ONE, GL_ZERO);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
+
+       if (r_shadow_polygonoffset.value != 0)
+       {
+               qglPolygonOffset(1.0f, r_shadow_polygonoffset.value);
+               qglEnable(GL_POLYGON_OFFSET_FILL);
+       }
+       else
+               qglDisable(GL_POLYGON_OFFSET_FILL);
        qglColorMask(0, 0, 0, 0);
-       qglDisable(GL_BLEND);
-       qglDepthMask(0);
        qglDepthFunc(GL_LESS);
        qglEnable(GL_STENCIL_TEST);
        qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        qglStencilFunc(GL_ALWAYS, 128, 0xFF);
-       qglEnable(GL_CULL_FACE);
-       qglEnable(GL_DEPTH_TEST);
        r_shadowstage = SHADOWSTAGE_STENCIL;
+
        qglClear(GL_STENCIL_BUFFER_BIT);
        c_rt_clears++;
        // LordHavoc note: many shadow volumes reside entirely inside the world
@@ -584,22 +798,24 @@ void R_Shadow_Stage_ShadowVolumes(void)
 void R_Shadow_Stage_LightWithoutShadows(void)
 {
        rmeshstate_t m;
-       //R_Mesh_EndBatch();
+
        memset(&m, 0, sizeof(m));
-       R_Mesh_TextureState(&m);
-       qglActiveTexture(GL_TEXTURE0_ARB);
+       R_Mesh_State_Texture(&m);
 
-       qglEnable(GL_BLEND);
-       qglBlendFunc(GL_ONE, GL_ONE);
        GL_Color(1, 1, 1, 1);
+       GL_BlendFunc(GL_ONE, GL_ONE);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
+       qglDisable(GL_POLYGON_OFFSET_FILL);
+
+       //GL_DepthTest(false);
+
        qglColorMask(1, 1, 1, 1);
-       qglDepthMask(0);
-       qglDepthFunc(GL_EQUAL);
+       qglDepthFunc(GL_LEQUAL);
        qglDisable(GL_STENCIL_TEST);
        qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        qglStencilFunc(GL_EQUAL, 128, 0xFF);
-       qglEnable(GL_CULL_FACE);
-       qglEnable(GL_DEPTH_TEST);
+
        r_shadowstage = SHADOWSTAGE_LIGHT;
        c_rt_lights++;
 }
@@ -607,24 +823,26 @@ void R_Shadow_Stage_LightWithoutShadows(void)
 void R_Shadow_Stage_LightWithShadows(void)
 {
        rmeshstate_t m;
-       //R_Mesh_EndBatch();
+
        memset(&m, 0, sizeof(m));
-       R_Mesh_TextureState(&m);
-       qglActiveTexture(GL_TEXTURE0_ARB);
+       R_Mesh_State_Texture(&m);
 
-       qglEnable(GL_BLEND);
-       qglBlendFunc(GL_ONE, GL_ONE);
        GL_Color(1, 1, 1, 1);
+       GL_BlendFunc(GL_ONE, GL_ONE);
+       GL_DepthMask(false);
+       GL_DepthTest(true);
+       qglDisable(GL_POLYGON_OFFSET_FILL);
+
+       //GL_DepthTest(false);
+
        qglColorMask(1, 1, 1, 1);
-       qglDepthMask(0);
-       qglDepthFunc(GL_EQUAL);
+       qglDepthFunc(GL_LEQUAL);
        qglEnable(GL_STENCIL_TEST);
        qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        // only draw light where this geometry was already rendered AND the
        // stencil is 128 (values other than this mean shadow)
        qglStencilFunc(GL_EQUAL, 128, 0xFF);
-       qglEnable(GL_CULL_FACE);
-       qglEnable(GL_DEPTH_TEST);
+
        r_shadowstage = SHADOWSTAGE_LIGHT;
        c_rt_lights++;
 }
@@ -632,29 +850,23 @@ void R_Shadow_Stage_LightWithShadows(void)
 void R_Shadow_Stage_End(void)
 {
        rmeshstate_t m;
-       //R_Mesh_EndBatch();
-       // attempt to restore state to what Mesh_State thinks it is
-       qglDisable(GL_BLEND);
-       qglBlendFunc(GL_ONE, GL_ZERO);
-       qglDepthMask(1);
-       // now restore the rest of the state to normal
+
+       memset(&m, 0, sizeof(m));
+       R_Mesh_State_Texture(&m);
+
        GL_Color(1, 1, 1, 1);
+       GL_BlendFunc(GL_ONE, GL_ZERO);
+       GL_DepthMask(true);
+       GL_DepthTest(true);
+       qglDisable(GL_POLYGON_OFFSET_FILL);
+
        qglColorMask(1, 1, 1, 1);
        qglDisable(GL_SCISSOR_TEST);
        qglDepthFunc(GL_LEQUAL);
        qglDisable(GL_STENCIL_TEST);
        qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        qglStencilFunc(GL_ALWAYS, 128, 0xFF);
-       qglEnable(GL_CULL_FACE);
-       qglEnable(GL_DEPTH_TEST);
-       // force mesh state to reset by using various combinations of features
-       memset(&m, 0, sizeof(m));
-       m.blendfunc1 = GL_SRC_ALPHA;
-       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
-       R_Mesh_State(&m);
-       m.blendfunc1 = GL_ONE;
-       m.blendfunc2 = GL_ZERO;
-       R_Mesh_State(&m);
+
        r_shadowstage = SHADOWSTAGE_NONE;
 }
 
@@ -672,14 +884,12 @@ int R_Shadow_ScissorForBBoxAndSphere(const float *mins, const float *maxs, const
         && r_origin[1] >= mins[1] && r_origin[1] <= maxs[1]
         && r_origin[2] >= mins[2] && r_origin[2] <= maxs[2])
        {
-               //R_Mesh_EndBatch();
                qglDisable(GL_SCISSOR_TEST);
                return false;
        }
        VectorSubtract(r_origin, origin, v);
        if (DotProduct(v, v) < radius * radius)
        {
-               //R_Mesh_EndBatch();
                qglDisable(GL_SCISSOR_TEST);
                return false;
        }
@@ -794,7 +1004,6 @@ int R_Shadow_ScissorForBBoxAndSphere(const float *mins, const float *maxs, const
        if (ix2 <= ix1 || iy2 <= iy1)
                return true;
        // set up the scissor rectangle
-       //R_Mesh_EndBatch();
        qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
        qglEnable(GL_SCISSOR_TEST);
        c_rt_scissored++;
@@ -815,7 +1024,6 @@ int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
        // (?!?  seems like a driver bug) so abort if gl_stencil is false
        if (!gl_stencil || BoxesOverlap(r_origin, r_origin, mins, maxs))
        {
-               //R_Mesh_EndBatch();
                qglDisable(GL_SCISSOR_TEST);
                return false;
        }
@@ -969,7 +1177,6 @@ int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
        if (ix2 <= ix1 || iy2 <= iy1)
                return true;
        // set up the scissor rectangle
-       //R_Mesh_EndBatch();
        qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
        qglEnable(GL_SCISSOR_TEST);
        c_rt_scissored++;
@@ -1101,11 +1308,12 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
        int renders;
        float color[3], color2[3];
        rmeshstate_t m;
-       memset(&m, 0, sizeof(m));
+       GL_VertexPointer(vertex3f);
        if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
        {
                if (!bumptexture)
                        bumptexture = r_shadow_blankbumptexture;
+               GL_Color(1,1,1,1);
                // colorscale accounts for how much we multiply the brightness during combine
                // mult is how many times the final pass of the lighting will be
                // performed to get more brightness than otherwise possible
@@ -1113,39 +1321,32 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
                if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
                {
                        // 3/2 3D combine path (Geforce3, Radeon 8500)
-                       //R_Mesh_EndBatch();
+                       memset(&m, 0, sizeof(m));
                        m.tex[0] = R_GetTexture(bumptexture);
                        m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
                        m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
                        m.texcombinergb[0] = GL_REPLACE;
                        m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-                       R_Mesh_TextureState(&m);
+                       m.pointer_texcoord[0] = texcoord2f;
+                       m.pointer_texcoord[1] = varray_texcoord3f[1];
+                       m.pointer_texcoord[2] = varray_texcoord3f[2];
+                       R_Mesh_State_Texture(&m);
                        qglColorMask(0,0,0,1);
-                       qglDisable(GL_BLEND);
-                       GL_Color(1,1,1,1);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
+                       GL_BlendFunc(GL_ONE, GL_ZERO);
                        R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
                        R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
-                       R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
 
-                       //R_Mesh_EndBatch();
+                       memset(&m, 0, sizeof(m));
                        m.tex[0] = R_GetTexture(basetexture);
-                       m.tex[1] = 0;
                        m.texcubemap[1] = R_GetTexture(lightcubemap);
-                       m.tex3d[2] = 0;
-                       m.texcombinergb[0] = GL_MODULATE;
-                       m.texcombinergb[1] = GL_MODULATE;
-                       R_Mesh_TextureState(&m);
+                       m.pointer_texcoord[0] = texcoord2f;
+                       m.pointer_texcoord[1] = lightcubemap ? varray_texcoord3f[1] : NULL;
+                       R_Mesh_State_Texture(&m);
                        qglColorMask(1,1,1,0);
-                       qglBlendFunc(GL_DST_ALPHA, GL_ONE);
-                       qglEnable(GL_BLEND);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
+                       GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                        if (lightcubemap)
                                R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltofilter);
                        VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color2);
@@ -1155,7 +1356,7 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
                                color[1] = bound(0, color2[1], 1);
                                color[2] = bound(0, color2[2], 1);
                                GL_Color(color[0], color[1], color[2], 1);
-                               R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                               R_Mesh_Draw(numverts, numtriangles, elements);
                                c_rt_lightmeshes++;
                                c_rt_lighttris += numtriangles;
                        }
@@ -1163,47 +1364,39 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
                else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
                {
                        // 1/2/2 3D combine path (original Radeon)
-                       //R_Mesh_EndBatch();
+                       memset(&m, 0, sizeof(m));
                        m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
-                       R_Mesh_TextureState(&m);
+                       m.pointer_texcoord[0] = varray_texcoord3f[0];
+                       R_Mesh_State_Texture(&m);
                        qglColorMask(0,0,0,1);
-                       qglDisable(GL_BLEND);
-                       GL_Color(1,1,1,1);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
+                       GL_BlendFunc(GL_ONE, GL_ZERO);
                        R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
-                       R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
 
-                       //R_Mesh_EndBatch();
+                       memset(&m, 0, sizeof(m));
                        m.tex[0] = R_GetTexture(bumptexture);
-                       m.tex3d[0] = 0;
                        m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
                        m.texcombinergb[0] = GL_REPLACE;
                        m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-                       R_Mesh_TextureState(&m);
-                       qglBlendFunc(GL_DST_ALPHA, GL_ZERO);
-                       qglEnable(GL_BLEND);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
+                       m.pointer_texcoord[0] = texcoord2f;
+                       m.pointer_texcoord[1] = varray_texcoord3f[1];
+                       R_Mesh_State_Texture(&m);
+                       GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
                        R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
-                       R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
 
-                       //R_Mesh_EndBatch();
+                       memset(&m, 0, sizeof(m));
                        m.tex[0] = R_GetTexture(basetexture);
                        m.texcubemap[1] = R_GetTexture(lightcubemap);
-                       m.texcombinergb[0] = GL_MODULATE;
-                       m.texcombinergb[1] = GL_MODULATE;
-                       R_Mesh_TextureState(&m);
+                       m.pointer_texcoord[0] = texcoord2f;
+                       m.pointer_texcoord[1] = lightcubemap ? varray_texcoord3f[1] : NULL;
+                       R_Mesh_State_Texture(&m);
                        qglColorMask(1,1,1,0);
-                       qglBlendFunc(GL_DST_ALPHA, GL_ONE);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
+                       GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                        if (lightcubemap)
                                R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltofilter);
                        VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color2);
@@ -1213,7 +1406,7 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
                                color[1] = bound(0, color2[1], 1);
                                color[2] = bound(0, color2[2], 1);
                                GL_Color(color[0], color[1], color[2], 1);
-                               R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                               R_Mesh_Draw(numverts, numtriangles, elements);
                                c_rt_lightmeshes++;
                                c_rt_lighttris += numtriangles;
                        }
@@ -1221,37 +1414,29 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
                else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
                {
                        // 2/2 3D combine path (original Radeon)
-                       //R_Mesh_EndBatch();
+                       memset(&m, 0, sizeof(m));
                        m.tex[0] = R_GetTexture(bumptexture);
                        m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
                        m.texcombinergb[0] = GL_REPLACE;
                        m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-                       R_Mesh_TextureState(&m);
-                       GL_Color(1,1,1,1);
+                       m.pointer_texcoord[0] = texcoord2f;
+                       m.pointer_texcoord[1] = varray_texcoord3f[1];
+                       R_Mesh_State_Texture(&m);
                        qglColorMask(0,0,0,1);
-                       qglDisable(GL_BLEND);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
+                       GL_BlendFunc(GL_ONE, GL_ZERO);
                        R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
-                       R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
 
-                       //R_Mesh_EndBatch();
+                       memset(&m, 0, sizeof(m));
                        m.tex[0] = R_GetTexture(basetexture);
                        m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
-                       m.texcubemap[1] = 0;
-                       m.texcombinergb[0] = GL_MODULATE;
-                       m.texcombinergb[1] = GL_MODULATE;
-                       R_Mesh_TextureState(&m);
-                       R_Mesh_GetSpace(numverts);
+                       m.pointer_texcoord[0] = texcoord2f;
+                       m.pointer_texcoord[1] = varray_texcoord3f[1];
+                       R_Mesh_State_Texture(&m);
                        qglColorMask(1,1,1,0);
-                       qglBlendFunc(GL_DST_ALPHA, GL_ONE);
-                       qglEnable(GL_BLEND);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
+                       GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                        R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
                        VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color2);
                        for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
@@ -1260,7 +1445,7 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
                                color[1] = bound(0, color2[1], 1);
                                color[2] = bound(0, color2[2], 1);
                                GL_Color(color[0], color[1], color[2], 1);
-                               R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                               R_Mesh_Draw(numverts, numtriangles, elements);
                                c_rt_lightmeshes++;
                                c_rt_lighttris += numtriangles;
                        }
@@ -1268,41 +1453,35 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
                else if (r_textureunits.integer >= 4)
                {
                        // 4/2 2D combine path (Geforce3, Radeon 8500)
-                       //R_Mesh_EndBatch();
+                       memset(&m, 0, sizeof(m));
                        m.tex[0] = R_GetTexture(bumptexture);
                        m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
                        m.texcombinergb[0] = GL_REPLACE;
                        m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                        m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
                        m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
-                       R_Mesh_TextureState(&m);
+                       m.pointer_texcoord[0] = texcoord2f;
+                       m.pointer_texcoord[1] = varray_texcoord3f[1];
+                       m.pointer_texcoord[2] = varray_texcoord2f[2];
+                       m.pointer_texcoord[3] = varray_texcoord2f[3];
+                       R_Mesh_State_Texture(&m);
                        qglColorMask(0,0,0,1);
-                       qglDisable(GL_BLEND);
-                       GL_Color(1,1,1,1);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
+                       GL_BlendFunc(GL_ONE, GL_ZERO);
                        R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
                        R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
                        R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
-                       R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
 
-                       //R_Mesh_EndBatch();
+                       memset(&m, 0, sizeof(m));
                        m.tex[0] = R_GetTexture(basetexture);
                        m.texcubemap[1] = R_GetTexture(lightcubemap);
-                       m.texcombinergb[0] = GL_MODULATE;
-                       m.texcombinergb[1] = GL_MODULATE;
-                       m.tex[2] = 0;
-                       m.tex[3] = 0;
-                       R_Mesh_TextureState(&m);
+                       m.pointer_texcoord[0] = texcoord2f;
+                       m.pointer_texcoord[1] = lightcubemap ? varray_texcoord3f[1] : NULL;
+                       R_Mesh_State_Texture(&m);
                        qglColorMask(1,1,1,0);
-                       qglBlendFunc(GL_DST_ALPHA, GL_ONE);
-                       qglEnable(GL_BLEND);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
+                       GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                        if (lightcubemap)
                                R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltofilter);
                        VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color2);
@@ -1312,7 +1491,7 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
                                color[1] = bound(0, color2[1], 1);
                                color[2] = bound(0, color2[2], 1);
                                GL_Color(color[0], color[1], color[2], 1);
-                               R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                               R_Mesh_Draw(numverts, numtriangles, elements);
                                c_rt_lightmeshes++;
                                c_rt_lighttris += numtriangles;
                        }
@@ -1320,49 +1499,42 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
                else
                {
                        // 2/2/2 2D combine path (any dot3 card)
-                       //R_Mesh_EndBatch();
+                       memset(&m, 0, sizeof(m));
                        m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
                        m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-                       R_Mesh_TextureState(&m);
+                       m.pointer_texcoord[0] = varray_texcoord2f[0];
+                       m.pointer_texcoord[1] = varray_texcoord2f[1];
+                       R_Mesh_State_Texture(&m);
                        qglColorMask(0,0,0,1);
-                       qglDisable(GL_BLEND);
-                       GL_Color(1,1,1,1);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
+                       GL_BlendFunc(GL_ONE, GL_ZERO);
                        R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
                        R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
-                       R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
 
-                       //R_Mesh_EndBatch();
+                       memset(&m, 0, sizeof(m));
                        m.tex[0] = R_GetTexture(bumptexture);
-                       m.tex[1] = 0;
                        m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
                        m.texcombinergb[0] = GL_REPLACE;
                        m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-                       R_Mesh_TextureState(&m);
-                       qglBlendFunc(GL_DST_ALPHA, GL_ZERO);
-                       qglEnable(GL_BLEND);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
+                       m.pointer_texcoord[0] = texcoord2f;
+                       m.pointer_texcoord[1] = varray_texcoord3f[1];
+                       R_Mesh_State_Texture(&m);
+                       GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
                        R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
-                       R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
 
-                       //R_Mesh_EndBatch();
+                       memset(&m, 0, sizeof(m));
                        m.tex[0] = R_GetTexture(basetexture);
                        m.texcubemap[1] = R_GetTexture(lightcubemap);
-                       m.texcombinergb[0] = GL_MODULATE;
-                       m.texcombinergb[1] = GL_MODULATE;
-                       R_Mesh_TextureState(&m);
+                       m.pointer_texcoord[0] = texcoord2f;
+                       m.pointer_texcoord[1] = lightcubemap ? varray_texcoord3f[1] : NULL;
+                       R_Mesh_State_Texture(&m);
                        qglColorMask(1,1,1,0);
-                       qglBlendFunc(GL_DST_ALPHA, GL_ONE);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
+                       GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                        if (lightcubemap)
                                R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltofilter);
                        VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color2);
@@ -1372,7 +1544,7 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
                                color[1] = bound(0, color2[1], 1);
                                color[2] = bound(0, color2[2], 1);
                                GL_Color(color[0], color[1], color[2], 1);
-                               R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                               R_Mesh_Draw(numverts, numtriangles, elements);
                                c_rt_lightmeshes++;
                                c_rt_lighttris += numtriangles;
                        }
@@ -1380,70 +1552,34 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
        }
        else
        {
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+               GL_DepthMask(false);
+               GL_DepthTest(true);
+               GL_ColorPointer(varray_color4f);
+               VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color2);
+               memset(&m, 0, sizeof(m));
+               m.tex[0] = R_GetTexture(basetexture);
+               m.pointer_texcoord[0] = texcoord2f;
                if (r_textureunits.integer >= 2)
                {
                        // voodoo2
-                       //R_Mesh_EndBatch();
-#if 1
-                       m.tex[0] = R_GetTexture(basetexture);
-                       m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-                       R_Mesh_TextureState(&m);
-                       qglBlendFunc(GL_SRC_ALPHA, GL_ONE);
-                       qglEnable(GL_BLEND);
-#else
-                       m.tex[0] = R_GetTexture(basetexture);
                        m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
-                       m.blendfunc1 = GL_SRC_ALPHA;
-                       m.blendfunc2 = GL_ONE;
-                       R_Mesh_State(&m);
-#endif
-                       VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color2);
-                       for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
-                       {
-                               color[0] = bound(0, color2[0], 1);
-                               color[1] = bound(0, color2[1], 1);
-                               color[2] = bound(0, color2[2], 1);
-                               GL_UseColorArray();
-                               R_Mesh_GetSpace(numverts);
-                               R_Mesh_CopyVertex3f(vertex3f, numverts);
-                               R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
-                               R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
-                               R_Shadow_VertexLightingWithXYAttenuationTexture(numverts, vertex3f, normal3f, color, matrix_modeltofilter);
-                               R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
-                               c_rt_lightmeshes++;
-                               c_rt_lighttris += numtriangles;
-                       }
+                       m.pointer_texcoord[1] = varray_texcoord2f[1];
+                       R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
                }
-               else
+               R_Mesh_State_Texture(&m);
+               for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
                {
-                       // voodoo1
-                       //R_Mesh_EndBatch();
-#if 1
-                       m.tex[0] = R_GetTexture(basetexture);
-                       R_Mesh_TextureState(&m);
-                       qglBlendFunc(GL_SRC_ALPHA, GL_ONE);
-                       qglEnable(GL_BLEND);
-#else
-                       m.tex[0] = R_GetTexture(basetexture);
-                       m.blendfunc1 = GL_SRC_ALPHA;
-                       m.blendfunc2 = GL_ONE;
-                       R_Mesh_State(&m);
-#endif
-                       VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color2);
-                       for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
-                       {
-                               color[0] = bound(0, color2[0], 1);
-                               color[1] = bound(0, color2[1], 1);
-                               color[2] = bound(0, color2[2], 1);
-                               GL_UseColorArray();
-                               R_Mesh_GetSpace(numverts);
-                               R_Mesh_CopyVertex3f(vertex3f, numverts);
-                               R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
+                       color[0] = bound(0, color2[0], 1);
+                       color[1] = bound(0, color2[1], 1);
+                       color[2] = bound(0, color2[2], 1);
+                       if (r_textureunits.integer >= 2)
+                               R_Shadow_VertexLightingWithXYAttenuationTexture(numverts, vertex3f, normal3f, color, matrix_modeltofilter);
+                       else
                                R_Shadow_VertexLighting(numverts, vertex3f, normal3f, color, matrix_modeltofilter);
-                               R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
-                               c_rt_lightmeshes++;
-                               c_rt_lighttris += numtriangles;
-                       }
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
                }
        }
 }
@@ -1455,75 +1591,65 @@ void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elemen
        rmeshstate_t m;
        if (!gl_dot3arb || !gl_texturecubemap || !gl_combine.integer || !gl_stencil)
                return;
-       memset(&m, 0, sizeof(m));
        if (!bumptexture)
                bumptexture = r_shadow_blankbumptexture;
        if (!glosstexture)
                glosstexture = r_shadow_blankglosstexture;
        if (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture))
        {
+               GL_VertexPointer(vertex3f);
+               GL_Color(1,1,1,1);
                if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
                {
                        // 2/0/0/1/2 3D combine blendsquare path
-                       //R_Mesh_EndBatch();
+                       memset(&m, 0, sizeof(m));
                        m.tex[0] = R_GetTexture(bumptexture);
                        m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
                        m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-                       R_Mesh_TextureState(&m);
+                       m.pointer_texcoord[0] = texcoord2f;
+                       m.pointer_texcoord[1] = varray_texcoord3f[1];
+                       R_Mesh_State_Texture(&m);
                        qglColorMask(0,0,0,1);
                        // this squares the result
-                       qglEnable(GL_BLEND);
-                       qglBlendFunc(GL_SRC_ALPHA, GL_ZERO);
-                       GL_Color(1,1,1,1);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
+                       GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
                        R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
-                       R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
 
-                       //R_Mesh_EndBatch();
-                       m.tex[0] = 0;
-                       m.texcubemap[1] = 0;
-                       m.texcombinergb[1] = GL_MODULATE;
-                       R_Mesh_TextureState(&m);
+                       memset(&m, 0, sizeof(m));
+                       R_Mesh_State_Texture(&m);
                        // square alpha in framebuffer a few times to make it shiny
-                       qglBlendFunc(GL_ZERO, GL_DST_ALPHA);
+                       GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
                        // these comments are a test run through this math for intensity 0.5
                        // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
                        // 0.25 * 0.25 = 0.0625 (this is another pass)
                        // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
-                       R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
 
-                       //R_Mesh_EndBatch();
+                       memset(&m, 0, sizeof(m));
                        m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
-                       R_Mesh_TextureState(&m);
-                       qglBlendFunc(GL_DST_ALPHA, GL_ZERO);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
+                       m.pointer_texcoord[0] = varray_texcoord3f[0];
+                       R_Mesh_State_Texture(&m);
+                       GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
                        R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
-                       R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
 
-                       //R_Mesh_EndBatch();
-                       m.tex3d[0] = 0;
+                       memset(&m, 0, sizeof(m));
                        m.tex[0] = R_GetTexture(glosstexture);
                        m.texcubemap[1] = R_GetTexture(lightcubemap);
-                       R_Mesh_TextureState(&m);
+                       m.pointer_texcoord[0] = texcoord2f;
+                       m.pointer_texcoord[1] = lightcubemap ? varray_texcoord3f[1] : NULL;
+                       R_Mesh_State_Texture(&m);
                        qglColorMask(1,1,1,0);
-                       qglBlendFunc(GL_DST_ALPHA, GL_ONE);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
+                       GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                        if (lightcubemap)
                                R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltofilter);
                        VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value * 0.25f, color2);
@@ -1533,7 +1659,7 @@ void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elemen
                                color[1] = bound(0, color2[1], 1);
                                color[2] = bound(0, color2[2], 1);
                                GL_Color(color[0], color[1], color[2], 1);
-                               R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                               R_Mesh_Draw(numverts, numtriangles, elements);
                                c_rt_lightmeshes++;
                                c_rt_lighttris += numtriangles;
                        }
@@ -1541,56 +1667,44 @@ void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elemen
                else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
                {
                        // 2/0/0/2 3D combine blendsquare path
-                       //R_Mesh_EndBatch();
+                       memset(&m, 0, sizeof(m));
                        m.tex[0] = R_GetTexture(bumptexture);
                        m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
                        m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-                       R_Mesh_TextureState(&m);
+                       m.pointer_texcoord[0] = texcoord2f;
+                       m.pointer_texcoord[1] = varray_texcoord3f[1];
+                       R_Mesh_State_Texture(&m);
                        qglColorMask(0,0,0,1);
                        // this squares the result
-                       qglEnable(GL_BLEND);
-                       qglBlendFunc(GL_SRC_ALPHA, GL_ZERO);
-                       GL_Color(1,1,1,1);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
+                       GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
                        R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
-                       R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
 
-                       //R_Mesh_EndBatch();
-                       m.tex[0] = 0;
-                       m.texcubemap[1] = 0;
-                       m.texcombinergb[1] = GL_MODULATE;
-                       R_Mesh_TextureState(&m);
+                       memset(&m, 0, sizeof(m));
+                       R_Mesh_State_Texture(&m);
                        // square alpha in framebuffer a few times to make it shiny
-                       qglBlendFunc(GL_ZERO, GL_DST_ALPHA);
+                       GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
                        // these comments are a test run through this math for intensity 0.5
                        // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
                        // 0.25 * 0.25 = 0.0625 (this is another pass)
                        // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
-                       R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
                        c_rt_lightmeshes++;
                        c_rt_lighttris += numtriangles;
 
-                       //R_Mesh_EndBatch();
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
+                       memset(&m, 0, sizeof(m));
                        m.tex[0] = R_GetTexture(glosstexture);
                        m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
-                       R_Mesh_TextureState(&m);
+                       m.pointer_texcoord[0] = texcoord2f;
+                       m.pointer_texcoord[1] = varray_texcoord3f[1];
+                       R_Mesh_State_Texture(&m);
                        qglColorMask(1,1,1,0);
-                       qglBlendFunc(GL_DST_ALPHA, GL_ONE);
-                       R_Mesh_GetSpace(numverts);
-                       R_Mesh_CopyVertex3f(vertex3f, numverts);
-                       R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts);
+                       GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
                        R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
                        VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value * 0.25f, color2);
                        for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
@@ -1599,7 +1713,7 @@ void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elemen
                                color[1] = bound(0, color2[1], 1);
                                color[2] = bound(0, color2[2], 1);
                                GL_Color(color[0], color[1], color[2], 1);
-                               R_Mesh_Draw_NoBatching(numverts, numtriangles, elements);
+