]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
implemented vbo rendering of map, models, and compiled shadow volumes
[xonotic/darkplaces.git] / r_shadow.c
index 352dc74acbf1b45878cdf28868edf3b868734dc9..cc4e6a13a39a1a5021280dfb3721ef067c708991 100644 (file)
@@ -198,6 +198,7 @@ int r_shadow_rtlight_numfrustumplanes;
 mplane_t r_shadow_rtlight_frustumplanes[12+6+6]; // see R_Shadow_ComputeShadowCasterCullingPlanes
 
 rtexturepool_t *r_shadow_texturepool;
+rtexture_t *r_shadow_attenuationgradienttexture;
 rtexture_t *r_shadow_attenuation2dtexture;
 rtexture_t *r_shadow_attenuation3dtexture;
 
@@ -210,12 +211,13 @@ rtexturepool_t *r_shadow_filters_texturepool;
 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
+cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
-cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5", "changes attenuation texture generation (does not affect r_glsl lighting)"};
-cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_glsl lighting)"};
+cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
+cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
@@ -238,7 +240,7 @@ cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs mor
 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_glsl lighting)"};
-cvar_t gl_ext_separatestencil = {0, "gl_ext_separatetencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
+cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
@@ -247,7 +249,16 @@ cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how
 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
 
-float r_shadow_attenpower, r_shadow_attenscale;
+// note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
+#define ATTENTABLESIZE 256
+// 1D gradient, 2D circle and 3D sphere attenuation textures
+#define ATTEN1DSIZE 32
+#define ATTEN2DSIZE 64
+#define ATTEN3DSIZE 32
+
+static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
+static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
+static float r_shadow_attentable[ATTENTABLESIZE+1];
 
 rtlight_t *r_shadow_compilingrtlight;
 dlight_t *r_shadow_worldlightchain;
@@ -282,6 +293,7 @@ void r_shadow_start(void)
 {
        // allocate vertex processing arrays
        numcubemaps = 0;
+       r_shadow_attenuationgradienttexture = NULL;
        r_shadow_attenuation2dtexture = NULL;
        r_shadow_attenuation3dtexture = NULL;
        r_shadow_texturepool = NULL;
@@ -317,6 +329,7 @@ void r_shadow_shutdown(void)
 {
        R_Shadow_UncompileWorldLights();
        numcubemaps = 0;
+       r_shadow_attenuationgradienttexture = NULL;
        r_shadow_attenuation2dtexture = NULL;
        r_shadow_attenuation3dtexture = NULL;
        R_FreeTexturePool(&r_shadow_texturepool);
@@ -382,8 +395,8 @@ void R_Shadow_Help_f(void)
 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
 "r_shadow_gloss2intensity : brightness of forced gloss\n"
 "r_shadow_glossintensity : brightness of textured gloss\n"
-"r_shadow_lightattenuationpower : used to generate attenuation texture\n"
-"r_shadow_lightattenuationscale : used to generate attenuation texture\n"
+"r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
+"r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
 "r_shadow_portallight : use portal visibility for static light precomputation\n"
@@ -411,13 +424,14 @@ void R_Shadow_Init(void)
 {
        Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
        Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
+       Cvar_RegisterVariable(&r_shadow_usenormalmap);
        Cvar_RegisterVariable(&r_shadow_debuglight);
        Cvar_RegisterVariable(&r_shadow_gloss);
        Cvar_RegisterVariable(&r_shadow_gloss2intensity);
        Cvar_RegisterVariable(&r_shadow_glossintensity);
        Cvar_RegisterVariable(&r_shadow_glossexponent);
-       Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
-       Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
+       Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
+       Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
        Cvar_RegisterVariable(&r_shadow_lightintensityscale);
        Cvar_RegisterVariable(&r_shadow_lightradiusscale);
        Cvar_RegisterVariable(&r_shadow_portallight);
@@ -886,77 +900,71 @@ void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *verte
        }
        r_refdef.stats.lights_shadowtriangles += numtriangles;
        CHECKGLERROR
-       R_Mesh_VertexPointer(vertex3f);
+       R_Mesh_VertexPointer(vertex3f, 0, 0);
        GL_LockArrays(0, numvertices);
        if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
        {
                // decrement stencil if backface is behind depthbuffer
                GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
                qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
-               R_Mesh_Draw(0, numvertices, numtriangles, element3i);
+               R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
                // increment stencil if frontface is behind depthbuffer
                GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
                qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
        }
-       R_Mesh_Draw(0, numvertices, numtriangles, element3i);
+       R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
        GL_LockArrays(0, 0);
        CHECKGLERROR
 }
 
+static unsigned char R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
+{
+       float dist = sqrt(x*x+y*y+z*z);
+       float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
+       return (unsigned char)bound(0, intensity * 256.0f, 255);
+}
+
 static void R_Shadow_MakeTextures(void)
 {
-       int x, y, z, d;
-       float v[3], intensity;
+       int x, y, z;
+       float intensity, dist;
        unsigned char *data;
+       unsigned int palette[256];
        R_FreeTexturePool(&r_shadow_texturepool);
        r_shadow_texturepool = R_AllocTexturePool();
-       r_shadow_attenpower = r_shadow_lightattenuationpower.value;
-       r_shadow_attenscale = r_shadow_lightattenuationscale.value;
-#define ATTEN2DSIZE 64
-#define ATTEN3DSIZE 32
-       data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
+       r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
+       r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
+       // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
+       for (x = 0;x < 256;x++)
+               palette[x] = x * 0x01010101;
+       data = (unsigned char *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE));
+       // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
+       for (x = 0;x <= ATTENTABLESIZE;x++)
+       {
+               dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
+               intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
+               r_shadow_attentable[x] = bound(0, intensity, 1);
+       }
+       // 1D gradient texture
+       for (x = 0;x < ATTEN1DSIZE;x++)
+               data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
+       r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
+       // 2D circle texture
        for (y = 0;y < ATTEN2DSIZE;y++)
-       {
                for (x = 0;x < ATTEN2DSIZE;x++)
-               {
-                       v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
-                       v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
-                       v[2] = 0;
-                       intensity = 1.0f - sqrt(DotProduct(v, v));
-                       if (intensity > 0)
-                               intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
-                       d = (int)bound(0, intensity, 255);
-                       data[(y*ATTEN2DSIZE+x)*4+0] = d;
-                       data[(y*ATTEN2DSIZE+x)*4+1] = d;
-                       data[(y*ATTEN2DSIZE+x)*4+2] = d;
-                       data[(y*ATTEN2DSIZE+x)*4+3] = d;
-               }
-       }
-       r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
+                       data[y*ATTEN2DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), 0);
+       r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
+       // 3D sphere texture
        if (r_shadow_texture3d.integer && gl_texture3d)
        {
                for (z = 0;z < ATTEN3DSIZE;z++)
-               {
                        for (y = 0;y < ATTEN3DSIZE;y++)
-                       {
                                for (x = 0;x < ATTEN3DSIZE;x++)
-                               {
-                                       v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
-                                       v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
-                                       v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
-                                       intensity = 1.0f - sqrt(DotProduct(v, v));
-                                       if (intensity > 0)
-                                               intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
-                                       d = (int)bound(0, intensity, 255);
-                                       data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
-                                       data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
-                                       data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
-                                       data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
-                               }
-                       }
-               }
-               r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
+                                       data[(z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375));
+               r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
        }
+       else
+               r_shadow_attenuation3dtexture = NULL;
        Mem_Free(data);
 }
 
