]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_backend.c
Add GL_ExtensionSupported in vid_null.c because vid_shared.c relies on
[xonotic/darkplaces.git] / gl_backend.c
index afaf8b08f503df80143e8d0fb3643e054170cf8a..34895d13730c9d396ec40fbc3a2ddc4981030239 100644 (file)
@@ -2,80 +2,9 @@
 #include "quakedef.h"
 #include "cl_collision.h"
 
-// on GLES we have to use some proper #define's
-#ifndef GL_FRAMEBUFFER
-#define GL_FRAMEBUFFER                                   0x8D40
-#define GL_DEPTH_ATTACHMENT                              0x8D00
-#define GL_COLOR_ATTACHMENT0                             0x8CE0
-#define GL_INVALID_FRAMEBUFFER_OPERATION                 0x0506
-#endif
-#ifndef GL_COLOR_ATTACHMENT1
-#define GL_COLOR_ATTACHMENT1                             0x8CE1
-#define GL_COLOR_ATTACHMENT2                             0x8CE2
-#define GL_COLOR_ATTACHMENT3                             0x8CE3
-#define GL_COLOR_ATTACHMENT4                             0x8CE4
-#define GL_COLOR_ATTACHMENT5                             0x8CE5
-#define GL_COLOR_ATTACHMENT6                             0x8CE6
-#define GL_COLOR_ATTACHMENT7                             0x8CE7
-#define GL_COLOR_ATTACHMENT8                             0x8CE8
-#define GL_COLOR_ATTACHMENT9                             0x8CE9
-#define GL_COLOR_ATTACHMENT10                            0x8CEA
-#define GL_COLOR_ATTACHMENT11                            0x8CEB
-#define GL_COLOR_ATTACHMENT12                            0x8CEC
-#define GL_COLOR_ATTACHMENT13                            0x8CED
-#define GL_COLOR_ATTACHMENT14                            0x8CEE
-#define GL_COLOR_ATTACHMENT15                            0x8CEF
-#endif
-#ifndef GL_ARRAY_BUFFER
-#define GL_ARRAY_BUFFER               0x8892
-#define GL_ELEMENT_ARRAY_BUFFER       0x8893
-#endif
-#ifndef GL_TEXTURE0
-#define GL_TEXTURE0                                    0x84C0
-#define GL_TEXTURE1                                    0x84C1
-#define GL_TEXTURE2                                    0x84C2
-#define GL_TEXTURE3                                    0x84C3
-#define GL_TEXTURE4                                    0x84C4
-#define GL_TEXTURE5                                    0x84C5
-#define GL_TEXTURE6                                    0x84C6
-#define GL_TEXTURE7                                    0x84C7
-#define GL_TEXTURE8                                    0x84C8
-#define GL_TEXTURE9                                    0x84C9
-#define GL_TEXTURE10                           0x84CA
-#define GL_TEXTURE11                           0x84CB
-#define GL_TEXTURE12                           0x84CC
-#define GL_TEXTURE13                           0x84CD
-#define GL_TEXTURE14                           0x84CE
-#define GL_TEXTURE15                           0x84CF
-#define GL_TEXTURE16                           0x84D0
-#define GL_TEXTURE17                           0x84D1
-#define GL_TEXTURE18                           0x84D2
-#define GL_TEXTURE19                           0x84D3
-#define GL_TEXTURE20                           0x84D4
-#define GL_TEXTURE21                           0x84D5
-#define GL_TEXTURE22                           0x84D6
-#define GL_TEXTURE23                           0x84D7
-#define GL_TEXTURE24                           0x84D8
-#define GL_TEXTURE25                           0x84D9
-#define GL_TEXTURE26                           0x84DA
-#define GL_TEXTURE27                           0x84DB
-#define GL_TEXTURE28                           0x84DC
-#define GL_TEXTURE29                           0x84DD
-#define GL_TEXTURE30                           0x84DE
-#define GL_TEXTURE31                           0x84DF
-#endif
-
-#ifndef GL_TEXTURE_3D
-#define GL_TEXTURE_3D                          0x806F
-#endif
-#ifndef GL_TEXTURE_CUBE_MAP
-#define GL_TEXTURE_CUBE_MAP                0x8513
-#endif
-
-
 #define MAX_RENDERTARGETS 4
 
-cvar_t gl_mesh_drawrangeelements = {0, "gl_mesh_drawrangeelements", "1", "use glDrawRangeElements function if available instead of glDrawElements (for performance comparisons or bug testing)"};
+cvar_t gl_debug = {0, "gl_debug", "0", "enables OpenGL debug output, 0 = off, 1 = HIGH severity only, 2 = also MEDIUM severity, 3 = also LOW severity messages.  (note: enabling may not take effect until vid_restart on some drivers)"};
 cvar_t gl_paranoid = {0, "gl_paranoid", "0", "enables OpenGL error checking and other tests"};
 cvar_t gl_printcheckerror = {0, "gl_printcheckerror", "0", "prints all OpenGL error checks, useful to identify location of driver crashes"};
 
@@ -83,11 +12,6 @@ cvar_t r_render = {0, "r_render", "1", "enables rendering 3D views (you want thi
 cvar_t r_renderview = {0, "r_renderview", "1", "enables rendering 3D views (you want this on!)"};
 cvar_t r_waterwarp = {CVAR_SAVE, "r_waterwarp", "1", "warp view while underwater"};
 cvar_t gl_polyblend = {CVAR_SAVE, "gl_polyblend", "1", "tints view while underwater, hurt, etc"};
-cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1", "enables OpenGL dithering (16bit looks bad with this off)"};
-cvar_t gl_vbo = {CVAR_SAVE, "gl_vbo", "3", "make use of GL_ARB_vertex_buffer_object extension to store static geometry in video memory for faster rendering, 0 disables VBO allocation or use, 1 enables VBOs for vertex and triangle data, 2 only for vertex data, 3 for vertex data and triangle data of simple meshes (ones with only one surface)"};
-cvar_t gl_vbo_dynamicvertex = {CVAR_SAVE, "gl_vbo_dynamicvertex", "0", "make use of GL_ARB_vertex_buffer_object extension when rendering dynamic (animated/procedural) geometry such as text and particles"};
-cvar_t gl_vbo_dynamicindex = {CVAR_SAVE, "gl_vbo_dynamicindex", "0", "make use of GL_ARB_vertex_buffer_object extension when rendering dynamic (animated/procedural) geometry such as text and particles"};
-cvar_t gl_fbo = {CVAR_SAVE, "gl_fbo", "1", "make use of GL_ARB_framebuffer_object extension to enable shadowmaps and other features using pixel formats different from the framebuffer"};
 
 cvar_t v_flipped = {0, "v_flipped", "0", "mirror the screen (poor man's left handed mode)"};
 qboolean v_flipped_state = false;
@@ -102,9 +26,6 @@ float gl_modelview16f[16];
 float gl_modelviewprojection16f[16];
 qboolean gl_modelmatrixchanged;
 
-int gl_maxdrawrangeelementsvertices;
-int gl_maxdrawrangeelementsindices;
-
 #ifdef DEBUGGL
 int gl_errornumber = 0;
 
@@ -157,6 +78,36 @@ void GL_PrintError(int errornumber, const char *filename, int linenumber)
                break;
        }
 }
+
+static void GLAPIENTRY GL_DebugOutputCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const GLvoid* userParam)
+{
+       const char *sev = "ENUM?", *typ = "ENUM?", *src = "ENUM?";
+       switch (severity)
+       {
+       case GL_DEBUG_SEVERITY_LOW_ARB: sev = "LOW"; break;
+       case GL_DEBUG_SEVERITY_MEDIUM_ARB: sev = "MED"; break;
+       case GL_DEBUG_SEVERITY_HIGH_ARB: sev = "HIGH"; break;
+       }
+       switch (type)
+       {
+       case GL_DEBUG_TYPE_ERROR_ARB: typ = "ERROR"; break;
+       case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: typ = "DEPRECATED"; break;
+       case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: typ = "UNDEFINED"; break;
+       case GL_DEBUG_TYPE_PORTABILITY_ARB: typ = "PORTABILITY"; break;
+       case GL_DEBUG_TYPE_PERFORMANCE_ARB: typ = "PERFORMANCE"; break;
+       case GL_DEBUG_TYPE_OTHER_ARB: typ = "OTHER"; break;
+       }
+       switch (source)
+       {
+       case GL_DEBUG_SOURCE_API_ARB: src = "API"; break;
+       case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: src = "SHADER"; break;
+       case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: src = "WIN"; break;
+       case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: src = "THIRDPARTY"; break;
+       case GL_DEBUG_SOURCE_APPLICATION_ARB: src = "APP"; break;
+       case GL_DEBUG_SOURCE_OTHER_ARB: src = "OTHER"; break;
+       }
+       Con_Printf("GLDEBUG: %s %s %s: %u: %s\n", sev, typ, src, (unsigned int)id, message);
+}
 #endif
 
 #define BACKENDACTIVECHECK if (!gl_state.active) Sys_Error("GL backend function called when backend is not active");
@@ -175,12 +126,6 @@ typedef struct gltextureunit_s
        rtexture_t *texture;
        int t2d, t3d, tcubemap;
        int arrayenabled;
-       int rgbscale, alphascale;
-       int combine;
-       int combinergb, combinealpha;
-       // texmatrixenabled exists only to avoid unnecessary texmatrix compares
-       int texmatrixenabled;
-       matrix4x4_t matrix;
 }
 gltextureunit_t;
 
@@ -197,13 +142,9 @@ typedef struct gl_state_s
        int depthfunc;
        float depthrange[2];
        float polygonoffset[2];
-       int alphatest;
-       int alphafunc;
-       float alphafuncvalue;
        qboolean alphatocoverage;
        int scissortest;
        unsigned int unit;
-       unsigned int clientunit;
        gltextureunit_t units[MAX_TEXTUREUNITS];
        float color4f[4];
        int lockrange_first;
@@ -215,6 +156,9 @@ typedef struct gl_state_s
        int defaultframebufferobject; // deal with platforms that use a non-zero default fbo
        qboolean pointer_color_enabled;
 
