]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
Overhauled shadowmap rendering to use an atlas texture, this is overall a speed loss...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 11 Sep 2016 23:05:08 +0000 (23:05 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 11 Sep 2016 23:05:08 +0000 (23:05 +0000)
On video drivers with higher framebuffer switching costs, this should be a framerate gain in all situations.

Feature-wise this brings support (in future) for shadowmapping on transparent lit surfaces, and imposes an upper bound on how many pixels of shadowmaps will be rendered in a frame (shadowmap resolution automatically becomes more coarse on frames where they do not fit).

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@12281 d7cf8633-e32d-0410-b094-e92efae38249

13 files changed:
client.h
gl_backend.c
gl_backend.h
gl_rmain.c
gl_rsurf.c
model_brush.c
model_shared.c
model_shared.h
r_shadow.c
r_shadow.h
render.h
shader_glsl.h
shader_hlsl.h

index 4b6e5660355086a153db3b68cc7b5c000f4cd912..4230c6a82d27819abfee3aa1b0497b4b83330df9 100644 (file)
--- a/client.h
+++ b/client.h
@@ -286,7 +286,7 @@ typedef struct rtlight_s
        char cubemapname[64];
        /// light style to monitor for brightness
        int style;
-       /// whether light should render shadows
+       /// whether light should render shadows (see castshadows for whether it actually does this frame)
        int shadow;
        /// intensity of corona to render
        vec_t corona;
@@ -323,6 +323,8 @@ typedef struct rtlight_s
        rtexture_t *currentcubemap;
        /// set by R_Shadow_PrepareLight to decide whether R_Shadow_DrawLight should draw it
        qboolean draw;
+       /// set by R_Shadow_PrepareLight to indicate whether R_Shadow_DrawShadowMaps should do anything
+       qboolean castshadows;
        /// these fields are set by R_Shadow_PrepareLight for later drawing
        int cached_numlightentities;
        int cached_numlightentities_noselfshadow;
@@ -352,6 +354,12 @@ typedef struct rtlight_s
        int compiled;
        /// the shadowing mode used to compile this light
        int shadowmode;
+       /// the size that this light should have (assuming no scene LOD kicking in to reduce it)
+       int shadowmapsidesize;
+       /// position of this light in the shadowmap atlas
+       int shadowmapatlasposition[2];
+       /// size of one side of this light in the shadowmap atlas (for omnidirectional shadowmaps this is the min corner of a 2x3 arrangement, or a 4x3 arrangement in the case of noselfshadow entities being present)
+       int shadowmapatlassidesize;
        /// premade shadow volumes to render for world entity
        shadowmesh_t *static_meshchain_shadow_zpass;
        shadowmesh_t *static_meshchain_shadow_zfail;
index 450d194f2d03d02090c0b3db1731362fdfbabf1b..61e5291e748b104f4aac39ee45ad47316062f8fd 100644 (file)
@@ -1106,15 +1106,15 @@ void R_Viewport_InitCubeSideView(r_viewport_t *v, const matrix4x4_t *cameramatri
        Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
 }
 
-void R_Viewport_InitRectSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, int border, float nearclip, float farclip, const float *nearplane)
+void R_Viewport_InitRectSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, int border, float nearclip, float farclip, const float *nearplane, int offsetx, int offsety)
 {
        matrix4x4_t tempmatrix, basematrix;
        float m[16];
        memset(v, 0, sizeof(*v));
        v->type = R_VIEWPORTTYPE_PERSPECTIVECUBESIDE;
        v->cameramatrix = *cameramatrix;
-       v->x = (side & 1) * size;
-       v->y = (side >> 1) * size;
+       v->x = offsetx + (side & 1) * size;
+       v->y = offsety + (side >> 1) * size;
        v->width = size;
        v->height = size;
        v->depth = 1;
index 04d23db1d884ce3c96755526f0108b2224ada2d4..b770d68700923c7473c8c9a2aac4b68131c6e52b 100644 (file)
@@ -28,7 +28,7 @@ void R_Viewport_InitOrtho(r_viewport_t *v, const matrix4x4_t *cameramatrix, int
 void R_Viewport_InitPerspective(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float zNear, float zFar, const float *nearplane);
 void R_Viewport_InitPerspectiveInfinite(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float zNear, const float *nearplane);
 void R_Viewport_InitCubeSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, float nearclip, float farclip, const float *nearplane);
-void R_Viewport_InitRectSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, int border, float nearclip, float farclip, const float *nearplane);
+void R_Viewport_InitRectSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, int border, float nearclip, float farclip, const float *nearplane, int offsetx, int offsety);
 void R_SetViewport(const r_viewport_t *v);
 void R_GetViewport(r_viewport_t *v);
 void GL_Finish(void);
index b0c146c0b07d3fd95ccf79c4561832029c1f351b..b57df7c1863269fa9c5b9a64d10de753465c59ee 100644 (file)
@@ -2136,8 +2136,10 @@ extern rtexture_t *r_shadow_attenuation2dtexture;
 extern rtexture_t *r_shadow_attenuation3dtexture;
 extern qboolean r_shadow_usingshadowmap2d;
 extern qboolean r_shadow_usingshadowmaportho;
-extern float r_shadow_shadowmap_texturescale[2];
-extern float r_shadow_shadowmap_parameters[4];
+extern float r_shadow_modelshadowmap_texturescale[4];
+extern float r_shadow_modelshadowmap_parameters[4];
+extern float r_shadow_lightshadowmap_texturescale[4];
+extern float r_shadow_lightshadowmap_parameters[4];
 extern qboolean r_shadow_shadowmapvsdct;
 extern rtexture_t *r_shadow_shadowmap2ddepthbuffer;
 extern rtexture_t *r_shadow_shadowmap2ddepthtexture;
@@ -2673,8 +2675,16 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        if (mode == SHADERMODE_WATER)
                                hlslPSSetParameter2f(D3DPSREGISTER_NormalmapScrollBlend, rsurface.texture->r_water_waterscroll[0], rsurface.texture->r_water_waterscroll[1]);
                }
-               hlslPSSetParameter2f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
-               hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+               if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
+               {
+                       hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
+                       hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
+               }
+               else
+               {
+                       hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+                       hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
+               }
                hlslPSSetParameter3f(D3DPSREGISTER_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]);
                hlslPSSetParameter1f(D3DPSREGISTER_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1));
                hlslPSSetParameter3f(D3DPSREGISTER_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
@@ -2836,8 +2846,16 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
                if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
                if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
-               if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
-               if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+               if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
+               {
+                       if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
+                       if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
+               }
+               else
+               {
+                       if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+                       if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
+               }
 
                if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]);
                if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1));
@@ -2982,8 +3000,16 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_TexMatrixM1, 1, false, m16f);}
                {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_BackgroundTexMatrixM1, 1, false, m16f);}
                {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ShadowMapMatrixM1, 1, false, m16f);}
-               DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
-               DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+               if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
+               {
+                       DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
+                       DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
+               }
+               else
+               {
+                       DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+                       DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
+               }
 
                DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]);
                DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1));
@@ -3111,8 +3137,8 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
                hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Ambient , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
                hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
                hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Specular, lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
-               hlslPSSetParameter2f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
-               hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+               hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+               hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
                hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
                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);
@@ -3138,8 +3164,8 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
                if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
                if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
                if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