@@ -990,12 +998,12 @@ void R_Shadow_RenderMode_Begin(void)
 
        if (!r_shadow_attenuation2dtexture
         || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
-        || r_shadow_lightattenuationpower.value != r_shadow_attenpower
-        || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
+        || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
+        || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
                R_Shadow_MakeTextures();
 
        CHECKGLERROR
-       R_Mesh_ColorPointer(NULL);
+       R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthTest(true);
@@ -1036,7 +1044,7 @@ void R_Shadow_RenderMode_Reset(void)
        {
                qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
        }
-       R_Mesh_ColorPointer(NULL);
+       R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
        GL_DepthTest(true);
        GL_DepthMask(false);
@@ -1259,92 +1267,155 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu
        float dist, dot, distintensity, shadeintensity, v[3], n[3];
        if (r_textureunits.integer >= 3)
        {
-               for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
+               if (VectorLength2(diffusecolor) > 0)
                {
-                       Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
-                       Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
-                       if ((dot = DotProduct(n, v)) < 0)
+                       for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
                        {
-                               shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
-                               color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
-                               color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
-                               color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
+                               Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
+                               Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
+                               if ((dot = DotProduct(n, v)) < 0)
+                               {
+                                       shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
+                                       VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
+                               }
+                               else
+                                       VectorCopy(ambientcolor, color4f);
                                if (r_refdef.fogenabled)
                                {
                                        float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
                                        VectorScale(color4f, f, color4f);
                                }
+                               color4f[3] = 1;
+                       }
+               }
+               else
+               {
+                       for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
+                       {
+                               VectorCopy(ambientcolor, color4f);
+                               if (r_refdef.fogenabled)
+                               {
+                                       float f;
+                                       Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
+                                       f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
+                                       VectorScale(color4f, f, color4f);
+                               }
+                               color4f[3] = 1;
                        }
-                       else
-                               VectorClear(color4f);
-                       color4f[3] = 1;
                }
        }
        else if (r_textureunits.integer >= 2)
        {
-               for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
+               if (VectorLength2(diffusecolor) > 0)
                {
-                       Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
-                       if ((dist = fabs(v[2])) < 1)
+                       for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
                        {
-                               distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
-                               Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
-                               if ((dot = DotProduct(n, v)) < 0)
+                               Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
+                               if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
                                {
-                                       shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
-                                       color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
-                                       color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
-                                       color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
+                                       Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
+                                       if ((dot = DotProduct(n, v)) < 0)
+                                       {
+                                               shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
+                                               color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
+                                               color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
+                                               color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
+                                       }
+                                       else
+                                       {
+                                               color4f[0] = ambientcolor[0] * distintensity;
+                                               color4f[1] = ambientcolor[1] * distintensity;
+                                               color4f[2] = ambientcolor[2] * distintensity;
+                                       }
+                                       if (r_refdef.fogenabled)
+                                       {
+                                               float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
+                                               VectorScale(color4f, f, color4f);
+                                       }
                                }
                                else
+                                       VectorClear(color4f);
+                               color4f[3] = 1;
+                       }
+               }
+               else
+               {
+                       for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
+                       {
+                               Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
+                               if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
                                {
                                        color4f[0] = ambientcolor[0] * distintensity;
                                        color4f[1] = ambientcolor[1] * distintensity;
                                        color4f[2] = ambientcolor[2] * distintensity;
+                                       if (r_refdef.fogenabled)
+                                       {
+                                               float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
+                                               VectorScale(color4f, f, color4f);
+                                       }
                                }
-                               if (r_refdef.fogenabled)
-                               {
-                                       float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
-                                       VectorScale(color4f, f, color4f);
-                               }
+                               else
+                                       VectorClear(color4f);
+                               color4f[3] = 1;
                        }
-                       else
-                               VectorClear(color4f);
-                       color4f[3] = 1;
                }
        }
        else
        {
-               for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
+               if (VectorLength2(diffusecolor) > 0)
                {
-                       Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
-                       if ((dist = DotProduct(v, v)) < 1)
+                       for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
                        {
-                               dist = sqrt(dist);
-                               distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
-                               Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
-                               if ((dot = DotProduct(n, v)) < 0)
+                               Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
+                               if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
                                {
-                                       shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
-                                       color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
-                                       color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
-                                       color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
+                                       distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
+                                       Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
+                                       if ((dot = DotProduct(n, v)) < 0)
+                                       {
+                                               shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
+                                               color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
+                                               color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
+                                               color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
+                                       }
+                                       else
+                                       {
+                                               color4f[0] = ambientcolor[0] * distintensity;
+                                               color4f[1] = ambientcolor[1] * distintensity;
+                                               color4f[2] = ambientcolor[2] * distintensity;
+                                       }
+                                       if (r_refdef.fogenabled)
+                                       {
+                                               float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
+                                               VectorScale(color4f, f, color4f);
+                                       }
                                }
                                else
+                                       VectorClear(color4f);
+                               color4f[3] = 1;
+                       }
+               }
+               else
+               {
+                       for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
+                       {
+                               Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
+                               if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
                                {
+                                       distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
                                        color4f[0] = ambientcolor[0] * distintensity;
                                        color4f[1] = ambientcolor[1] * distintensity;
                                        color4f[2] = ambientcolor[2] * distintensity;
+                                       if (r_refdef.fogenabled)
+                                       {
+                                               float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
+                                               VectorScale(color4f, f, color4f);
+                                       }
                                }
-                               if (r_refdef.fogenabled)
-                               {
-                                       float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
-                                       VectorScale(color4f, f, color4f);
-                               }
+                               else
+                                       VectorClear(color4f);
+                               color4f[3] = 1;
                        }
-                       else
-                               VectorClear(color4f);
-                       color4f[3] = 1;
                }
        }
 }