+       // GL3.2 Core requires that we have a GL_VERTEX_ARRAY_OBJECT, but... just one.
+       unsigned int defaultvao;
+
        int pointer_vertex_components;
        int pointer_vertex_gltype;
        size_t pointer_vertex_stride;
@@ -231,15 +175,8 @@ typedef struct gl_state_s
 
        void *preparevertices_tempdata;
        size_t preparevertices_tempdatamaxsize;
-       r_vertexgeneric_t *preparevertices_vertexgeneric;
-       r_vertexmesh_t *preparevertices_vertexmesh;
        int preparevertices_numvertices;
 
-       qboolean usevbo_staticvertex;
-       qboolean usevbo_staticindex;
-       qboolean usevbo_dynamicvertex;
-       qboolean usevbo_dynamicindex;
-
        memexpandablearray_t meshbufferarray;
 
        qboolean active;
@@ -315,42 +252,31 @@ static void GL_VBOStats_f(void)
 
 static void GL_Backend_ResetState(void);
 
-static void R_Mesh_SetUseVBO(void)
-{
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_GLES2:
-               gl_state.usevbo_staticvertex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo;
-               gl_state.usevbo_staticindex = (vid.support.arb_vertex_buffer_object && (gl_vbo.integer == 1 || gl_vbo.integer == 3)) || vid.forcevbo;
-               gl_state.usevbo_dynamicvertex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicvertex.integer && gl_vbo.integer) || vid.forcevbo;
-               gl_state.usevbo_dynamicindex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicindex.integer && gl_vbo.integer) || vid.forcevbo;
-               break;
-       }
-}
-
 static void gl_backend_start(void)
 {
        memset(&gl_state, 0, sizeof(gl_state));
 
-       R_Mesh_SetUseVBO();
        Mem_ExpandableArray_NewArray(&gl_state.meshbufferarray, r_main_mempool, sizeof(r_meshbuffer_t), 128);
 
        Con_DPrintf("OpenGL backend started.\n");
 
        CHECKGLERROR
 
-       GL_Backend_ResetState();
-
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
+               // GL3.2 Core requires that we have a VAO bound - but using more than one has no performance benefit so this is just placeholder
+               qglGenVertexArrays(1, &gl_state.defaultvao);
+               qglBindVertexArray(gl_state.defaultvao);
+               // fall through
        case RENDERPATH_GLES2:
                // fetch current fbo here (default fbo is not 0 on some GLES devices)
-               if (vid.support.ext_framebuffer_object)
-                       qglGetIntegerv(GL_FRAMEBUFFER_BINDING, &gl_state.defaultframebufferobject);
+               CHECKGLERROR
+               qglGetIntegerv(GL_FRAMEBUFFER_BINDING, &gl_state.defaultframebufferobject);CHECKGLERROR
                break;
        }
+
+       GL_Backend_ResetState();
 }
 
 static void gl_backend_shutdown(void)
@@ -359,7 +285,7 @@ static void gl_backend_shutdown(void)
 
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                break;
        }
@@ -382,7 +308,7 @@ static void gl_backend_devicelost(void)
        r_meshbuffer_t *buffer;
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                break;
        }
@@ -394,7 +320,7 @@ static void gl_backend_devicelost(void)
                        continue;
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL20:
+               case RENDERPATH_GL32:
                case RENDERPATH_GLES2:
                        break;
                }
@@ -405,7 +331,7 @@ static void gl_backend_devicerestored(void)
 {
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                break;
        }
@@ -442,15 +368,10 @@ void gl_backend_init(void)
        Cvar_RegisterVariable(&r_waterwarp);
        Cvar_RegisterVariable(&gl_polyblend);
        Cvar_RegisterVariable(&v_flipped);
-       Cvar_RegisterVariable(&gl_dither);
-       Cvar_RegisterVariable(&gl_vbo);
-       Cvar_RegisterVariable(&gl_vbo_dynamicvertex);
-       Cvar_RegisterVariable(&gl_vbo_dynamicindex);
+       Cvar_RegisterVariable(&gl_debug);
        Cvar_RegisterVariable(&gl_paranoid);
        Cvar_RegisterVariable(&gl_printcheckerror);
 
-       Cvar_RegisterVariable(&gl_mesh_drawrangeelements);
-
        Cmd_AddCommand("gl_vbostats", GL_VBOStats_f, "prints a list of all buffer objects (vertex data and triangle elements) and total video memory used by them");
 
        R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap, gl_backend_devicelost, gl_backend_devicerestored);
@@ -478,9 +399,10 @@ void GL_Finish(void)
 {
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
-               qglFinish();
+               CHECKGLERROR
+               qglFinish();CHECKGLERROR
                break;
        }
 }
@@ -617,7 +539,7 @@ qboolean R_ScissorForBBox(const float *mins, const float *maxs, int *scissor)
        // D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                break;
        }
@@ -642,19 +564,6 @@ static void R_Viewport_ApplyNearClipPlaneFloatGL(const r_viewport_t *v, float *m
        // FIXME: LordHavoc: I think this can be done more efficiently somehow but I can't remember the technique
        clipPlane[3] = -DotProduct(v4, clipPlane);
 
-#if 0
-{
-       // testing code for comparing results
-       float clipPlane2[4];
-       VectorCopy4(clipPlane, clipPlane2);
-       R_EntityMatrix(&identitymatrix);
-       VectorSet(q, normal[0], normal[1], normal[2], -dist);
-       qglClipPlane(GL_CLIP_PLANE0, q);
-       qglGetClipPlane(GL_CLIP_PLANE0, q);
-       VectorCopy4(q, clipPlane);
-}
-#endif
-
        // Calculate the clip-space corner point opposite the clipping plane
        // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
        // transform it into camera space by multiplying it
@@ -697,7 +606,7 @@ void R_Viewport_InitOrtho(r_viewport_t *v, const matrix4x4_t *cameramatrix, int
        m[15] = 1;
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                break;
        }
@@ -997,7 +906,7 @@ void R_SetViewport(const r_viewport_t *v)
 
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                CHECKGLERROR
                qglViewport(v->x, v->y, v->width, v->height);CHECKGLERROR
@@ -1020,7 +929,7 @@ static void GL_BindVBO(int bufferobject)
        {
                gl_state.vertexbufferobject = bufferobject;
                CHECKGLERROR
-               qglBindBufferARB(GL_ARRAY_BUFFER, bufferobject);CHECKGLERROR
+               qglBindBuffer(GL_ARRAY_BUFFER, bufferobject);CHECKGLERROR
        }
 }
 
@@ -1030,7 +939,7 @@ static void GL_BindEBO(int bufferobject)
        {
                gl_state.elementbufferobject = bufferobject;
                CHECKGLERROR
-               qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, bufferobject);CHECKGLERROR
+               qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferobject);CHECKGLERROR
        }
 }
 
@@ -1041,7 +950,7 @@ static void GL_BindUBO(int bufferobject)
                gl_state.uniformbufferobject = bufferobject;
 #ifdef GL_UNIFORM_BUFFER
                CHECKGLERROR
-               qglBindBufferARB(GL_UNIFORM_BUFFER, bufferobject);CHECKGLERROR
+               qglBindBuffer(GL_UNIFORM_BUFFER, bufferobject);CHECKGLERROR
 #endif
        }
 }
@@ -1049,135 +958,77 @@ static void GL_BindUBO(int bufferobject)
 static const GLuint drawbuffers[4] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
 int R_Mesh_CreateFramebufferObject(rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4)
 {
+       int temp;
+       GLuint status;
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
-               if (vid.support.arb_framebuffer_object)
-               {
-                       int temp;
-                       GLuint status;
-                       qglGenFramebuffers(1, (GLuint*)&temp);CHECKGLERROR
-                       R_Mesh_SetRenderTargets(temp, NULL, NULL, NULL, NULL, NULL);
-                       // GL_ARB_framebuffer_object (GL3-class hardware) - depth stencil attachment
+               CHECKGLERROR
+               qglGenFramebuffers(1, (GLuint*)&temp);CHECKGLERROR
+               R_Mesh_SetRenderTargets(temp, NULL, NULL, NULL, NULL, NULL);
+               // GL_ARB_framebuffer_object (GL3-class hardware) - depth stencil attachment
 #ifdef USE_GLES2
-                       // FIXME: separate stencil attachment on GLES
-                       if (depthtexture  && depthtexture->texnum ) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT  , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR
-                       if (depthtexture  && depthtexture->renderbuffernum ) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT  , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR
+               // FIXME: separate stencil attachment on GLES
+               if (depthtexture  && depthtexture->texnum ) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT  , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR
+               if (depthtexture  && depthtexture->renderbuffernum ) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT  , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR
 #else
-                       if (depthtexture  && depthtexture->texnum )
-                       {
-                               qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT  , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR
-                               if (depthtexture->glisdepthstencil) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT  , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR
-                       }
-                       if (depthtexture  && depthtexture->renderbuffernum )
-                       {
-                               qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT  , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR
-                               if (depthtexture->glisdepthstencil) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT  , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR
-                       }
+               if (depthtexture  && depthtexture->texnum )
+               {
+                       qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT  , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR
+                       if (depthtexture->glisdepthstencil) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT  , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR
+               }
+               if (depthtexture  && depthtexture->renderbuffernum )
+               {
+                       qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT  , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR
+                       if (depthtexture->glisdepthstencil) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT  , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR
+               }
 #endif
-                       if (colortexture  && colortexture->texnum ) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , colortexture->gltexturetypeenum , colortexture->texnum , 0);CHECKGLERROR
-                       if (colortexture2 && colortexture2->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , colortexture2->gltexturetypeenum, colortexture2->texnum, 0);CHECKGLERROR
-                       if (colortexture3 && colortexture3->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , colortexture3->gltexturetypeenum, colortexture3->texnum, 0);CHECKGLERROR
-                       if (colortexture4 && colortexture4->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , colortexture4->gltexturetypeenum, colortexture4->texnum, 0);CHECKGLERROR
-                       if (colortexture  && colortexture->renderbuffernum ) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , GL_RENDERBUFFER, colortexture->renderbuffernum );CHECKGLERROR
-                       if (colortexture2 && colortexture2->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , GL_RENDERBUFFER, colortexture2->renderbuffernum);CHECKGLERROR
-                       if (colortexture3 && colortexture3->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , GL_RENDERBUFFER, colortexture3->renderbuffernum);CHECKGLERROR
-                       if (colortexture4 && colortexture4->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , GL_RENDERBUFFER, colortexture4->renderbuffernum);CHECKGLERROR
+               if (colortexture  && colortexture->texnum ) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , colortexture->gltexturetypeenum , colortexture->texnum , 0);CHECKGLERROR
+               if (colortexture2 && colortexture2->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , colortexture2->gltexturetypeenum, colortexture2->texnum, 0);CHECKGLERROR
+               if (colortexture3 && colortexture3->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , colortexture3->gltexturetypeenum, colortexture3->texnum, 0);CHECKGLERROR
+               if (colortexture4 && colortexture4->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , colortexture4->gltexturetypeenum, colortexture4->texnum, 0);CHECKGLERROR
+               if (colortexture  && colortexture->renderbuffernum ) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , GL_RENDERBUFFER, colortexture->renderbuffernum );CHECKGLERROR
+               if (colortexture2 && colortexture2->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , GL_RENDERBUFFER, colortexture2->renderbuffernum);CHECKGLERROR
+               if (colortexture3 && colortexture3->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , GL_RENDERBUFFER, colortexture3->renderbuffernum);CHECKGLERROR
+               if (colortexture4 && colortexture4->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , GL_RENDERBUFFER, colortexture4->renderbuffernum);CHECKGLERROR
 
 #ifndef USE_GLES2
