]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
force R_GetCurrentTexture to regenerate data when
[xonotic/darkplaces.git] / gl_rmain.c
index 6cd860528850760f7cd110603ea76cb4c127d95f..e5452b18d28f064a6fa4e19d709e963e3f9a1b09 100644 (file)
@@ -95,7 +95,7 @@ cvar_t r_polygonoffset_decals_factor = {0, "r_polygonoffset_decals_factor", "0",
 cvar_t r_polygonoffset_decals_offset = {0, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
 cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
 cvar_t r_drawfog = {CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
-cvar_t r_transparentdepthmasking = {CVAR_SAVE, "r_transparentdepthmasking", "1", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
+cvar_t r_transparentdepthmasking = {CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
 
 cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
@@ -343,7 +343,8 @@ static void R_BuildNormalizationCube(void)
        vec3_t v;
        vec_t s, t, intensity;
 #define NORMSIZE 64
-       unsigned char data[6][NORMSIZE][NORMSIZE][4];
+       unsigned char *data;
+       data = Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
        for (side = 0;side < 6;side++)
        {
                for (y = 0;y < NORMSIZE;y++)
@@ -387,14 +388,15 @@ static void R_BuildNormalizationCube(void)
                                        break;
                                }
                                intensity = 127.0f / sqrt(DotProduct(v, v));
-                               data[side][y][x][2] = (unsigned char)(128.0f + intensity * v[0]);
-                               data[side][y][x][1] = (unsigned char)(128.0f + intensity * v[1]);
-                               data[side][y][x][0] = (unsigned char)(128.0f + intensity * v[2]);
-                               data[side][y][x][3] = 255;
+                               data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
+                               data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
+                               data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
+                               data[((side*64+y)*64+x)*4+3] = 255;
                        }
                }
        }
-       r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, &data[0][0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
+       r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
+       Mem_Free(data);
 }
 
 static void R_BuildFogTexture(void)
@@ -448,8 +450,8 @@ static void R_BuildFogTexture(void)
        }
        else
        {
-               r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
-               //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
+               r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT | TEXF_ALLOWUPDATES, NULL);
+               //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALLOWUPDATES, NULL);
        }
 }
 
@@ -484,13 +486,16 @@ static const char *builtinshaderstring =
 "#endif\n"
 "#else // !MODE_SHOWDEPTH\n"
 "#ifdef MODE_POSTPROCESS\n"
+"varying vec2 TexCoord1;\n"
+"varying vec2 TexCoord2;\n"
+"\n"
 "#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\n"
 "      gl_Position = ftransform();\n"
-"      gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
+"      TexCoord1 = gl_MultiTexCoord0.xy;\n"
 "#ifdef USEBLOOM\n"
-"      gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;\n"
+"      TexCoord2 = gl_MultiTexCoord1.xy;\n"
 "#endif\n"
 "}\n"
 "#endif\n"
@@ -518,9 +523,9 @@ static const char *builtinshaderstring =
 "uniform vec2 PixelSize;\n"
 "void main(void)\n"
 "{\n"
-"      gl_FragColor = texture2D(Texture_First, gl_TexCoord[0].xy);\n"
+"      gl_FragColor = texture2D(Texture_First, TexCoord1);\n"
 "#ifdef USEBLOOM\n"
-"      gl_FragColor += texture2D(Texture_Second, gl_TexCoord[1].xy);\n"
+"      gl_FragColor += texture2D(Texture_Second, TexCoord2);\n"
 "#endif\n"
 "#ifdef USEVIEWTINT\n"
 "      gl_FragColor = mix(gl_FragColor, ViewTintColor, ViewTintColor.a);\n"
@@ -529,11 +534,11 @@ static const char *builtinshaderstring =
 "#ifdef USEPOSTPROCESSING\n"
 "// do r_glsl_dumpshader, edit glsl/default.glsl, and replace this by your own postprocessing if you want\n"
 "// this code does a blur with the radius specified in the first component of r_glsl_postprocess_uservec1 and blends it using the second component\n"
