]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
Fix a coverity false positive.
[xonotic/darkplaces.git] / gl_rmain.c
index a1530a6fdc5f79207131175e05430d1799086a13..50fca5992bd3dab5b0a5def378e6c12f7779ba81 100644 (file)
@@ -238,12 +238,12 @@ cvar_t r_glsl_saturation_redcompensate = {CVAR_SAVE, "r_glsl_saturation_redcompe
 cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
 
 cvar_t r_framedatasize = {CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
-cvar_t r_bufferdatasize[R_BUFFERDATA_COUNT] =
+cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
 {
-       {CVAR_SAVE, "r_bufferdatasize_vertex", "4", "vertex buffer size for one frame"},
-       {CVAR_SAVE, "r_bufferdatasize_index16", "1", "index buffer size for one frame (16bit indices)"},
-       {CVAR_SAVE, "r_bufferdatasize_index32", "1", "index buffer size for one frame (32bit indices)"},
-       {CVAR_SAVE, "r_bufferdatasize_uniform", "0.25", "uniform buffer size for one frame"},
+       {CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
+       {CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
+       {CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
+       {CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
 };
 
 extern cvar_t v_glslgamma;
@@ -678,7 +678,8 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
        {"#define USETRIPPY\n", " trippy"},
        {"#define USEDEPTHRGB\n", " depthrgb"},
        {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
-       {"#define USESKELETAL\n", " skeletal"}
+       {"#define USESKELETAL\n", " skeletal"},
+       {"#define USEOCCLUDE\n", " occlude"}
 };
 
 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
@@ -881,8 +882,9 @@ enum
        SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
        SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
        SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
+       SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
 };
-#define SHADERSTATICPARMS_COUNT 13
+#define SHADERSTATICPARMS_COUNT 14
 
 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
 static int shaderstaticparms_count = 0;
@@ -894,7 +896,7 @@ extern qboolean r_shadow_shadowmapsampler;
 extern int r_shadow_shadowmappcf;
 qboolean R_CompileShader_CheckStaticParms(void)
 {
-       static int r_compileshader_staticparms_save[1];
+       static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
        memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
        memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
 
@@ -916,6 +918,8 @@ qboolean R_CompileShader_CheckStaticParms(void)
                if (r_glsl_postprocess_uservec4_enable.integer)
                        R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
        }
+       if (r_fxaa.integer)
+               R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
        if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
                R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
 
@@ -956,6 +960,7 @@ static void R_CompileShader_AddStaticParms(unsigned int mode, unsigned int permu
        R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
        R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
        R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
+       R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
 }
 
 /// information about each possible shader permutation
@@ -1163,6 +1168,26 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                // look up all the uniform variable names we care about, so we don't
                // have to look them up every time we set them
 
+#if 0
+               // debugging aid
+               {
+                       GLint activeuniformindex = 0;
+                       GLint numactiveuniforms = 0;
+                       char uniformname[128];
+                       GLsizei uniformnamelength = 0;
+                       GLint uniformsize = 0;
+                       GLenum uniformtype = 0;
+                       memset(uniformname, 0, sizeof(uniformname));
+                       qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
+                       Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
+                       for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
+                       {
+                               qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
+                               Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
+                       }
+               }
+#endif
+
                p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
                p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
                p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
@@ -1311,12 +1336,19 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
                if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
                // get the uniform block indices so we can bind them
-               p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
+#ifndef USE_GLES2 /* FIXME: GLES3 only */
+               if (vid.support.arb_uniform_buffer_object)
+                       p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
+               else
+#endif
+                       p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
                // clear the uniform block bindings
                p->ubibind_Skeletal_Transform12_UniformBlock = -1;
                // bind the uniform blocks in use
                ubibind = 0;
+#ifndef USE_GLES2 /* FIXME: GLES3 only */
                if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
+#endif
                // we're done compiling and setting up the shader, at least until it is used
                CHECKGLERROR
                Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
@@ -1338,7 +1370,10 @@ static void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int per
                if (!r_glsl_permutation->program)
                {
                        if (!r_glsl_permutation->compiled)
+                       {
+                               Con_DPrintf("Compiling shader mode %u permutation %u\n", mode, permutation);
                                R_GLSL_CompilePermutation(perm, mode, permutation);
+                       }
                        if (!r_glsl_permutation->program)
                        {
                                // remove features until we find a valid permutation
@@ -1371,6 +1406,7 @@ static void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int per
        if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
        if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
        if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
+       CHECKGLERROR
 }
 
 #ifdef SUPPORTD3D
@@ -1594,7 +1630,7 @@ static void R_HLSL_CacheShader(r_hlsl_permutation_t *p, const char *cachename, c
                                        vsresult = qD3DXCompileShaderFromFileA(va(vabuf, sizeof(vabuf), "%s/%s_vs.fx", fs_gamedir, cachename), NULL, NULL, "main", vsversion, shaderflags, &vsbuffer, &vslog, &vsconstanttable);
                                }
                                else
-                                       vsresult = qD3DXCompileShader(vertstring, strlen(vertstring), NULL, NULL, "main", vsversion, shaderflags, &vsbuffer, &vslog, &vsconstanttable);
+                                       vsresult = qD3DXCompileShader(vertstring, (unsigned int)strlen(vertstring), NULL, NULL, "main", vsversion, shaderflags, &vsbuffer, &vslog, &vsconstanttable);
                                if (vsbuffer)
                                {
                                        vsbinsize = ID3DXBuffer_GetBufferSize(vsbuffer);
@@ -1617,7 +1653,7 @@ static void R_HLSL_CacheShader(r_hlsl_permutation_t *p, const char *cachename, c
                                        psresult = qD3DXCompileShaderFromFileA(va(vabuf, sizeof(vabuf), "%s/%s_ps.fx", fs_gamedir, cachename), NULL, NULL, "main", psversion, shaderflags, &psbuffer, &pslog, &psconstanttable);
                                }
                                else
-                                       psresult = qD3DXCompileShader(fragstring, strlen(fragstring), NULL, NULL, "main", psversion, shaderflags, &psbuffer, &pslog, &psconstanttable);
+                                       psresult = qD3DXCompileShader(fragstring, (unsigned int)strlen(fragstring), NULL, NULL, "main", psversion, shaderflags, &psbuffer, &pslog, &psconstanttable);
                                if (psbuffer)
                                {
                                        psbinsize = ID3DXBuffer_GetBufferSize(psbuffer);
@@ -1745,23 +1781,23 @@ static void R_HLSL_CompilePermutation(r_hlsl_permutation_t *p, unsigned int mode
 
        vertstring_length = 0;
        for (i = 0;i < vertstrings_count;i++)
-               vertstring_length += strlen(vertstrings_list[i]);
+               vertstring_length += (int)strlen(vertstrings_list[i]);
        vertstring = t = (char *)Mem_Alloc(tempmempool, vertstring_length + 1);
-       for (i = 0;i < vertstrings_count;t += strlen(vertstrings_list[i]), i++)
+       for (i = 0;i < vertstrings_count;t += (int)strlen(vertstrings_list[i]), i++)
                memcpy(t, vertstrings_list[i], strlen(vertstrings_list[i]));
 
        geomstring_length = 0;
        for (i = 0;i < geomstrings_count;i++)
-               geomstring_length += strlen(geomstrings_list[i]);
+               geomstring_length += (int)strlen(geomstrings_list[i]);
        geomstring = t = (char *)Mem_Alloc(tempmempool, geomstring_length + 1);
-       for (i = 0;i < geomstrings_count;t += strlen(geomstrings_list[i]), i++)
+       for (i = 0;i < geomstrings_count;t += (int)strlen(geomstrings_list[i]), i++)
                memcpy(t, geomstrings_list[i], strlen(geomstrings_list[i]));
 
        fragstring_length = 0;
        for (i = 0;i < fragstrings_count;i++)
-               fragstring_length += strlen(fragstrings_list[i]);
+               fragstring_length += (int)strlen(fragstrings_list[i]);
        fragstring = t = (char *)Mem_Alloc(tempmempool, fragstring_length + 1);
-       for (i = 0;i < fragstrings_count;t += strlen(fragstrings_list[i]), i++)
+       for (i = 0;i < fragstrings_count;t += (int)strlen(fragstrings_list[i]), i++)
                memcpy(t, fragstrings_list[i], strlen(fragstrings_list[i]));
 
        // try to load the cached shader, or generate one
@@ -1865,7 +1901,7 @@ void R_GLSL_Restart_f(void)
                {
                        r_hlsl_permutation_t *p;
                        r_hlsl_permutation = NULL;
-                       limit = Mem_ExpandableArray_IndexRange(&r_hlsl_permutationarray);
+                       limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_hlsl_permutationarray);
                        for (i = 0;i < limit;i++)
                        {
                                if ((p = (r_hlsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_hlsl_permutationarray, i)))
@@ -1892,7 +1928,7 @@ void R_GLSL_Restart_f(void)
                {
                        r_glsl_permutation_t *p;
                        r_glsl_permutation = NULL;
-                       limit = Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
+                       limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
                        for (i = 0;i < limit;i++)
                        {
                                if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
@@ -2064,7 +2100,9 @@ void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean
        case RENDERPATH_GL20:
        case RENDERPATH_GLES2:
                R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
+#ifndef USE_GLES2 /* FIXME: GLES3 only */
                if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
+#endif
                break;
        case RENDERPATH_GL13:
        case RENDERPATH_GLES1:
@@ -2165,6 +2203,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                permutation |= SHADERPERMUTATION_TRIPPY;
        if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
                permutation |= SHADERPERMUTATION_ALPHAKILL;
+       if (rsurface.texture->currentmaterialflags & MATERIALFLAG_OCCLUDE)
+               permutation |= SHADERPERMUTATION_OCCLUDE;
        if (rsurface.texture->r_water_waterscroll[0] && rsurface.texture->r_water_waterscroll[1])
                permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
        if (rsurfacepass == RSURFPASS_BACKGROUND)
@@ -2722,7 +2762,9 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                if (rsurface.batchskeletaltransform3x4buffer)
                        permutation |= SHADERPERMUTATION_SKELETAL;
                R_SetupShader_SetPermutationGLSL(mode, permutation);
+#ifndef USE_GLES2 /* FIXME: GLES3 only */
                if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
+#endif
                if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
                if (mode == SHADERMODE_LIGHTSOURCE)
                {
@@ -3127,7 +3169,7 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
 
 typedef struct
 {
-       int loadsequence; // incremented each level change
+       unsigned int loadsequence; // incremented each level change
        memexpandablearray_t array;
        skinframe_t *hash[SKINFRAME_HASH];
 }
@@ -3361,6 +3403,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        skinframe->fog = NULL;
        skinframe->reflect = NULL;
        skinframe->hasalpha = false;
+       // we could store the q2animname here too
 
        if (ddsbase)
        {
@@ -4004,9 +4047,11 @@ static void gl_main_start(void)
                r_loadnormalmap = true;
                r_loadgloss = true;
                r_loadfog = false;
+#ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
                if (vid.support.arb_uniform_buffer_object)
                        qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
-               break;
+#endif
+                       break;
        case RENDERPATH_GL13:
        case RENDERPATH_GLES1:
                Cvar_SetValueQuick(&r_textureunits, vid.texunits);
@@ -4074,6 +4119,27 @@ static void gl_main_start(void)
        r_texture_numcubemaps = 0;
 
        r_refdef.fogmasktable_density = 0;
+
+#ifdef __ANDROID__
+       // For Steelstorm Android
+       // FIXME CACHE the program and reload
+       // FIXME see possible combinations for SS:BR android
+       Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
+       R_SetupShader_SetPermutationGLSL(0, 12);
+       R_SetupShader_SetPermutationGLSL(0, 13);
+       R_SetupShader_SetPermutationGLSL(0, 8388621);
+       R_SetupShader_SetPermutationGLSL(3, 0);
+       R_SetupShader_SetPermutationGLSL(3, 2048);
+       R_SetupShader_SetPermutationGLSL(5, 0);
+       R_SetupShader_SetPermutationGLSL(5, 2);
+       R_SetupShader_SetPermutationGLSL(5, 2048);
+       R_SetupShader_SetPermutationGLSL(5, 8388608);
+       R_SetupShader_SetPermutationGLSL(11, 1);
+       R_SetupShader_SetPermutationGLSL(11, 2049);
+       R_SetupShader_SetPermutationGLSL(11, 8193);
+       R_SetupShader_SetPermutationGLSL(11, 10241);
+       Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
+#endif
 }
 
 static void gl_main_shutdown(void)
@@ -4091,7 +4157,7 @@ static void gl_main_shutdown(void)
        case RENDERPATH_GL20:
        case RENDERPATH_GLES1:
        case RENDERPATH_GLES2:
-#ifdef GL_SAMPLES_PASSED_ARB
+#if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
                if (r_maxqueries)
                        qglDeleteQueriesARB(r_maxqueries, r_queries);
 #endif
@@ -4353,10 +4419,17 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
        Cvar_RegisterVariable(&r_framedatasize);
        for (i = 0;i < R_BUFFERDATA_COUNT;i++)
-               Cvar_RegisterVariable(&r_bufferdatasize[i]);
+               Cvar_RegisterVariable(&r_buffermegs[i]);
        Cvar_RegisterVariable(&r_batch_dynamicbuffer);
        if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
                Cvar_SetValue("r_fullbrights", 0);
+#ifdef DP_MOBILETOUCH
+       // GLES devices have terrible depth precision in general, so...
+       Cvar_SetValueQuick(&r_nearclip, 4);
+       Cvar_SetValueQuick(&r_farclip_base, 4096);
+       Cvar_SetValueQuick(&r_farclip_world, 0);
+       Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
+#endif
        R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
 }
 
@@ -4405,7 +4478,11 @@ void GL_Init (void)
        VID_CheckExtensions();
 
        // LordHavoc: report supported extensions
+#ifdef CONFIG_MENU
        Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
+#else
+       Con_DPrintf("\nQuakeC extensions for server and client: %s\n", vm_sv_extensions );
+#endif
 
        // clear to black (loading plaque will be seen over this)
        GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
@@ -4420,9 +4497,6 @@ int R_CullBox(const vec3_t mins, const vec3_t maxs)
                return false;
        for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
        {
-               // skip nearclip plane, it often culls portals when you are very close, and is almost never useful
-               if (i == 4)
-                       continue;
                p = r_refdef.view.frustum + i;
                switch(p->signbits)
                {
@@ -4628,8 +4702,8 @@ void R_FrameData_ReturnToMark(void)
 
 //==================================================================================
 
-// avoid reusing the same buffer objects on consecutive buffers
-#define R_BUFFERDATA_CYCLE 2
+// avoid reusing the same buffer objects on consecutive frames
+#define R_BUFFERDATA_CYCLE 3
 
 typedef struct r_bufferdata_buffer_s
 {
@@ -4653,7 +4727,7 @@ void R_BufferData_Reset(void)
                for (type = 0;type < R_BUFFERDATA_COUNT;type++)
                {
                        // free all buffers
-                       p = &r_bufferdata_buffer[r_bufferdata_cycle][type];
+                       p = &r_bufferdata_buffer[cycle][type];
                        while (*p)
                        {
                                mem = *p;
@@ -4667,12 +4741,30 @@ void R_BufferData_Reset(void)
 }
 
 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
-static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow)
+static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
 {
        r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
        size_t size;
-       size = (size_t)(r_bufferdatasize[type].value * 1024*1024);
-       size = bound(65536, size, 512*1024*1024);
+       float newvalue = r_buffermegs[type].value;
+
+       // increase the cvar if we have to (but only if we already have a mem)
+       if (mustgrow && mem)
+               newvalue *= 2.0f;
+       newvalue = bound(0.25f, newvalue, 256.0f);
+       while (newvalue * 1024*1024 < minsize)
+               newvalue *= 2.0f;
+
+       // clamp the cvar to valid range
+       newvalue = bound(0.25f, newvalue, 256.0f);
+       if (r_buffermegs[type].value != newvalue)
+               Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
+
+       // calculate size in bytes
+       size = (size_t)(newvalue * 1024*1024);
+       size = bound(131072, size, 256*1024*1024);
+
+       // allocate a new buffer if the size is different (purge old one later)
+       // or if we were told we must grow the buffer
        if (!mem || mem->size != size || mustgrow)
        {
                mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
@@ -4702,7 +4794,7 @@ void R_BufferData_NewFrame(void)
        {
                if (r_bufferdata_buffer[r_bufferdata_cycle][type])
                {
-                       R_BufferData_Resize(type, false);
+                       R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
                        // free all but the head buffer, this is how we recycle obsolete
                        // buffers after they are no longer in use
                        p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
@@ -4720,12 +4812,11 @@ void R_BufferData_NewFrame(void)
        }
 }
 
-r_meshbuffer_t *R_BufferData_Store(size_t datasize, void *data, r_bufferdata_type_t type, int *returnbufferoffset, qboolean allowfail)
+r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
 {
        r_bufferdata_buffer_t *mem;
        int offset = 0;
        int padsize;
-       float newvalue;
 
        *returnbufferoffset = 0;
 
@@ -4736,19 +4827,16 @@ r_meshbuffer_t *R_BufferData_Store(size_t datasize, void *data, r_bufferdata_typ
        else
                padsize = (datasize + 15) & ~15;
 
-       while (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
-       {
-               // emergency - we ran out of space, allocate more memory
-               newvalue = bound(0.25f, r_bufferdatasize[type].value * 2.0f, 256.0f);
-               // if we're already at the limit, just fail (if allowfail is false we might run out of video ram)
-               if (newvalue == r_bufferdatasize[type].value && allowfail)
-                       return NULL;
-               Cvar_SetValueQuick(&r_bufferdatasize[type], newvalue);
-               R_BufferData_Resize(type, true);
-       }
+       // if we ran out of space in this buffer we must allocate a new one
+       if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
+               R_BufferData_Resize(type, true, padsize);
+
+       // if the resize did not give us enough memory, fail
+       if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
+               Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
 
        mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
-       offset = mem->current;
+       offset = (int)mem->current;
        mem->current += padsize;
 
        // upload the data to the buffer at the chosen offset
@@ -4870,106 +4958,14 @@ qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qbool
        if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
        {
                // cache the skeleton so the vertex shader can use it
-               int i;
-               int blends;
-               const skeleton_t *skeleton = ent->skeleton;
-               const frameblend_t *frameblend = ent->frameblend;
-               float *boneposerelative;
-               float m[12];
-               static float bonepose[256][12];
                r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
                r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
                r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
                ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
-               boneposerelative = ent->animcache_skeletaltransform3x4;
-               if (skeleton && !skeleton->relativetransforms)
-                       skeleton = NULL;
-               // resolve hierarchy and make relative transforms (deforms) which the shader wants
-               if (skeleton)
-               {
-                       for (i = 0;i < model->num_bones;i++)
-                       {
-                               Matrix4x4_ToArray12FloatD3D(&skeleton->relativetransforms[i], m);
-                               if (model->data_bones[i].parent >= 0)
-                                       R_ConcatTransforms(bonepose[model->data_bones[i].parent], m, bonepose[i]);
-                               else
-                                       memcpy(bonepose[i], m, sizeof(m));
-
-                               // create a relative deformation matrix to describe displacement
-                               // from the base mesh, which is used by the actual weighting
-                               R_ConcatTransforms(bonepose[i], model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
-                       }
-               }
-               else
-               {
-                       for (i = 0;i < model->num_bones;i++)
-                       {
-                               const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i);
-                               float lerp = frameblend[0].lerp,
-                                       tx = pose7s[0], ty = pose7s[1], tz = pose7s[2],
-                                       rx = pose7s[3] * lerp,
-                                       ry = pose7s[4] * lerp,
-                                       rz = pose7s[5] * lerp,
-                                       rw = pose7s[6] * lerp,
-                                       dx = tx*rw + ty*rz - tz*ry,
-                                       dy = -tx*rz + ty*rw + tz*rx,
-                                       dz = tx*ry - ty*rx + tz*rw,
-                                       dw = -tx*rx - ty*ry - tz*rz,
-                                       scale, sx, sy, sz, sw;
-                               for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
-                               {
-                                       const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i);
-                                       float lerp = frameblend[blends].lerp,
-                                               tx = pose7s[0], ty = pose7s[1], tz = pose7s[2],
-                                               qx = pose7s[3], qy = pose7s[4], qz = pose7s[5], qw = pose7s[6];
-                                       if(rx*qx + ry*qy + rz*qz + rw*qw < 0) lerp = -lerp;
-                                       qx *= lerp;
-                                       qy *= lerp;
-                                       qz *= lerp;
-                                       qw *= lerp;
-                                       rx += qx;
-                                       ry += qy;
-                                       rz += qz;
-                                       rw += qw;
-                                       dx += tx*qw + ty*qz - tz*qy;
-                                       dy += -tx*qz + ty*qw + tz*qx;
-                                       dz += tx*qy - ty*qx + tz*qw;
-                                       dw += -tx*qx - ty*qy - tz*qz;
-                               }
-                               scale = 1.0f / (rx*rx + ry*ry + rz*rz + rw*rw);
-                               sx = rx * scale;
-                               sy = ry * scale;
-                               sz = rz * scale;
-                               sw = rw * scale;
-                               m[0] = sw*rw + sx*rx - sy*ry - sz*rz;
-                               m[1] = 2*(sx*ry - sw*rz);
-                               m[2] = 2*(sx*rz + sw*ry);
-                               m[3] = model->num_posescale*(dx*sw - dy*sz + dz*sy - dw*sx);
-                               m[4] = 2*(sx*ry + sw*rz);
-                               m[5] = sw*rw + sy*ry - sx*rx - sz*rz;
-                               m[6] = 2*(sy*rz - sw*rx);
-                               m[7] = model->num_posescale*(dx*sz + dy*sw - dz*sx - dw*sy);
-                               m[8] = 2*(sx*rz - sw*ry);
-                               m[9] = 2*(sy*rz + sw*rx);
-                               m[10] = sw*rw + sz*rz - sx*rx - sy*ry;
-                               m[11] = model->num_posescale*(dy*sx + dz*sw - dx*sy - dw*sz);
-                               if (i == r_skeletal_debugbone.integer)
-                                       m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
-                               m[3] *= r_skeletal_debugtranslatex.value;
-                               m[7] *= r_skeletal_debugtranslatey.value;
-                               m[11] *= r_skeletal_debugtranslatez.value;
-                               if (model->data_bones[i].parent >= 0)
-                                       R_ConcatTransforms(bonepose[model->data_bones[i].parent], m, bonepose[i]);
-                               else
-                                       memcpy(bonepose[i], m, sizeof(m));
-                               // create a relative deformation matrix to describe displacement
-                               // from the base mesh, which is used by the actual weighting
-                               R_ConcatTransforms(bonepose[i], model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
-                       }
-               }
+               Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
                // note: this can fail if the buffer is at the grow limit
                ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
-               ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset, true);
+               ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
        }
        else if (ent->animcache_vertex3f)
        {
@@ -5218,18 +5214,20 @@ static void R_View_UpdateEntityVisible (void)
        int samples;
        entity_render_t *ent;
 
-       renderimask = r_refdef.envmap                                    ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL)
-               : r_fb.water.hideplayer                                      ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL)
-               : (chase_active.integer || r_fb.water.renderingscene)  ? RENDER_VIEWMODEL
-               :                                                          RENDER_EXTERIORMODEL;
+       if (r_refdef.envmap || r_fb.water.hideplayer)
+               renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
+       else if (chase_active.integer || r_fb.water.renderingscene)
+               renderimask = RENDER_VIEWMODEL;
+       else
+               renderimask = RENDER_EXTERIORMODEL;
        if (!r_drawviewmodel.integer)
                renderimask |= RENDER_VIEWMODEL;
        if (!r_drawexteriormodel.integer)
                renderimask |= RENDER_EXTERIORMODEL;
+       memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
        if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
        {
                // worldmodel can check visibility
-               memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
                for (i = 0;i < r_refdef.scene.numentities;i++)
                {
                        ent = r_refdef.scene.entities[i];
@@ -5245,10 +5243,12 @@ static void R_View_UpdateEntityVisible (void)
                for (i = 0;i < r_refdef.scene.numentities;i++)
                {
                        ent = r_refdef.scene.entities[i];
-                       r_refdef.viewcache.entityvisible[i] = !(ent->flags & renderimask) && ((ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)) || !R_CullBox(ent->mins, ent->maxs));
+                       if (!(ent->flags & renderimask))
+                       if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
+                               r_refdef.viewcache.entityvisible[i] = true;
                }
        }
-       if(r_cullentities_trace.integer && r_refdef.scene.worldmodel->brush.TraceLineOfSight && !r_refdef.view.useclipplane && !r_trippy.integer)
+       if(r_cullentities_trace.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.TraceLineOfSight && !r_refdef.view.useclipplane && !r_trippy.integer)
                // sorry, this check doesn't work for portal/reflection/refraction renders as the view origin is not useful for culling
        {
                for (i = 0;i < r_refdef.scene.numentities;i++)
@@ -5711,7 +5711,9 @@ void R_EntityMatrix(const matrix4x4_t *matrix)
                case RENDERPATH_GL11:
                case RENDERPATH_GL13:
                case RENDERPATH_GLES1:
+#ifndef USE_GLES2
                        qglLoadMatrixf(gl_modelview16f);CHECKGLERROR
+#endif
                        break;
                case RENDERPATH_SOFT:
                        DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1, 1, false, gl_modelviewprojection16f);
@@ -5873,10 +5875,10 @@ static void R_Water_StartFrame(void)
        }
        else
        {
-               for (texturewidth   = 1;texturewidth   < waterwidth ;texturewidth   *= 2);
-               for (textureheight  = 1;textureheight  < waterheight;textureheight  *= 2);
-               for (camerawidth    = 1;camerawidth   <= waterwidth; camerawidth    *= 2); camerawidth  /= 2;
-               for (cameraheight   = 1;cameraheight  <= waterheight;cameraheight   *= 2); cameraheight /= 2;
+               for (texturewidth   = 1;texturewidth     <  waterwidth ;texturewidth   *= 2);
+               for (textureheight  = 1;textureheight    <  waterheight;textureheight  *= 2);
+               for (camerawidth    = 1;camerawidth  * 2 <= waterwidth ;camerawidth    *= 2);
+               for (cameraheight   = 1;cameraheight * 2 <= waterheight;cameraheight   *= 2);
        }
 
        // allocate textures as needed
@@ -5999,25 +6001,33 @@ void R_Water_AddWaterPlane(msurface_t *surface, int entno)
                }
        }
        planeindex = bestplaneindex;
-       p = r_fb.water.waterplanes + planeindex;
 
        // if this surface does not fit any known plane rendered this frame, add one
-       if ((planeindex < 0 || bestplanescore > 0.001f) && r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
+       if (planeindex < 0 || bestplanescore > 0.001f)
        {
-               // store the new plane
-               planeindex = r_fb.water.numwaterplanes++;
-               p = r_fb.water.waterplanes + planeindex;
-               p->plane = plane;
-               // clear materialflags and pvs
-               p->materialflags = 0;
-               p->pvsvalid = false;
-               p->camera_entity = t->camera_entity;
-               VectorCopy(mins, p->mins);
-               VectorCopy(maxs, p->maxs);
+               if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
+               {
+                       // store the new plane
+                       planeindex = r_fb.water.numwaterplanes++;
+                       p = r_fb.water.waterplanes + planeindex;
+                       p->plane = plane;
+                       // clear materialflags and pvs
+                       p->materialflags = 0;
+                       p->pvsvalid = false;
+                       p->camera_entity = t->camera_entity;
+                       VectorCopy(mins, p->mins);
+                       VectorCopy(maxs, p->maxs);
+               }
+               else
+               {
+                       // We're totally screwed.
+                       return;
+               }
        }
        else
        {
                // merge mins/maxs when we're adding this surface to the plane
+               p = r_fb.water.waterplanes + planeindex;
                p->mins[0] = min(p->mins[0], mins[0]);
                p->mins[1] = min(p->mins[1], mins[1]);
                p->mins[2] = min(p->mins[2], mins[2]);
@@ -6164,7 +6174,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
                                        memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
                        }
 
-                       r_fb.water.hideplayer = r_water_hideplayer.integer >= 2;
+                       r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
                        R_ResetViewRendering3D(p->fbo_reflection, r_fb.water.depthtexture, p->texture_reflection);
                        R_ClearScreen(r_refdef.fogenabled);
                        if(r_water_scissormode.integer & 2)
@@ -6193,7 +6203,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
                                        continue; // FIXME the plane then still may get rendered but with broken texture, but it sure won't be visible
                        }
 
-                       r_fb.water.hideplayer = r_water_hideplayer.integer >= 1;
+                       r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
 
                        r_refdef.view.clipplane = p->plane;
                        VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
@@ -6414,7 +6424,7 @@ static void R_Bloom_StartFrame(void)
                Cvar_SetValueQuick(&r_damageblur, 0);
        }
 
-       if (!(r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial))
+       if (!((r_glsl_postprocess.integer || r_fxaa.integer) || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial))
         && !r_bloom.integer
         && (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0))
         && !useviewfbo
@@ -7201,8 +7211,6 @@ void R_RenderView(void)
                R_SortEntities();
 
        R_AnimCache_ClearCache();
-       R_FrameData_NewFrame();
-       R_BufferData_NewFrame();
 
        /* adjust for stereo display */
        if(R_Stereo_Active())
@@ -8010,10 +8018,22 @@ static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
 {
        int w, h, idx;
-       double f;
-       double offsetd[2];
+       float shadertime;
+       float f;
+       float offsetd[2];
        float tcmat[12];
        matrix4x4_t matrix, temp;
+       // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
+       // it's better to have one huge fixup every 9 hours than gradual
+       // degradation over time which looks consistently bad after many hours.
+       //
+       // tcmod scroll in particular suffers from this degradation which can't be
+       // effectively worked around even with floor() tricks because we don't
+       // know if tcmod scroll is the last tcmod being applied, and for clampmap
+       // a workaround involving floor() would be incorrect anyway...
+       shadertime = rsurface.shadertime;
+       if (shadertime >= 32768.0f)
+               shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
        switch(tcmod->tcmod)
        {
                case Q3TCMOD_COUNT:
@@ -8029,16 +8049,17 @@ static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcm
                        Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
                        break;
                case Q3TCMOD_ROTATE:
-                       f = tcmod->parms[0] * rsurface.shadertime;
                        Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
-                       Matrix4x4_ConcatRotate(&matrix, (f / 360 - floor(f / 360)) * 360, 0, 0, 1);
+                       Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
                        Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
                        break;
                case Q3TCMOD_SCALE:
                        Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
                        break;
                case Q3TCMOD_SCROLL:
-                       // extra care is needed because of precision breakdown with large values of time
+                       // this particular tcmod is a "bug for bug" compatible one with regards to
+                       // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
+                       // specifically did the wrapping and so we must mimic that...
                        offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
                        offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
                        Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
@@ -8134,7 +8155,9 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                {
                        // use an alternate animation if the entity's frame is not 0,
                        // and only if the texture has an alternate animation
-                       if (rsurface.ent_alttextures && t->anim_total[1])
+                       if (t->animated == 2) // q2bsp
+                               t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
+                       else if (rsurface.ent_alttextures && t->anim_total[1])
                                t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
                        else
                                t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
@@ -8165,7 +8188,7 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                t->backgroundcurrentskinframe = t->backgroundskinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundskinframerate, t->backgroundnumskinframes)];
 
        t->currentmaterialflags = t->basematerialflags;
-       t->currentalpha = rsurface.colormod[3];
+       t->currentalpha = rsurface.colormod[3] * t->basealpha;
        if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer || r_trippy.integer))
                t->currentalpha *= r_wateralpha.value;
        if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
@@ -9425,12 +9448,12 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                                        rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
                        }
                        // upload buffer data for the copytriangles batch
-                       if (vid.forcevbo || (r_batch_dynamicbuffer.integer && vid.support.arb_vertex_buffer_object))
+                       if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
                        {
                                if (rsurface.batchelement3s)
-                                       rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset, !vid.forcevbo);
+                                       rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
                                else if (rsurface.batchelement3i)
-                                       rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset, !vid.forcevbo);
+                                       rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
                        }
                }
                else
@@ -10086,77 +10109,80 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                }
        }
 
-       // generate texcoords based on the chosen texcoord source
-       switch(rsurface.texture->tcgen.tcgen)
+       if (rsurface.batchtexcoordtexture2f)
        {
-       default:
-       case Q3TCGEN_TEXTURE:
-               break;
-       case Q3TCGEN_LIGHTMAP:
-//             rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
-//             rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-//             rsurface.batchtexcoordtexture2f_bufferoffset = 0;
-               if (rsurface.batchtexcoordlightmap2f)
-                       memcpy(rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordtexture2f, batchnumvertices * sizeof(float[2]));
-               break;
-       case Q3TCGEN_VECTOR:
-//             rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
-//             rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-//             rsurface.batchtexcoordtexture2f_bufferoffset = 0;
-               for (j = 0;j < batchnumvertices;j++)
-               {
-                       rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->tcgen.parms);
-                       rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->tcgen.parms + 3);
-               }
-               break;
-       case Q3TCGEN_ENVIRONMENT:
-               // make environment reflections using a spheremap
-               rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
-               rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-               rsurface.batchtexcoordtexture2f_bufferoffset = 0;
-               for (j = 0;j < batchnumvertices;j++)
+       // generate texcoords based on the chosen texcoord source
+               switch(rsurface.texture->tcgen.tcgen)
                {
-                       // identical to Q3A's method, but executed in worldspace so
-                       // carried models can be shiny too
+               default:
+               case Q3TCGEN_TEXTURE:
+                       break;
+               case Q3TCGEN_LIGHTMAP:
+       //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
+       //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
+       //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
+                       if (rsurface.batchtexcoordlightmap2f)
+                               memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
+                       break;
+               case Q3TCGEN_VECTOR:
+       //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
+       //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
+       //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
+                       for (j = 0;j < batchnumvertices;j++)
+                       {
+                               rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->tcgen.parms);
+                               rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->tcgen.parms + 3);
+                       }
+                       break;
+               case Q3TCGEN_ENVIRONMENT:
+                       // make environment reflections using a spheremap
+                       rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
+                       rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
+                       rsurface.batchtexcoordtexture2f_bufferoffset = 0;
+                       for (j = 0;j < batchnumvertices;j++)
+                       {
+                               // identical to Q3A's method, but executed in worldspace so
+                               // carried models can be shiny too
 
-                       float viewer[3], d, reflected[3], worldreflected[3];
+                               float viewer[3], d, reflected[3], worldreflected[3];
 
-                       VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
-                       // VectorNormalize(viewer);
+                               VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
+                               // VectorNormalize(viewer);
 
-                       d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
+                               d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
 
-                       reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
-                       reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
-                       reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
-                       // note: this is proportinal to viewer, so we can normalize later
+                               reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
+                               reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
+                               reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
+                               // note: this is proportinal to viewer, so we can normalize later
 
-                       Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
-                       VectorNormalize(worldreflected);
+                               Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
+                               VectorNormalize(worldreflected);
 
-                       // note: this sphere map only uses world x and z!
-                       // so positive and negative y will LOOK THE SAME.
-                       rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
-                       rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
+                               // note: this sphere map only uses world x and z!
+                               // so positive and negative y will LOOK THE SAME.
+                               rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
+                               rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
+                       }
+                       break;
                }
-               break;
-       }
-       // the only tcmod that needs software vertex processing is turbulent, so
-       // check for it here and apply the changes if needed
-       // and we only support that as the first one
-       // (handling a mixture of turbulent and other tcmods would be problematic
-       //  without punting it entirely to a software path)
-       if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
-       {
-               amplitude = rsurface.texture->tcmods[0].parms[1];
-               animpos = rsurface.texture->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->tcmods[0].parms[3];
-//             rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
-//             rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-//             rsurface.batchtexcoordtexture2f_bufferoffset = 0;
-               for (j = 0;j < batchnumvertices;j++)
-               {
-                       rsurface.batchtexcoordtexture2f[j*2+0] += amplitude * sin(((rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+2]) * 1.0 / 1024.0f + animpos) * M_PI * 2);
-                       rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
+               // the only tcmod that needs software vertex processing is turbulent, so
+               // check for it here and apply the changes if needed
+               // and we only support that as the first one
+               // (handling a mixture of turbulent and other tcmods would be problematic
+               //  without punting it entirely to a software path)
+               if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
+               {
+                       amplitude = rsurface.texture->tcmods[0].parms[1];
+                       animpos = rsurface.texture->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->tcmods[0].parms[3];
+       //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
+       //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
+       //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
+                       for (j = 0;j < batchnumvertices;j++)
+                       {
+                               rsurface.batchtexcoordtexture2f[j*2+0] += amplitude * sin(((rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+2]) * 1.0 / 1024.0f + animpos) * M_PI * 2);
+                               rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
+                       }
                }
        }
 
@@ -10200,35 +10226,35 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
        }
 
        // upload buffer data for the dynamic batch