-                       if (colortexture4 && qglDrawBuffersARB)
-                       {
-                               qglDrawBuffersARB(4, drawbuffers);CHECKGLERROR
-                               qglReadBuffer(GL_NONE);CHECKGLERROR
-                       }
-                       else if (colortexture3 && qglDrawBuffersARB)
-                       {
-                               qglDrawBuffersARB(3, drawbuffers);CHECKGLERROR
-                               qglReadBuffer(GL_NONE);CHECKGLERROR
-                       }
-                       else if (colortexture2 && qglDrawBuffersARB)
-                       {
-                               qglDrawBuffersARB(2, drawbuffers);CHECKGLERROR
-                               qglReadBuffer(GL_NONE);CHECKGLERROR
-                       }
-                       else if (colortexture && qglDrawBuffer)
-                       {
-                               qglDrawBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR
-                               qglReadBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR
-                       }
-                       else if (qglDrawBuffer)
-                       {
-                               qglDrawBuffer(GL_NONE);CHECKGLERROR
-                               qglReadBuffer(GL_NONE);CHECKGLERROR
-                       }
-#endif
-                       status = qglCheckFramebufferStatus(GL_FRAMEBUFFER);CHECKGLERROR
-                       if (status != GL_FRAMEBUFFER_COMPLETE)
-                       {
-                               Con_Printf("R_Mesh_CreateFramebufferObject: glCheckFramebufferStatus returned %i\n", status);
-                               gl_state.framebufferobject = 0; // GL unbinds it for us
-                               qglDeleteFramebuffers(1, (GLuint*)&temp);
-                               temp = 0;
-                       }
-                       return temp;
+               if (colortexture4)
+               {
+                       qglDrawBuffers(4, drawbuffers);CHECKGLERROR
+                       qglReadBuffer(GL_NONE);CHECKGLERROR
                }
-               else if (vid.support.ext_framebuffer_object)
+               else if (colortexture3)
                {
-                       int temp;
-                       GLuint status;
-                       qglGenFramebuffers(1, (GLuint*)&temp);CHECKGLERROR
-                       R_Mesh_SetRenderTargets(temp, NULL, NULL, NULL, NULL, NULL);
-                       // GL_EXT_framebuffer_object (GL2-class hardware) - no depth stencil attachment, let it break stencil
-                       if (depthtexture  && depthtexture->texnum ) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT  , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR
-                       if (depthtexture  && depthtexture->renderbuffernum ) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT  , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR
-                       if (colortexture  && colortexture->texnum ) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , colortexture->gltexturetypeenum , colortexture->texnum , 0);CHECKGLERROR
-                       if (colortexture2 && colortexture2->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , colortexture2->gltexturetypeenum, colortexture2->texnum, 0);CHECKGLERROR
-                       if (colortexture3 && colortexture3->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , colortexture3->gltexturetypeenum, colortexture3->texnum, 0);CHECKGLERROR
-                       if (colortexture4 && colortexture4->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , colortexture4->gltexturetypeenum, colortexture4->texnum, 0);CHECKGLERROR
-                       if (colortexture  && colortexture->renderbuffernum ) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , GL_RENDERBUFFER, colortexture->renderbuffernum );CHECKGLERROR
-                       if (colortexture2 && colortexture2->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , GL_RENDERBUFFER, colortexture2->renderbuffernum);CHECKGLERROR
-                       if (colortexture3 && colortexture3->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , GL_RENDERBUFFER, colortexture3->renderbuffernum);CHECKGLERROR
-                       if (colortexture4 && colortexture4->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , GL_RENDERBUFFER, colortexture4->renderbuffernum);CHECKGLERROR
-
-#ifndef USE_GLES2
-                       if (colortexture4 && qglDrawBuffersARB)
-                       {
-                               qglDrawBuffersARB(4, drawbuffers);CHECKGLERROR
-                               qglReadBuffer(GL_NONE);CHECKGLERROR
-                       }
-                       else if (colortexture3 && qglDrawBuffersARB)
-                       {
-                               qglDrawBuffersARB(3, drawbuffers);CHECKGLERROR
-                               qglReadBuffer(GL_NONE);CHECKGLERROR
-                       }
-                       else if (colortexture2 && qglDrawBuffersARB)
-                       {
-                               qglDrawBuffersARB(2, drawbuffers);CHECKGLERROR
-                               qglReadBuffer(GL_NONE);CHECKGLERROR
-                       }
-                       else if (colortexture && qglDrawBuffer)
-                       {
-                               qglDrawBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR
-                               qglReadBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR
-                       }
-                       else if (qglDrawBuffer)
-                       {
-                               qglDrawBuffer(GL_NONE);CHECKGLERROR
-                               qglReadBuffer(GL_NONE);CHECKGLERROR
-                       }
+                       qglDrawBuffers(3, drawbuffers);CHECKGLERROR
+                       qglReadBuffer(GL_NONE);CHECKGLERROR
+               }
+               else if (colortexture2)
+               {
+                       qglDrawBuffers(2, drawbuffers);CHECKGLERROR
+                       qglReadBuffer(GL_NONE);CHECKGLERROR
+               }
+               else if (colortexture)
+               {
+                       qglDrawBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR
+                       qglReadBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR
+               }
+               else
+               {
+                       qglDrawBuffer(GL_NONE);CHECKGLERROR
+                       qglReadBuffer(GL_NONE);CHECKGLERROR
+               }
 #endif
-                       status = qglCheckFramebufferStatus(GL_FRAMEBUFFER);CHECKGLERROR
-                       if (status != GL_FRAMEBUFFER_COMPLETE)
-                       {
-                               Con_Printf("R_Mesh_CreateFramebufferObject: glCheckFramebufferStatus returned %i\n", status);
-                               gl_state.framebufferobject = 0; // GL unbinds it for us
-                               qglDeleteFramebuffers(1, (GLuint*)&temp);
-                               temp = 0;
-                       }
-                       return temp;
+               status = qglCheckFramebufferStatus(GL_FRAMEBUFFER);CHECKGLERROR
+               if (status != GL_FRAMEBUFFER_COMPLETE)
+               {
+                       Con_Printf("R_Mesh_CreateFramebufferObject: glCheckFramebufferStatus returned %i\n", status);
+                       gl_state.framebufferobject = 0; // GL unbinds it for us
+                       qglDeleteFramebuffers(1, (GLuint*)&temp);CHECKGLERROR
+                       temp = 0;
                }
-               return 0;
+               return temp;
        }
        return 0;
 }
@@ -1186,14 +1037,14 @@ void R_Mesh_DestroyFramebufferObject(int fbo)
 {
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                if (fbo)
                {
                        // GL clears the binding if we delete something bound
                        if (gl_state.framebufferobject == fbo)
                                gl_state.framebufferobject = 0;
-                       qglDeleteFramebuffers(1, (GLuint*)&fbo);
+                       qglDeleteFramebuffers(1, (GLuint*)&fbo);CHECKGLERROR
                }
                break;
        }
@@ -1209,18 +1060,18 @@ void R_Mesh_SetRenderTargets(int fbo, rtexture_t *depthtexture, rtexture_t *colo
        // unbind any matching textures immediately, otherwise D3D will complain about a bound texture being used as a render target
        for (j = 0;j < 5;j++)
                if (textures[j])
-                       for (i = 0;i < vid.teximageunits;i++)
+                       for (i = 0;i < MAX_TEXTUREUNITS;i++)
                                if (gl_state.units[i].texture == textures[j])
                                        R_Mesh_TexBind(i, NULL);
        // set up framebuffer object or render targets for the active rendering API
        switch (vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                if (gl_state.framebufferobject != fbo)
                {
                        gl_state.framebufferobject = fbo;
-                       qglBindFramebuffer(GL_FRAMEBUFFER, gl_state.framebufferobject ? gl_state.framebufferobject : gl_state.defaultframebufferobject);
+                       qglBindFramebuffer(GL_FRAMEBUFFER, gl_state.framebufferobject ? gl_state.framebufferobject : gl_state.defaultframebufferobject);CHECKGLERROR
                }
                break;
        }
@@ -1228,12 +1079,8 @@ void R_Mesh_SetRenderTargets(int fbo, rtexture_t *depthtexture, rtexture_t *colo
 
 static void GL_Backend_ResetState(void)
 {
-       unsigned int i;
        gl_state.active = true;
        gl_state.depthtest = true;
-       gl_state.alphatest = false;
-       gl_state.alphafunc = GL_GEQUAL;
-       gl_state.alphafuncvalue = 0.5f;
        gl_state.alphatocoverage = false;
        gl_state.blendfunc1 = GL_ONE;
        gl_state.blendfunc2 = GL_ZERO;
@@ -1252,8 +1099,27 @@ static void GL_Backend_ResetState(void)
 
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
+               // set up debug output early
+               if (vid.support.arb_debug_output)
+               {
+                       GLuint unused = 0;
+                       CHECKGLERROR
+                       if (gl_debug.integer >= 1)
+                               qglEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
+                       if (gl_debug.integer >= 3)
+                               qglDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, &unused, gl_debug.integer >= 3 ? GL_TRUE : GL_FALSE);
+                       else if (gl_debug.integer >= 1)
+                       {
+                               qglDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, &unused, gl_debug.integer >= 3 ? GL_TRUE : GL_FALSE);
+                               qglDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM_ARB, 0, &unused, gl_debug.integer >= 2 ? GL_TRUE : GL_FALSE);
+                               qglDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH_ARB, 0, &unused, gl_debug.integer >= 1 ? GL_TRUE : GL_FALSE);
+                       }
+                       else
+                               qglDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, &unused, GL_FALSE);
+                       qglDebugMessageCallbackARB(GL_DebugOutputCallback, NULL);
+               }
                CHECKGLERROR
                qglColorMask(1, 1, 1, 1);CHECKGLERROR
                qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