-               if (r_glsl_permutation->loc_ShadowMap_TextureScale    >= 0) qglUniform2f(       r_glsl_permutation->loc_ShadowMap_TextureScale   , r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
-               if (r_glsl_permutation->loc_ShadowMap_Parameters      >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_Parameters     , r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+               if (r_glsl_permutation->loc_ShadowMap_TextureScale    >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_TextureScale   , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+               if (r_glsl_permutation->loc_ShadowMap_Parameters      >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_Parameters     , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
                if (r_glsl_permutation->loc_SpecularPower             >= 0) qglUniform1f(       r_glsl_permutation->loc_SpecularPower            , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
                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);
@@ -3161,8 +3187,8 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
                DPSOFTRAST_Uniform3f(       DPSOFTRAST_UNIFORM_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
                DPSOFTRAST_Uniform3f(       DPSOFTRAST_UNIFORM_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
                DPSOFTRAST_Uniform3f(       DPSOFTRAST_UNIFORM_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
-               DPSOFTRAST_Uniform2f(       DPSOFTRAST_UNIFORM_ShadowMap_TextureScale   , r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
-               DPSOFTRAST_Uniform4f(       DPSOFTRAST_UNIFORM_ShadowMap_Parameters     , r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+               DPSOFTRAST_Uniform4f(       DPSOFTRAST_UNIFORM_ShadowMap_TextureScale   , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+               DPSOFTRAST_Uniform4f(       DPSOFTRAST_UNIFORM_ShadowMap_Parameters     , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
                DPSOFTRAST_Uniform1f(       DPSOFTRAST_UNIFORM_SpecularPower            , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
                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);
@@ -7371,6 +7397,7 @@ static void R_DrawEntityBBoxes(void);
 static void R_DrawModelDecals(void);
 extern cvar_t cl_decals_newsystem;
 extern qboolean r_shadow_usingdeferredprepass;
+extern int r_shadow_shadowmapatlas_modelshadows_size;
 void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
        qboolean shadowmapping = false;
@@ -7422,18 +7449,25 @@ void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
                }
        }
 
+       R_Shadow_PrepareModelShadows();
        R_Shadow_PrepareLights(fbo, depthtexture, colortexture);
-       if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
-               R_Shadow_PrepareModelShadows();
        if (r_timereport_active)
                R_TimeReport("preparelights");
 
-       if (R_Shadow_ShadowMappingEnabled())
-               shadowmapping = true;
+       // render all the shadowmaps that will be used for this view
+       shadowmapping = R_Shadow_ShadowMappingEnabled();
+       if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
+       {
+               R_Shadow_DrawShadowMaps();
+               if (r_timereport_active)
+                       R_TimeReport("shadowmaps");
+       }
 
+       // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
        if (r_shadow_usingdeferredprepass)
                R_Shadow_DrawPrepass();
 
+       // now we begin the forward pass of the view render
        if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
        {
                r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
@@ -7447,16 +7481,6 @@ void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
                        R_TimeReport("modeldepth");
        }
 
-       if (r_shadows.integer >= 2 && shadowmapping && r_refdef.lightmapintensity > 0)
-       {
-               R_ResetViewRendering3D(fbo, depthtexture, colortexture);
-               R_DrawModelShadowMaps(fbo, depthtexture, colortexture);
-               R_ResetViewRendering3D(fbo, depthtexture, colortexture);
-               // don't let sound skip if going slow
-               if (r_refdef.scene.extraupdate)
-                       S_ExtraUpdate ();
-       }
-
        if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
        {
                r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
@@ -7479,7 +7503,7 @@ void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
        if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && !r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
        {
                R_ResetViewRendering3D(fbo, depthtexture, colortexture);
-               R_DrawModelShadows(fbo, depthtexture, colortexture);
+               R_Shadow_DrawModelShadows();
                R_ResetViewRendering3D(fbo, depthtexture, colortexture);
                // don't let sound skip if going slow
                if (r_refdef.scene.extraupdate)
@@ -7500,7 +7524,7 @@ void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
        if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
        {
                R_ResetViewRendering3D(fbo, depthtexture, colortexture);
-               R_DrawModelShadows(fbo, depthtexture, colortexture);
+               R_Shadow_DrawModelShadows();
                R_ResetViewRendering3D(fbo, depthtexture, colortexture);
                // don't let sound skip if going slow
                if (r_refdef.scene.extraupdate)
index d589cfcb1b726f3f83304063c83b4267411b8628..c86bf2f60ad223167fb1c30ea3a8dd3a836c52b7 100644 (file)
@@ -1449,7 +1449,7 @@ static void R_Q1BSP_DrawLight_TransparentCallback(const entity_render_t *ent, co
        // note: in practice this never actually receives batches
        R_Shadow_RenderMode_Begin();
        R_Shadow_RenderMode_ActiveLight(rtlight);
-       R_Shadow_RenderMode_Lighting(false, true, false);
+       R_Shadow_RenderMode_Lighting(false, true, false, (ent->flags & RENDER_NOSELFSHADOW) != 0);
        R_Shadow_SetupEntityLight(ent);
        for (i = 0;i < numsurfaces;i = j)
        {
index 842be1ae26580842924775a2e0fdaa6fe1ede100..ac24a2d7c6d3d6f47211578588b4ab73270b9977 100644 (file)
@@ -2685,7 +2685,7 @@ static void Mod_Q1BSP_LoadFaces(sizebuf_t *sb)
                int stainmapsize = 0;
                mod_alloclightmap_state_t allocState;
 
-               Mod_AllocLightmap_Init(&allocState, lightmapsize, lightmapsize);
+               Mod_AllocLightmap_Init(&allocState, loadmodel->mempool, lightmapsize, lightmapsize);
                for (surfacenum = 0, surface = loadmodel->data_surfaces;surfacenum < count;surfacenum++, surface++)
                {
                        int iu, iv, lightmapx = 0, lightmapy = 0;
index 14186218393bdd593c50cb2f8e7a6b34776aa9bb..67471410864d998def6b59354e358c82ab9bbc03 100644 (file)
@@ -3492,14 +3492,14 @@ static void Mod_Decompile_f(void)
        }
 }
 
-void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, int width, int height)
+void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, mempool_t *mempool, int width, int height)
 {
        int y;
        memset(state, 0, sizeof(*state));
        state->width = width;
        state->height = height;
        state->currentY = 0;
-       state->rows = (mod_alloclightmap_row_t *)Mem_Alloc(loadmodel->mempool, state->height * sizeof(*state->rows));
+       state->rows = (mod_alloclightmap_row_t *)Mem_Alloc(mempool, state->height * sizeof(*state->rows));
        for (y = 0;y < state->height;y++)
        {
                state->rows[y].currentX = 0;
@@ -4202,7 +4202,7 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
        lm_borderpixels = mod_generatelightmaps_borderpixels.integer;
        lm_texturesize = bound(lm_borderpixels*2+1, 64, (int)vid.maxtexturesize_2d);
        //lm_maxpixels = lm_texturesize-(lm_borderpixels*2+1);
-       Mod_AllocLightmap_Init(&lmstate, lm_texturesize, lm_texturesize);
+       Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize);
        lightmapnumber = 0;
        for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
        {
@@ -4250,7 +4250,7 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
                                surfaceindex = -1;
                                lightmapnumber = 0;
                                Mod_AllocLightmap_Free(&lmstate);
-                               Mod_AllocLightmap_Init(&lmstate, lm_texturesize, lm_texturesize);
+                               Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize);
                                break;
                        }
                        // if we have maxed out the lightmap size, and this triangle does
index 3fa07c791a4ad076ae21c75ae4789ca572a301e8..b687b1f0481b116884243cdc3fbb2cc66e1e36db 100644 (file)
@@ -1190,7 +1190,7 @@ typedef struct mod_alloclightmap_state_s
 }
 mod_alloclightmap_state_t;
 
-void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, int width, int height);
+void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, mempool_t *mempool, int width, int height);
 void Mod_AllocLightmap_Free(mod_alloclightmap_state_t *state);
 void Mod_AllocLightmap_Reset(mod_alloclightmap_state_t *state);
 qboolean Mod_AllocLightmap_Block(mod_alloclightmap_state_t *state, int blockwidth, int blockheight, int *outx, int *outy);
index 6e4d9a0c268c66a12f7cf73ce4d1e0a07874d683..202ca281736b812e6246287f022e103da9b7d624 100644 (file)
@@ -179,11 +179,16 @@ r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
+int r_shadow_scenemaxlights;
+int r_shadow_scenenumlights;
+rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
 qboolean r_shadow_usingshadowmap2d;
 qboolean r_shadow_usingshadowmaportho;
 int r_shadow_shadowmapside;
-float r_shadow_shadowmap_texturescale[2];
-float r_shadow_shadowmap_parameters[4];
+float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
+float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
+float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
+float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
 #if 0
 int r_shadow_drawbuffer;
 int r_shadow_readbuffer;
@@ -194,6 +199,7 @@ r_shadow_shadowmode_t r_shadow_shadowmode;
 int r_shadow_shadowmapfilterquality;
 int r_shadow_shadowmapdepthbits;
 int r_shadow_shadowmapmaxsize;
+int r_shadow_shadowmaptexturesize;
 qboolean r_shadow_shadowmapvsdct;
 qboolean r_shadow_shadowmapsampler;
 qboolean r_shadow_shadowmapshadowsampler;
@@ -203,6 +209,10 @@ matrix4x4_t r_shadow_shadowmapmatrix;
 int r_shadow_lightscissor[4];
 qboolean r_shadow_usingdeferredprepass;
 qboolean r_shadow_shadowmapdepthtexture;
+mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
+int r_shadow_shadowmapatlas_modelshadows_x;
+int r_shadow_shadowmapatlas_modelshadows_y;
+int r_shadow_shadowmapatlas_modelshadows_size;
 int maxshadowtriangles;
 int *shadowelements;
 
@@ -248,7 +258,6 @@ skinframe_t *r_shadow_lightcorona;
 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
 rtexture_t *r_shadow_shadowmap2ddepthtexture;
 rtexture_t *r_shadow_shadowmapvsdcttexture;
-int r_shadow_shadowmapsize; // changes for each light based on distance
 
 GLuint r_shadow_prepassgeometryfbo;
 GLuint r_shadow_prepasslightingdiffusespecularfbo;
@@ -310,8 +319,9 @@ cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmappin
 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
-cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
-cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
+cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "limit of shadowmap side size - must be at least r_shadow_shadowmapping_bordersize+2"};
+cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "limit of shadowmap side size - can not be more than 1/8th of atlassize because lights store 6 sides (2x3 grid) and sometimes 12 sides (4x3 grid for shadows from EF_NOSELFSHADOW entities) and there are multiple lights..."};
+cvar_t r_shadow_shadowmapping_texturesize = { CVAR_SAVE, "r_shadow_shadowmapping_texturesize", "4096", "size of shadowmap atlas texture - all shadowmaps are packed into this texture at frame start"};
 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
@@ -423,19 +433,23 @@ skinframe_t *r_editlights_sprcubemaplight;
 skinframe_t *r_editlights_sprcubemapnoshadowlight;
 skinframe_t *r_editlights_sprselection;
 
+static void R_Shadow_DrawModelShadowMaps(void);
+static void R_Shadow_MakeShadowMap(int texturesize);
+static void R_Shadow_MakeVSDCT(void);
 static void R_Shadow_SetShadowMode(void)
 {
-       r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
+       r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
+       r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
+       r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
        r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
        r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
        r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
        r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
-       r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
-       r_shadow_shadowmapsize = 0;
        r_shadow_shadowmapsampler = false;
        r_shadow_shadowmappcf = 0;
        r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
        r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
+       Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
        if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
        {
                switch(vid.renderpath)
@@ -512,6 +526,8 @@ qboolean R_Shadow_ShadowMappingEnabled(void)
 
 static void R_Shadow_FreeShadowMaps(void)
 {
+       Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
+
        R_Shadow_SetShadowMode();
 
        R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
@@ -544,7 +560,7 @@ static void r_shadow_start(void)
        r_shadow_shadowmap2ddepthbuffer = NULL;
        r_shadow_shadowmapvsdcttexture = NULL;
        r_shadow_shadowmapmaxsize = 0;
-       r_shadow_shadowmapsize = 0;
+       r_shadow_shadowmaptexturesize = 0;
        r_shadow_shadowmapfilterquality = -1;
        r_shadow_shadowmapdepthbits = 0;
        r_shadow_shadowmapvsdct = false;
@@ -558,6 +574,9 @@ static void r_shadow_start(void)
        r_shadow_filters_texturepool = NULL;
        R_Shadow_ValidateCvars();
        R_Shadow_MakeTextures();
+       r_shadow_scenemaxlights = 0;
+       r_shadow_scenenumlights = 0;
+       r_shadow_scenelightlist = NULL;
        maxshadowtriangles = 0;
        shadowelements = NULL;
        maxshadowvertices = 0;
@@ -629,6 +648,11 @@ static void r_shadow_shutdown(void)
        r_shadow_prepass_width = r_shadow_prepass_height = 0;
 
        CHECKGLERROR
+       r_shadow_scenemaxlights = 0;
+       r_shadow_scenenumlights = 0;
+       if (r_shadow_scenelightlist)
+               Mem_Free(r_shadow_scenelightlist);
+       r_shadow_scenelightlist = NULL;
        memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
        r_shadow_attenuationgradienttexture = NULL;
        r_shadow_attenuation2dtexture = NULL;
@@ -750,6 +774,7 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
+       Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
 //     Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
 //     Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
        Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
@@ -800,6 +825,9 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&gl_ext_stenciltwoside);
        R_Shadow_EditLights_Init();
        Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
+       r_shadow_scenemaxlights = 0;
+       r_shadow_scenenumlights = 0;
+       r_shadow_scenelightlist = NULL;
        maxshadowtriangles = 0;
        shadowelements = NULL;
        maxshadowvertices = 0;
@@ -2062,7 +2090,6 @@ void R_Shadow_RenderMode_Reset(void)
        GL_BlendFunc(GL_ONE, GL_ZERO);
        R_SetupShader_Generic_NoTexture(false, false);
        r_shadow_usingshadowmap2d = false;
-       r_shadow_usingshadowmaportho = false;
        R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
 }
 
@@ -2119,7 +2146,7 @@ static void R_Shadow_MakeVSDCT(void)
        r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
 }
 
-static void R_Shadow_MakeShadowMap(int side, int size)
+static void R_Shadow_MakeShadowMap(int texturesize)
 {
        switch (r_shadow_shadowmode)
        {
@@ -2127,14 +2154,14 @@ static void R_Shadow_MakeShadowMap(int side, int size)
                if (r_shadow_shadowmap2ddepthtexture) return;
                if (r_fb.usedepthtextures)
                {
-                       r_shadow_shadowmap2ddepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits >= 24 ? (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP24_COMP : TEXTYPE_SHADOWMAP24_RAW) : (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP16_COMP : TEXTYPE_SHADOWMAP16_RAW), r_shadow_shadowmapsampler);
+                       r_shadow_shadowmap2ddepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP24_COMP : TEXTYPE_SHADOWMAP24_RAW) : (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP16_COMP : TEXTYPE_SHADOWMAP16_RAW), r_shadow_shadowmapsampler);
                        r_shadow_shadowmap2ddepthbuffer = NULL;
                        r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
                }
                else
                {
-                       r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
-                       r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
+                       r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
+                       r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
                        r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
                }
                break;
@@ -2143,58 +2170,120 @@ static void R_Shadow_MakeShadowMap(int side, int size)
        }
 }
 
-static void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
+void R_Shadow_ClearShadowMapTexture(void)
 {
-       float nearclip, farclip, bias;
        r_viewport_t viewport;
-       int flipped;
-       GLuint fbo2d = 0;
        float clearcolor[4];
-       nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
-       farclip = 1.0f;
-       bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
-       r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
-       r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
-       r_shadow_shadowmapside = side;
-       r_shadow_shadowmapsize = size;
-
-       r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
-       r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
-       R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
-       if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
 
-       // complex unrolled cube approach (more flexible)
+       // if they don't exist, create our textures now
+       if (!r_shadow_shadowmap2ddepthtexture)
+               R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
        if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
                R_Shadow_MakeVSDCT();
-       if (!r_shadow_shadowmap2ddepthtexture)
-               R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
-       fbo2d = r_shadow_fbo2d;
-       r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
-       r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
+
+       // we're setting up to render shadowmaps, so change rendermode
        r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
 
        R_Mesh_ResetTextureState();
        R_Shadow_RenderMode_Reset();
        if (r_shadow_shadowmap2ddepthbuffer)
-               R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
+               R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
        else
-               R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
+               R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
        R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
        GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
        GL_DepthMask(true);
        GL_DepthTest(true);
 
-init_done:
+       // we have to set a viewport to clear anything in some renderpaths (D3D)
+       R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
        R_SetViewport(&viewport);
-       flipped = (side & 1) ^ (side >> 2);
-       r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
-       r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
+       GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
+       if (r_shadow_shadowmap2ddepthbuffer)
+               GL_ColorMask(1, 1, 1, 1);
+       else
+               GL_ColorMask(0, 0, 0, 0);
+       switch (vid.renderpath)
+       {
+       case RENDERPATH_GL11:
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL20:
+       case RENDERPATH_SOFT:
+       case RENDERPATH_GLES1:
+       case RENDERPATH_GLES2:
+               GL_CullFace(r_refdef.view.cullface_back);
+               break;
+       case RENDERPATH_D3D9:
+       case RENDERPATH_D3D10:
+       case RENDERPATH_D3D11:
+               // we invert the cull mode because we flip the projection matrix
+               // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
+               GL_CullFace(r_refdef.view.cullface_front);
+               break;
+       }
+       Vector4Set(clearcolor, 1, 1, 1, 1);
+       if (r_shadow_shadowmap2ddepthbuffer)
+               GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
+       else
+               GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
+}
+
+static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
+{
+       int size = rsurface.rtlight->shadowmapatlassidesize;
+       float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
+       float farclip = 1.0f;
+       float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
+       r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
+       r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
+       r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
+       r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
+       r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
+       r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
+       r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
+       r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
        if (r_shadow_shadowmap2ddepthbuffer)
        {
                // completely different meaning than in depthtexture approach
-               r_shadow_shadowmap_parameters[1] = 0;
-               r_shadow_shadowmap_parameters[3] = -bias;
+               r_shadow_lightshadowmap_parameters[1] = 0;
+               r_shadow_lightshadowmap_parameters[3] = -bias;
        }
+}
+
+static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
+{
+       float nearclip, farclip, bias;
+       r_viewport_t viewport;
+       int flipped;
+       float clearcolor[4];
+
+       if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
+       {
+               r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
+
+               R_Mesh_ResetTextureState();
+               R_Shadow_RenderMode_Reset();
+               if (r_shadow_shadowmap2ddepthbuffer)
+                       R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
+               else
+                       R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
+               R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
+               GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
+               GL_DepthMask(true);
+               GL_DepthTest(true);
+       }
+
+       nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
+       farclip = 1.0f;
+       bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
+
+       R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
+       R_SetViewport(&viewport);
+       GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
+       flipped = (side & 1) ^ (side >> 2);
+       r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
+       r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
+
        Vector4Set(clearcolor, 1,1,1,1);
        if (r_shadow_shadowmap2ddepthbuffer)
                GL_ColorMask(1,1,1,1);
@@ -2209,24 +2298,6 @@ init_done:
        case RENDERPATH_GLES1:
        case RENDERPATH_GLES2:
                GL_CullFace(r_refdef.view.cullface_back);
-               // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
-               if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
-               {
-                       // get tightest scissor rectangle that encloses all viewports in the clear mask
-                       int x1 = clear & 0x15 ? 0 : size;
-                       int x2 = clear & 0x2A ? 2 * size : size;
-                       int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
-                       int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
-                       GL_Scissor(x1, y1, x2 - x1, y2 - y1);
-                       if (clear)
-                       {
-                               if (r_shadow_shadowmap2ddepthbuffer)
-                                       GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
-                               else
-                                       GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
-                       }
-               }
-               GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
                break;
        case RENDERPATH_D3D9:
        case RENDERPATH_D3D10:
@@ -2234,20 +2305,14 @@ init_done:
                // we invert the cull mode because we flip the projection matrix
                // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
                GL_CullFace(r_refdef.view.cullface_front);
-               // D3D considers it an error to use a scissor larger than the viewport...  clear just this view
-               GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
-               if (clear)
-               {
-                       if (r_shadow_shadowmap2ddepthbuffer)
-                               GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
-                       else
-                               GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
-               }
                break;
        }
+
+       // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
+       r_shadow_shadowmapside = side;
 }
 
-void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
+void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
 {
        R_Mesh_ResetTextureState();
        if (transparent)
@@ -2257,6 +2322,8 @@ void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qb
                r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
                r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
        }
+       if (shadowmapping)
+               R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
        R_Shadow_RenderMode_Reset();
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
        if (!transparent)
@@ -2296,7 +2363,7 @@ static const float bboxpoints[8][3] =
        { 1, 1, 1},
 };
 
-void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
+void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
 {
        int i;
        float vertex3f[8*3];
@@ -2306,9 +2373,7 @@ void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadow
        r_shadow_rendermode = r_shadow_lightingrendermode;
        R_EntityMatrix(&identitymatrix);
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
-       // only draw light where this geometry was already rendered AND the
-       // stencil is 128 (values other than this mean shadow)
-       R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
+       R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
        if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
                R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
        else
@@ -4333,6 +4398,7 @@ static void R_Shadow_PrepareLight(rtlight_t *rtlight)
        int numlightentities_noselfshadow;
        int numshadowentities;
        int numshadowentities_noselfshadow;
+       // FIXME: bounds check lightentities and shadowentities, etc.
        static entity_render_t *lightentities[MAX_EDICTS];
        static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
        static entity_render_t *shadowentities[MAX_EDICTS];
@@ -4341,18 +4407,19 @@ static void R_Shadow_PrepareLight(rtlight_t *rtlight)
        qboolean castshadows;
 
        rtlight->draw = false;
-       rtlight->cached_numlightentities               = 0;
-       rtlight->cached_numlightentities_noselfshadow  = 0;
-       rtlight->cached_numshadowentities              = 0;
+       rtlight->cached_numlightentities = 0;
+       rtlight->cached_numlightentities_noselfshadow = 0;
+       rtlight->cached_numshadowentities = 0;
        rtlight->cached_numshadowentities_noselfshadow = 0;
-       rtlight->cached_numsurfaces                    = 0;
-       rtlight->cached_lightentities                  = NULL;
-       rtlight->cached_lightentities_noselfshadow     = NULL;
-       rtlight->cached_shadowentities                 = NULL;
-       rtlight->cached_shadowentities_noselfshadow    = NULL;
-       rtlight->cached_shadowtrispvs                  = NULL;
-       rtlight->cached_lighttrispvs                   = NULL;
-       rtlight->cached_surfacelist                    = NULL;
+       rtlight->cached_numsurfaces = 0;
+       rtlight->cached_lightentities = NULL;
+       rtlight->cached_lightentities_noselfshadow = NULL;
+       rtlight->cached_shadowentities = NULL;
+       rtlight->cached_shadowentities_noselfshadow = NULL;
+       rtlight->cached_shadowtrispvs = NULL;
+       rtlight->cached_lighttrispvs = NULL;
+       rtlight->cached_surfacelist = NULL;
+       rtlight->shadowmapsidesize = 0;
 
        // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
        // skip lights that are basically invisible (color 0 0 0)
@@ -4448,7 +4515,7 @@ static void R_Shadow_PrepareLight(rtlight_t *rtlight)
        // check if light is illuminating any visible leafs
        if (numleafs)
        {
-               for (i = 0;i < numleafs;i++)
+               for (i = 0; i < numleafs; i++)
                        if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
                                break;
                if (i == numleafs)
@@ -4462,7 +4529,7 @@ static void R_Shadow_PrepareLight(rtlight_t *rtlight)
        numshadowentities_noselfshadow = 0;
 
        // add dynamic entities that are lit by the light
-       for (i = 0;i < r_refdef.scene.numentities;i++)
+       for (i = 0; i < r_refdef.scene.numentities; i++)
        {
                dp_model_t *model;
                entity_render_t *ent = r_refdef.scene.entities[i];
@@ -4538,13 +4605,30 @@ static void R_Shadow_PrepareLight(rtlight_t *rtlight)
        castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
        if (!castshadows)
                numshadowentities = numshadowentities_noselfshadow = 0;
+       rtlight->castshadows = castshadows;
 
        // cache all the animated entities that cast a shadow but are not visible
-       for (i = 0;i < numshadowentities;i++)
+       for (i = 0; i < numshadowentities; i++)
                R_AnimCache_GetEntity(shadowentities[i], false, false);
-       for (i = 0;i < numshadowentities_noselfshadow;i++)
+       for (i = 0; i < numshadowentities_noselfshadow; i++)
                R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
 
+       // we can convert noselfshadow to regular if there are no receivers of that type (or we're using r_shadow_deferred which doesn't support noselfshadow anyway)
+       if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
+       {
+               for (i = 0; i < numshadowentities_noselfshadow; i++)
+                       shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
+               numshadowentities_noselfshadow = 0;
+       }
+
+       // we can convert noselfshadow to regular if there are no casters of that type
+       if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
+       {
+               for (i = 0; i < numlightentities_noselfshadow; i++)
+                       lightentities[numlightentities++] = lightentities_noselfshadow[i];
+               numlightentities_noselfshadow = 0;
+       }
+
        // allocate some temporary memory for rendering this light later in the frame
        // reusable buffers need to be copied, static data can be used as-is
        rtlight->cached_numlightentities               = numlightentities;
@@ -4571,9 +4655,26 @@ static void R_Shadow_PrepareLight(rtlight_t *rtlight)
                rtlight->cached_lighttrispvs = lighttrispvs;
                rtlight->cached_surfacelist = surfacelist;
        }
+
+       if (R_Shadow_ShadowMappingEnabled())
+       {
+               // figure out the shadowmapping parameters for this light
+               vec3_t nearestpoint;
+               vec_t distance;
+               int lodlinear;
+               nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
+               nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
+               nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
+               distance = VectorDistance(nearestpoint, r_refdef.view.origin);
+               lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
+               //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
+               lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
+               rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
+               // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
+       }
 }
 
-static void R_Shadow_DrawLight(rtlight_t *rtlight)
+static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
 {
        int i;
        int numsurfaces;
@@ -4589,14 +4690,31 @@ static void R_Shadow_DrawLight(rtlight_t *rtlight)
        int *surfacelist;
        static unsigned char entitysides[MAX_EDICTS];
        static unsigned char entitysides_noselfshadow[MAX_EDICTS];
-       vec3_t nearestpoint;
-       vec_t distance;
-       qboolean castshadows;
-       int lodlinear;
+       float borderbias;
+       int side;
+       int size;
+       int castermask;
+       int receivermask;
+       matrix4x4_t radiustolight;
 
        // check if we cached this light this frame (meaning it is worth drawing)
-       if (!rtlight->draw)
+       if (!rtlight->draw || !rtlight->castshadows)
+               return;
+
+       // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
+       if (rtlight->shadowmapatlassidesize == 0)
+       {
+               rtlight->castshadows = false;
                return;
+       }
+
+       // set up a scissor rectangle for this light
+       if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
+               return;
+
+       // don't let sound skip if going slow
+       if (r_refdef.scene.extraupdate)
+               S_ExtraUpdate();
 
        numlightentities = rtlight->cached_numlightentities;
        numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
@@ -4611,13 +4729,135 @@ static void R_Shadow_DrawLight(rtlight_t *rtlight)
        lighttrispvs = rtlight->cached_lighttrispvs;
        surfacelist = rtlight->cached_surfacelist;
 
+       // make this the active rtlight for rendering purposes
+       R_Shadow_RenderMode_ActiveLight(rtlight);
+
+       radiustolight = rtlight->matrix_worldtolight;
+       Matrix4x4_Abs(&radiustolight);
+
+       size = rtlight->shadowmapatlassidesize;
+       borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
+
+       surfacesides = NULL;
+       castermask = 0;
+       receivermask = 0;
+       if (numsurfaces)
+       {
+               if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
+               {
+                       castermask = rtlight->static_shadowmap_casters;
+                       receivermask = rtlight->static_shadowmap_receivers;
+               }
+               else
+               {
+                       surfacesides = r_shadow_buffer_surfacesides;
+                       for (i = 0; i < numsurfaces; i++)
+                       {
+                               msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
+                               surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
+                               castermask |= surfacesides[i];
+                               receivermask |= surfacesides[i];
+                       }
+               }
+       }
+
+       for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
+               receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
+       for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
+               receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
+
+       receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
+
+       if (receivermask)
+       {
+               for (i = 0; i < numshadowentities; i++)
+                       castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
+               for (i = 0; i < numshadowentities_noselfshadow; i++)
+                       castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
+       }
+
+       // there is no need to render shadows for sides that have no receivers...
+       castermask &= receivermask;
+
+       //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
+
+       // render shadow casters into shadowmaps for this light
+       for (side = 0; side < 6; side++)
+       {
+               int bit = 1 << side;
+               if (castermask & bit)
+               {
+                       R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
+                       if (numsurfaces)
+                               R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
+                       for (i = 0; i < numshadowentities; i++)
+                               if (entitysides[i] & bit)
+                                       R_Shadow_DrawEntityShadow(shadowentities[i]);
+                       for (i = 0; i < numshadowentities_noselfshadow; i++)
+                               if (entitysides_noselfshadow[i] & bit)
+                                       R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
+               }
+       }
+       // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
+       if (numshadowentities_noselfshadow)
+       {
+               for (side = 0; side < 6; side++)
+               {
+                       int bit = 1 << side;
+                       if (castermask & bit)
+                       {
+                               R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
+                               if (numsurfaces)
+                                       R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
+                               for (i = 0; i < numshadowentities; i++)
+                                       if (entitysides[i] & bit)
+                                               R_Shadow_DrawEntityShadow(shadowentities[i]);
+                       }
+               }
+       }
+}
+
+static void R_Shadow_DrawLight(rtlight_t *rtlight)
+{
+       int i;
+       int numsurfaces;
+       unsigned char *shadowtrispvs, *lighttrispvs;
+       int numlightentities;
+       int numlightentities_noselfshadow;
+       int numshadowentities;
+       int numshadowentities_noselfshadow;
+       entity_render_t **lightentities;
+       entity_render_t **lightentities_noselfshadow;
+       entity_render_t **shadowentities;
+       entity_render_t **shadowentities_noselfshadow;
+       int *surfacelist;
+       qboolean castshadows;
+
+       // check if we cached this light this frame (meaning it is worth drawing)
+       if (!rtlight->draw)
+               return;
+
        // set up a scissor rectangle for this light
        if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
                return;
 
        // don't let sound skip if going slow
        if (r_refdef.scene.extraupdate)
-               S_ExtraUpdate ();
+               S_ExtraUpdate();
+
+       numlightentities = rtlight->cached_numlightentities;
+       numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
+       numshadowentities = rtlight->cached_numshadowentities;
+       numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
+       numsurfaces = rtlight->cached_numsurfaces;
+       lightentities = rtlight->cached_lightentities;
+       lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
+       shadowentities = rtlight->cached_shadowentities;
+       shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
+       shadowtrispvs = rtlight->cached_shadowtrispvs;
+       lighttrispvs = rtlight->cached_lighttrispvs;
+       surfacelist = rtlight->cached_surfacelist;
+       castshadows = rtlight->castshadows;
 
        // make this the active rtlight for rendering purposes
        R_Shadow_RenderMode_ActiveLight(rtlight);
@@ -4649,111 +4889,44 @@ static void R_Shadow_DrawLight(rtlight_t *rtlight)
                        R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
        }
 
-       castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
-
-       nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
-       nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
-       nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
-       distance = VectorDistance(nearestpoint, r_refdef.view.origin);
-
-       lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
-       //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
-       lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
-
        if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
        {
                float borderbias;
-               int side;
                int size;
-               int castermask = 0;
-               int receivermask = 0;
+               float shadowmapoffsetnoselfshadow = 0;
                matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
                Matrix4x4_Abs(&radiustolight);
 
-               size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
-                       
+               size = rtlight->shadowmapatlassidesize;
                borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
 
-               surfacesides = NULL;
-               if (numsurfaces)
-               {
-                       if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
-                       {
-                               castermask = rtlight->static_shadowmap_casters;
-                               receivermask = rtlight->static_shadowmap_receivers;
-                       }
-                       else
-                       {
-                               surfacesides = r_shadow_buffer_surfacesides;
-                               for(i = 0;i < numsurfaces;i++)
-                               {
-                                       msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
-                                       surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);           
-                                       castermask |= surfacesides[i];
-                                       receivermask |= surfacesides[i];
-                               }
-                       }
-               }
-               if (receivermask < 0x3F) 
-               {
-                       for (i = 0;i < numlightentities;i++)
-                               receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
-                       if (receivermask < 0x3F)
-                               for(i = 0; i < numlightentities_noselfshadow;i++)
-                                       receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
-               }
-
-               receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
-
-               if (receivermask)
-               {
-                       for (i = 0;i < numshadowentities;i++)
-                               castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
-                       for (i = 0;i < numshadowentities_noselfshadow;i++)
-                               castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); 
-               }
-
                //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
 
-               // render shadow casters into 6 sided depth texture
-               for (side = 0;side < 6;side++) if (receivermask & (1 << side))
+               if (rtlight->cached_numshadowentities_noselfshadow)
+                       shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
+
+               // render lighting using the depth texture as shadowmap
+               // draw lighting in the unmasked areas
+               if (numsurfaces + numlightentities)
                {
-                       R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
-                       if (! (castermask & (1 << side))) continue;
+                       R_Shadow_RenderMode_Lighting(false, false, true, false);
+                       // draw lighting in the unmasked areas
                        if (numsurfaces)
-                               R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
-                       for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
-                               R_Shadow_DrawEntityShadow(shadowentities[i]);
+                               R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
+                       for (i = 0; i < numlightentities; i++)
+                               R_Shadow_DrawEntityLight(lightentities[i]);
                }
-
+               // offset to the noselfshadow part of the atlas and draw those too
                if (numlightentities_noselfshadow)
                {
-                       // render lighting using the depth texture as shadowmap
-                       // draw lighting in the unmasked areas
-                       R_Shadow_RenderMode_Lighting(false, false, true);
-                       for (i = 0;i < numlightentities_noselfshadow;i++)
+                       R_Shadow_RenderMode_Lighting(false, false, true, true);
+                       for (i = 0; i < numlightentities_noselfshadow; i++)
                                R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
                }
 
-               // render shadow casters into 6 sided depth texture
-               if (numshadowentities_noselfshadow)
-               {
-                       for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
-                       {
-                               R_Shadow_RenderMode_ShadowMap(side, 0, size);
-                               for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
-                                       R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
-                       }
-               }
-
-               // render lighting using the depth texture as shadowmap
-               // draw lighting in the unmasked areas
-               R_Shadow_RenderMode_Lighting(false, false, true);
-               // draw lighting in the unmasked areas
-               if (numsurfaces)
-                       R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
-               for (i = 0;i < numlightentities;i++)
-                       R_Shadow_DrawEntityLight(lightentities[i]);
+               // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
+               if (r_shadow_usingdeferredprepass)
+                       R_Shadow_RenderMode_DrawDeferredLight(true);
        }
        else if (castshadows && vid.stencil)
        {
@@ -4768,7 +4941,7 @@ static void R_Shadow_DrawLight(rtlight_t *rtlight)
                        R_Shadow_DrawEntityShadow(shadowentities[i]);
 
                // draw lighting in the unmasked areas
-               R_Shadow_RenderMode_Lighting(true, false, false);
+               R_Shadow_RenderMode_Lighting(true, false, false, false);
                for (i = 0;i < numlightentities_noselfshadow;i++)
                        R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
 
@@ -4776,33 +4949,30 @@ static void R_Shadow_DrawLight(rtlight_t *rtlight)
                        R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
 
                // draw lighting in the unmasked areas
-               R_Shadow_RenderMode_Lighting(true, false, false);
+               R_Shadow_RenderMode_Lighting(true, false, false, false);
                if (numsurfaces)
                        R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
                for (i = 0;i < numlightentities;i++)
                        R_Shadow_DrawEntityLight(lightentities[i]);
+
+               // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
+               if (r_shadow_usingdeferredprepass)
+                       R_Shadow_RenderMode_DrawDeferredLight(false);
        }
        else
        {
                // draw lighting in the unmasked areas
-               R_Shadow_RenderMode_Lighting(false, false, false);
+               R_Shadow_RenderMode_Lighting(false, false, false, false);
                if (numsurfaces)
                        R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
                for (i = 0;i < numlightentities;i++)
                        R_Shadow_DrawEntityLight(lightentities[i]);
                for (i = 0;i < numlightentities_noselfshadow;i++)
                        R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
-       }
 
