]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
fix for .alpha and other effects on sprites that use the same frame,
[xonotic/darkplaces.git] / gl_rmain.c
index cdcadf37da309130d04feddef29399592c584909..07faae9a191ecd7453f081cb001dad19ffac4691 100644 (file)
@@ -77,6 +77,8 @@ cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip pla
 cvar_t r_deformvertexes = {0, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
 cvar_t r_transparent = {0, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
 cvar_t r_transparent_alphatocoverage = {0, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
+cvar_t r_transparent_sortsurfacesbynearest = {0, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"};
+cvar_t r_transparent_useplanardistance = {0, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
 cvar_t r_showoverdraw = {0, "r_showoverdraw", "0", "shows overlapping geometry"};
 cvar_t r_showbboxes = {0, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
 cvar_t r_showsurfaces = {0, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
@@ -130,6 +132,8 @@ cvar_t r_transparentdepthmasking = {CVAR_SAVE, "r_transparentdepthmasking", "0",
 cvar_t r_transparent_sortmindist = {CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
 cvar_t r_transparent_sortmaxdist = {CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
 cvar_t r_transparent_sortarraysize = {CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
+cvar_t r_celshading = {CVAR_SAVE, "r_celshading", "0", "cartoon-style light shading"};
+cvar_t r_celoutlines = {CVAR_SAVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred)"};
 
 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)"};
@@ -147,7 +151,7 @@ cvar_t r_textureunits = {0, "r_textureunits", "32", "number of texture units to
 static cvar_t gl_combine = {CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
 static cvar_t r_glsl = {CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
 
-cvar_t r_usedepthtextures = {CVAR_SAVE, "r_usedepthtextures", "0", "use depth texture instead of depth renderbuffer where possible, may not be slower on some hardware"};
+cvar_t r_usedepthtextures = {CVAR_SAVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
 cvar_t r_viewfbo = {CVAR_SAVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
 cvar_t r_viewscale = {CVAR_SAVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
 cvar_t r_viewscale_fpsscaling = {CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
@@ -643,9 +647,6 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
        {"#define USEOFFSETMAPPING\n", " offsetmapping"},
        {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
        {"#define USESHADOWMAP2D\n", " shadowmap2d"},
-       {"#define USESHADOWMAPPCF 1\n", " shadowmappcf"}, // TODO make this a static parm
-       {"#define USESHADOWMAPPCF 2\n", " shadowmappcf2"}, // TODO make this a static parm
-       {"#define USESHADOWSAMPLER\n", " shadowsampler"}, // TODO make this a static parm
        {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
        {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
        {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
@@ -656,6 +657,7 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
        {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
        {"#define USETRIPPY\n", " trippy"},
        {"#define USEDEPTHRGB\n", " depthrgb"},
+       {"#define USEALPHAGENVERTEX\n", "alphagenvertex"}
 };
 
 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
@@ -850,15 +852,23 @@ enum
        SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
        SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
        SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
+       SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
+       SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
+       SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
+       SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
+       SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
 };
-#define SHADERSTATICPARMS_COUNT 8
+#define SHADERSTATICPARMS_COUNT 13
 
 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
 static int shaderstaticparms_count = 0;
 
 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
-static qboolean R_CompileShader_CheckStaticParms(void)
+
+extern qboolean r_shadow_shadowmapsampler;
+extern int r_shadow_shadowmappcf;
+qboolean R_CompileShader_CheckStaticParms(void)
 {
        static int r_compileshader_staticparms_save[1];
        memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
@@ -884,6 +894,18 @@ static qboolean R_CompileShader_CheckStaticParms(void)
        }
        if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
                R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
+
+       if (r_shadow_shadowmapsampler)
+               R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
+       if (r_shadow_shadowmappcf > 1)
+               R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
+       else if (r_shadow_shadowmappcf)
+               R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
+       if (r_celshading.integer)
+               R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
+       if (r_celoutlines.integer)
+               R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
+
        return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
 }
 
@@ -905,6 +927,11 @@ static void R_CompileShader_AddStaticParms(unsigned int mode, unsigned int permu
        R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
        R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
        R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
+       R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
+       R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
+       R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
+       R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
+       R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
 }
 
 /// information about each possible shader permutation
@@ -1784,7 +1811,7 @@ static void R_SetupShader_SetPermutationSoft(unsigned int mode, unsigned int per
        DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_ClientTime, cl.time);
 }
 
-static void R_GLSL_Restart_f(void)
+void R_GLSL_Restart_f(void)
 {
        unsigned int i, limit;
        if (glslshaderstring && glslshaderstring != builtinshaderstring)
@@ -2045,8 +2072,6 @@ extern qboolean r_shadow_usingshadowmaportho;
 extern float r_shadow_shadowmap_texturescale[2];
 extern float r_shadow_shadowmap_parameters[4];
 extern qboolean r_shadow_shadowmapvsdct;
-extern qboolean r_shadow_shadowmapsampler;
-extern int r_shadow_shadowmappcf;
 extern rtexture_t *r_shadow_shadowmap2ddepthbuffer;
 extern rtexture_t *r_shadow_shadowmap2ddepthtexture;
 extern rtexture_t *r_shadow_shadowmapvsdcttexture;
@@ -2131,6 +2156,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
                {
                        mode = SHADERMODE_WATER;
+                       if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
+                               permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
                        if((r_wateralpha.value < 1) && (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERALPHA))
                        {
                                // this is the right thing to do for wateralpha
@@ -2147,6 +2174,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFRACTION)
                {
                        mode = SHADERMODE_REFRACTION;
+                       if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
+                               permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
                        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                        blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                }
@@ -2195,6 +2224,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
+                       permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
                // light source
                mode = SHADERMODE_LIGHTSOURCE;
                if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
@@ -2213,12 +2244,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        if(r_shadow_shadowmapvsdct)
                                permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
 
-                       if (r_shadow_shadowmapsampler)
-                               permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
-                       if (r_shadow_shadowmappcf > 1)
-                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
-                       else if (r_shadow_shadowmappcf)
-                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
                        if (r_shadow_shadowmap2ddepthbuffer)
                                permutation |= SHADERPERMUTATION_DEPTHRGB;
                }
@@ -2243,10 +2268,12 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
+                       permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
                // unshaded geometry (fullbright or ambient model lighting)
                mode = SHADERMODE_FLATCOLOR;
                ambientscale = diffusescale = specularscale = 0;
-               if (rsurface.texture->glowtexture && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
+               if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
                        permutation |= SHADERPERMUTATION_GLOW;
                if (r_refdef.fogenabled)
                        permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
@@ -2257,12 +2284,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
                        permutation |= SHADERPERMUTATION_SHADOWMAP2D;
 
-                       if (r_shadow_shadowmapsampler)
-                               permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
-                       if (r_shadow_shadowmappcf > 1)
-                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
-                       else if (r_shadow_shadowmappcf)
-                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
                        if (r_shadow_shadowmap2ddepthbuffer)
                                permutation |= SHADERPERMUTATION_DEPTHRGB;
                }
@@ -2298,9 +2319,11 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
+                       permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
                // directional model lighting
                mode = SHADERMODE_LIGHTDIRECTION;
-               if (rsurface.texture->glowtexture && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
+               if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
                        permutation |= SHADERPERMUTATION_GLOW;
                permutation |= SHADERPERMUTATION_DIFFUSE;
                if (specularscale > 0)
@@ -2314,12 +2337,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
                        permutation |= SHADERPERMUTATION_SHADOWMAP2D;
 
-                       if (r_shadow_shadowmapsampler)
-                               permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
-                       if (r_shadow_shadowmappcf > 1)
-                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
-                       else if (r_shadow_shadowmappcf)
-                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
                        if (r_shadow_shadowmap2ddepthbuffer)
                                permutation |= SHADERPERMUTATION_DEPTHRGB;
                }
@@ -2363,9 +2380,11 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
+                       permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
                // ambient model lighting
                mode = SHADERMODE_LIGHTDIRECTION;
-               if (rsurface.texture->glowtexture && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
+               if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
                        permutation |= SHADERPERMUTATION_GLOW;
                if (r_refdef.fogenabled)
                        permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
@@ -2376,12 +2395,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
                        permutation |= SHADERPERMUTATION_SHADOWMAP2D;
 
-                       if (r_shadow_shadowmapsampler)
-                               permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
-                       if (r_shadow_shadowmappcf > 1)
-                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
-                       else if (r_shadow_shadowmappcf)
-                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
                        if (r_shadow_shadowmap2ddepthbuffer)
                                permutation |= SHADERPERMUTATION_DEPTHRGB;
                }
@@ -2425,8 +2438,10 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
                        permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
+                       permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
                // lightmapped wall
-               if (rsurface.texture->glowtexture && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
+               if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
                        permutation |= SHADERPERMUTATION_GLOW;
                if (r_refdef.fogenabled)
                        permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
@@ -2437,12 +2452,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
                        permutation |= SHADERPERMUTATION_SHADOWMAP2D;
 
-                       if (r_shadow_shadowmapsampler)
-                               permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
-                       if (r_shadow_shadowmappcf > 1)
-                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
-                       else if (r_shadow_shadowmappcf)
-                               permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
                        if (r_shadow_shadowmap2ddepthbuffer)
                                permutation |= SHADERPERMUTATION_DEPTHRGB;
                }
@@ -2619,7 +2628,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
                                max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
                        );
-               hlslPSSetParameter1f(D3DPSREGISTER_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer);
+               hlslPSSetParameter1f(D3DPSREGISTER_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
                hlslPSSetParameter1f(D3DPSREGISTER_OffsetMapping_Bias, rsurface.texture->offsetbias);
                hlslPSSetParameter2f(D3DPSREGISTER_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
                hlslPSSetParameter2f(D3DPSREGISTER_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height);
@@ -2780,7 +2789,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
                                max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
                        );
-               if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer);
+               if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
                if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, rsurface.texture->offsetbias);
                if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
                if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
@@ -2926,7 +2935,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
                                max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
                        );
-               DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer);
+               DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
                DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_OffsetMapping_Bias, rsurface.texture->offsetbias);
                DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
                DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
@@ -3006,12 +3015,6 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
                if (r_shadow_shadowmapvsdct)
                        permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
 
-               if (r_shadow_shadowmapsampler)
-                       permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
-               if (r_shadow_shadowmappcf > 1)
-                       permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
-               else if (r_shadow_shadowmappcf)
-                       permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
                if (r_shadow_shadowmap2ddepthbuffer)
                        permutation |= SHADERPERMUTATION_DEPTHRGB;
        }
@@ -3307,7 +3310,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        Image_StripImageExtension(name, basename, sizeof(basename));
 
        // check for DDS texture file first
-       if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel)))
+       if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
        {
                basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
                if (basepixels == NULL)
@@ -3341,7 +3344,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
                skinframe->hasalpha = ddshasalpha;
                VectorCopy(ddsavgcolor, skinframe->avgcolor);
                if (r_loadfog && skinframe->hasalpha)
-                       skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel);
+                       skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel, true);
                //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
        }
        else
@@ -3388,13 +3391,13 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        {
                mymiplevel = savemiplevel;
                if (r_loadnormalmap)
-                       skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), false, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel);
-               skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel);
+                       skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), false, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel, true);
+               skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
                if (r_loadgloss)
-                       skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel);
-               skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel);
-               skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel);
-               skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel);
+                       skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
+               skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
+               skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
+               skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
        }
 
        // _norm is the name used by tenebrae and has been adopted as standard