@@ -1393,35 +1464,35 @@ static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int nu
        }
 }
 
-static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
+static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
 {
        // used to display how many times a surface is lit for level design purposes
        GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
-       R_Mesh_ColorPointer(NULL);
+       R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
-       R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+       R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 }
 
-static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
+static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
 {
        // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
-       R_SetupSurfaceShader(lightcolorbase, false);
-       R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f);
-       R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
-       R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
-       R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
+       R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale);
+       R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f, rsurface_model->surfmesh.vbo, rsurface_model->surfmesh.vbooffset_texcoordtexture2f);
+       R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f, rsurface_svector3f_bufferobject, rsurface_svector3f_bufferoffset);
+       R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f, rsurface_tvector3f_bufferobject, rsurface_tvector3f_bufferoffset);
+       R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f, rsurface_normal3f_bufferobject, rsurface_normal3f_bufferoffset);
        if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
        {
                qglDepthFunc(GL_EQUAL);CHECKGLERROR
        }
-       R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+       R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
        if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
        {
                qglDepthFunc(GL_LEQUAL);CHECKGLERROR
        }
 }
 
-static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int numvertices, int numtriangles, const int *element3i, float r, float g, float b)
+static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, float r, float g, float b)
 {
        // shared final code for all the dot3 layers
        int renders;
@@ -1429,11 +1500,11 @@ static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int num
        for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
        {
                GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
-               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
        }
 }
 