-       if (r_shadow_usingdeferredprepass)
-       {
-               // when rendering deferred lighting, we simply rasterize the box
-               if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
-                       R_Shadow_RenderMode_DrawDeferredLight(false, true);
-               else if (castshadows && vid.stencil)
-                       R_Shadow_RenderMode_DrawDeferredLight(true, false);
-               else
-                       R_Shadow_RenderMode_DrawDeferredLight(false, false);
+               // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
+               if (r_shadow_usingdeferredprepass)
+                       R_Shadow_RenderMode_DrawDeferredLight(false);
        }
 }
 
@@ -4837,11 +5007,7 @@ static void R_Shadow_FreeDeferred(void)
 void R_Shadow_DrawPrepass(void)
 {
        int i;
-       int flag;
        int lnum;
-       size_t lightindex;
-       dlight_t *light;
-       size_t range;
        entity_render_t *ent;
        float clearcolor[4];
 
@@ -4886,28 +5052,8 @@ void R_Shadow_DrawPrepass(void)
 
        R_Shadow_RenderMode_Begin();
 
-       flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
-       if (r_shadow_debuglight.integer >= 0)
-       {
-               lightindex = r_shadow_debuglight.integer;
-               light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
-               if (light && (light->flags & flag) && light->rtlight.draw)
-                       R_Shadow_DrawLight(&light->rtlight);
-       }
-       else
-       {
-               range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
-               for (lightindex = 0;lightindex < range;lightindex++)
-               {
-                       light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
-                       if (light && (light->flags & flag) && light->rtlight.draw)
-                               R_Shadow_DrawLight(&light->rtlight);
-               }
-       }
-       if (r_refdef.scene.rtdlight)
-               for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
-                       if (r_refdef.scene.lights[lnum]->draw)
-                               R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
+       for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
+               R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
 
        R_Shadow_RenderMode_End();
 
@@ -4915,6 +5061,20 @@ void R_Shadow_DrawPrepass(void)
                R_TimeReport("prepasslights");
 }
 