@@ -4186,6 +4189,8 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_deformvertexes);
        Cvar_RegisterVariable(&r_transparent);
        Cvar_RegisterVariable(&r_transparent_alphatocoverage);
+       Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
+       Cvar_RegisterVariable(&r_transparent_useplanardistance);
        Cvar_RegisterVariable(&r_showoverdraw);
        Cvar_RegisterVariable(&r_showbboxes);
        Cvar_RegisterVariable(&r_showsurfaces);
@@ -4268,6 +4273,8 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
        Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
        Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
+       Cvar_RegisterVariable(&r_celshading);
+       Cvar_RegisterVariable(&r_celoutlines);
 
        Cvar_RegisterVariable(&r_water);
        Cvar_RegisterVariable(&r_water_resolutionmultiplier);
@@ -4736,12 +4743,12 @@ static void R_View_UpdateEntityLighting (void)
        {
                ent = r_refdef.scene.entities[i];
 
-               // skip unseen models and models that updated by CSQC
-               if ((!r_refdef.viewcache.entityvisible[i] && skipunseen) || ent->flags & RENDER_CUSTOMIZEDMODELLIGHT)
+               // skip unseen models
+               if ((!r_refdef.viewcache.entityvisible[i] && skipunseen))
                        continue;
 
                // skip bsp models
-               if (ent->model && (ent->model == cl.worldmodel || ent->model->brush.parentmodel == cl.worldmodel))
+               if (ent->model && ent->model == cl.worldmodel)
                {
                        // TODO: use modellight for r_ambient settings on world?
                        VectorSet(ent->modellight_ambient, 0, 0, 0);
@@ -4749,74 +4756,83 @@ static void R_View_UpdateEntityLighting (void)
                        VectorSet(ent->modellight_lightdir, 0, 0, 1);
                        continue;
                }
-
-               // fetch the lighting from the worldmodel data
-               VectorClear(ent->modellight_ambient);
-               VectorClear(ent->modellight_diffuse);
-               VectorClear(tempdiffusenormal);
-               if (ent->flags & RENDER_LIGHT)
+               
+               if (ent->flags & RENDER_CUSTOMIZEDMODELLIGHT)
                {
-                       vec3_t org;
-                       Matrix4x4_OriginFromMatrix(&ent->matrix, org);
-
-                       // complete lightning for lit sprites
-                       // todo: make a EF_ field so small ents could be lit purely by modellight and skipping real rtlight pass (like EF_NORTLIGHT)?
-                       if (ent->model->type == mod_sprite && !(ent->model->data_textures[0].basematerialflags & MATERIALFLAG_FULLBRIGHT))
+                       // aleady updated by CSQC
+                       // TODO: force modellight on BSP models in this case?
+                       VectorCopy(ent->modellight_lightdir, tempdiffusenormal); 
+               }
+               else
+               {
+                       // fetch the lighting from the worldmodel data
+                       VectorClear(ent->modellight_ambient);
+                       VectorClear(ent->modellight_diffuse);
+                       VectorClear(tempdiffusenormal);
+                       if (ent->flags & RENDER_LIGHT)
                        {
-                               if (ent->model->sprite.sprnum_type == SPR_OVERHEAD) // apply offset for overhead sprites
-                                       org[2] = org[2] + r_overheadsprites_pushback.value;
-                               R_LightPoint(ent->modellight_ambient, org, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT);
-                       }
-                       else
-                               R_CompleteLightPoint(ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal, org, LP_LIGHTMAP);
+                               vec3_t org;
+                               Matrix4x4_OriginFromMatrix(&ent->matrix, org);
 
-                       if(ent->flags & RENDER_EQUALIZE)
-                       {
-                               // first fix up ambient lighting...
-                               if(r_equalize_entities_minambient.value > 0)
+                               // complete lightning for lit sprites
+                               // todo: make a EF_ field so small ents could be lit purely by modellight and skipping real rtlight pass (like EF_NORTLIGHT)?
+                               if (ent->model->type == mod_sprite && !(ent->model->data_textures[0].basematerialflags & MATERIALFLAG_FULLBRIGHT))
                                {
-                                       fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2];
-                                       if(fd > 0)
+                                       if (ent->model->sprite.sprnum_type == SPR_OVERHEAD) // apply offset for overhead sprites
+                                               org[2] = org[2] + r_overheadsprites_pushback.value;
+                                       R_LightPoint(ent->modellight_ambient, org, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT);
+                               }
+                               else
+                                       R_CompleteLightPoint(ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal, org, LP_LIGHTMAP);
+
+                               if(ent->flags & RENDER_EQUALIZE)
+                               {
+                                       // first fix up ambient lighting...
+                                       if(r_equalize_entities_minambient.value > 0)
                                        {
-                                               fa = (0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2]);
-                                               if(fa < r_equalize_entities_minambient.value * fd)
+                                               fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2];
+                                               if(fd > 0)
                                                {
-                                                       // solve:
-                                                       //   fa'/fd' = minambient
-                                                       //   fa'+0.25*fd' = fa+0.25*fd
-                                                       //   ...
-                                                       //   fa' = fd' * minambient
-                                                       //   fd'*(0.25+minambient) = fa+0.25*fd
-                                                       //   ...
-                                                       //   fd' = (fa+0.25*fd) * 1 / (0.25+minambient)
-                                                       //   fa' = (fa+0.25*fd) * minambient / (0.25+minambient)
-                                                       //   ...
-                                                       fdd = (fa + 0.25f * fd) / (0.25f + r_equalize_entities_minambient.value);
-                                                       f = fdd / fd; // f>0 because all this is additive; f<1 because fdd<fd because this follows from fa < r_equalize_entities_minambient.value * fd
-                                                       VectorMA(ent->modellight_ambient, (1-f)*0.25f, ent->modellight_diffuse, ent->modellight_ambient);
-                                                       VectorScale(ent->modellight_diffuse, f, ent->modellight_diffuse);
+                                                       fa = (0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2]);
+                                                       if(fa < r_equalize_entities_minambient.value * fd)
+                                                       {
+                                                               // solve:
+                                                               //   fa'/fd' = minambient
+                                                               //   fa'+0.25*fd' = fa+0.25*fd
+                                                               //   ...
+                                                               //   fa' = fd' * minambient
+                                                               //   fd'*(0.25+minambient) = fa+0.25*fd
+                                                               //   ...
+                                                               //   fd' = (fa+0.25*fd) * 1 / (0.25+minambient)
+                                                               //   fa' = (fa+0.25*fd) * minambient / (0.25+minambient)
+                                                               //   ...
+                                                               fdd = (fa + 0.25f * fd) / (0.25f + r_equalize_entities_minambient.value);
+                                                               f = fdd / fd; // f>0 because all this is additive; f<1 because fdd<fd because this follows from fa < r_equalize_entities_minambient.value * fd
+                                                               VectorMA(ent->modellight_ambient, (1-f)*0.25f, ent->modellight_diffuse, ent->modellight_ambient);
+                                                               VectorScale(ent->modellight_diffuse, f, ent->modellight_diffuse);
+                                                       }
                                                }
                                        }