-"      gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.987688, -0.156434)) * UserVec1.y;\n"
-"      gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.156434, -0.891007)) * UserVec1.y;\n"
-"      gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2( 0.891007, -0.453990)) * UserVec1.y;\n"
-"      gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2( 0.707107,  0.707107)) * UserVec1.y;\n"
-"      gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.453990,  0.891007)) * UserVec1.y;\n"
+"      gl_FragColor += texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2(-0.987688, -0.156434)) * UserVec1.y;\n"
+"      gl_FragColor += texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2(-0.156434, -0.891007)) * UserVec1.y;\n"
+"      gl_FragColor += texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2( 0.891007, -0.453990)) * UserVec1.y;\n"
+"      gl_FragColor += texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2( 0.707107,  0.707107)) * UserVec1.y;\n"
+"      gl_FragColor += texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2(-0.453990,  0.891007)) * UserVec1.y;\n"
 "      gl_FragColor /= (1 + 5 * UserVec1.y);\n"
 "#endif\n"
 "\n"
@@ -553,15 +558,21 @@ static const char *builtinshaderstring =
 "#endif\n"
 "#else // !MODE_POSTPROCESS\n"
 "#ifdef MODE_GENERIC\n"
+"#ifdef USEDIFFUSE\n"
+"varying vec2 TexCoord1;\n"
+"#endif\n"
+"#ifdef USESPECULAR\n"
+"varying vec2 TexCoord2;\n"
+"#endif\n"
 "#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\n"
 "      gl_FrontColor = gl_Color;\n"
 "#ifdef USEDIFFUSE\n"
-"      gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
+"      TexCoord1 = gl_MultiTexCoord0.xy;\n"
 "#endif\n"
 "#ifdef USESPECULAR\n"
-"      gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;\n"
+"      TexCoord2 = gl_MultiTexCoord1.xy;\n"
 "#endif\n"
 "      gl_Position = ftransform();\n"
 "}\n"
@@ -579,11 +590,11 @@ static const char *builtinshaderstring =
 "{\n"
 "      gl_FragColor = gl_Color;\n"
 "#ifdef USEDIFFUSE\n"
-"      gl_FragColor *= texture2D(Texture_First, gl_TexCoord[0].xy);\n"
+"      gl_FragColor *= texture2D(Texture_First, TexCoord1);\n"
 "#endif\n"
 "\n"
 "#ifdef USESPECULAR\n"
-"      vec4 tex2 = texture2D(Texture_Second, gl_TexCoord[1].xy);\n"
+"      vec4 tex2 = texture2D(Texture_Second, TexCoord2);\n"
 "#endif\n"
 "#ifdef USECOLORMAPPING\n"
 "      gl_FragColor *= tex2;\n"
@@ -598,11 +609,12 @@ static const char *builtinshaderstring =
 "#endif\n"
 "#else // !MODE_GENERIC\n"
 "#ifdef MODE_BLOOMBLUR\n"
+"varying TexCoord;\n"
 "#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\n"
 "      gl_FrontColor = gl_Color;\n"
-"      gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
+"      TexCoord = gl_MultiTexCoord0.xy;\n"
 "      gl_Position = ftransform();\n"
 "}\n"
 "#endif\n"
@@ -614,7 +626,7 @@ static const char *builtinshaderstring =
 "void main(void)\n"
 "{\n"
 "      int i;\n"
-"      vec2 tc = gl_TexCoord[0].xy;\n"
+"      vec2 tc = TexCoord;\n"
 "      vec3 color = texture2D(Texture_First, tc).rgb;\n"
 "      tc += BloomBlur_Parameters.xy;\n"
 "      for (i = 1;i < SAMPLES;i++)\n"
@@ -629,11 +641,12 @@ static const char *builtinshaderstring =
 "#ifdef MODE_REFRACTION\n"
 "varying vec2 TexCoord;\n"
 "varying vec4 ModelViewProjectionPosition;\n"
+"uniform mat4 TexMatrix;\n"
 "#ifdef VERTEX_SHADER\n"
 "\n"
 "void main(void)\n"
 "{\n"
-"      TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
+"      TexCoord = vec2(TexMatrix * gl_MultiTexCoord0);\n"
 "      gl_Position = ftransform();\n"
 "      ModelViewProjectionPosition = gl_Position;\n"
 "}\n"
@@ -678,10 +691,11 @@ static const char *builtinshaderstring =
 "varying vec4 ModelViewProjectionPosition;\n"
 "#ifdef VERTEX_SHADER\n"
 "uniform vec3 EyePosition;\n"
+"uniform mat4 TexMatrix;\n"
 "\n"
 "void main(void)\n"
 "{\n"