@@ -1264,39 +1130,13 @@ static void GL_Backend_ResetState(void)
                qglEnable(GL_DEPTH_TEST);CHECKGLERROR
                qglDepthMask(gl_state.depthmask);CHECKGLERROR
                qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
-               if (vid.support.arb_vertex_buffer_object)
-               {
-                       qglBindBufferARB(GL_ARRAY_BUFFER, 0);
-                       qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0);
-               }
-               if (vid.support.ext_framebuffer_object)
-                       qglBindFramebuffer(GL_FRAMEBUFFER, gl_state.defaultframebufferobject);
+               qglBindBuffer(GL_ARRAY_BUFFER, 0);
+               qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+               qglBindFramebuffer(GL_FRAMEBUFFER, gl_state.defaultframebufferobject);
                qglEnableVertexAttribArray(GLSLATTRIB_POSITION);
-               qglVertexAttribPointer(GLSLATTRIB_POSITION, 3, GL_FLOAT, false, sizeof(float[3]), NULL);CHECKGLERROR
                qglDisableVertexAttribArray(GLSLATTRIB_COLOR);
-               qglVertexAttribPointer(GLSLATTRIB_COLOR, 4, GL_FLOAT, false, sizeof(float[4]), NULL);CHECKGLERROR
                qglVertexAttrib4f(GLSLATTRIB_COLOR, 1, 1, 1, 1);
                gl_state.unit = MAX_TEXTUREUNITS;
-               gl_state.clientunit = MAX_TEXTUREUNITS;
-               for (i = 0;i < vid.teximageunits;i++)
-               {
-                       GL_ActiveTexture(i);
-                       qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
-                       if (vid.support.ext_texture_3d)
-                       {
-                               qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
-                       }
-                       if (vid.support.arb_texture_cube_map)
-                       {
-                               qglBindTexture(GL_TEXTURE_CUBE_MAP, 0);CHECKGLERROR
-                       }
-               }
-               for (i = 0;i < vid.texarrayunits;i++)
-               {
-                       GL_BindVBO(0);
-                       qglVertexAttribPointer(i+GLSLATTRIB_TEXCOORD0, 2, GL_FLOAT, false, sizeof(float[2]), NULL);CHECKGLERROR
-                       qglDisableVertexAttribArray(i+GLSLATTRIB_TEXCOORD0);CHECKGLERROR
-               }
                CHECKGLERROR
                break;
        }
@@ -1309,11 +1149,10 @@ void GL_ActiveTexture(unsigned int num)
                gl_state.unit = num;
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL20:
+               case RENDERPATH_GL32:
                case RENDERPATH_GLES2:
                        CHECKGLERROR
-                       qglActiveTexture(GL_TEXTURE0 + gl_state.unit);
-                       CHECKGLERROR
+                       qglActiveTexture(GL_TEXTURE0 + gl_state.unit);CHECKGLERROR
                        break;
                }
        }
@@ -1329,7 +1168,7 @@ void GL_BlendFunc(int blendfunc1, int blendfunc2)
                blendenable = (gl_state.blendfunc1 != GL_ONE || gl_state.blendfunc2 != GL_ZERO);
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL20:
+               case RENDERPATH_GL32:
                case RENDERPATH_GLES2:
                        CHECKGLERROR
                        if (qglBlendFuncSeparate)
@@ -1364,7 +1203,7 @@ void GL_DepthMask(int state)
                gl_state.depthmask = state;
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL20:
+               case RENDERPATH_GL32:
                case RENDERPATH_GLES2:
                        CHECKGLERROR
                        qglDepthMask(gl_state.depthmask);CHECKGLERROR
@@ -1380,7 +1219,7 @@ void GL_DepthTest(int state)
                gl_state.depthtest = state;
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL20:
+               case RENDERPATH_GL32:
                case RENDERPATH_GLES2:
                        CHECKGLERROR
                        if (gl_state.depthtest)
@@ -1403,7 +1242,7 @@ void GL_DepthFunc(int state)
                gl_state.depthfunc = state;
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL20:
+               case RENDERPATH_GL32:
                case RENDERPATH_GLES2:
                        CHECKGLERROR
                        qglDepthFunc(gl_state.depthfunc);CHECKGLERROR
@@ -1420,64 +1259,24 @@ void GL_DepthRange(float nearfrac, float farfrac)
                gl_state.depthrange[1] = farfrac;
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL20:
+               case RENDERPATH_GL32:
                case RENDERPATH_GLES2:
+                       CHECKGLERROR
 #ifdef USE_GLES2
-                       qglDepthRangef(gl_state.depthrange[0], gl_state.depthrange[1]);
+                       qglDepthRangef(gl_state.depthrange[0], gl_state.depthrange[1]);CHECKGLERROR
 #else
-                       qglDepthRange(gl_state.depthrange[0], gl_state.depthrange[1]);
+                       qglDepthRange(gl_state.depthrange[0], gl_state.depthrange[1]);CHECKGLERROR
 #endif
                        break;
                }
        }
 }
 
-void R_SetStencilSeparate(qboolean enable, int writemask, int frontfail, int frontzfail, int frontzpass, int backfail, int backzfail, int backzpass, int frontcompare, int backcompare, int comparereference, int comparemask)
-{
-       switch (vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_GLES2:
-               CHECKGLERROR
-               if (enable)
-               {
-                       qglEnable(GL_STENCIL_TEST);CHECKGLERROR
-               }
-               else
-               {
-                       qglDisable(GL_STENCIL_TEST);CHECKGLERROR
-               }
-               if (vid.support.ati_separate_stencil)
-               {
-                       qglStencilMask(writemask);CHECKGLERROR
-                       qglStencilOpSeparate(GL_FRONT, frontfail, frontzfail, frontzpass);CHECKGLERROR
-                       qglStencilOpSeparate(GL_BACK, backfail, backzfail, backzpass);CHECKGLERROR
-                       qglStencilFuncSeparate(GL_FRONT, frontcompare, comparereference, comparereference);CHECKGLERROR
-                       qglStencilFuncSeparate(GL_BACK, backcompare, comparereference, comparereference);CHECKGLERROR
-               }
-               else if (vid.support.ext_stencil_two_side)
-               {
-#if defined(GL_STENCIL_TEST_TWO_SIDE_EXT) && !defined(USE_GLES2)
-                       qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
-                       qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR
-                       qglStencilMask(writemask);CHECKGLERROR
-                       qglStencilOp(frontfail, frontzfail, frontzpass);CHECKGLERROR
-                       qglStencilFunc(frontcompare, comparereference, comparemask);CHECKGLERROR
-                       qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR
-                       qglStencilMask(writemask);CHECKGLERROR
-                       qglStencilOp(backfail, backzfail, backzpass);CHECKGLERROR
-                       qglStencilFunc(backcompare, comparereference, comparemask);CHECKGLERROR
-#endif
-               }
-               break;
-       }
-}
-
 void R_SetStencil(qboolean enable, int writemask, int fail, int zfail, int zpass, int compare, int comparereference, int comparemask)
 {
        switch (vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                CHECKGLERROR
                if (enable)
@@ -1488,12 +1287,6 @@ void R_SetStencil(qboolean enable, int writemask, int fail, int zfail, int zpass
                {
                        qglDisable(GL_STENCIL_TEST);CHECKGLERROR
                }
-               if (vid.support.ext_stencil_two_side)
-               {
-#ifdef GL_STENCIL_TEST_TWO_SIDE_EXT
-                       qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
-#endif
-               }
                qglStencilMask(writemask);CHECKGLERROR
                qglStencilOp(fail, zfail, zpass);CHECKGLERROR
                qglStencilFunc(compare, comparereference, comparemask);CHECKGLERROR
@@ -1510,9 +1303,10 @@ void GL_PolygonOffset(float planeoffset, float depthoffset)
                gl_state.polygonoffset[1] = depthoffset;
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL20:
+               case RENDERPATH_GL32:
                case RENDERPATH_GLES2:
-                       qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
+                       CHECKGLERROR
+                       qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);CHECKGLERROR
                        break;
                }
        }
@@ -1531,8 +1325,9 @@ void GL_SetMirrorState(qboolean state)
                        return;
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL20:
+               case RENDERPATH_GL32:
                case RENDERPATH_GLES2:
+                       CHECKGLERROR
                        qglCullFace(gl_state.cullface);CHECKGLERROR
                        break;
                }
@@ -1551,7 +1346,7 @@ void GL_CullFace(int state)
 
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                CHECKGLERROR
 
