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;
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]);
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));
{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));
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);
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);
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);
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;
}
}
+ 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);
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);
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)
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)
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;
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;
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;
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;
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"};
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)
static void R_Shadow_FreeShadowMaps(void)
{
+ Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
+
R_Shadow_SetShadowMode();
R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
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;
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;
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;
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);
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;
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);
}
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)
{
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;
}
}
-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);
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:
// 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)
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)
{ 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];
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
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];
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)
// 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)
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];
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;
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;
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;
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);
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)
{
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]);
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);
}
}
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];
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();
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)
{
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();
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;
}
}
+ // 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();
}
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))
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;
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))
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;
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);
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
}
#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);
#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;
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();
//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);