-"      TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
+"      TexCoord = vec2(TexMatrix * gl_MultiTexCoord0);\n"
 "      vec3 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
 "      EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
 "      EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
@@ -837,12 +851,16 @@ static const char *builtinshaderstring =
 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3), this would require sending a 4 component texcoord1 with W as 1 or -1 according to which side the texcoord2 should be on\n"
 "\n"
 "#ifdef MODE_DEFERREDGEOMETRY\n"
+"uniform mat4 TexMatrix;\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"uniform mat4 BackgroundTexMatrix;\n"
+"#endif\n"
 "void main(void)\n"
 "{\n"
-"      TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
+"      TexCoord = vec2(TexMatrix * gl_MultiTexCoord0);\n"
 "#ifdef USEVERTEXTEXTUREBLEND\n"
 "      gl_FrontColor = gl_Color;\n"
-"      TexCoord2 = vec2(gl_TextureMatrix[1] * gl_MultiTexCoord0);\n"
+"      TexCoord2 = vec2(BackgroundTexMatrix * gl_MultiTexCoord0);\n"
 "#endif\n"
 "\n"
 "      // transform unnormalized eye direction into tangent space\n"
@@ -866,15 +884,22 @@ static const char *builtinshaderstring =
 "      gl_Position = ftransform();\n"
 "}\n"
 "#else // !MODE_DEFERREDLIGHTSOURCE\n"
+"uniform mat4 TexMatrix;\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"uniform mat4 BackgroundTexMatrix;\n"
+"#endif\n"
+"#ifdef MODE_LIGHTSOURCE\n"
+"uniform mat4 ModelToLight;\n"
+"#endif\n"
 "void main(void)\n"
 "{\n"
 "#if defined(MODE_VERTEXCOLOR) || defined(USEVERTEXTEXTUREBLEND)\n"
 "      gl_FrontColor = gl_Color;\n"
 "#endif\n"
 "      // copy the surface texcoord\n"
-"      TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
+"      TexCoord = vec2(TexMatrix * gl_MultiTexCoord0);\n"
 "#ifdef USEVERTEXTEXTUREBLEND\n"
-"      TexCoord2 = vec2(gl_TextureMatrix[1] * gl_MultiTexCoord0);\n"
+"      TexCoord2 = vec2(BackgroundTexMatrix * gl_MultiTexCoord0);\n"
 "#endif\n"
 "#ifdef USELIGHTMAP\n"
 "      TexCoordLightmap = vec2(gl_MultiTexCoord4);\n"
@@ -883,7 +908,7 @@ static const char *builtinshaderstring =
 "#ifdef MODE_LIGHTSOURCE\n"
 "      // transform vertex position into light attenuation/cubemap space\n"
 "      // (-1 to +1 across the light box)\n"
-"      CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
+"      CubeVector = vec3(ModelToLight * gl_Vertex);\n"
 "\n"
 "# ifdef USEDIFFUSE\n"
 "      // transform unnormalized light direction into tangent space\n"
@@ -1801,6 +1826,9 @@ typedef struct r_glsl_permutation_s
        int loc_UserVec4;
        int loc_ViewTintColor;
        int loc_ViewToLight;
+       int loc_ModelToLight;
+       int loc_TexMatrix;
+       int loc_BackgroundTexMatrix;
 }
 r_glsl_permutation_t;
 
@@ -2008,6 +2036,9 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                p->loc_UserVec4                   = qglGetUniformLocationARB(p->program, "UserVec4");
                p->loc_ViewTintColor              = qglGetUniformLocationARB(p->program, "ViewTintColor");
                p->loc_ViewToLight                = qglGetUniformLocationARB(p->program, "ViewToLight");
+               p->loc_ModelToLight               = qglGetUniformLocationARB(p->program, "ModelToLight");
+               p->loc_TexMatrix                  = qglGetUniformLocationARB(p->program, "TexMatrix");
+               p->loc_BackgroundTexMatrix        = qglGetUniformLocationARB(p->program, "BackgroundTexMatrix");
                // initialize the samplers to refer to the texture units we use
                if (p->loc_Texture_First           >= 0) qglUniform1iARB(p->loc_Texture_First          , GL20TU_FIRST);
                if (p->loc_Texture_Second          >= 0) qglUniform1iARB(p->loc_Texture_Second         , GL20TU_SECOND);