@@ -1589,19 +1384,19 @@ void GL_AlphaToCoverage(qboolean state)
                {
                case RENDERPATH_GLES2:
                        break;
-               case RENDERPATH_GL20:
-#ifdef GL_SAMPLE_ALPHA_TO_COVERAGE_ARB
+               case RENDERPATH_GL32:
+#ifndef USE_GLES2
                        // alpha to coverage turns the alpha value of the pixel into 0%, 25%, 50%, 75% or 100% by masking the multisample fragments accordingly
                        CHECKGLERROR
                        if (gl_state.alphatocoverage)
                        {
-                               qglEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);CHECKGLERROR
-//                             qglEnable(GL_MULTISAMPLE_ARB);CHECKGLERROR
+                               qglEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);CHECKGLERROR
+//                             qglEnable(GL_MULTISAMPLE);CHECKGLERROR
                        }
                        else
                        {
-                               qglDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);CHECKGLERROR
-//                             qglDisable(GL_MULTISAMPLE_ARB);CHECKGLERROR
+                               qglDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);CHECKGLERROR
+//                             qglDisable(GL_MULTISAMPLE);CHECKGLERROR
                        }
 #endif
                        break;
@@ -1618,7 +1413,7 @@ void GL_ColorMask(int r, int g, int b, int a)
                gl_state.colormask = state;
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL20:
+               case RENDERPATH_GL32:
                case RENDERPATH_GLES2:
                        CHECKGLERROR
                        qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR
@@ -1637,9 +1432,9 @@ void GL_Color(float cr, float cg, float cb, float ca)
                gl_state.color4f[3] = ca;
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL20:
+               case RENDERPATH_GL32:
                case RENDERPATH_GLES2:
-                       qglVertexAttrib4f(GLSLATTRIB_COLOR, cr, cg, cb, ca);
+                       qglVertexAttrib4f(GLSLATTRIB_COLOR, cr, cg, cb, ca);CHECKGLERROR
                        break;
                }
        }
@@ -1649,11 +1444,10 @@ void GL_Scissor (int x, int y, int width, int height)
 {
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                CHECKGLERROR
-               qglScissor(x, y,width,height);
-               CHECKGLERROR
+               qglScissor(x, y,width,height);CHECKGLERROR
                break;
        }
 }
@@ -1665,7 +1459,7 @@ void GL_ScissorTest(int state)
                gl_state.scissortest = state;
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL20:
+               case RENDERPATH_GL32:
                case RENDERPATH_GLES2:
                        CHECKGLERROR
                        if(gl_state.scissortest)
@@ -1692,7 +1486,7 @@ void GL_Clear(int mask, const float *colorvalue, float depthvalue, int stencilva
        }
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                CHECKGLERROR
                if (mask & GL_COLOR_BUFFER_BIT)
@@ -1720,7 +1514,7 @@ void GL_ReadPixelsBGRA(int x, int y, int width, int height, unsigned char *outpi
 {
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                CHECKGLERROR
 #ifndef GL_BGRA
@@ -1755,7 +1549,6 @@ void R_Mesh_Start(void)
 {
        BACKENDACTIVECHECK
        R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
-       R_Mesh_SetUseVBO();
        if (gl_printcheckerror.integer && !gl_paranoid.integer)
        {
                Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n");
@@ -1816,9 +1609,9 @@ unsigned int GL_Backend_CompileProgram(int vertexstrings_count, const char **ver
        qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD6, "Attrib_SkeletalIndex");
        qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD7, "Attrib_SkeletalWeight");
 #ifndef USE_GLES2
-       if(vid.support.gl20shaders130)
-               qglBindFragDataLocation(programobject, 0, "dp_FragColor");
+       qglBindFragDataLocation(programobject, 0, "dp_FragColor");
 #endif
+       CHECKGLERROR
 
        if (vertexstrings_count && !GL_Backend_CompileShader(programobject, GL_VERTEX_SHADER, "vertex", vertexstrings_count, vertexstrings_list))
                goto cleanup;
@@ -1868,7 +1661,6 @@ void GL_Backend_FreeProgram(unsigned int prog)
 }
 
 // renders triangles using vertices from the active arrays
-int paranoidblah = 0;
 void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const r_meshbuffer_t *element3i_indexbuffer, int element3i_bufferoffset, const unsigned short *element3s, const r_meshbuffer_t *element3s_indexbuffer, int element3s_bufferoffset)
 {
        unsigned int numelements = numtriangles * 3;
@@ -1891,27 +1683,15 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
                element3s += firsttriangle * 3;
        if (element3s_indexbuffer)
                element3s_bufferoffset += firsttriangle * 3 * sizeof(*element3s);
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_GLES2:
-               // check if the user specified to ignore static index buffers
-               if (!gl_state.usevbo_staticindex || (gl_vbo.integer == 3 && !vid.forcevbo && (element3i_bufferoffset || element3s_bufferoffset)))
-               {
-                       element3i_indexbuffer = NULL;
-                       element3s_indexbuffer = NULL;
-               }
-               break;
-       }
        // upload a dynamic index buffer if needed
        if (element3s)
        {
-               if (!element3s_indexbuffer && gl_state.usevbo_dynamicindex)
+               if (!element3s_indexbuffer)
                        element3s_indexbuffer = R_BufferData_Store(numelements * sizeof(*element3s), (void *)element3s, R_BUFFERDATA_INDEX16, &element3s_bufferoffset);
        }
        else if (element3i)
        {
-               if (!element3i_indexbuffer && gl_state.usevbo_dynamicindex)
+               if (!element3i_indexbuffer)
                        element3i_indexbuffer = R_BufferData_Store(numelements * sizeof(*element3i), (void *)element3i, R_BUFFERDATA_INDEX32, &element3i_bufferoffset);
        }
        bufferobject3i = element3i_indexbuffer ? element3i_indexbuffer->bufferobject : 0;
@@ -1924,44 +1704,6 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
        if (gl_paranoid.integer)
        {
                unsigned int i;
-               // LordHavoc: disabled this - it needs to be updated to handle components and gltype and stride in each array
-#if 0
-               unsigned int j, size;
-               const int *p;
-               // note: there's no validation done here on buffer objects because it
-               // is somewhat difficult to get at the data, and gl_paranoid can be
-               // used without buffer objects if the need arises
-               // (the data could be gotten using glMapBuffer but it would be very
-               //  slow due to uncachable video memory reads)
-               if (!qglIsEnabled(GL_VERTEX_ARRAY))
-                       Con_Print("R_Mesh_Draw: vertex array not enabled\n");
-               CHECKGLERROR
-               if (gl_state.pointer_vertex_pointer)
-                       for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++)
-                               paranoidblah += *p;
-               if (gl_state.pointer_color_enabled)
-               {
-                       if (!qglIsEnabled(GL_COLOR_ARRAY))
-                               Con_Print("R_Mesh_Draw: color array set but not enabled\n");
-                       CHECKGLERROR
-                       if (gl_state.pointer_color && gl_state.pointer_color_enabled)
-                               for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++)
-                                       paranoidblah += *p;
-               }
-               for (i = 0;i < vid.texarrayunits;i++)
-               {
-                       if (gl_state.units[i].arrayenabled)
-                       {
-                               GL_ClientActiveTexture(i);
-                               if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
-                                       Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
-                               CHECKGLERROR
-                               if (gl_state.units[i].pointer_texcoord && gl_state.units[i].arrayenabled)
-                                       for (j = 0, size = numvertices * gl_state.units[i].arraycomponents, p = (int *)((float *)gl_state.units[i].pointer_texcoord + firstvertex * gl_state.units[i].arraycomponents);j < size;j++, p++)
-                                               paranoidblah += *p;
-                       }
-               }
-#endif
                if (element3i)
                {
                        for (i = 0;i < (unsigned int) numtriangles * 3;i++)
@@ -1989,108 +1731,22 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
        {
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL20:
-                       CHECKGLERROR
-                       if (bufferobject3s)
-                       {
-                               GL_BindEBO(bufferobject3s);
-#ifndef USE_GLES2
-                               if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
-                               {
-                                       qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s);
-                                       CHECKGLERROR
-                               }
-                               else
-#endif
-                               {
-                                       qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s);
-                                       CHECKGLERROR
-                               }
-                       }
-                       else if (bufferobject3i)
-                       {
-                               GL_BindEBO(bufferobject3i);
-#ifndef USE_GLES2
-                               if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
-                               {
-                                       qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, (void *)bufferoffset3i);
-                                       CHECKGLERROR
-                               }
-                               else
-#endif
-                               {
-                                       qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, (void *)bufferoffset3i);
-                                       CHECKGLERROR
-                               }
-                       }
-                       else if (element3s)
-                       {
-                               GL_BindEBO(0);
-#ifndef USE_GLES2
-                               if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
-                               {
-                                       qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, element3s);
-                                       CHECKGLERROR
-                               }
-                               else
-#endif
-                               {
-                                       qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, element3s);
-                                       CHECKGLERROR
-                               }
-                       }
-                       else if (element3i)
-                       {
-                               GL_BindEBO(0);
-#ifndef USE_GLES2
-                               if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
-                               {
-                                       qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, element3i);
-                                       CHECKGLERROR
-                               }
-                               else
-#endif
-                               {
-                                       qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, element3i);
-                                       CHECKGLERROR
-                               }
-                       }
-                       else
-                       {
-                               qglDrawArrays(GL_TRIANGLES, firstvertex, numvertices);
-                               CHECKGLERROR
-                       }
-                       break;
+               case RENDERPATH_GL32:
                case RENDERPATH_GLES2:
-                       // GLES does not have glDrawRangeElements so this is a bit shorter than the GL20 path
+                       CHECKGLERROR
                        if (bufferobject3s)
                        {
                                GL_BindEBO(bufferobject3s);
-                               qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s);
-                               CHECKGLERROR
+                               qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s);CHECKGLERROR
                        }
                        else if (bufferobject3i)
                        {
                                GL_BindEBO(bufferobject3i);
-                               qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, (void *)bufferoffset3i);
-                               CHECKGLERROR
-                       }
-                       else if (element3s)
-                       {
-                               GL_BindEBO(0);
-                               qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, element3s);
-                               CHECKGLERROR
-                       }
-                       else if (element3i)
-                       {
-                               GL_BindEBO(0);
-                               qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, element3i);
-                               CHECKGLERROR
+                               qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, (void *)bufferoffset3i);CHECKGLERROR
                        }
                        else
                        {
-                               qglDrawArrays(GL_TRIANGLES, firstvertex, numvertices);
-                               CHECKGLERROR
+                               qglDrawArrays(GL_TRIANGLES, firstvertex, numvertices);CHECKGLERROR
                        }
                        break;
                }