-                               }
 
-                               if(r_equalize_entities_to.value > 0 && r_equalize_entities_by.value != 0)
-                               {
-                                       fa = 0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2];
-                                       fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2];
-                                       f = fa + 0.25 * fd;
-                                       if(f > 0)
+                                       if(r_equalize_entities_to.value > 0 && r_equalize_entities_by.value != 0)
                                        {
-                                               // adjust brightness and saturation to target
-                                               avg[0] = avg[1] = avg[2] = fa / f;
-                                               VectorLerp(ent->modellight_ambient, r_equalize_entities_by.value, avg, ent->modellight_ambient);
-                                               avg[0] = avg[1] = avg[2] = fd / f;
-                                               VectorLerp(ent->modellight_diffuse, r_equalize_entities_by.value, avg, ent->modellight_diffuse);
+                                               fa = 0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2];
+                                               fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2];
+                                               f = fa + 0.25 * fd;
+                                               if(f > 0)
+                                               {
+                                                       // adjust brightness and saturation to target
+                                                       avg[0] = avg[1] = avg[2] = fa / f;
+                                                       VectorLerp(ent->modellight_ambient, r_equalize_entities_by.value, avg, ent->modellight_ambient);
+                                                       avg[0] = avg[1] = avg[2] = fd / f;
+                                                       VectorLerp(ent->modellight_diffuse, r_equalize_entities_by.value, avg, ent->modellight_diffuse);
+                                               }
                                        }
                                }
                        }