@@ -2210,6 +2241,7 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
        // fragment shader on features that are not being used
        unsigned int permutation = 0;
        unsigned int mode = 0;
+       float m16f[16];
        // TODO: implement geometry-shader based shadow volumes someday
        if (r_glsl_offsetmapping.integer)
        {
@@ -2385,6 +2417,7 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
        R_SetupShader_SetPermutation(mode, permutation);
        if (mode == SHADERMODE_LIGHTSOURCE)
        {
+               if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
                if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
                if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);
                if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Ambient, rsurface.colormod[0] * ambientscale, rsurface.colormod[1] * ambientscale, rsurface.colormod[2] * ambientscale);
@@ -2439,6 +2472,8 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectOffset, rsurface.texture->reflectmin);
                if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));
        }
+       if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
+       if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
        if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]);
        if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1fARB(r_glsl_permutation->loc_Alpha, rsurface.texture->lightmapcolor[3]);
        if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
@@ -4148,8 +4183,8 @@ void R_View_Update(void)
 
 void R_SetupView(qboolean allowwaterclippingplane)
 {
-       const double *customclipplane = NULL;
-       double plane[4];
+       const float *customclipplane = NULL;
+       float plane[4];
        if (r_refdef.view.useclipplane && allowwaterclippingplane)
        {
                // LordHavoc: couldn't figure out how to make this approach the
@@ -4785,6 +4820,7 @@ void R_HDR_RenderBloomTexture(void)
        r_refdef.view.width = oldwidth;
        r_refdef.view.height = oldheight;
        r_refdef.view.colorscale = oldcolorscale;
+       r_frame++; // used only by R_GetCurrentTexture
 
        R_ResetViewRendering3D();
 
@@ -5101,7 +5137,7 @@ void R_UpdateVariables(void)
                                }
                                else
                                {
-                                       r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
+                                       r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT | TEXF_ALLOWUPDATES, NULL);
                                }
                        }
                }
@@ -7065,7 +7101,7 @@ void RSurf_DrawBatch_Simple(int texturenumsurfaces, const msurface_t **texturesu
        {
                #define MAXBATCHTRIANGLES 4096
                int batchtriangles = 0;
-               int batchelements[MAXBATCHTRIANGLES*3];
+               static int batchelements[MAXBATCHTRIANGLES*3];
                for (i = 0;i < texturenumsurfaces;i = j)
                {
                        surface = texturesurfacelist[i];
@@ -7674,8 +7710,6 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface
        if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)))
                return;
 
-       R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
-       R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
        R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
        R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
        R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
@@ -7784,7 +7818,6 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface
        int texturesurfaceindex;
        qboolean applycolor;
        qboolean applyfog;
-       rmeshstate_t m;
        int layerindex;
        const texturelayer_t *layer;
        RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
@@ -7827,18 +7860,15 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface
                switch (layer->type)
                {
                case TEXTURELAYERTYPE_LITTEXTURE:
-                       memset(&m, 0, sizeof(m));
-                       m.tex[0] = R_GetTexture(r_texture_white);
-                       m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
-                       m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
-                       m.tex[1] = R_GetTexture(layer->texture);
-                       m.texmatrix[1] = layer->texmatrix;
-                       m.texrgbscale[1] = layertexrgbscale;
-                       m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
-                       m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
-                       R_Mesh_TextureState(&m);
+                       // single-pass lightmapped texture with 2x rgbscale
+                       R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
+                       R_Mesh_TexMatrix(0, NULL);
+                       R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+                       R_Mesh_TexCoordPointer(0, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
+                       R_Mesh_TexBind(1, R_GetTexture(layer->texture));
+                       R_Mesh_TexMatrix(1, &layer->texmatrix);
+                       R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, layertexrgbscale, 1);
+                       R_Mesh_TexCoordPointer(1, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                        if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
                                RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
                        else if (rsurface.uselightmaptexture)
@@ -7847,28 +7877,31 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface
                                RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
                        break;
                case TEXTURELAYERTYPE_TEXTURE:
-                       memset(&m, 0, sizeof(m));
-                       m.tex[0] = R_GetTexture(layer->texture);
-                       m.texmatrix[0] = layer->texmatrix;
-                       m.texrgbscale[0] = layertexrgbscale;
-                       m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-                       m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-                       R_Mesh_TextureState(&m);
+                       // singletexture unlit texture with transparency support
+                       R_Mesh_TexBind(0, R_GetTexture(layer->texture));
+                       R_Mesh_TexMatrix(0, &layer->texmatrix);
+                       R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, layertexrgbscale, 1);
+                       R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+                       R_Mesh_TexBind(1, 0);
+                       R_Mesh_TexCoordPointer(1, 2, NULL, 0, 0);
                        RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
                        break;
                case TEXTURELAYERTYPE_FOG:
-                       memset(&m, 0, sizeof(m));
-                       m.texrgbscale[0] = layertexrgbscale;
+                       // singletexture fogging
                        if (layer->texture)
                        {
-                               m.tex[0] = R_GetTexture(layer->texture);
-                               m.texmatrix[0] = layer->texmatrix;
-                               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-                               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-                               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
+                               R_Mesh_TexBind(0, R_GetTexture(layer->texture));
+                               R_Mesh_TexMatrix(0, &layer->texmatrix);
+                               R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, layertexrgbscale, 1);
+                               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
+                       }
+                       else
+                       {
+                               R_Mesh_TexBind(0, 0);
+                               R_Mesh_TexCoordPointer(0, 2, NULL, 0, 0);
                        }