@@ -2106,18 +1762,6 @@ void R_Mesh_Finish(void)
 r_meshbuffer_t *R_Mesh_CreateMeshBuffer(const void *data, size_t size, const char *name, qboolean isindexbuffer, qboolean isuniformbuffer, qboolean isdynamic, qboolean isindex16)
 {
        r_meshbuffer_t *buffer;
-       if (isuniformbuffer)
-       {
-               if (!vid.support.arb_uniform_buffer_object)
-                       return NULL;
-       }
-       else
-       {
-               if (!vid.support.arb_vertex_buffer_object)
-                       return NULL;
-               if (!isdynamic && !(isindexbuffer ? gl_state.usevbo_staticindex : gl_state.usevbo_staticvertex))
-                       return NULL;
-       }
        buffer = (r_meshbuffer_t *)Mem_ExpandableArray_AllocRecord(&gl_state.meshbufferarray);
        memset(buffer, 0, sizeof(*buffer));
        buffer->bufferobject = 0;
@@ -2150,10 +1794,11 @@ void R_Mesh_UpdateMeshBuffer(r_meshbuffer_t *buffer, const void *data, size_t si
                buffer->size = size;
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                if (!buffer->bufferobject)
-                       qglGenBuffersARB(1, (GLuint *)&buffer->bufferobject);
+                       qglGenBuffers(1, (GLuint *)&buffer->bufferobject);
+               CHECKGLERROR
                if (buffer->isuniformbuffer)
                        GL_BindUBO(buffer->bufferobject);
                else if (buffer->isindexbuffer)
@@ -2168,10 +1813,12 @@ void R_Mesh_UpdateMeshBuffer(r_meshbuffer_t *buffer, const void *data, size_t si
                        if (buffer->isuniformbuffer)
                                buffertype = GL_UNIFORM_BUFFER;
 #endif
+                       CHECKGLERROR
                        if (subdata)
-                               qglBufferSubDataARB(buffertype, offset, size, data);
+                               qglBufferSubData(buffertype, offset, size, data);
                        else
-                               qglBufferDataARB(buffertype, size, data, buffer->isdynamic ? GL_STREAM_DRAW : GL_STATIC_DRAW);
+                               qglBufferData(buffertype, size, data, buffer->isdynamic ? GL_STREAM_DRAW : GL_STATIC_DRAW);
+                       CHECKGLERROR
                }
                if (buffer->isuniformbuffer)
                        GL_BindUBO(0);
@@ -2185,7 +1832,7 @@ void R_Mesh_DestroyMeshBuffer(r_meshbuffer_t *buffer)
                return;
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                // GL clears the binding if we delete something bound
                if (gl_state.uniformbufferobject == buffer->bufferobject)
@@ -2194,7 +1841,8 @@ void R_Mesh_DestroyMeshBuffer(r_meshbuffer_t *buffer)
                        gl_state.vertexbufferobject = 0;
                if (gl_state.elementbufferobject == buffer->bufferobject)
                        gl_state.elementbufferobject = 0;
-               qglDeleteBuffersARB(1, (GLuint *)&buffer->bufferobject);
+               CHECKGLERROR
+               qglDeleteBuffers(1, (GLuint *)&buffer->bufferobject);CHECKGLERROR
                break;
        }
        Mem_ExpandableArray_FreeRecord(&gl_state.meshbufferarray, (void *)buffer);
@@ -2253,11 +1901,13 @@ void R_Mesh_VertexPointer(int components, int gltype, size_t stride, const void
 {
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                if (gl_state.pointer_vertex_components != components || gl_state.pointer_vertex_gltype != gltype || gl_state.pointer_vertex_stride != stride || gl_state.pointer_vertex_pointer != pointer || gl_state.pointer_vertex_vertexbuffer != vertexbuffer || gl_state.pointer_vertex_offset != bufferoffset)
                {
                        int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0;
+                       if (!bufferobject && gl_paranoid.integer)
+                               Con_DPrintf("Warning: no bufferobject in R_Mesh_VertexPointer(%i, %i, %i, %p, %p, %08x)", components, gltype, (int)stride, pointer, vertexbuffer, (unsigned int)bufferoffset);
                        gl_state.pointer_vertex_components = components;
                        gl_state.pointer_vertex_gltype = gltype;
                        gl_state.pointer_vertex_stride = stride;
@@ -2279,7 +1929,7 @@ void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *
        // the pointer only.
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                CHECKGLERROR
                if (pointer)
@@ -2325,12 +1975,14 @@ void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *
 void R_Mesh_TexCoordPointer(unsigned int unitnum, int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
 {
        gltextureunit_t *unit = gl_state.units + unitnum;
+       if (unitnum >= MAX_TEXTUREUNITS)
+               Sys_Error("R_Mesh_TexCoordPointer: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS);
        // update array settings
        // note: there is no need to check bufferobject here because all cases
        // that involve a valid bufferobject also supply a texcoord array
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                CHECKGLERROR
                if (pointer)
@@ -2372,8 +2024,8 @@ void R_Mesh_TexCoordPointer(unsigned int unitnum, int components, int gltype, si
 int R_Mesh_TexBound(unsigned int unitnum, int id)
 {
        gltextureunit_t *unit = gl_state.units + unitnum;
-       if (unitnum >= vid.teximageunits)
-               return 0;
+       if (unitnum >= MAX_TEXTUREUNITS)
+               Sys_Error("R_Mesh_TexCoordPointer: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS);
        if (id == GL_TEXTURE_2D)
                return unit->t2d;
        if (id == GL_TEXTURE_3D)
@@ -2387,7 +2039,7 @@ void R_Mesh_CopyToTexture(rtexture_t *tex, int tx, int ty, int sx, int sy, int w
 {
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                R_Mesh_TexBind(0, tex);
                GL_ActiveTexture(0);CHECKGLERROR
@@ -2400,16 +2052,12 @@ void R_Mesh_ClearBindingsForTexture(int texnum)
 {
        gltextureunit_t *unit;
        unsigned int unitnum;
-       // this doesn't really unbind the texture, but it does prevent a mistaken "do nothing" behavior on the next time this same texnum is bound on the same unit as the same type (this mainly affects r_shadow_bouncegrid because 3D textures are so rarely used)
-       for (unitnum = 0;unitnum < vid.teximageunits;unitnum++)
+       // unbind the texture from any units it is bound on - this prevents accidental reuse of certain textures whose bindings can linger far too long otherwise (e.g. bouncegrid which is a 3D texture) and confuse the driver later.
+       for (unitnum = 0; unitnum < MAX_TEXTUREUNITS; unitnum++)
        {
                unit = gl_state.units + unitnum;
-               if (unit->t2d == texnum)
-                       unit->t2d = -1;
-               if (unit->t3d == texnum)
-                       unit->t3d = -1;
-               if (unit->tcubemap == texnum)
-                       unit->tcubemap = -1;
+               if (unit->texture && unit->texture->texnum == texnum)
+                       R_Mesh_TexBind(unitnum, NULL);
        }
 }
 
@@ -2417,13 +2065,13 @@ void R_Mesh_TexBind(unsigned int unitnum, rtexture_t *tex)
 {
        gltextureunit_t *unit = gl_state.units + unitnum;
        int texnum;
-       if (unitnum >= vid.teximageunits)
-               return;
+       if (unitnum >= MAX_TEXTUREUNITS)
+               Sys_Error("R_Mesh_TexBind: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS);
        if (unit->texture == tex)
                return;
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                if (!tex)
                {
@@ -2450,353 +2098,95 @@ void R_Mesh_ResetTextureState(void)
 
        BACKENDACTIVECHECK
 
-       for (unitnum = 0;unitnum < vid.teximageunits;unitnum++)
+       for (unitnum = 0;unitnum < MAX_TEXTUREUNITS;unitnum++)
                R_Mesh_TexBind(unitnum, NULL);
-       for (unitnum = 0;unitnum < vid.texarrayunits;unitnum++)
-               R_Mesh_TexCoordPointer(unitnum, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
 }
 
-
-
 void R_Mesh_PrepareVertices_Vertex3f(int numvertices, const float *vertex3f, const r_meshbuffer_t *vertexbuffer, int bufferoffset)
 {
        // upload temporary vertexbuffer for this rendering
-       if (!gl_state.usevbo_staticvertex)
-               vertexbuffer = NULL;
-       if (!vertexbuffer && gl_state.usevbo_dynamicvertex)
+       if (!vertexbuffer)
                vertexbuffer = R_BufferData_Store(numvertices * sizeof(float[3]), (void *)vertex3f, R_BUFFERDATA_VERTEX, &bufferoffset);
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_GLES2:
-               if (vertexbuffer)
-               {
-                       R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, bufferoffset);
-                       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0);
-               }
-               else
-               {
-                       R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0);
-                       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0);
-               }
-               break;
-       }
-}
-
-
-
-r_vertexgeneric_t *R_Mesh_PrepareVertices_Generic_Lock(int numvertices)
-{
-       size_t size;
-       size = sizeof(r_vertexgeneric_t) * numvertices;
-       if (gl_state.preparevertices_tempdatamaxsize < size)
-       {
-               gl_state.preparevertices_tempdatamaxsize = size;
-               gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize);
-       }
-       gl_state.preparevertices_vertexgeneric = (r_vertexgeneric_t *)gl_state.preparevertices_tempdata;
-       gl_state.preparevertices_numvertices = numvertices;
-       return gl_state.preparevertices_vertexgeneric;
-}
-
-qboolean R_Mesh_PrepareVertices_Generic_Unlock(void)
-{
-       R_Mesh_PrepareVertices_Generic(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexgeneric, NULL, 0);
-       gl_state.preparevertices_vertexgeneric = NULL;
-       gl_state.preparevertices_numvertices = 0;
-       return true;
+       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(float[3])        , vertex3f  , vertexbuffer     , bufferoffset           );
+       R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(float[4])        , NULL      , NULL             , 0                      );
+       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(float[2])        , NULL      , NULL             , 0                      );
+       R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(float[3])        , NULL      , NULL             , 0                      );
+       R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(float[3])        , NULL      , NULL             , 0                      );
+       R_Mesh_TexCoordPointer(3, 3, GL_FLOAT        , sizeof(float[3])        , NULL      , NULL             , 0                      );
+       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(float[2])        , NULL      , NULL             , 0                      );
+       R_Mesh_TexCoordPointer(5, 2, GL_FLOAT        , sizeof(float[2])        , NULL      , NULL             , 0                      );
+       R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL      , NULL             , 0                      );
+       R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL      , NULL             , 0                      );
 }
 
 void R_Mesh_PrepareVertices_Generic_Arrays(int numvertices, const float *vertex3f, const float *color4f, const float *texcoord2f)
 {
-       int i;
-       r_vertexgeneric_t *vertex;
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_GLES2:
-               if (gl_state.usevbo_dynamicvertex)
-               {
-                       r_meshbuffer_t *buffer_vertex3f = NULL;
-                       r_meshbuffer_t *buffer_color4f = NULL;
-                       r_meshbuffer_t *buffer_texcoord2f = NULL;
-                       int bufferoffset_vertex3f = 0;
-                       int bufferoffset_color4f = 0;
-                       int bufferoffset_texcoord2f = 0;
-                       buffer_color4f    = R_BufferData_Store(numvertices * sizeof(float[4]), color4f   , R_BUFFERDATA_VERTEX, &bufferoffset_color4f   );
-                       buffer_vertex3f   = R_BufferData_Store(numvertices * sizeof(float[3]), vertex3f  , R_BUFFERDATA_VERTEX, &bufferoffset_vertex3f  );
-                       buffer_texcoord2f = R_BufferData_Store(numvertices * sizeof(float[2]), texcoord2f, R_BUFFERDATA_VERTEX, &bufferoffset_texcoord2f);
-                       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(float[3])        , vertex3f          , buffer_vertex3f          , bufferoffset_vertex3f          );
-                       R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(float[4])        , color4f           , buffer_color4f           , bufferoffset_color4f           );
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(float[2])        , texcoord2f        , buffer_texcoord2f        , bufferoffset_texcoord2f        );
-                       R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(float[3])        , NULL              , NULL                     , 0                              );
-                       R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(float[3])        , NULL              , NULL                     , 0                              );
-                       R_Mesh_TexCoordPointer(3, 3, GL_FLOAT        , sizeof(float[3])        , NULL              , NULL                     , 0                              );
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(float[2])        , NULL              , NULL                     , 0                              );
-                       R_Mesh_TexCoordPointer(5, 2, GL_FLOAT        , sizeof(float[2])        , NULL              , NULL                     , 0                              );
-                       R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL              , NULL                     , 0                              );
-                       R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL              , NULL                     , 0                              );
-               }
-               else if (!vid.useinterleavedarrays)
-               {
-                       R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
-                       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoord2f, NULL, 0);
-                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0);
-                       return;
-               }
-               break;
-       }
-
-       // no quick path for this case, convert to vertex structs
-       vertex = R_Mesh_PrepareVertices_Generic_Lock(numvertices);
-       for (i = 0;i < numvertices;i++)
-               VectorCopy(vertex3f + 3*i, vertex[i].vertex3f);
-       if (color4f)
-       {
-               for (i = 0;i < numvertices;i++)
-                       Vector4Copy(color4f + 4*i, vertex[i].color4f);
-       }
-       else
-       {
-               for (i = 0;i < numvertices;i++)
-                       Vector4Copy(gl_state.color4f, vertex[i].color4f);
-       }
-       if (texcoord2f)
-               for (i = 0;i < numvertices;i++)
-                       Vector2Copy(texcoord2f + 2*i, vertex[i].texcoord2f);
-       R_Mesh_PrepareVertices_Generic_Unlock();
-       R_Mesh_PrepareVertices_Generic(numvertices, vertex, NULL, 0);
-}
-
-void R_Mesh_PrepareVertices_Generic(int numvertices, const r_vertexgeneric_t *vertex, const r_meshbuffer_t *vertexbuffer, int bufferoffset)
-{
-       // upload temporary vertexbuffer for this rendering
-       if (!gl_state.usevbo_staticvertex)
-               vertexbuffer = NULL;
-       if (!vertexbuffer && gl_state.usevbo_dynamicvertex)
-               vertexbuffer = R_BufferData_Store(numvertices * sizeof(*vertex), (void *)vertex, R_BUFFERDATA_VERTEX, &bufferoffset);
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_GLES2:
-               if (vertexbuffer)
-               {
-                       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
-                       R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->color4f            - (unsigned char *)vertex));
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->texcoord2f         - (unsigned char *)vertex));
-                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0);
-               }
-               else
-               {
-                       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
-                       R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , NULL, 0);
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoord2f        , NULL, 0);
-                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0);
-               }
-               break;
-       }
-}
-
-
-
-r_vertexmesh_t *R_Mesh_PrepareVertices_Mesh_Lock(int numvertices)
-{
-       size_t size;
-       size = sizeof(r_vertexmesh_t) * numvertices;
-       if (gl_state.preparevertices_tempdatamaxsize < size)
-       {
-               gl_state.preparevertices_tempdatamaxsize = size;
-               gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize);
-       }
-       gl_state.preparevertices_vertexmesh = (r_vertexmesh_t *)gl_state.preparevertices_tempdata;
-       gl_state.preparevertices_numvertices = numvertices;
-       return gl_state.preparevertices_vertexmesh;
-}
-
-qboolean R_Mesh_PrepareVertices_Mesh_Unlock(void)
-{
-       R_Mesh_PrepareVertices_Mesh(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexmesh, NULL, 0);
-       gl_state.preparevertices_vertexmesh = NULL;
-       gl_state.preparevertices_numvertices = 0;
-       return true;
+       r_meshbuffer_t *buffer_vertex3f = NULL;
+       r_meshbuffer_t *buffer_color4f = NULL;
+       r_meshbuffer_t *buffer_texcoord2f = NULL;
+       int bufferoffset_vertex3f = 0;
+       int bufferoffset_color4f = 0;
+       int bufferoffset_texcoord2f = 0;
+       buffer_color4f    = R_BufferData_Store(numvertices * sizeof(float[4]), color4f   , R_BUFFERDATA_VERTEX, &bufferoffset_color4f   );
+       buffer_vertex3f   = R_BufferData_Store(numvertices * sizeof(float[3]), vertex3f  , R_BUFFERDATA_VERTEX, &bufferoffset_vertex3f  );
+       buffer_texcoord2f = R_BufferData_Store(numvertices * sizeof(float[2]), texcoord2f, R_BUFFERDATA_VERTEX, &bufferoffset_texcoord2f);
+       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(float[3])        , vertex3f          , buffer_vertex3f          , bufferoffset_vertex3f          );
+       R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(float[4])        , color4f           , buffer_color4f           , bufferoffset_color4f           );
+       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(float[2])        , texcoord2f        , buffer_texcoord2f        , bufferoffset_texcoord2f        );
+       R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(float[3])        , NULL              , NULL                     , 0                              );
+       R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(float[3])        , NULL              , NULL                     , 0                              );
+       R_Mesh_TexCoordPointer(3, 3, GL_FLOAT        , sizeof(float[3])        , NULL              , NULL                     , 0                              );
+       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(float[2])        , NULL              , NULL                     , 0                              );
+       R_Mesh_TexCoordPointer(5, 2, GL_FLOAT        , sizeof(float[2])        , NULL              , NULL                     , 0                              );
+       R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL              , NULL                     , 0                              );
+       R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL              , NULL                     , 0                              );
 }
 
 void R_Mesh_PrepareVertices_Mesh_Arrays(int numvertices, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *color4f, const float *texcoordtexture2f, const float *texcoordlightmap2f)
 {
-       int i;
-       r_vertexmesh_t *vertex;
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_GLES2:
-               if (gl_state.usevbo_dynamicvertex)
-               {
-                       r_meshbuffer_t *buffer_vertex3f = NULL;
-                       r_meshbuffer_t *buffer_color4f = NULL;
-                       r_meshbuffer_t *buffer_texcoordtexture2f = NULL;
-                       r_meshbuffer_t *buffer_svector3f = NULL;
-                       r_meshbuffer_t *buffer_tvector3f = NULL;
-                       r_meshbuffer_t *buffer_normal3f = NULL;
-                       r_meshbuffer_t *buffer_texcoordlightmap2f = NULL;
-                       int bufferoffset_vertex3f = 0;
-                       int bufferoffset_color4f = 0;
-                       int bufferoffset_texcoordtexture2f = 0;
-                       int bufferoffset_svector3f = 0;
-                       int bufferoffset_tvector3f = 0;
-                       int bufferoffset_normal3f = 0;
-                       int bufferoffset_texcoordlightmap2f = 0;
-                       buffer_color4f            = R_BufferData_Store(numvertices * sizeof(float[4]), color4f           , R_BUFFERDATA_VERTEX, &bufferoffset_color4f           );
-                       buffer_vertex3f           = R_BufferData_Store(numvertices * sizeof(float[3]), vertex3f          , R_BUFFERDATA_VERTEX, &bufferoffset_vertex3f          );
-                       buffer_svector3f          = R_BufferData_Store(numvertices * sizeof(float[3]), svector3f         , R_BUFFERDATA_VERTEX, &bufferoffset_svector3f         );
-                       buffer_tvector3f          = R_BufferData_Store(numvertices * sizeof(float[3]), tvector3f         , R_BUFFERDATA_VERTEX, &bufferoffset_tvector3f         );
-                       buffer_normal3f           = R_BufferData_Store(numvertices * sizeof(float[3]), normal3f          , R_BUFFERDATA_VERTEX, &bufferoffset_normal3f          );
-                       buffer_texcoordtexture2f  = R_BufferData_Store(numvertices * sizeof(float[2]), texcoordtexture2f , R_BUFFERDATA_VERTEX, &bufferoffset_texcoordtexture2f );
-                       buffer_texcoordlightmap2f = R_BufferData_Store(numvertices * sizeof(float[2]), texcoordlightmap2f, R_BUFFERDATA_VERTEX, &bufferoffset_texcoordlightmap2f);
-                       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(float[3])        , vertex3f          , buffer_vertex3f          , bufferoffset_vertex3f          );
-                       R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(float[4])        , color4f           , buffer_color4f           , bufferoffset_color4f           );
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(float[2])        , texcoordtexture2f , buffer_texcoordtexture2f , bufferoffset_texcoordtexture2f );
-                       R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(float[3])        , svector3f         , buffer_svector3f         , bufferoffset_svector3f         );
-                       R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(float[3])        , tvector3f         , buffer_tvector3f         , bufferoffset_tvector3f         );
-                       R_Mesh_TexCoordPointer(3, 3, GL_FLOAT        , sizeof(float[3])        , normal3f          , buffer_normal3f          , bufferoffset_normal3f          );
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(float[2])        , texcoordlightmap2f, buffer_texcoordlightmap2f, bufferoffset_texcoordlightmap2f);
-                       R_Mesh_TexCoordPointer(5, 2, GL_FLOAT        , sizeof(float[2])        , NULL              , NULL                     , 0                              );
-                       R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL              , NULL                     , 0                              );
-                       R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL              , NULL                     , 0                              );
-               }
-               else if (!vid.useinterleavedarrays)
-               {
-                       R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
-                       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoordtexture2f, NULL, 0);
-                       R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), svector3f, NULL, 0);
-                       R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), tvector3f, NULL, 0);
-                       R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), normal3f, NULL, 0);
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), texcoordlightmap2f, NULL, 0);
-                       R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0);
-                       return;
-               }
-               break;
-       }
-
-       vertex = R_Mesh_PrepareVertices_Mesh_Lock(numvertices);
-       for (i = 0;i < numvertices;i++)
-               VectorCopy(vertex3f + 3*i, vertex[i].vertex3f);
-       if (svector3f)
-               for (i = 0;i < numvertices;i++)
-                       VectorCopy(svector3f + 3*i, vertex[i].svector3f);
-       if (tvector3f)
-               for (i = 0;i < numvertices;i++)
-                       VectorCopy(tvector3f + 3*i, vertex[i].tvector3f);
-       if (normal3f)
-               for (i = 0;i < numvertices;i++)
-                       VectorCopy(normal3f + 3*i, vertex[i].normal3f);
-       if (color4f)
-       {
-               for (i = 0;i < numvertices;i++)
-                       Vector4Copy(color4f + 4*i, vertex[i].color4f);
-       }
-       else
-       {
-               for (i = 0;i < numvertices;i++)
-                       Vector4Copy(gl_state.color4f, vertex[i].color4f);
-       }
-       if (texcoordtexture2f)
-               for (i = 0;i < numvertices;i++)
-                       Vector2Copy(texcoordtexture2f + 2*i, vertex[i].texcoordtexture2f);
-       if (texcoordlightmap2f)
-               for (i = 0;i < numvertices;i++)
-                       Vector2Copy(texcoordlightmap2f + 2*i, vertex[i].texcoordlightmap2f);
-       R_Mesh_PrepareVertices_Mesh_Unlock();
-       R_Mesh_PrepareVertices_Mesh(numvertices, vertex, NULL, 0);
-}
-
-void R_Mesh_PrepareVertices_Mesh(int numvertices, const r_vertexmesh_t *vertex, const r_meshbuffer_t *vertexbuffer, int bufferoffset)
-{
-       // upload temporary vertexbuffer for this rendering
-       if (!gl_state.usevbo_staticvertex)
-               vertexbuffer = NULL;
-       if (!vertexbuffer && gl_state.usevbo_dynamicvertex)
-               vertexbuffer = R_BufferData_Store(numvertices * sizeof(*vertex), (void *)vertex, R_BUFFERDATA_VERTEX, &bufferoffset);
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL20:
-       case RENDERPATH_GLES2:
-               if (vertexbuffer)
-               {
-                       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
-                       R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->color4f            - (unsigned char *)vertex));
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->texcoordtexture2f  - (unsigned char *)vertex));
-                       R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(*vertex), vertex->svector3f         , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->svector3f          - (unsigned char *)vertex));
-                       R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(*vertex), vertex->tvector3f         , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->tvector3f          - (unsigned char *)vertex));
-                       R_Mesh_TexCoordPointer(3, 3, GL_FLOAT        , sizeof(*vertex), vertex->normal3f          , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->normal3f           - (unsigned char *)vertex));
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->texcoordlightmap2f - (unsigned char *)vertex));
-                       R_Mesh_TexCoordPointer(5, 2, GL_FLOAT        , sizeof(*vertex), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(*vertex), vertex->skeletalindex4ub  , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->skeletalindex4ub   - (unsigned char *)vertex));
-                       R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->skeletalweight4ub , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->skeletalweight4ub  - (unsigned char *)vertex));
-               }
-               else
-               {
-                       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
-                       R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(*vertex), vertex->color4f           , NULL, 0);
-                       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordtexture2f , NULL, 0);
-                       R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(*vertex), vertex->svector3f         , NULL, 0);
-                       R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(*vertex), vertex->tvector3f         , NULL, 0);
-                       R_Mesh_TexCoordPointer(3, 3, GL_FLOAT        , sizeof(*vertex), vertex->normal3f          , NULL, 0);
-                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(*vertex), vertex->texcoordlightmap2f, NULL, 0);
-                       R_Mesh_TexCoordPointer(5, 2, GL_FLOAT        , sizeof(*vertex), NULL, NULL, 0);
-                       R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(*vertex), vertex->skeletalindex4ub  , NULL, 0);
-                       R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->skeletalweight4ub , NULL, 0);
-               }
-               break;
-       }
+       r_meshbuffer_t *buffer_vertex3f = NULL;
+       r_meshbuffer_t *buffer_color4f = NULL;
+       r_meshbuffer_t *buffer_texcoordtexture2f = NULL;
+       r_meshbuffer_t *buffer_svector3f = NULL;
+       r_meshbuffer_t *buffer_tvector3f = NULL;
+       r_meshbuffer_t *buffer_normal3f = NULL;
+       r_meshbuffer_t *buffer_texcoordlightmap2f = NULL;
+       int bufferoffset_vertex3f = 0;
+       int bufferoffset_color4f = 0;
+       int bufferoffset_texcoordtexture2f = 0;
+       int bufferoffset_svector3f = 0;
+       int bufferoffset_tvector3f = 0;
+       int bufferoffset_normal3f = 0;
+       int bufferoffset_texcoordlightmap2f = 0;
+       buffer_color4f            = R_BufferData_Store(numvertices * sizeof(float[4]), color4f           , R_BUFFERDATA_VERTEX, &bufferoffset_color4f           );
+       buffer_vertex3f           = R_BufferData_Store(numvertices * sizeof(float[3]), vertex3f          , R_BUFFERDATA_VERTEX, &bufferoffset_vertex3f          );
+       buffer_svector3f          = R_BufferData_Store(numvertices * sizeof(float[3]), svector3f         , R_BUFFERDATA_VERTEX, &bufferoffset_svector3f         );
+       buffer_tvector3f          = R_BufferData_Store(numvertices * sizeof(float[3]), tvector3f         , R_BUFFERDATA_VERTEX, &bufferoffset_tvector3f         );
+       buffer_normal3f           = R_BufferData_Store(numvertices * sizeof(float[3]), normal3f          , R_BUFFERDATA_VERTEX, &bufferoffset_normal3f          );
+       buffer_texcoordtexture2f  = R_BufferData_Store(numvertices * sizeof(float[2]), texcoordtexture2f , R_BUFFERDATA_VERTEX, &bufferoffset_texcoordtexture2f );
+       buffer_texcoordlightmap2f = R_BufferData_Store(numvertices * sizeof(float[2]), texcoordlightmap2f, R_BUFFERDATA_VERTEX, &bufferoffset_texcoordlightmap2f);
+       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(float[3])        , vertex3f          , buffer_vertex3f          , bufferoffset_vertex3f          );
+       R_Mesh_ColorPointer(      4, GL_FLOAT        , sizeof(float[4])        , color4f           , buffer_color4f           , bufferoffset_color4f           );
+       R_Mesh_TexCoordPointer(0, 2, GL_FLOAT        , sizeof(float[2])        , texcoordtexture2f , buffer_texcoordtexture2f , bufferoffset_texcoordtexture2f );
+       R_Mesh_TexCoordPointer(1, 3, GL_FLOAT        , sizeof(float[3])        , svector3f         , buffer_svector3f         , bufferoffset_svector3f         );
+       R_Mesh_TexCoordPointer(2, 3, GL_FLOAT        , sizeof(float[3])        , tvector3f         , buffer_tvector3f         , bufferoffset_tvector3f         );
+       R_Mesh_TexCoordPointer(3, 3, GL_FLOAT        , sizeof(float[3])        , normal3f          , buffer_normal3f          , bufferoffset_normal3f          );
+       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT        , sizeof(float[2])        , texcoordlightmap2f, buffer_texcoordlightmap2f, bufferoffset_texcoordlightmap2f);
+       R_Mesh_TexCoordPointer(5, 2, GL_FLOAT        , sizeof(float[2])        , NULL              , NULL                     , 0                              );
+       R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL              , NULL                     , 0                              );
+       R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL              , NULL                     , 0                              );
 }
 
 void GL_BlendEquationSubtract(qboolean negated)
 {
+       CHECKGLERROR
        if(negated)
        {
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL20:
+               case RENDERPATH_GL32:
                case RENDERPATH_GLES2:
-                       qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT);
+                       qglBlendEquation(GL_FUNC_REVERSE_SUBTRACT);CHECKGLERROR
                        break;
                }
        }
@@ -2804,9 +2194,9 @@ void GL_BlendEquationSubtract(qboolean negated)
        {
                switch(vid.renderpath)
                {
-               case RENDERPATH_GL20:
+               case RENDERPATH_GL32:
                case RENDERPATH_GLES2:
-                       qglBlendEquationEXT(GL_FUNC_ADD);
+                       qglBlendEquation(GL_FUNC_ADD);CHECKGLERROR
                        break;
                }
        }