+                       else // highly rare
+                               VectorSet(ent->modellight_ambient, 1, 1, 1);
                }
-               else // highly rare
-                       VectorSet(ent->modellight_ambient, 1, 1, 1);
 
                // move the light direction into modelspace coordinates for lighting code
                Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir);
@@ -5277,7 +5293,6 @@ static void R_View_UpdateWithScissor(const int *myscissor)
        R_View_WorldVisibility(r_refdef.view.useclipplane);
        R_View_UpdateEntityVisible();
        R_View_UpdateEntityLighting();
-       R_AnimCache_CacheVisibleEntities();
 }
 
 static void R_View_Update(void)
@@ -5287,7 +5302,6 @@ static void R_View_Update(void)
        R_View_WorldVisibility(r_refdef.view.useclipplane);
        R_View_UpdateEntityVisible();
        R_View_UpdateEntityLighting();
-       R_AnimCache_CacheVisibleEntities();
 }
 
 float viewscalefpsadjusted = 1.0f;
@@ -5477,7 +5491,7 @@ void R_ResetViewRendering3D(int fbo, rtexture_t *depthtexture, rtexture_t *color
 R_RenderView_UpdateViewVectors
 ================
 */
-static void R_RenderView_UpdateViewVectors(void)
+void R_RenderView_UpdateViewVectors(void)
 {
        // break apart the view matrix into vectors for various purposes
        // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
@@ -5831,6 +5845,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
                                R_View_UpdateWithScissor(myscissor);
                        else
                                R_View_Update();
+                       R_AnimCache_CacheVisibleEntities();
                        if(r_water_scissormode.integer & 1)
                                GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
                        R_RenderScene(p->fbo_reflection, r_fb.water.depthtexture, p->texture_reflection);
@@ -5879,6 +5894,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
                                R_View_UpdateWithScissor(myscissor);
                        else
                                R_View_Update();
+                       R_AnimCache_CacheVisibleEntities();
                        if(r_water_scissormode.integer & 1)
                                GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
                        R_RenderScene(p->fbo_refraction, r_fb.water.depthtexture, p->texture_refraction);
@@ -5933,6 +5949,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
                        R_ResetViewRendering3D(p->fbo_camera, r_fb.water.depthtexture, p->texture_camera);
                        R_ClearScreen(r_refdef.fogenabled);
                        R_View_Update();
+                       R_AnimCache_CacheVisibleEntities();
                        R_RenderScene(p->fbo_camera, r_fb.water.depthtexture, p->texture_camera);
 
                        if (!p->fbo_camera)
@@ -5948,6 +5965,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
        if (!r_fb.water.depthtexture)
                R_ClearScreen(r_refdef.fogenabled);
        R_View_Update();
+       R_AnimCache_CacheVisibleEntities();
        goto finish;
 error:
        r_refdef.view = originalview;
@@ -6041,7 +6059,7 @@ static void R_Bloom_StartFrame(void)
 
        // set bloomwidth and bloomheight to the bloom resolution that will be
        // used (often less than the screen resolution for faster rendering)
-       r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.height);
+       r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
        r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
        r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
        r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
@@ -6147,7 +6165,7 @@ static void R_Bloom_StartFrame(void)
        }
 
        // bloom texture is a different resolution