-       if (vid.forcevbo || (r_batch_dynamicbuffer.integer && vid.support.arb_vertex_buffer_object))
+       if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicvertex.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
        {
                if (rsurface.batchvertexmesh)
-                       rsurface.batchvertexmesh_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(r_vertexmesh_t), rsurface.batchvertexmesh, R_BUFFERDATA_VERTEX, &rsurface.batchvertexmesh_bufferoffset, !vid.forcevbo);
+                       rsurface.batchvertexmesh_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(r_vertexmesh_t), rsurface.batchvertexmesh, R_BUFFERDATA_VERTEX, &rsurface.batchvertexmesh_bufferoffset);
                else
                {
                        if (rsurface.batchvertex3f)
-                               rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset, !vid.forcevbo);
+                               rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
                        if (rsurface.batchsvector3f)
-                               rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset, !vid.forcevbo);
+                               rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
                        if (rsurface.batchtvector3f)
-                               rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset, !vid.forcevbo);
+                               rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
                        if (rsurface.batchnormal3f)
-                               rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset, !vid.forcevbo);
-                       if (rsurface.batchlightmapcolor4f && r_batch_dynamicbuffer.integer && vid.support.arb_vertex_buffer_object)
-                               rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset, !vid.forcevbo);
-                       if (rsurface.batchtexcoordtexture2f && r_batch_dynamicbuffer.integer && vid.support.arb_vertex_buffer_object)
-                               rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset, !vid.forcevbo);
-                       if (rsurface.batchtexcoordlightmap2f && r_batch_dynamicbuffer.integer && vid.support.arb_vertex_buffer_object)
-                               rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset, !vid.forcevbo);
+                               rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
+                       if (rsurface.batchlightmapcolor4f)
+                               rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
+                       if (rsurface.batchtexcoordtexture2f)
+                               rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
+                       if (rsurface.batchtexcoordlightmap2f)
+                               rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
                        if (rsurface.batchskeletalindex4ub)