-static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
+static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
 {
        rmeshstate_t m;
        // colorscale accounts for how much we multiply the brightness
@@ -1450,12 +1521,18 @@ static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int
                memset(&m, 0, sizeof(m));
                m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
                m.tex[1] = R_GetTexture(basetexture);
                m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[1] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[1] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[1] = rsurface_texture->currenttexmatrix;
                m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
                m.pointer_texcoord3f[2] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[2] = r_shadow_entitytolight;
                GL_BlendFunc(GL_ONE, GL_ONE);
        }
@@ -1465,9 +1542,13 @@ static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int
                memset(&m, 0, sizeof(m));
                m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
                m.tex[1] = R_GetTexture(basetexture);
                m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[1] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[1] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[1] = rsurface_texture->currenttexmatrix;
                GL_BlendFunc(GL_ONE, GL_ONE);
        }
@@ -1477,17 +1558,25 @@ static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
                m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[1] = r_shadow_entitytoattenuationz;
                m.tex[2] = R_GetTexture(basetexture);
                m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[2] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[2] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[2] = rsurface_texture->currenttexmatrix;
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
                        m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
                        m.pointer_texcoord3f[3] = rsurface_vertex3f;
+                       m.pointer_texcoord_bufferobject[3] = rsurface_vertex3f_bufferobject;
+                       m.pointer_texcoord_bufferoffset[3] = rsurface_vertex3f_bufferoffset;
                        m.texmatrix[3] = r_shadow_entitytolight;
                }
                GL_BlendFunc(GL_ONE, GL_ONE);
@@ -1498,12 +1587,18 @@ static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
                m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[1] = r_shadow_entitytoattenuationz;
                m.tex[2] = R_GetTexture(basetexture);
                m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[2] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[2] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[2] = rsurface_texture->currenttexmatrix;
                GL_BlendFunc(GL_ONE, GL_ONE);
        }
@@ -1513,34 +1608,42 @@ static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
                m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[1] = r_shadow_entitytoattenuationz;
                R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 
                // second pass
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(basetexture);
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
                        m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
                        m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
+                       m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
                        m.texmatrix[1] = r_shadow_entitytolight;
                }
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
        }
        // this final code is shared
        R_Mesh_TextureState(&m);
-       R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
+       R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
 }
 