-                       R_Mesh_TextureState(&m);
+                       R_Mesh_TexBind(1, 0);
+                       R_Mesh_TexCoordPointer(1, 2, NULL, 0, 0);
                        // generate a color array for the fog pass
                        R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
                        for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
@@ -7907,7 +7940,6 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
        // OpenGL 1.1 - crusty old voodoo path
        int texturesurfaceindex;
        qboolean applyfog;
-       rmeshstate_t m;
        int layerindex;
        const texturelayer_t *layer;
        RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
@@ -7935,12 +7967,10 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
                        {
                                // two-pass lit texture with 2x rgbscale
                                // first the lightmap pass
-                               memset(&m, 0, sizeof(m));
-                               m.tex[0] = R_GetTexture(r_texture_white);
-                               m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
-                               m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
-                               m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
-                               R_Mesh_TextureState(&m);
+                               R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
+                               R_Mesh_TexMatrix(0, NULL);
+                               R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+                               R_Mesh_TexCoordPointer(0, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
                                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
                                        RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
                                else if (rsurface.uselightmaptexture)
@@ -7950,25 +7980,19 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
                                GL_LockArrays(0, 0);
                                // then apply the texture to it
                                GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
-                               memset(&m, 0, sizeof(m));
-                               m.tex[0] = R_GetTexture(layer->texture);
-                               m.texmatrix[0] = layer->texmatrix;
-                               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-                               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-                               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-                               R_Mesh_TextureState(&m);
+                               R_Mesh_TexBind(0, R_GetTexture(layer->texture));
+                               R_Mesh_TexMatrix(0, &layer->texmatrix);
+                               R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+                               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                                RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layer->color[0] * 0.5f, layer->color[1] * 0.5f, layer->color[2] * 0.5f, layer->color[3], layer->color[0] != 2 || layer->color[1] != 2 || layer->color[2] != 2 || layer->color[3] != 1, false);
                        }
                        else
                        {
                                // single pass vertex-lighting-only texture with 1x rgbscale and transparency support
-                               memset(&m, 0, sizeof(m));
-                               m.tex[0] = R_GetTexture(layer->texture);
-                               m.texmatrix[0] = layer->texmatrix;
-                               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-                               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-                               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-                               R_Mesh_TextureState(&m);
+                               R_Mesh_TexBind(0, R_GetTexture(layer->texture));
+                               R_Mesh_TexMatrix(0, &layer->texmatrix);
+                               R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+                               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
                                        RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
                                else
@@ -7977,31 +8001,28 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface
                        break;
                case TEXTURELAYERTYPE_TEXTURE:
                        // singletexture unlit texture with transparency support
-                       memset(&m, 0, sizeof(m));
-                       m.tex[0] = R_GetTexture(layer->texture);
-                       m.texmatrix[0] = layer->texmatrix;
-                       m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-                       m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-                       m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-                       R_Mesh_TextureState(&m);
+                       R_Mesh_TexBind(0, R_GetTexture(layer->texture));
+                       R_Mesh_TexMatrix(0, &layer->texmatrix);
+                       R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+                       R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                        RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
                        break;
                case TEXTURELAYERTYPE_FOG:
                        // singletexture fogging
-                       R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
                        if (layer->texture)
                        {
-                               memset(&m, 0, sizeof(m));
-                               m.tex[0] = R_GetTexture(layer->texture);
-                               m.texmatrix[0] = layer->texmatrix;
-                               m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
-                               m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
-                               m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
-                               R_Mesh_TextureState(&m);
+                               R_Mesh_TexBind(0, R_GetTexture(layer->texture));
+                               R_Mesh_TexMatrix(0, &layer->texmatrix);
+                               R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+                               R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
                        }
                        else
-                               R_Mesh_ResetTextureState();
+                       {
+                               R_Mesh_TexBind(0, 0);
+                               R_Mesh_TexCoordPointer(0, 2, NULL, 0, 0);
+                       }
                        // generate a color array for the fog pass
+                       R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
                        for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                        {
                                int i;
@@ -8192,7 +8213,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
        int texturenumsurfaces, endsurface;
        texture_t *texture;
        const msurface_t *surface;
-       const msurface_t *texturesurfacelist[1024];
+       const msurface_t *texturesurfacelist[256];
 
        // if the model is static it doesn't matter what value we give for
        // wantnormals and wanttangents, so this logic uses only rules applicable
@@ -8673,7 +8694,6 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor
        matrix4x4_t projection;
        decalsystem_t *decalsystem;
        qboolean dynamic;
-       qboolean notworld = ent != r_refdef.scene.worldentity;
        dp_model_t *model;
        const float *vertex3f;
        const msurface_t *surface;
@@ -8865,7 +8885,7 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor
                                R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[1], v[2], tc[0], tc[1], tc[2], c[0], c[1], c[2], triangleindex+surface->num_firsttriangle, surfaceindex, decalsequence);
                        else
                                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, notworld ? -1 : surfaceindex, decalsequence);