+#define MAX_SCENELIGHTS 65536
+qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
+{
+       if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
+               return false;
+       if (r_shadow_scenemaxlights <= r_shadow_scenenumlights && r_shadow_scenemaxlights < MAX_SCENELIGHTS)
+       {
+               r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, 65536);
+               r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights);
+       }
+       r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
+       return true;
+}
+
 void R_Shadow_DrawLightSprites(void);
 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
@@ -4925,13 +5085,18 @@ void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *color
        size_t range;
        float f;
 
-       if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
+       int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
+       int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
+       int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
+
+       if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
                (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
-               r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) || 
-               r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || 
-               r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) || 
-               r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer || 
-               r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16) ||
+               r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
+               r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
+               r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
+               r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
+               r_shadow_shadowmapborder != shadowmapborder ||
+               r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
                r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
                R_Shadow_FreeShadowMaps();
 
@@ -5001,32 +5166,29 @@ void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *color
 
        R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
 
+       r_shadow_scenenumlights = 0;
        flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
-       if (r_shadow_debuglight.integer >= 0)
-       {
-               lightindex = r_shadow_debuglight.integer;
-               light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
-               if (light)
-                       R_Shadow_PrepareLight(&light->rtlight);
-       }
-       else
+       range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
+       for (lightindex = 0; lightindex < range; lightindex++)
        {
-               range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
-               for (lightindex = 0;lightindex < range;lightindex++)
+               light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+               if (light && (light->flags & flag))
                {
-                       light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
-                       if (light && (light->flags & flag))
-                               R_Shadow_PrepareLight(&light->rtlight);
+                       R_Shadow_PrepareLight(&light->rtlight);
+                       R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
                }
        }
        if (r_refdef.scene.rtdlight)
        {
-               for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
+               for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
+               {
                        R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
+                       R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
+               }
        }