-static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
+static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
 {
        rmeshstate_t m;
        // colorscale accounts for how much we multiply the brightness
@@ -1560,27 +1663,37 @@ static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int
                m.tex[0] = R_GetTexture(normalmaptexture);
                m.texcombinergb[0] = GL_REPLACE;
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
+               m.pointer_texcoord_bufferobject[1] = 0;
+               m.pointer_texcoord_bufferoffset[1] = 0;
                m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
                m.pointer_texcoord3f[2] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
                R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 
                // second pass
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(basetexture);
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
                        m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
                        m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
+                       m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
                        m.texmatrix[1] = r_shadow_entitytolight;
                }
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
@@ -1591,34 +1704,44 @@ static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int
                memset(&m, 0, sizeof(m));
                m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
                R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 
                // second pass
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(normalmaptexture);
                m.texcombinergb[0] = GL_REPLACE;
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
+               m.pointer_texcoord_bufferobject[1] = 0;
+               m.pointer_texcoord_bufferoffset[1] = 0;
                R_Mesh_TextureState(&m);
                GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 
                // second pass
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(basetexture);
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
                        m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
                        m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
+                       m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
                        m.texmatrix[1] = r_shadow_entitytolight;
                }
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
@@ -1630,22 +1753,30 @@ static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int
                m.tex[0] = R_GetTexture(normalmaptexture);
                m.texcombinergb[0] = GL_REPLACE;
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
+               m.pointer_texcoord_bufferobject[1] = 0;
+               m.pointer_texcoord_bufferoffset[1] = 0;
                R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 
                // second pass
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(basetexture);
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
                m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
        }
@@ -1656,30 +1787,42 @@ static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int
                m.tex[0] = R_GetTexture(normalmaptexture);
                m.texcombinergb[0] = GL_REPLACE;
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
+               m.pointer_texcoord_bufferobject[1] = 0;
+               m.pointer_texcoord_bufferoffset[1] = 0;
                m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
                m.pointer_texcoord3f[2] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
                m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
                m.pointer_texcoord3f[3] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[3] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[3] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[3] = r_shadow_entitytoattenuationz;
                R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 
                // second pass
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(basetexture);
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
                        m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
                        m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
+                       m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
                        m.texmatrix[1] = r_shadow_entitytolight;
                }
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
@@ -1690,47 +1833,59 @@ static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
                m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[1] = r_shadow_entitytoattenuationz;
                R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 
                // second pass
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(normalmaptexture);
                m.texcombinergb[0] = GL_REPLACE;
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
+               m.pointer_texcoord_bufferobject[1] = 0;
+               m.pointer_texcoord_bufferoffset[1] = 0;
                R_Mesh_TextureState(&m);
                GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 
                // second pass
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(basetexture);
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
                        m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
                        m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
+                       m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
                        m.texmatrix[1] = r_shadow_entitytolight;
                }
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
        }
        // this final code is shared
        R_Mesh_TextureState(&m);
-       R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
+       R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
 }
 
-static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
+static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
 {
        float glossexponent;
        rmeshstate_t m;
@@ -1746,41 +1901,51 @@ static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(normalmaptexture);
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
+               m.pointer_texcoord_bufferobject[1] = 0;
+               m.pointer_texcoord_bufferoffset[1] = 0;
                R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                // this squares the result
                GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 
                // second and third pass
                R_Mesh_ResetTextureState();
                // square alpha in framebuffer a few times to make it shiny
                GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
                for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
-                       R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+                       R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 
                // fourth pass
                memset(&m, 0, sizeof(m));
                m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
                R_Mesh_TextureState(&m);
                GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 
                // fifth pass
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(glosstexture);
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
                        m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
                        m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
+                       m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
                        m.texmatrix[1] = r_shadow_entitytolight;
                }
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
@@ -1791,30 +1956,38 @@ static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(normalmaptexture);
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
+               m.pointer_texcoord_bufferobject[1] = 0;
+               m.pointer_texcoord_bufferoffset[1] = 0;
                R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                // this squares the result
                GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 
                // second and third pass
                R_Mesh_ResetTextureState();
                // square alpha in framebuffer a few times to make it shiny
                GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
                for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
-                       R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+                       R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 
                // fourth pass
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(glosstexture);
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
                m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
        }
@@ -1824,85 +1997,97 @@ static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(normalmaptexture);
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
+               m.pointer_texcoord_bufferobject[1] = 0;
+               m.pointer_texcoord_bufferoffset[1] = 0;
                R_Mesh_TextureState(&m);
                GL_ColorMask(0,0,0,1);
                // this squares the result
                GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 
                // second and third pass
                R_Mesh_ResetTextureState();
                // square alpha in framebuffer a few times to make it shiny
                GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
                for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