-       r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.height);
+       r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
        r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
        r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
        r_fb.bloomwidth = bound(1, r_fb.bloomwidth, r_fb.bloomtexturewidth);
@@ -6164,6 +6182,14 @@ static void R_Bloom_StartFrame(void)
        r_fb.screentexcoord2f[6] = 0;
        r_fb.screentexcoord2f[7] = 0;
 
+       if(r_fb.fbo) 
+       {
+               for (i = 1;i < 8;i += 2)
+               {
+                       r_fb.screentexcoord2f[i] += 1 - (float)(viewheight + r_refdef.view.y) / (float)r_fb.screentextureheight;
+               }
+       }
+
        // set up a texcoord array for the reduced resolution bloom image
        // (which will be additive blended over the screen image)
        r_fb.bloomtexcoord2f[0] = 0;
@@ -6187,20 +6213,17 @@ static void R_Bloom_StartFrame(void)
        case RENDERPATH_D3D9:
        case RENDERPATH_D3D10:
        case RENDERPATH_D3D11:
+               for (i = 0;i < 4;i++)
                {
-                       int i;
-                       for (i = 0;i < 4;i++)
-                       {
-                               r_fb.screentexcoord2f[i*2+0] += 0.5f / (float)r_fb.screentexturewidth;
-                               r_fb.screentexcoord2f[i*2+1] += 0.5f / (float)r_fb.screentextureheight;
-                               r_fb.bloomtexcoord2f[i*2+0] += 0.5f / (float)r_fb.bloomtexturewidth;
-                               r_fb.bloomtexcoord2f[i*2+1] += 0.5f / (float)r_fb.bloomtextureheight;
-                       }
+                       r_fb.screentexcoord2f[i*2+0] += 0.5f / (float)r_fb.screentexturewidth;
+                       r_fb.screentexcoord2f[i*2+1] += 0.5f / (float)r_fb.screentextureheight;
+                       r_fb.bloomtexcoord2f[i*2+0] += 0.5f / (float)r_fb.bloomtexturewidth;
+                       r_fb.bloomtexcoord2f[i*2+1] += 0.5f / (float)r_fb.bloomtextureheight;
                }
                break;
        }
 