-       else if(gl_flashblend.integer)
+       else if (gl_flashblend.integer)
        {
-               for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
+               for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
                {
                        rtlight_t *rtlight = r_refdef.scene.lights[lnum];
                        f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
@@ -5034,41 +5196,104 @@ void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *color
                }
        }
 
+       // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
+       if (r_shadow_debuglight.integer >= 0)
+       {
+               r_shadow_scenenumlights = 0;
+               lightindex = r_shadow_debuglight.integer;
+               light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+               if (light)
+               {
+                       R_Shadow_PrepareLight(&light->rtlight);
+                       R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
+               }
+       }
+
+       // if we're doing shadowmaps we need to prepare the atlas layout now
+       if (R_Shadow_ShadowMappingEnabled())
+       {
+               int lod;
+
+               // allocate shadowmaps in the atlas now
+               // we may have to make multiple attempts to fit the shadowmaps in the limited space of the atlas, this will appear as lod popping of all shadowmaps whenever it changes, but at least we can still cast shadows from all lights...
+               for (lod = 0; lod < 16; lod++)
+               {
+                       int packing_success = 0;
+                       int packing_failure = 0;
+                       Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
+                       // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
+                       if (r_shadow_shadowmapatlas_modelshadows_size)
+                               Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, r_shadow_shadowmapatlas_modelshadows_size, r_shadow_shadowmapatlas_modelshadows_size, &r_shadow_shadowmapatlas_modelshadows_x, &r_shadow_shadowmapatlas_modelshadows_y);
+                       for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
+                       {
+                               rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
+                               int size = rtlight->shadowmapsidesize >> lod;
+                               int width, height;
+                               if (!rtlight->castshadows)
+                                       continue;
+                               size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
+                               width = size * 2;
+                               height = size * 3;
+                               // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
+                               if (rtlight->cached_numshadowentities_noselfshadow)
+                                       width *= 2;
+                               if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
+                               {
+                                       rtlight->shadowmapatlassidesize = size;
+                                       packing_success++;
+                               }
+                               else
+                               {
+                                       // note down that we failed to pack this one, it will have to disable shadows
+                                       rtlight->shadowmapatlassidesize = 0;
+                                       packing_failure++;
+                               }
+                       }
+                       // generally everything fits and we stop here on the first iteration
+                       if (packing_failure == 0)
+                               break;
+               }
+       }
+
        if (r_editlights.integer)
                R_Shadow_DrawLightSprites();
 }
 