-                               rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset, !vid.forcevbo);
+                               rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
                        if (rsurface.batchskeletalweight4ub)
-                               rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset, !vid.forcevbo);
+                               rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
                }
                if (rsurface.batchelement3s)
-                       rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset, !vid.forcevbo);
+                       rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
                else if (rsurface.batchelement3i)
-                       rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset, !vid.forcevbo);
+                       rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
        }
 }
 
@@ -10646,7 +10672,7 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_
        // in Quake3 maps as it causes problems with q3map2 sky tricks,
        // and skymasking also looks very bad when noclipping outside the
        // level, so don't use it then either.
-       if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_refdef.viewcache.world_novis && !r_trippy.integer)
+       if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.skymasking && r_q1bsp_skymasking.integer && !r_refdef.viewcache.world_novis && !r_trippy.integer)
        {
                R_Mesh_ResetTextureState();
                if (skyrendermasked)
@@ -11608,7 +11634,7 @@ void R_DecalSystem_Reset(decalsystem_t *decalsystem)
        memset(decalsystem, 0, sizeof(*decalsystem));
 }
 
-static void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, const float *v1, const float *v2, const float *t0, const float *t1, const float *t2, const float *c0, const float *c1, const float *c2, int triangleindex, int surfaceindex, int decalsequence)
+static void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, const float *v1, const float *v2, const float *t0, const float *t1, const float *t2, const float *c0, const float *c1, const float *c2, int triangleindex, int surfaceindex, unsigned int decalsequence)
 {
        tridecal_t *decal;
        tridecal_t *decals;
@@ -11688,7 +11714,7 @@ extern cvar_t cl_decals_bias;
 extern cvar_t cl_decals_models;
 extern cvar_t cl_decals_newsystem_intensitymultiplier;
 // baseparms, parms, temps
-static void R_DecalSystem_SplatTriangle(decalsystem_t *decalsystem, float r, float g, float b, float a, float s1, float t1, float s2, float t2, int decalsequence, qboolean dynamic, float (*planes)[4], matrix4x4_t *projection, int triangleindex, int surfaceindex)
+static void R_DecalSystem_SplatTriangle(decalsystem_t *decalsystem, float r, float g, float b, float a, float s1, float t1, float s2, float t2, unsigned int decalsequence, qboolean dynamic, float (*planes)[4], matrix4x4_t *projection, int triangleindex, int surfaceindex)
 {
        int cornerindex;
        int index;
@@ -11781,7 +11807,7 @@ static void R_DecalSystem_SplatTriangle(decalsystem_t *decalsystem, float r, flo
                for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
                        R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[cornerindex+1], v[cornerindex+2], tc[0], tc[cornerindex+1], tc[cornerindex+2], c[0], c[cornerindex+1], c[cornerindex+2], -1, surfaceindex, decalsequence);
 }
-static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, int decalsequence)
+static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, unsigned int decalsequence)
 {
        matrix4x4_t projection;
        decalsystem_t *decalsystem;
@@ -11942,7 +11968,7 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor
 }
 
 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