-                       R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+                       R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 
                // fourth pass
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
                m.pointer_texcoord3f[0] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
                m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
                m.texmatrix[1] = r_shadow_entitytoattenuationz;
                R_Mesh_TextureState(&m);
                GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
-               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
+               R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
 
                // fifth pass
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(glosstexture);
                m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+               m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+               m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
                m.texmatrix[0] = rsurface_texture->currenttexmatrix;
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                {
                        m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
                        m.pointer_texcoord3f[1] = rsurface_vertex3f;
+                       m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
+                       m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
                        m.texmatrix[1] = r_shadow_entitytolight;
                }
                GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
        }
        // this final code is shared
        R_Mesh_TextureState(&m);
-       R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
+       R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
 }
 
-static void R_Shadow_RenderLighting_Light_Dot3(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
+static void R_Shadow_RenderLighting_Light_Dot3(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
 {
        // ARB path (any Geforce, any Radeon)
-       qboolean doambient = r_shadow_rtlight->ambientscale > 0;
-       qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
+       qboolean doambient = ambientscale > 0;
+       qboolean dodiffuse = diffusescale > 0;
        qboolean dospecular = specularscale > 0;
        if (!doambient && !dodiffuse && !dospecular)
                return;
-       R_Mesh_ColorPointer(NULL);
+       R_Mesh_ColorPointer(NULL, 0, 0);
        if (doambient)
-               R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
+               R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_view.colorscale);
        if (dodiffuse)
-               R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
+               R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_view.colorscale);
        if (dopants)
        {
                if (doambient)
-                       R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
+                       R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_view.colorscale);
                if (dodiffuse)
-                       R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
+                       R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_view.colorscale);
        }
        if (doshirt)
        {
                if (doambient)
-                       R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
+                       R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_view.colorscale);
                if (dodiffuse)
-                       R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
+                       R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_view.colorscale);
        }
        if (dospecular)
-               R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
+               R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
 }
 
-void R_Shadow_RenderLighting_Light_Vertex_Pass(const model_t *model, int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
+void R_Shadow_RenderLighting_Light_Vertex_Pass(const model_t *model, int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, vec3_t diffusecolor2, vec3_t ambientcolor2)
 {
        int renders;
        int i;
@@ -1913,7 +2098,7 @@ void R_Shadow_RenderLighting_Light_Vertex_Pass(const model_t *model, int firstve
        int *newe;
        const int *e;
        float *c;
-       int newelements[3072];
+       int newelements[4096*3];
        R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
        for (renders = 0;renders < 64;renders++)
        {
@@ -1950,9 +2135,9 @@ void R_Shadow_RenderLighting_Light_Vertex_Pass(const model_t *model, int firstve
                                newe[2] = e[2];
                                newnumtriangles++;
                                newe += 3;
-                               if (newnumtriangles >= 1024)
+                               if (newnumtriangles >= (int)(sizeof(newelements)/sizeof(float[3])))
                                {
-                                       R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements);
+                                       R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
                                        newnumtriangles = 0;
                                        newe = newelements;
                                        stop = false;
@@ -1961,7 +2146,11 @@ void R_Shadow_RenderLighting_Light_Vertex_Pass(const model_t *model, int firstve
                }
                if (newnumtriangles >= 1)
                {
-                       R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements);
+                       // if all triangles are included, use the original array to take advantage of the bufferobject if possible
+                       if (newnumtriangles == numtriangles)
+                               R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
+                       else
+                               R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
                        stop = false;
                }
                // if we couldn't find any lit triangles, exit early
@@ -1990,7 +2179,7 @@ void R_Shadow_RenderLighting_Light_Vertex_Pass(const model_t *model, int firstve
        }
 }
 
-static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
+static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
 {
        // OpenGL 1.1 path (anything)
        model_t *model = rsurface_entity->model;
@@ -1998,56 +2187,72 @@ static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertice
        float ambientcolorpants[3], diffusecolorpants[3];
        float ambientcolorshirt[3], diffusecolorshirt[3];
        rmeshstate_t m;
-       VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorbase);
-       VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorbase);
-       VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorpants);
-       VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorpants);
-       VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
-       VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
+       VectorScale(lightcolorbase, ambientscale * 2 * r_view.colorscale, ambientcolorbase);
+       VectorScale(lightcolorbase, diffusescale * 2 * r_view.colorscale, diffusecolorbase);
+       VectorScale(lightcolorpants, ambientscale * 2 * r_view.colorscale, ambientcolorpants);
+       VectorScale(lightcolorpants, diffusescale * 2 * r_view.colorscale, diffusecolorpants);
+       VectorScale(lightcolorshirt, ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
+       VectorScale(lightcolorshirt, diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
-       R_Mesh_ColorPointer(rsurface_array_color4f);
+       R_Mesh_ColorPointer(rsurface_array_color4f, 0, 0);
        memset(&m, 0, sizeof(m));
        m.tex[0] = R_GetTexture(basetexture);
        m.texmatrix[0] = rsurface_texture->currenttexmatrix;
        m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
+       m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
+       m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
        if (r_textureunits.integer >= 2)
        {
                // voodoo2 or TNT
                m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
                m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
                m.pointer_texcoord3f[1] = rsurface_vertex3f;
+               m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
+               m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
                if (r_textureunits.integer >= 3)
                {
                        // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
                        m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
                        m.texmatrix[2] = r_shadow_entitytoattenuationz;
                        m.pointer_texcoord3f[2] = rsurface_vertex3f;
+                       m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
+                       m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
                }
        }
        R_Mesh_TextureState(&m);
-       R_Mesh_TexBind(0, R_GetTexture(basetexture));
-       R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
+       //R_Mesh_TexBind(0, R_GetTexture(basetexture));
+       R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase);
        if (dopants)
        {
                R_Mesh_TexBind(0, R_GetTexture(pantstexture));
-               R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
+               R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants);
        }
        if (doshirt)
        {
                R_Mesh_TexBind(0, R_GetTexture(shirttexture));
-               R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
+               R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt);
        }
 }
 