-void R_Shadow_DrawLights(void)
+void R_Shadow_DrawShadowMaps(void)
 {
-       int flag;
-       int lnum;
-       size_t lightindex;
-       dlight_t *light;
-       size_t range;
-
        R_Shadow_RenderMode_Begin();
+       R_Shadow_RenderMode_ActiveLight(NULL);
 
-       flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
-       if (r_shadow_debuglight.integer >= 0)
+       // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
+       R_Shadow_ClearShadowMapTexture();
+
+       // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
+       if (r_shadow_shadowmapatlas_modelshadows_size)
        {
-               lightindex = r_shadow_debuglight.integer;
-               light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
-               if (light)
-                       R_Shadow_DrawLight(&light->rtlight);
+               R_Shadow_DrawModelShadowMaps();
+               // don't let sound skip if going slow
+               if (r_refdef.scene.extraupdate)
+                       S_ExtraUpdate();
        }
-       else
+
+       if (R_Shadow_ShadowMappingEnabled())
        {
-               range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
-               for (lightindex = 0;lightindex < range;lightindex++)
-               {
-                       light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
-                       if (light && (light->flags & flag))
-                               R_Shadow_DrawLight(&light->rtlight);
-               }
+               int lnum;
+               for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
+                       R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
        }
-       if (r_refdef.scene.rtdlight)
-               for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
-                       R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
+
+       R_Shadow_RenderMode_End();
+}
+
+void R_Shadow_DrawLights(void)
+{
+       int lnum;
+
+       R_Shadow_RenderMode_Begin();
+
+       for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
+               R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
 
        R_Shadow_RenderMode_End();
 }
@@ -5086,19 +5311,21 @@ void R_Shadow_PrepareModelShadows(void)
        entity_render_t *ent;
 
        r_shadow_nummodelshadows = 0;
-       if (!r_refdef.scene.numentities)
+       r_shadow_shadowmapatlas_modelshadows_size = 0;
+
+       if (!r_refdef.scene.numentities || r_refdef.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
                return;
 
        switch (r_shadow_shadowmode)
        {
        case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
-               if (r_shadows.integer >= 2) 
+               if (r_shadows.integer >= 2)
                        break;
                // fall through
        case R_SHADOW_SHADOWMODE_STENCIL:
                if (!vid.stencil)
                        return;
-               for (i = 0;i < r_refdef.scene.numentities;i++)
+               for (i = 0; i < r_refdef.scene.numentities; i++)
                {
                        ent = r_refdef.scene.entities[i];
                        if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
@@ -5114,7 +5341,7 @@ void R_Shadow_PrepareModelShadows(void)
                return;
        }
 
-       size = 2*r_shadow_shadowmapmaxsize;
+       size = 2 * r_shadow_shadowmapmaxsize;
        scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
        radius = 0.5f * size / scale;
 
@@ -5146,7 +5373,7 @@ void R_Shadow_PrepareModelShadows(void)
        shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
        shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
 
-       for (i = 0;i < r_refdef.scene.numentities;i++)
+       for (i = 0; i < r_refdef.scene.numentities; i++)
        {
                ent = r_refdef.scene.entities[i];
                if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
@@ -5160,9 +5387,16 @@ void R_Shadow_PrepareModelShadows(void)
                        R_AnimCache_GetEntity(ent, false, false);
                }
        }
+
+       if (r_shadow_nummodelshadows)
+       {
+               r_shadow_shadowmapatlas_modelshadows_x = 0;
+               r_shadow_shadowmapatlas_modelshadows_y = 0;
+               r_shadow_shadowmapatlas_modelshadows_size = size;
+       }
 }
 
-void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
+static void R_Shadow_DrawModelShadowMaps(void)
 {
        int i;
        float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
@@ -5175,53 +5409,24 @@ void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colort
        float m[12];
        matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
        r_viewport_t viewport;
-       GLuint shadowfbo = 0;
-       float clearcolor[4];
-
-       if (!r_shadow_nummodelshadows)
-               return;
-
-       switch (r_shadow_shadowmode)
-       {
-       case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
-               break;
-       default:
-               return;
-       }
-
-       r_shadow_fb_fbo = fbo;
-       r_shadow_fb_depthtexture = depthtexture;
-       r_shadow_fb_colortexture = colortexture;
 
-       R_ResetViewRendering3D(fbo, depthtexture, colortexture);
-       R_Shadow_RenderMode_Begin();
-       R_Shadow_RenderMode_ActiveLight(NULL);
-
-       switch (r_shadow_shadowmode)
-       {
-       case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
-               if (!r_shadow_shadowmap2ddepthtexture)
-                       R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
-               shadowfbo = r_shadow_fbo2d;
-               r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
-               r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
-               r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
-               break;
-       default:
-               break;
-       }
-
-       size = 2*r_shadow_shadowmapmaxsize;
+       size = r_shadow_shadowmapatlas_modelshadows_size;
        scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
        radius = 0.5f / scale;
        nearclip = -r_shadows_throwdistance.value;
        farclip = r_shadows_throwdistance.value;
        bias = (r_shadows_shadowmapbias.value < 0) ? r_shadow_shadowmapping_bias.value : r_shadows_shadowmapbias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
 
-       r_shadow_shadowmap_parameters[0] = size;
-       r_shadow_shadowmap_parameters[1] = size;
-       r_shadow_shadowmap_parameters[2] = 1.0;
-       r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
+       // set the parameters that will be used on the regular model renders using these shadows we're about to produce
+       r_shadow_modelshadowmap_parameters[0] = size;
+       r_shadow_modelshadowmap_parameters[1] = size;
+       r_shadow_modelshadowmap_parameters[2] = 1.0;
+       r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
+       r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
+       r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
+       r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
+       r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
+       r_shadow_usingshadowmaportho = true;
 
        Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
        VectorCopy(prvmshadowdir, shadowdir);
@@ -5250,27 +5455,11 @@ void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colort
        m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
        Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
        Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
-       R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL); 
+       R_Viewport_InitOrtho(&viewport, &cameramatrix, r_shadow_shadowmapatlas_modelshadows_x, r_shadow_shadowmapatlas_modelshadows_y, r_shadow_shadowmapatlas_modelshadows_size, r_shadow_shadowmapatlas_modelshadows_size, 0, 0, 1, 1, 0, -1, NULL);
+       R_SetViewport(&viewport);
 
        VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
 
-       if (r_shadow_shadowmap2ddepthbuffer)
-               R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
-       else
-               R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
-       R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
-       GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
-       GL_DepthMask(true);
-       GL_DepthTest(true);
-       R_SetViewport(&viewport);
-       GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
-       Vector4Set(clearcolor, 1,1,1,1);
-       // in D3D9 we have to render to a color texture shadowmap
-       // in GL we render directly to a depth texture only
-       if (r_shadow_shadowmap2ddepthbuffer)
-               GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
-       else
-               GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
        // render into a slightly restricted region so that the borders of the
        // shadowmap area fade away, rather than streaking across everything
        // outside the usable area
@@ -5308,8 +5497,6 @@ void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colort
        }
 #endif
 
-       R_Shadow_RenderMode_End();
-
        Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
        Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
        Matrix4x4_CreateScale3(&scalematrix, size, -size, 1); 
@@ -5342,19 +5529,9 @@ void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colort
 #endif
                break;
        }
-
-       r_shadow_usingshadowmaportho = true;
-       switch (r_shadow_shadowmode)
-       {
-       case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
-               r_shadow_usingshadowmap2d = true;
-               break;
-       default:
-               break;
-       }
 }
 
-void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
+void R_Shadow_DrawModelShadows(void)
 {
        int i;
        float relativethrowdistance;
@@ -5368,11 +5545,7 @@ void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortext
        if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
                return;
 
-       r_shadow_fb_fbo = fbo;
-       r_shadow_fb_depthtexture = depthtexture;
-       r_shadow_fb_colortexture = colortexture;
-
-       R_ResetViewRendering3D(fbo, depthtexture, colortexture);
+       R_ResetViewRendering3D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
        //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
        //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
        R_Shadow_RenderMode_Begin();
@@ -5455,7 +5628,7 @@ void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortext
        //GL_ScissorTest(true);
        //R_EntityMatrix(&identitymatrix);
        //R_Mesh_ResetTextureState();
-       R_ResetViewRendering2D(fbo, depthtexture, colortexture);
+       R_ResetViewRendering2D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
 
        // set up a darkening blend on shadowed areas
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
index 685018a18279631dc8964da9050a2c6ba48dc236..30403f4b623de40e25bf758e53405855f616258c 100644 (file)
@@ -105,8 +105,8 @@ void R_Shadow_RenderMode_Begin(void);
 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight);
 void R_Shadow_RenderMode_Reset(void);
 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass);
-void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping);
-void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping);
+void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass);
+void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping);
 void R_Shadow_RenderMode_VisibleShadowVolumes(void);
 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent);
 void R_Shadow_RenderMode_End(void);