-static void R_DecalSystem_ApplySplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, int decalsequence)
+static void R_DecalSystem_ApplySplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, unsigned int decalsequence)
 {
        int renderentityindex;
        float worldmins[3];
@@ -11978,7 +12004,7 @@ typedef struct r_decalsystem_splatqueue_s
        float color[4];
        float tcrange[4];
        float worldsize;
-       int decalsequence;
+       unsigned int decalsequence;
 }
 r_decalsystem_splatqueue_t;
 
@@ -12017,7 +12043,7 @@ static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
        int i;
        decalsystem_t *decalsystem = &ent->decalsystem;
        int numdecals;
-       int killsequence;
+       unsigned int killsequence;
        tridecal_t *decal;
        float frametime;
        float lifetime;
@@ -12034,7 +12060,7 @@ static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
                return;
        }
 
-       killsequence = cl.decalsequence - max(1, cl_decals_max.integer);
+       killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
        lifetime = cl_decals_time.value + cl_decals_fadetime.value;
 
        if (decalsystem->lastupdatetime)
@@ -12049,7 +12075,7 @@ static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
                if (decal->color4f[0][3])
                {
                        decal->lived += frametime;
-                       if (killsequence - decal->decalsequence > 0 || decal->lived >= lifetime)
+                       if (killsequence > decal->decalsequence || decal->lived >= lifetime)
                        {
                                memset(decal, 0, sizeof(*decal));
                                if (decalsystem->freedecal > i)
@@ -12254,10 +12280,9 @@ extern cvar_t mod_collision_bih;
 static void R_DrawDebugModel(void)
 {
        entity_render_t *ent = rsurface.entity;
-       int i, j, k, l, flagsmask;
+       int i, j, flagsmask;
        const msurface_t *surface;
        dp_model_t *model = ent->model;
-       vec3_t v;
 
        if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
                return;
@@ -12389,6 +12414,8 @@ static void R_DrawDebugModel(void)
 
        if (r_shownormals.value != 0 && qglBegin)
        {
+               int l, k;
+               vec3_t v;
                if (r_showdisabledepthtest.integer)
                {
                        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -12708,6 +12735,7 @@ void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, i
 
        texture.update_lastrenderframe = -1; // regenerate this texture
        texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
+       texture.basealpha = 1.0f;
        texture.currentskinframe = skinframe;
        texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
        texture.offsetmapping = OFFSETMAPPING_OFF;