-void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i)
+void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)
 {
+       float ambientscale, diffusescale, specularscale;
        // FIXME: support MATERIALFLAG_NODEPTHTEST
        vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
        // calculate colors to render this texture with
        lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
        lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
        lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
-       if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * rsurface_texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
+       ambientscale = r_shadow_rtlight->ambientscale;
+       diffusescale = r_shadow_rtlight->diffusescale;
+       specularscale = r_shadow_rtlight->specularscale * rsurface_texture->specularscale;
+       if (!r_shadow_usenormalmap.integer)
+       {
+               ambientscale += 1.0f * diffusescale;
+               diffusescale = 0;
+               specularscale = 0;
+       }
+       if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
                return;
        GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
        GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
@@ -2075,16 +2280,16 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                {
                case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
                        GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
-                       R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
+                       R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_GLSL:
-                       R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
+                       R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_DOT3:
-                       R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
+                       R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
-                       R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
+                       R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
                        break;
                default:
                        Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
@@ -2097,16 +2302,16 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles,
                {
                case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
                        GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
-                       R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
+                       R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_GLSL:
-                       R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
+                       R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_DOT3:
-                       R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
+                       R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
                        break;
                case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
-                       R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
+                       R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
                        break;
                default:
                        Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
@@ -2445,19 +2650,19 @@ void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned
                for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
                {
                        r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
-                       R_Mesh_VertexPointer(mesh->vertex3f);
+                       R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
                        GL_LockArrays(0, mesh->numverts);
                        if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
                        {
                                // decrement stencil if backface is behind depthbuffer
                                GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
                                qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
-                               R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
+                               R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
                                // increment stencil if frontface is behind depthbuffer
                                GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
                                qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
                        }
-                       R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
+                       R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
                        GL_LockArrays(0, 0);
                }
                CHECKGLERROR
@@ -2843,8 +3048,8 @@ void R_DrawModelShadows(void)
        GL_ScissorTest(true);
        R_Mesh_Matrix(&identitymatrix);
        R_Mesh_ResetTextureState();
-       R_Mesh_VertexPointer(vertex3f);
-       R_Mesh_ColorPointer(NULL);
+       R_Mesh_VertexPointer(vertex3f, 0, 0);
+       R_Mesh_ColorPointer(NULL, 0, 0);
 
        // set up a 50% darkening blend on shadowed areas
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -2860,7 +3065,7 @@ void R_DrawModelShadows(void)
        qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
 
        // apply the blend to the shadowed areas
-       R_Mesh_Draw(0, 4, 2, polygonelements);
+       R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
 
        // restoring the perspective view is done by R_RenderScene
        //R_SetupView(&r_view.matrix);