@@ -128,6 +128,7 @@ void R_RTLight_Compile(rtlight_t *rtlight);
 void R_RTLight_Uncompile(rtlight_t *rtlight);
 
 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
+void R_Shadow_ClearShadowMapTexture(void);
 void R_Shadow_DrawPrepass(void);
 void R_Shadow_DrawLights(void);
 void R_Shadow_DrawCoronas(void);
@@ -153,7 +154,7 @@ void R_Shadow_PrepareModelShadows(void);
 void R_LightPoint(float *color, const vec3_t p, const int flags);
 void R_CompleteLightPoint(float *ambientcolor, float *diffusecolor, float *diffusenormal, const vec3_t p, const int flags);
 
-void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
-void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
+void R_Shadow_DrawShadowMaps(void);
+void R_Shadow_DrawModelShadows(void);
 
 #endif
index b91bde74c16f009d266cb8196c55087456916a49..09782f54df2aa7514a63c47b4357066c08d10432 100644 (file)
--- a/render.h
+++ b/render.h
@@ -616,8 +616,6 @@ void R_Shadow_UpdateBounceGridTexture(void);
 void R_DrawLightningBeams(void);
 void VM_CL_AddPolygonsToMeshQueue(struct prvm_prog_s *prog);
 void R_DrawPortals(void);
-void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
-void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
 void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
 void R_Water_AddWaterPlane(msurface_t *surface, int entno);
 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color);
index 1f5803c07045bad0eff82940f5c90e9618add50e..90d5d770db2fe73fc52326f6e4dcb1479dc51a28 100644 (file)
 "#endif\n",
 "\n",
 "#if defined(USESHADOWMAP2D)\n",
-"uniform mediump vec2 ShadowMap_TextureScale;\n",
+"uniform mediump vec4 ShadowMap_TextureScale;\n",
 "uniform mediump vec4 ShadowMap_Parameters;\n",
 "#endif\n",
 "\n",
 "#if defined(USESHADOWMAP2D)\n",
 "# ifdef USESHADOWMAPORTHO\n",
-"#  define GetShadowMapTC2D(dir) (min(dir, ShadowMap_Parameters.xyz))\n",
+"#  define GetShadowMapTC2D(dir) (max(vec3(0.0, 0.0, 0.0), min(dir, ShadowMap_Parameters.xyz)))\n",
 "# else\n",
 "#  ifdef USESHADOWMAPVSDCT\n",
 "vec3 GetShadowMapTC2D(vec3 dir)\n",
 "# ifdef USESHADOWMAP2D\n",
 "float ShadowMapCompare(vec3 dir)\n",
 "{\n",
-"      vec3 shadowmaptc = GetShadowMapTC2D(dir);\n",
+"      vec3 shadowmaptc = GetShadowMapTC2D(dir) + vec3(ShadowMap_TextureScale.zw, 0.0f);\n",
 "      float f;\n",
 "\n",
 "#  ifdef USEDEPTHRGB\n",
 "#   ifdef USESHADOWMAPPCF\n",
-"#    define texval(x, y) decodedepthmacro(dp_texture2D(Texture_ShadowMap2D, center + vec2(x, y)*ShadowMap_TextureScale))\n",
+"#    define texval(x, y) decodedepthmacro(dp_texture2D(Texture_ShadowMap2D, center + vec2(x, y)*ShadowMap_TextureScale.xy))\n",
 "#    if USESHADOWMAPPCF > 1\n",
 "      vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n",
-"      center *= ShadowMap_TextureScale;\n",
+"      center *= ShadowMap_TextureScale.xy;\n",
 "      vec4 row1 = step(shadowmaptc.z, vec4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0)));\n",
 "      vec4 row2 = step(shadowmaptc.z, vec4(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0), texval( 2.0,  0.0)));\n",
 "      vec4 row3 = step(shadowmaptc.z, vec4(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0), texval( 2.0,  1.0)));\n",
 "      vec4 cols = row2 + row3 + mix(row1, row4, offset.y);\n",
 "      f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n",
 "#    else\n",
-"      vec2 center = shadowmaptc.xy*ShadowMap_TextureScale, offset = fract(shadowmaptc.xy);\n",
+"      vec2 center = shadowmaptc.xy*ShadowMap_TextureScale.xy, offset = fract(shadowmaptc.xy);\n",
 "      vec3 row1 = step(shadowmaptc.z, vec3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0)));\n",
 "      vec3 row2 = step(shadowmaptc.z, vec3(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0)));\n",
 "      vec3 row3 = step(shadowmaptc.z, vec3(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0)));\n",
 "      f = dot(mix(cols.xy, cols.yz, offset.x), vec2(0.25));\n",
 "#    endif\n",
 "#   else\n",
-"      f = step(shadowmaptc.z, decodedepthmacro(dp_texture2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale)));\n",
+"      f = step(shadowmaptc.z, decodedepthmacro(dp_texture2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale.xy)));\n",
 "#   endif\n",
 "#  else\n",
 "#   ifdef USESHADOWSAMPLER\n",
 "      vec2 offset = fract(shadowmaptc.xy - 0.5);\n",
 "   vec4 size = vec4(offset + 1.0, 2.0 - offset);\n",
 "#       if USESHADOWMAPPCF > 1\n",
-"   vec2 center = (shadowmaptc.xy - offset + 0.5)*ShadowMap_TextureScale;\n",
+"   vec2 center = (shadowmaptc.xy - offset + 0.5)*ShadowMap_TextureScale.xy;\n",
 "   vec4 weight = (vec4(-1.5, -1.5, 2.0, 2.0) + (shadowmaptc.xy - 0.5*offset).xyxy)*ShadowMap_TextureScale.xyxy;\n",
 "      f = (1.0/25.0)*dot(size.zxzx*size.wwyy, vec4(texval(weight.xy), texval(weight.zy), texval(weight.xw), texval(weight.zw))) +\n",
 "              (2.0/25.0)*dot(size, vec4(texval(vec2(weight.z, center.y)), texval(vec2(center.x, weight.w)), texval(vec2(weight.x, center.y)), texval(vec2(center.x, weight.y)))) +\n",
 "      f = (1.0/9.0)*dot(size.zxzx*size.wwyy, vec4(texval(weight.zw), texval(weight.xw), texval(weight.zy), texval(weight.xy)));\n",
 "#       endif        \n",
 "#     else\n",
-"      f = dp_shadow2D(Texture_ShadowMap2D, vec3(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z));\n",
+"      f = dp_shadow2D(Texture_ShadowMap2D, vec3(shadowmaptc.xy*ShadowMap_TextureScale.xy, shadowmaptc.z));\n",
 "#     endif\n",
 "#   else\n",
 "#     ifdef USESHADOWMAPPCF\n",
 "#       ifdef GL_ARB_texture_gather\n",
 "#         define texval(x, y) textureGatherOffset(Texture_ShadowMap2D, center, ivec2(x, y))\n",
 "#       else\n",
-"#         define texval(x, y) texture4(Texture_ShadowMap2D, center + vec2(x, y)*ShadowMap_TextureScale)\n",
+"#         define texval(x, y) texture4(Texture_ShadowMap2D, center + vec2(x, y)*ShadowMap_TextureScale.xy)\n",
 "#       endif\n",
-"      vec2 offset = fract(shadowmaptc.xy - 0.5), center = (shadowmaptc.xy - offset)*ShadowMap_TextureScale;\n",
+"      vec2 offset = fract(shadowmaptc.xy - 0.5), center = (shadowmaptc.xy - offset)*ShadowMap_TextureScale.xy;\n",
 "#       if USESHADOWMAPPCF > 1\n",
 "   vec4 group1 = step(shadowmaptc.z, texval(-2.0, -2.0));\n",
 "   vec4 group2 = step(shadowmaptc.z, texval( 0.0, -2.0));\n",
 "#       ifdef GL_EXT_gpu_shader4\n",
 "#         define texval(x, y) dp_textureOffset(Texture_ShadowMap2D, center, x, y).r\n",
 "#       else\n",
-"#         define texval(x, y) dp_texture2D(Texture_ShadowMap2D, center + vec2(x, y)*ShadowMap_TextureScale).r  \n",
+"#         define texval(x, y) dp_texture2D(Texture_ShadowMap2D, center + vec2(x, y)*ShadowMap_TextureScale.xy).r  \n",
 "#       endif\n",
 "#       if USESHADOWMAPPCF > 1\n",
 "      vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n",
-"      center *= ShadowMap_TextureScale;\n",
+"      center *= ShadowMap_TextureScale.xy;\n",
 "      vec4 row1 = step(shadowmaptc.z, vec4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0)));\n",
 "      vec4 row2 = step(shadowmaptc.z, vec4(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0), texval( 2.0,  0.0)));\n",
 "      vec4 row3 = step(shadowmaptc.z, vec4(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0), texval( 2.0,  1.0)));\n",
 "      vec4 cols = row2 + row3 + mix(row1, row4, offset.y);\n",
 "      f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n",
 "#       else\n",
-"      vec2 center = shadowmaptc.xy*ShadowMap_TextureScale, offset = fract(shadowmaptc.xy);\n",
+"      vec2 center = shadowmaptc.xy*ShadowMap_TextureScale.xy, offset = fract(shadowmaptc.xy);\n",
 "      vec3 row1 = step(shadowmaptc.z, vec3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0)));\n",
 "      vec3 row2 = step(shadowmaptc.z, vec3(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0)));\n",
 "      vec3 row3 = step(shadowmaptc.z, vec3(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0)));\n",
 "#       endif\n",
 "#      endif\n",
 "#     else\n",
-"      f = step(shadowmaptc.z, dp_texture2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale).r);\n",
+"      f = step(shadowmaptc.z, dp_texture2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale.xy).r);\n",
 "#     endif\n",
 "#   endif\n",
 "#  endif\n",
index 4a63f1c4f07e7861cd47c9f88b89b77f78189353..9b3f04c3faa71d9e5e0a4a3192c7d5e04904144c 100644 (file)
 "#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE) || defined(USESHADOWMAPORTHO)\n",
 "#if defined(USESHADOWMAP2D)\n",
 "# ifdef USESHADOWMAPORTHO\n",