-       R_Viewport_InitOrtho(&r_fb.bloomviewport, &identitymatrix, r_refdef.view.x, (r_fb.bloomfbo[0] ? r_fb.bloomtextureheight : vid.height) - r_fb.bloomheight - r_refdef.view.y, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
+       R_Viewport_InitOrtho(&r_fb.bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
 
        if (r_fb.fbo)
                r_refdef.view.clear = true;
@@ -6214,18 +6237,22 @@ static void R_Bloom_MakeTexture(void)
        float colorscale = r_bloom_colorscale.value;
 
        r_refdef.stats.bloom++;
-
+    
+#if 0
+    // this copy is unnecessary since it happens in R_BlendView already
        if (!r_fb.fbo)
        {
                R_Mesh_CopyToTexture(r_fb.colortexture, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
                r_refdef.stats.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
        }
+#endif
 
        // scale down screen texture to the bloom texture size
        CHECKGLERROR
        r_fb.bloomindex = 0;
        R_Mesh_SetRenderTargets(r_fb.bloomfbo[r_fb.bloomindex], NULL, r_fb.bloomtexture[r_fb.bloomindex], NULL, NULL, NULL);
        R_SetViewport(&r_fb.bloomviewport);
+       GL_DepthTest(false);
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_Color(colorscale, colorscale, colorscale, 1);
        // D3D has upside down Y coords, the easiest way to flip this is to flip the screen vertices rather than the texcoords, so we just use a different array for that...
@@ -6265,9 +6292,19 @@ static void R_Bloom_MakeTexture(void)
                r_fb.bloomindex ^= 1;
                R_Mesh_SetRenderTargets(r_fb.bloomfbo[r_fb.bloomindex], NULL, r_fb.bloomtexture[r_fb.bloomindex], NULL, NULL, NULL);
                x *= 2;
-               r = bound(0, r_bloom_colorexponent.value / x, 1);
-               GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
-               GL_Color(r,r,r,1);
+               r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
+               if (!r_fb.bloomfbo[r_fb.bloomindex])
+               {
+                       GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); // square it and multiply by two
+                       GL_Color(r,r,r,1); // apply fix factor
+               }
+               else
+               {
+                       if(x <= 2)
+                               GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
+                       GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
+                       GL_Color(1,1,1,1); // no fix factor supported here
+               }
                R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.bloomtexcoord2f);
                R_SetupShader_Generic(intex, NULL, GL_MODULATE, 1, false, true, false);
                R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
@@ -6304,14 +6341,14 @@ static void R_Bloom_MakeTexture(void)
                        xoffset /= (float)r_fb.bloomtexturewidth;
                        yoffset /= (float)r_fb.bloomtextureheight;
                        // compute a texcoord array with the specified x and y offset
-                       r_fb.offsettexcoord2f[0] = xoffset+0;
-                       r_fb.offsettexcoord2f[1] = yoffset+(float)r_fb.bloomheight / (float)r_fb.bloomtextureheight;
-                       r_fb.offsettexcoord2f[2] = xoffset+(float)r_fb.bloomwidth / (float)r_fb.bloomtexturewidth;
-                       r_fb.offsettexcoord2f[3] = yoffset+(float)r_fb.bloomheight / (float)r_fb.bloomtextureheight;
-                       r_fb.offsettexcoord2f[4] = xoffset+(float)r_fb.bloomwidth / (float)r_fb.bloomtexturewidth;
-                       r_fb.offsettexcoord2f[5] = yoffset+0;
-                       r_fb.offsettexcoord2f[6] = xoffset+0;
-                       r_fb.offsettexcoord2f[7] = yoffset+0;
+                       r_fb.offsettexcoord2f[0] = xoffset+r_fb.bloomtexcoord2f[0];
+                       r_fb.offsettexcoord2f[1] = yoffset+r_fb.bloomtexcoord2f[1];
+                       r_fb.offsettexcoord2f[2] = xoffset+r_fb.bloomtexcoord2f[2];
+                       r_fb.offsettexcoord2f[3] = yoffset+r_fb.bloomtexcoord2f[3];
+                       r_fb.offsettexcoord2f[4] = xoffset+r_fb.bloomtexcoord2f[4];
+                       r_fb.offsettexcoord2f[5] = yoffset+r_fb.bloomtexcoord2f[5];
+                       r_fb.offsettexcoord2f[6] = xoffset+r_fb.bloomtexcoord2f[6];
+                       r_fb.offsettexcoord2f[7] = yoffset+r_fb.bloomtexcoord2f[7];
                        // this r value looks like a 'dot' particle, fading sharply to
                        // black at the edges
                        // (probably not realistic but looks good enough)
@@ -6678,6 +6715,10 @@ void R_UpdateVariables(void)
        {
                r_refdef.lightmapintensity *= r_fakelight_intensity.value;
        }
+       else if (r_refdef.scene.worldmodel)
+       {
+               r_refdef.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
+       }
        if (r_showsurfaces.integer)
        {
                r_refdef.scene.rtworld = false;
@@ -6867,6 +6908,11 @@ void R_RenderView(void)
 
        r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
 
+       if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
+               // in sRGB fallback, behave similar to true sRGB: convert this
+               // value from linear to sRGB
+               r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
+
        R_RenderView_UpdateViewVectors();
 
        R_Shadow_UpdateWorldLightSelection();
@@ -6899,6 +6945,10 @@ void R_RenderView(void)
        if (r_timereport_active)
                R_TimeReport("visibility");
 
+       R_AnimCache_CacheVisibleEntities();
+       if (r_timereport_active)
+               R_TimeReport("animcache");
+
        R_Shadow_UpdateBounceGridTexture();
        if (r_timereport_active && r_shadow_bouncegrid.integer)
                R_TimeReport("bouncegrid");
@@ -7267,6 +7317,7 @@ static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtligh
                        case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
                        case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
                        case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
+                       case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
                        default:             Vector4Set(color, 0, 0, 0, 0.50);break;
                }
                color[3] *= r_showbboxes.value;
@@ -7299,7 +7350,7 @@ static void R_DrawEntityBBoxes(void)
                if(PRVM_serveredictedict(edict, viewmodelforclient) != 0)
                        continue;
                VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
-               R_MeshQueue_AddTransparent(center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)NULL);
+               R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)NULL);
        }
 }
 