+                                       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);
                }
        }
 }
@@ -9025,7 +9045,7 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
        float *c4f;
        float *t2f;
        const int *e;
-       const unsigned char *surfacevisible = r_refdef.viewcache.world_surfacevisible;
+       const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
        int numtris = 0;
 
        numdecals = decalsystem->numdecals;
@@ -9064,7 +9084,7 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
                if (!decal->color4ub[0][3])
                        continue;
 
-               if (decal->surfaceindex >= 0 && !surfacevisible[decal->surfaceindex])
+               if (surfacevisible && !surfacevisible[decal->surfaceindex])
                        continue;
 
                // update color values for fading decals
@@ -9407,10 +9427,31 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep
        }
        // update lightmaps if needed
        if (update)
+       {
+               int updated = 0;
                for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
+               {
                        if (r_refdef.viewcache.world_surfacevisible[j])
+                       {
                                if (update[j])
+                               {
+                                       updated++;
                                        R_BuildLightMap(r_refdef.scene.worldentity, surfaces + j);
+                               }
+                       }
+               }
+               if (updated)
+               {
+                       int count = model->brushq3.num_mergedlightmaps;
+                       for (i = 0;i < count;i++)
+                       {
+                               if (model->brushq3.data_deluxemaps[i])
+                                       R_FlushTexture(model->brushq3.data_deluxemaps[i]);
+                               if (model->brushq3.data_lightmaps[i])
+                                       R_FlushTexture(model->brushq3.data_lightmaps[i]);
+                       }
+               }
+       }
        // don't do anything if there were no surfaces
        if (!numsurfacelist)
        {
@@ -9519,6 +9560,29 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr
                return;
        }
        // update lightmaps if needed
+       if (update)
+       {
+               int updated = 0;
+               for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
+               {
+                       if (update[j])
+                       {
+                               updated++;
+                               R_BuildLightMap(ent, surfaces + j);
+                       }
+               }
+               if (updated)
+               {
+                       int count = model->brushq3.num_mergedlightmaps;
+                       for (i = 0;i < count;i++)
+                       {
+                               if (model->brushq3.data_deluxemaps[i])
+                                       R_FlushTexture(model->brushq3.data_deluxemaps[i]);
+                               if (model->brushq3.data_lightmaps[i])
+                                       R_FlushTexture(model->brushq3.data_lightmaps[i]);
+                       }
+               }
+       }
        if (update)
                for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
                        if (update[j])