-"#  define GetShadowMapTC2D(dir, ShadowMap_Parameters) (min(dir, ShadowMap_Parameters.xyz))\n",
+"#  define GetShadowMapTC2D(dir, ShadowMap_Parameters) (max(float3(0.0, 0.0, 0.0), min(dir, ShadowMap_Parameters.xyz)))\n",
 "# else\n",
 "#  ifdef USESHADOWMAPVSDCT\n",
 "float3 GetShadowMapTC2D(float3 dir, float4 ShadowMap_Parameters, samplerCUBE Texture_CubeProjection)\n",
 "\n",
 "# ifdef USESHADOWMAP2D\n",
 "#ifdef USESHADOWMAPVSDCT\n",
-"float ShadowMapCompare(float3 dir, sampler Texture_ShadowMap2D, float4 ShadowMap_Parameters, float2 ShadowMap_TextureScale, samplerCUBE Texture_CubeProjection)\n",
+"float ShadowMapCompare(float3 dir, sampler Texture_ShadowMap2D, float4 ShadowMap_Parameters, float4 ShadowMap_TextureScale, samplerCUBE Texture_CubeProjection)\n",
 "#else\n",
-"float ShadowMapCompare(float3 dir, sampler Texture_ShadowMap2D, float4 ShadowMap_Parameters, float2 ShadowMap_TextureScale)\n",
+"float ShadowMapCompare(float3 dir, sampler Texture_ShadowMap2D, float4 ShadowMap_Parameters, float4 ShadowMap_TextureScale)\n",
 "#endif\n",
 "{\n",
 "#ifdef USESHADOWMAPVSDCT\n",
-"      float3 shadowmaptc = GetShadowMapTC2D(dir, ShadowMap_Parameters, Texture_CubeProjection);\n",
+"      float3 shadowmaptc = GetShadowMapTC2D(dir, ShadowMap_Parameters, Texture_CubeProjection) + float3(ShadowMap_TextureScale.zw, 0.0f);\n",
 "#else\n",
-"      float3 shadowmaptc = GetShadowMapTC2D(dir, ShadowMap_Parameters);\n",
+"      float3 shadowmaptc = GetShadowMapTC2D(dir, ShadowMap_Parameters) + float3(ShadowMap_TextureScale.zw, 0.0f);\n",
 "#endif\n",
 "      float f;\n",
 "\n",
 "#  ifdef USESHADOWSAMPLER\n",
 "#    ifdef USESHADOWMAPPCF\n",
-"#      define texval(x, y) tex2Dproj(Texture_ShadowMap2D, float4(center + float2(x, y)*ShadowMap_TextureScale, shadowmaptc.z, 1.0)).r  \n",
-"      float2 center = shadowmaptc.xy*ShadowMap_TextureScale;\n",
+"#      define texval(x, y) tex2Dproj(Texture_ShadowMap2D, float4(center + float2(x, y)*ShadowMap_TextureScale.xy, shadowmaptc.z, 1.0)).r  \n",
+"      float2 center = shadowmaptc.xy*ShadowMap_TextureScale.xy;\n",
 "      f = dot(float4(0.25,0.25,0.25,0.25), float4(texval(-0.4, 1.0), texval(-1.0, -0.4), texval(0.4, -1.0), texval(1.0, 0.4)));\n",
 "#    else\n",
-"      f = tex2Dproj(Texture_ShadowMap2D, float4(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z, 1.0)).r;\n",
+"      f = tex2Dproj(Texture_ShadowMap2D, float4(shadowmaptc.xy*ShadowMap_TextureScale.xy, shadowmaptc.z, 1.0)).r;\n",
 "#    endif\n",
 "#  else\n",
 "#    ifdef USESHADOWMAPPCF\n",
 "#      ifdef GL_ARB_texture_gather\n",
 "#        define texval(x, y) textureGatherOffset(Texture_ShadowMap2D, center, int2(x, y))\n",
 "#      else\n",
-"#        define texval(x, y) texture4(Texture_ShadowMap2D, center + float2(x, y)*ShadowMap_TextureScale)\n",
+"#        define texval(x, y) texture4(Texture_ShadowMap2D, center + float2(x, y)*ShadowMap_TextureScale.xy)\n",
 "#      endif\n",
-"      float2 offset = frac(shadowmaptc.xy - 0.5), center = (shadowmaptc.xy - offset)*ShadowMap_TextureScale;\n",
+"      float2 offset = frac(shadowmaptc.xy - 0.5), center = (shadowmaptc.xy - offset)*ShadowMap_TextureScale.xy;\n",
 "#      if USESHADOWMAPPCF > 1\n",
 "      float4 group1 = step(shadowmaptc.z, texval(-2.0, -2.0));\n",
 "      float4 group2 = step(shadowmaptc.z, texval( 0.0, -2.0));\n",
 "#      ifdef GL_EXT_gpu_shader4\n",
 "#        define texval(x, y) tex2DOffset(Texture_ShadowMap2D, center, int2(x, y)).r\n",
 "#      else\n",
-"#        define texval(x, y) texDepth2D(Texture_ShadowMap2D, center + float2(x, y)*ShadowMap_TextureScale).r  \n",
+"#        define texval(x, y) texDepth2D(Texture_ShadowMap2D, center + float2(x, y)*ShadowMap_TextureScale.xy).r  \n",
 "#      endif\n",
 "#      if USESHADOWMAPPCF > 1\n",
 "      float2 center = shadowmaptc.xy - 0.5, offset = frac(center);\n",
-"      center *= ShadowMap_TextureScale;\n",
+"      center *= ShadowMap_TextureScale.xy;\n",
 "      float4 row1 = step(shadowmaptc.z, float4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0)));\n",
 "      float4 row2 = step(shadowmaptc.z, float4(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0), texval( 2.0,  0.0)));\n",
 "      float4 row3 = step(shadowmaptc.z, float4(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0), texval( 2.0,  1.0)));\n",
 "      float4 cols = row2 + row3 + lerp(row1, row4, offset.y);\n",
 "      f = dot(lerp(cols.xyz, cols.yzw, offset.x), float3(1.0/9.0));\n",
 "#      else\n",
-"      float2 center = shadowmaptc.xy*ShadowMap_TextureScale, offset = frac(shadowmaptc.xy);\n",
+"      float2 center = shadowmaptc.xy*ShadowMap_TextureScale.xy, offset = frac(shadowmaptc.xy);\n",
 "      float3 row1 = step(shadowmaptc.z, float3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0)));\n",
 "      float3 row2 = step(shadowmaptc.z, float3(texval(-1.0,  0.0), texval( 0.0,  0.0), texval( 1.0,  0.0)));\n",
 "      float3 row3 = step(shadowmaptc.z, float3(texval(-1.0,  1.0), texval( 0.0,  1.0), texval( 1.0,  1.0)));\n",
 "#      endif\n",
 "#     endif\n",
 "#    else\n",
-"      f = step(shadowmaptc.z, tex2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale).r);\n",
+"      f = step(shadowmaptc.z, tex2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale.xy).r);\n",
 "#    endif\n",
 "#  endif\n",
 "#  ifdef USESHADOWMAPORTHO\n",
 "#endif\n",
 "\n",
 "#if defined(USESHADOWMAP2D)\n",
-"uniform float2 ShadowMap_TextureScale : register(c35),\n",
+"uniform float4 ShadowMap_TextureScale : register(c35),\n",
 "uniform float4 ShadowMap_Parameters : register(c34),\n",
 "#endif\n",
 "\n",
 "#endif\n",
 "\n",
 "#if defined(USESHADOWMAP2D)\n",
-"uniform float2 ShadowMap_TextureScale : register(c35),\n",
+"uniform float4 ShadowMap_TextureScale : register(c35),\n",
 "uniform float4 ShadowMap_Parameters : register(c34),\n",
 "#endif\n",
 "#endif // !defined(MODE_LIGHTSOURCE) && !defined(MODE_DEFERREDLIGHTSOURCE) && !defined(USESHADOWMAPORTHO)\n",
 "//    float3 shadowmaptc = GetShadowMapTC2D(CubeVector, ShadowMap_Parameters);\n",
 "#endif\n",
 "//    color.rgb = half3(tex2D(Texture_ShadowMap2D, float2(0.1,0.1)).rgb);\n",
-"//    color.rgb = half3(tex2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale).rgb);\n",
-"//    color.rgb = half3(shadowmaptc.xyz * float3(ShadowMap_TextureScale,1.0));\n",
-"//    color.r = half(texDepth2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale));\n",
+"//    color.rgb = half3(tex2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale.xy).rgb);\n",
+"//    color.rgb = half3(shadowmaptc.xyz * float3(ShadowMap_TextureScale.xy,1.0));\n",
+"//    color.r = half(texDepth2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale.xy));\n",
 "//    color.rgb = half3(tex2D(Texture_ShadowMap2D, float2(0.1,0.1)).rgb);\n",
-"//    color.rgb = half3(tex2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale).rgb);\n",
-"//    color.rgb = half3(shadowmaptc.xyz * float3(ShadowMap_TextureScale,1.0));\n",
-"//    color.r = half(texDepth2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale));\n",
-"//    color.r = half(shadowmaptc.z - texDepth2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale));\n",
+"//    color.rgb = half3(tex2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale.xy).rgb);\n",
+"//    color.rgb = half3(shadowmaptc.xyz * float3(ShadowMap_TextureScale.xy,1.0));\n",
+"//    color.r = half(texDepth2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale.xy));\n",
+"//    color.r = half(shadowmaptc.z - texDepth2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale.xy));\n",
 "//    color.r = half(shadowmaptc.z);\n",
-"//    color.r = half(texDepth2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale));\n",
+"//    color.r = half(texDepth2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale.xy));\n",
 "//    color.r = half(shadowmaptc.z);\n",
 "//    color.r = 1;\n",
 "//    color.rgb = abs(CubeVector);\n",