@@ -7407,7 +7458,7 @@ void R_DrawNoModel(entity_render_t *ent)
        vec3_t org;
        Matrix4x4_OriginFromMatrix(&ent->matrix, org);
        if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
-               R_MeshQueue_AddTransparent(ent->flags & RENDER_NODEPTHTEST ? r_refdef.view.origin : org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
+               R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? MESHQUEUE_SORT_HUD : MESHQUEUE_SORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
        else
                R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
 }
@@ -7718,7 +7769,7 @@ texture_t *R_GetCurrentTexture(texture_t *t)
        dp_model_t *model = ent->model;
        q3shaderinfo_layer_tcmod_t *tcmod;
 
-       if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent)
+       if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
                return t->currentframe;
        t->update_lastrenderframe = r_textureframe;
        t->update_lastrenderentity = (void *)ent;
@@ -7791,7 +7842,7 @@ texture_t *R_GetCurrentTexture(texture_t *t)
        {
                // no modellight if using fakelight for the map
        }
-       else if (rsurface.modeltexcoordlightmap2f == NULL && !(t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
+       else if ((rsurface.modeltexcoordlightmap2f == NULL || (rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT))) && !(t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
        {
                // pick a model lighting mode
                if (VectorLength2(rsurface.modellight_diffuse) >= (1.0f / 256.0f))
@@ -7867,6 +7918,11 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
                if (!t->backgroundnmaptexture)
                        t->backgroundnmaptexture = r_texture_blanknormalmap;
+               // make sure that if glow is going to be used, both textures are not NULL
+               if (!t->backgroundglowtexture && t->glowtexture)
+                       t->backgroundglowtexture = r_texture_black;
+               if (!t->glowtexture && t->backgroundglowtexture)
+                       t->glowtexture = r_texture_black;
        }
        else
        {
@@ -8128,6 +8184,7 @@ void RSurf_ActiveWorldEntity(void)
        rsurface.passcolor4f = NULL;
        rsurface.passcolor4f_vertexbuffer = NULL;
        rsurface.passcolor4f_bufferoffset = 0;
+       rsurface.forcecurrenttextureupdate = false;
 }
 
 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
@@ -8301,6 +8358,7 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
        rsurface.passcolor4f = NULL;
        rsurface.passcolor4f_vertexbuffer = NULL;
        rsurface.passcolor4f_bufferoffset = 0;
+       rsurface.forcecurrenttextureupdate = false;
 }
 
 void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qboolean wantnormals, qboolean wanttangents)
@@ -8424,6 +8482,7 @@ void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inve
        rsurface.passcolor4f = NULL;
        rsurface.passcolor4f_vertexbuffer = NULL;
        rsurface.passcolor4f_bufferoffset = 0;
+       rsurface.forcecurrenttextureupdate = true;
 
        if (rsurface.modelnumvertices && rsurface.modelelement3i)
        {
@@ -10405,7 +10464,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
 
-static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, const entity_render_t *queueentity)
+static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
 {
        // transparent surfaces get pushed off into the transparent queue
        int surfacelistindex;
@@ -10414,17 +10473,26 @@ static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const
        for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
        {
                surface = texturesurfacelist[surfacelistindex];
-               tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
-               tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
-               tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
+               if (r_transparent_sortsurfacesbynearest.integer)
+               {
+                       tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
+                       tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
+                       tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
+               }
+               else
+               {
+                       tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
+                       tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
+                       tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
+               }
                Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
-               if (queueentity->transparent_offset) // transparent offset
+               if (rsurface.entity->transparent_offset) // transparent offset
                {
-                       center[0] += r_refdef.view.forward[0]*queueentity->transparent_offset;
-                       center[1] += r_refdef.view.forward[1]*queueentity->transparent_offset;
-                       center[2] += r_refdef.view.forward[2]*queueentity->transparent_offset;
+                       center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
+                       center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
+                       center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
                }
-               R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_DrawSurface_TransparentCallback, queueentity, surface - rsurface.modelsurfaces, rsurface.rtlight);
+               R_MeshQueue_AddTransparent((rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) ? MESHQUEUE_SORT_HUD : ((rsurface.entity->flags & RENDER_WORLDOBJECT) ? MESHQUEUE_SORT_SKY : MESHQUEUE_SORT_DISTANCE), center, R_DrawSurface_TransparentCallback, rsurface.entity, surface - rsurface.modelsurfaces, rsurface.rtlight);
        }
 }
 
@@ -10445,7 +10513,6 @@ static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msu
 
 static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
 {
-       const entity_render_t *queueentity = r_refdef.scene.worldentity;
        CHECKGLERROR
        if (depthonly)
                R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
@@ -10454,7 +10521,7 @@ static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurf
                if (!rsurface.texture->currentnumlayers)
                        return;
                if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
-                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity);
+                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
                else
                        R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
        }
@@ -10462,11 +10529,11 @@ static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurf
                R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
        else if (!rsurface.texture->currentnumlayers)
                return;
-       else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))) && queueentity)
+       else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
        {
                // in the deferred case, transparent surfaces were queued during prepass
                if (!r_shadow_usingdeferredprepass)
-                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity);
+                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
        }
        else
        {
@@ -10522,7 +10589,7 @@ static void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacel
        R_FrameData_ReturnToMark();
 }
 
-static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity, qboolean prepass)
+static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
 {
        CHECKGLERROR
        if (depthonly)
@@ -10532,7 +10599,7 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf
                if (!rsurface.texture->currentnumlayers)
                        return;
                if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
-                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity);
+                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
                else
                        R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
        }
@@ -10540,11 +10607,11 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf
                R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
        else if (!rsurface.texture->currentnumlayers)
                return;
-       else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))) && queueentity)
+       else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
        {
                // in the deferred case, transparent surfaces were queued during prepass
                if (!r_shadow_usingdeferredprepass)
-                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity);
+                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
        }
        else
        {
@@ -10595,7 +10662,7 @@ static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const
                                ;
                }
                // render the range of surfaces
-               R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent, prepass);
+               R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
        }
        R_FrameData_ReturnToMark();
 }
@@ -10672,7 +10739,7 @@ void R_DrawLocs(void)
        for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
        {
                VectorLerp(loc->mins, 0.5f, loc->maxs, center);
-               R_MeshQueue_AddTransparent(center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
+               R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
        }
 }