qboolean r_shadow_usingshadowmaprect;
qboolean r_shadow_usingshadowmap2d;
qboolean r_shadow_usingshadowmapcube;
-float r_shadow_shadowmap_bias;
+int r_shadow_shadowmapside;
float r_shadow_shadowmap_texturescale[2];
float r_shadow_shadowmap_parameters[4];
int r_shadow_drawbuffer;
int r_shadow_readbuffer;
+int r_shadow_cullface;
GLuint r_shadow_fborectangle;
GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS][6];
GLuint r_shadow_fbo2d;
+int r_shadow_shadowmode;
+int r_shadow_shadowmapfilterquality;
+int r_shadow_shadowmaptexturetype;
+int r_shadow_shadowmapprecision;
int r_shadow_shadowmapmaxsize;
+qboolean r_shadow_shadowmapvsdct;
+qboolean r_shadow_shadowmapsampler;
+int r_shadow_shadowmappcf;
+int r_shadow_shadowmapborder;
int r_shadow_lightscissor[4];
int maxshadowtriangles;
int *shadowmarklist;
int shadowmarkcount;
+int maxshadowsides;
+int numshadowsides;
+unsigned char *shadowsides;
+int *shadowsideslist;
+
int maxvertexupdate;
int *vertexupdate;
int *vertexremap;
rtexture_t *r_shadow_lightcorona;
rtexture_t *r_shadow_shadowmaprectangletexture;
rtexture_t *r_shadow_shadowmap2dtexture;
-rtexture_t *r_shadow_shadowmapcubeprojectiontexture;
rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
+rtexture_t *r_shadow_shadowmapvsdcttexture;
int r_shadow_shadowmapsize; // changes for each light based on distance
int r_shadow_shadowmaplod; // changes for each light based on distance
cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
-cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "0", "shadowmap filter modes: 0 = no filtering, 1 = bilinear, 2 = bilinear small blur (fast), 3 = bilinear large blur (slow)"};
+cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "0", "shadowmap texture types: 0 = auto-select, 1 = 2D, 2 = rectangle, 3 = cubemap"};
+cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
+cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "24", "requested minimum shadowmap texture precision"};
+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", "1024", "shadowmap size limit"};
+cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
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"};
-cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "6", "shadowmap size bias for filtering"};
+cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
cachepic_t *r_editlights_sprcubemapnoshadowlight;
cachepic_t *r_editlights_sprselection;
+void R_Shadow_SetShadowMode(void)
+{
+ r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
+ r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
+ r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
+ r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
+ r_shadow_shadowmapprecision = r_shadow_shadowmapping_precision.integer;
+ r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
+ r_shadow_shadowmaplod = -1;
+ r_shadow_shadowmapsize = 0;
+ r_shadow_shadowmapsampler = false;
+ r_shadow_shadowmappcf = 0;
+ r_shadow_shadowmode = 0;
+ if(r_shadow_shadowmapping.integer)
+ {
+ if(r_shadow_shadowmapfilterquality < 0)
+ {
+ if(strstr(gl_vendor, "NVIDIA"))
+ {
+ r_shadow_shadowmapsampler = gl_support_arb_shadow;
+ r_shadow_shadowmappcf = 1;
+ }
+ else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather)
+ r_shadow_shadowmappcf = 1;
+ else if(strstr(gl_vendor, "ATI"))
+ r_shadow_shadowmappcf = 1;
+ else
+ r_shadow_shadowmapsampler = gl_support_arb_shadow;
+ }
+ else
+ {
+ switch (r_shadow_shadowmapfilterquality)
+ {
+ case 1:
+ r_shadow_shadowmapsampler = gl_support_arb_shadow;
+ break;
+ case 2:
+ r_shadow_shadowmapsampler = gl_support_arb_shadow;
+ r_shadow_shadowmappcf = 1;
+ break;
+ case 3:
+ r_shadow_shadowmappcf = 1;
+ break;
+ case 4:
+ r_shadow_shadowmappcf = 2;
+ break;
+ }
+ }
+ r_shadow_shadowmode = r_shadow_shadowmaptexturetype;
+ if(r_shadow_shadowmode <= 0)
+ {
+ if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
+ r_shadow_shadowmode = 1;
+ else if(gl_texturerectangle)
+ r_shadow_shadowmode = 2;
+ else
+ r_shadow_shadowmode = 1;
+ }
+ }
+}
+
+void R_Shadow_FreeShadowMaps(void)
+{
+ int i;
+
+ R_Shadow_SetShadowMode();
+
+ if (r_shadow_fborectangle)
+ qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
+ r_shadow_fborectangle = 0;
+ CHECKGLERROR
+
+ if (r_shadow_fbo2d)
+ qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
+ r_shadow_fbo2d = 0;
+ CHECKGLERROR
+ for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
+ if (r_shadow_fbocubeside[i][0])
+ qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
+ memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
+ CHECKGLERROR
+
+ if (r_shadow_shadowmaprectangletexture)
+ R_FreeTexture(r_shadow_shadowmaprectangletexture);
+ r_shadow_shadowmaprectangletexture = NULL;
+
+ if (r_shadow_shadowmap2dtexture)
+ R_FreeTexture(r_shadow_shadowmap2dtexture);
+ r_shadow_shadowmap2dtexture = NULL;
+
+ for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
+ if (r_shadow_shadowmapcubetexture[i])
+ R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
+ memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
+
+ if (r_shadow_shadowmapvsdcttexture)
+ R_FreeTexture(r_shadow_shadowmapvsdcttexture);
+ r_shadow_shadowmapvsdcttexture = NULL;
+
+ CHECKGLERROR
+}
+
void r_shadow_start(void)
{
// allocate vertex processing arrays
r_shadow_attenuationgradienttexture = NULL;
r_shadow_attenuation2dtexture = NULL;
r_shadow_attenuation3dtexture = NULL;
+ r_shadow_shadowmode = 0;
r_shadow_shadowmaprectangletexture = NULL;
- memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
- r_shadow_shadowmapcubeprojectiontexture = NULL;
r_shadow_shadowmap2dtexture = NULL;
+ memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
+ r_shadow_shadowmapvsdcttexture = NULL;
r_shadow_shadowmapmaxsize = 0;
r_shadow_shadowmapsize = 0;
r_shadow_shadowmaplod = 0;
+ r_shadow_shadowmapfilterquality = 0;
+ r_shadow_shadowmaptexturetype = 0;
+ r_shadow_shadowmapprecision = 0;
+ r_shadow_shadowmapvsdct = false;
+ r_shadow_shadowmapsampler = false;
+ r_shadow_shadowmappcf = 0;
r_shadow_fborectangle = 0;
- memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
r_shadow_fbo2d = 0;
+ memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
+
+ R_Shadow_FreeShadowMaps();
+
r_shadow_texturepool = NULL;
r_shadow_filters_texturepool = NULL;
R_Shadow_ValidateCvars();
shadowmark = NULL;
shadowmarklist = NULL;
shadowmarkcount = 0;
+ maxshadowsides = 0;
+ numshadowsides = 0;
+ shadowsides = NULL;
+ shadowsideslist = NULL;
r_shadow_buffer_numleafpvsbytes = 0;
r_shadow_buffer_visitingleafpvs = NULL;
r_shadow_buffer_leafpvs = NULL;
void r_shadow_shutdown(void)
{
- int i;
CHECKGLERROR
R_Shadow_UncompileWorldLights();
+
+ R_Shadow_FreeShadowMaps();
+
CHECKGLERROR
numcubemaps = 0;
r_shadow_attenuationgradienttexture = NULL;
r_shadow_attenuation2dtexture = NULL;
r_shadow_attenuation3dtexture = NULL;
- r_shadow_shadowmaprectangletexture = NULL;
- memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
- r_shadow_shadowmapcubeprojectiontexture = NULL;
- r_shadow_shadowmap2dtexture = NULL;
- r_shadow_shadowmapmaxsize = 0;
- r_shadow_shadowmapsize = 0;
- r_shadow_shadowmaplod = 0;
- CHECKGLERROR
- if (r_shadow_fborectangle)
- qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
- r_shadow_fborectangle = 0;
- CHECKGLERROR
- for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
- if (r_shadow_fbocubeside[i])
- qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
- memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
- CHECKGLERROR
- if (r_shadow_fbo2d)
- qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
- r_shadow_fbo2d = 0;
- CHECKGLERROR
R_FreeTexturePool(&r_shadow_texturepool);
R_FreeTexturePool(&r_shadow_filters_texturepool);
maxshadowtriangles = 0;
Mem_Free(shadowmarklist);
shadowmarklist = NULL;
shadowmarkcount = 0;
+ maxshadowsides = 0;
+ numshadowsides = 0;
+ if (shadowsides)
+ Mem_Free(shadowsides);
+ shadowsides = NULL;
+ if (shadowsideslist)
+ Mem_Free(shadowsideslist);
+ shadowsideslist = NULL;
r_shadow_buffer_numleafpvsbytes = 0;
if (r_shadow_buffer_visitingleafpvs)
Mem_Free(r_shadow_buffer_visitingleafpvs);
Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
Cvar_RegisterVariable(&r_shadow_scissor);
Cvar_RegisterVariable(&r_shadow_shadowmapping);
+ Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
+ Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
+ Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
shadowmark = NULL;
shadowmarklist = NULL;
shadowmarkcount = 0;
+ maxshadowsides = 0;
+ numshadowsides = 0;
+ shadowsides = NULL;
+ shadowsideslist = NULL;
r_shadow_buffer_numleafpvsbytes = 0;
r_shadow_buffer_visitingleafpvs = NULL;
r_shadow_buffer_leafpvs = NULL;
}
};
-void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
+void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
{
+ numvertices = ((numvertices + 255) & ~255) * vertscale;
+ numtriangles = ((numtriangles + 255) & ~255) * triscale;
// make sure shadowelements is big enough for this volume
if (maxshadowtriangles < numtriangles)
{
maxshadowtriangles = numtriangles;
if (shadowelements)
Mem_Free(shadowelements);
- shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
+ shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
}
// make sure shadowvertex3f is big enough for this volume
if (maxshadowvertices < numvertices)
maxshadowvertices = numvertices;
if (shadowvertex3f)
Mem_Free(shadowvertex3f);
- shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
+ shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
}
}
numshadowmark = 0;
}
+void R_Shadow_PrepareShadowSides(int numtris)
+{
+ if (maxshadowsides < numtris)
+ {
+ maxshadowsides = numtris;
+ if (shadowsides)
+ Mem_Free(shadowsides);
+ if (shadowsideslist)
+ Mem_Free(shadowsideslist);
+ shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
+ shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
+ }
+ numshadowsides = 0;
+}
+
static int R_Shadow_ConstructShadowVolume_ZFail(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
{
int i, j;
if (!numverts || !nummarktris)
return;
// make sure shadowelements is big enough for this volume
- if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
- R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
+ if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
+ R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
if (maxvertexupdate < numverts)
{
}
}
-void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, int vertex3f_bufferobject, int vertex3f_bufferoffset, const int *elements, int nummarktris, const int *marktris)
+int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
{
- int i, tris = nummarktris;
- int *outelement3i;
- const int *element;
- if (!numverts || !nummarktris)
+ // p1, p2, p3 are in the cubemap's local coordinate system
+ // bias = border/(size - border)
+ int mask = 0x3F;
+
+ float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
+ dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
+ dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
+ if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
+ mask &= (3<<4)
+ | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
+ | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
+ | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
+ if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
+ mask &= (3<<4)
+ | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
+ | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
+ | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
+
+ dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
+ dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
+ dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
+ if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
+ mask &= (3<<0)
+ | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
+ | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
+ | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
+ if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
+ mask &= (3<<0)
+ | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
+ | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
+ | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
+
+ dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
+ dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
+ dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
+ if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
+ mask &= (3<<2)
+ | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
+ | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
+ | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
+ if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
+ mask &= (3<<2)
+ | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
+ | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
+ | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
+
+ return mask;
+}
+
+int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
+{
+ // p is in the cubemap's local coordinate system
+ // bias = border/(size - border)
+ float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
+ float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
+ float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
+ int mask = 0x3F;
+ if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
+ if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
+ if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
+ if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
+ if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
+ if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
+ return mask;
+}
+
+void R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals)
+{
+ int t, tend;
+ const int *e;
+ const float *v[3];
+ float normal[3];
+ vec3_t p[3];
+ float bias;
+ unsigned char mask;
+ if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
return;
+ bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
+ tend = firsttriangle + numtris;
+ if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
+ {
+ // surface box entirely inside light box, no box cull
+ if (projectdirection)
+ {
+ for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+ {
+ v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
+ TriangleNormal(v[0], v[1], v[2], normal);
+ if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
+ {
+ Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
+ mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
+ totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
+ shadowsides[numshadowsides] = mask;
+ shadowsideslist[numshadowsides++] = t;
+ }
+ }
+ }
+ else
+ {
+ for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+ {
+ v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
+ if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
+ {
+ Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
+ mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
+ totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
+ shadowsides[numshadowsides] = mask;
+ shadowsideslist[numshadowsides++] = t;
+ }
+ }
+ }
+ }
+ else
+ {
+ // surface box not entirely inside light box, cull each triangle
+ if (projectdirection)
+ {
+ for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+ {
+ v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
+ TriangleNormal(v[0], v[1], v[2], normal);
+ if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
+ && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
+ {
+ Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
+ mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
+ totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
+ shadowsides[numshadowsides] = mask;
+ shadowsideslist[numshadowsides++] = t;
+ }
+ }
+ }
+ else
+ {
+ for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+ {
+ v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
+ if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
+ && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
+ {
+ Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
+ mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
+ totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
+ shadowsides[numshadowsides] = mask;
+ shadowsideslist[numshadowsides++] = t;
+ }
+ }
+ }
+ }
+}
+
+void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, const int *elements, int numsidetris, const int *sidetotals, const unsigned char *sides, const int *sidetris)
+{
+ int i, j, outtriangles = 0;
+ int *outelement3i[6];
+ if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
+ return;
+ outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
// make sure shadowelements is big enough for this mesh
- if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
- R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
+ if (maxshadowtriangles < outtriangles)
+ R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
- // gather up the (sparse) triangles into one array
- outelement3i = shadowelements;
- for (i = 0;i < nummarktris;i++)
+ // compute the offset and size of the separate index lists for each cubemap side
+ outtriangles = 0;
+ for (i = 0;i < 6;i++)
{
- element = elements + marktris[i] * 3;
- outelement3i[0] = element[0];
- outelement3i[1] = element[1];
- outelement3i[2] = element[2];
- outelement3i += 3;
+ outelement3i[i] = shadowelements + outtriangles * 3;
+ r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
+ r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
+ outtriangles += sidetotals[i];
}
- r_refdef.stats.lights_dynamicshadowtriangles += tris;
- r_refdef.stats.lights_shadowtriangles += tris;
- R_Mesh_VertexPointer(vertex3f, vertex3f_bufferobject, vertex3f_bufferoffset);
- R_Mesh_Draw(0, numverts, 0, tris, shadowelements, NULL, 0, 0);
+ // gather up the (sparse) triangles into separate index lists for each cubemap side
+ for (i = 0;i < numsidetris;i++)
+ {
+ const int *element = elements + sidetris[i] * 3;
+ for (j = 0;j < 6;j++)
+ {
+ if (sides[i] & (1 << j))
+ {
+ outelement3i[j][0] = element[0];
+ outelement3i[j][1] = element[1];
+ outelement3i[j][2] = element[2];
+ outelement3i[j] += 3;
+ }
+ }
+ }
+
+ Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
}
static void R_Shadow_MakeTextures_MakeCorona(void)
GL_DepthTest(true);
GL_DepthMask(false);
GL_Color(0, 0, 0, 1);
- GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
+ GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
r_shadow_drawbuffer = drawbuffer;
r_shadow_readbuffer = readbuffer;
+ r_shadow_cullface = r_refdef.view.cullface_back;
}
void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
qglStencilMask(~0);CHECKGLERROR
qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
+ r_refdef.view.cullface_back = r_shadow_cullface;
GL_CullFace(r_refdef.view.cullface_back);
GL_Color(1, 1, 1, 1);
GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
}
}
+static void R_Shadow_MakeVSDCT(void)
+{
+ // maps to a 2x3 texture rectangle with normalized coordinates
+ // +-
+ // XX
+ // YY
+ // ZZ
+ // stores abs(dir.xy), offset.xy/2.5
+ unsigned char data[4*6] =
+ {
+ 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
+ 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
+ 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
+ 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
+ 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
+ 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
+ };
+ r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
+}
+
void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
{
int i;
int status;
int maxsize;
- float nearclip, farclip;
+ float nearclip, farclip, bias;
r_viewport_t viewport;
CHECKGLERROR
- maxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
- if (r_shadow_shadowmapmaxsize != maxsize)
- {
- r_shadow_shadowmapmaxsize = maxsize;
-
- if (r_shadow_fborectangle)
- qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
- r_shadow_fborectangle = 0;
-
- if (r_shadow_fbo2d)
- qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
- r_shadow_fbo2d = 0;
-
- for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
- if (r_shadow_fbocubeside[i])
- qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
- memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
-
- if (r_shadow_shadowmaprectangletexture)
- R_FreeTexture(r_shadow_shadowmaprectangletexture);
- r_shadow_shadowmaprectangletexture = NULL;
-
- if (r_shadow_shadowmap2dtexture)
- R_FreeTexture(r_shadow_shadowmap2dtexture);
- r_shadow_shadowmap2dtexture = NULL;
-
- if (r_shadow_shadowmapcubeprojectiontexture)
- R_FreeTexture(r_shadow_shadowmapcubeprojectiontexture);
- r_shadow_shadowmapcubeprojectiontexture = NULL;
-
- for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
- if (r_shadow_shadowmapcubetexture[i])
- R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
- memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
-
- CHECKGLERROR
- }
+ maxsize = r_shadow_shadowmapmaxsize;
nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
farclip = 1.0f;
- r_shadow_shadowmap_bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
- r_shadow_shadowmap_parameters[0] = 1.0f - r_shadow_shadowmapping_bordersize.value / size;
- r_shadow_shadowmap_parameters[1] = 1.0f - r_shadow_shadowmapping_bordersize.value / size;
- r_shadow_shadowmap_parameters[2] = -(farclip + nearclip) / (farclip - nearclip);
- r_shadow_shadowmap_parameters[3] = -2.0f * nearclip * farclip / (farclip - nearclip);
- if (!r_shadow_shadowmapcubeprojectiontexture)
- r_shadow_shadowmapcubeprojectiontexture = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection");
- if (r_shadow_shadowmapping.integer == 1)
+ bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
+ r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
+ r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
+ r_shadow_shadowmapside = side;
+ r_shadow_shadowmapsize = size;
+ if (r_shadow_shadowmode == 1)
{
// complex unrolled cube approach (more flexible)
+ if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
+ R_Shadow_MakeVSDCT();
if (!r_shadow_shadowmap2dtexture)
{
#if 1
- r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*4);
+ int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
+ r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
R_SetupShowDepthShader();
qglClearColor(1,1,1,1);CHECKGLERROR
}
- R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
- r_shadow_shadowmap_texturescale[0] = (float)size / R_TextureWidth(r_shadow_shadowmap2dtexture);
- r_shadow_shadowmap_texturescale[1] = (float)size / R_TextureHeight(r_shadow_shadowmap2dtexture);
+ R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
+ r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
+ r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
+ r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
+ r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
}
- else if (r_shadow_shadowmapping.integer == 2)
+ else if (r_shadow_shadowmode == 2)
{
// complex unrolled cube approach (more flexible)
+ if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
+ R_Shadow_MakeVSDCT();
if (!r_shadow_shadowmaprectangletexture)
{
#if 1
- r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", size*2, size*4);
+ r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
R_SetupShowDepthShader();
qglClearColor(1,1,1,1);CHECKGLERROR
}
- R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
- r_shadow_shadowmap_texturescale[0] = size;
- r_shadow_shadowmap_texturescale[1] = size;
+ R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
+ r_shadow_shadowmap_texturescale[0] = 1.0f;
+ r_shadow_shadowmap_texturescale[1] = 1.0f;
+ r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
+ r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
}
- else if (r_shadow_shadowmapping.integer == 3)
+ else if (r_shadow_shadowmode == 3)
{
// simple cube approach
if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
{
-#if 1
- r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size);
+ #if 1
+ r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
for (i = 0;i < 6;i++)
{
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + i, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
}
-#endif
+ #endif
}
CHECKGLERROR
R_Shadow_RenderMode_Reset();
R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
+ r_shadow_shadowmap_parameters[0] = 1.0f;
+ r_shadow_shadowmap_parameters[1] = 1.0f;
r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
}
CHECKGLERROR
R_SetViewport(&viewport);
GL_PolygonOffset(0, 0);
- GL_CullFace(GL_NONE); // quake is backwards
+ if(r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 2)
+ {
+ static qboolean cullfront[6] = { false, true, false, true, true, false };
+ if(cullfront[side]) r_refdef.view.cullface_back = r_refdef.view.cullface_front;
+ }
+ GL_CullFace(r_refdef.view.cullface_back);
GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
GL_DepthMask(true);
GL_DepthTest(true);
CHECKGLERROR
if (shadowmapping)
{
- if (r_shadow_shadowmapping.integer == 1)
+ if (r_shadow_shadowmode == 1)
{
r_shadow_usingshadowmap2d = true;
R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
CHECKGLERROR
}
- else if (r_shadow_shadowmapping.integer == 2)
+ else if (r_shadow_shadowmode == 2)
{
r_shadow_usingshadowmaprect = true;
R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
CHECKGLERROR
}
- else if (r_shadow_shadowmapping.integer == 3)
+ else if (r_shadow_shadowmode == 3)
{
r_shadow_usingshadowmapcube = true;
R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
CHECKGLERROR
}
+
+ if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
+ {
+ R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
+ CHECKGLERROR
+ }
}
}
else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
R_Shadow_RenderMode_Reset();
R_Shadow_RenderMode_ActiveLight(NULL);
GL_DepthMask(true);
- GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
+ GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
}
int sign[8];
float f;
- r_shadow_lightscissor[0] = r_refdef.view.x;
- r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
- r_shadow_lightscissor[2] = r_refdef.view.width;
- r_shadow_lightscissor[3] = r_refdef.view.height;
+ r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
+ r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
+ r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
+ r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
if (!r_shadow_scissor.integer)
return false;
// now convert the scissor rectangle to integer screen coordinates
ix1 = (int)(x1 - 1.0f);
- iy1 = (int)(y1 - 1.0f);
+ iy1 = vid.height - (int)(y2 - 1.0f);
ix2 = (int)(x2 + 1.0f);
- iy2 = (int)(y2 + 1.0f);
+ iy2 = vid.height - (int)(y1 + 1.0f);
//Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
// clamp it to the screen
- if (ix1 < r_refdef.view.x) ix1 = r_refdef.view.x;
- if (iy1 < r_refdef.view.y) iy1 = r_refdef.view.y;
- if (ix2 > r_refdef.view.x + r_refdef.view.width) ix2 = r_refdef.view.x + r_refdef.view.width;
- if (iy2 > r_refdef.view.y + r_refdef.view.height) iy2 = r_refdef.view.y + r_refdef.view.height;
+ if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
+ if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
+ if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
+ if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
// if it is inside out, it's not visible
if (ix2 <= ix1 || iy2 <= iy1)
// the light area is visible, set up the scissor rectangle
r_shadow_lightscissor[0] = ix1;
- r_shadow_lightscissor[1] = vid.height - iy2;
+ r_shadow_lightscissor[1] = iy1;
r_shadow_lightscissor[2] = ix2 - ix1;
r_shadow_lightscissor[3] = iy2 - iy1;
// compile the light
rtlight->compiled = true;
+ rtlight->shadowmode = rtlight->shadow ? r_shadow_shadowmode : -1;
rtlight->static_numleafs = 0;
rtlight->static_numleafpvsbytes = 0;
rtlight->static_leaflist = NULL;
if (model && model->GetLightInfo)
{
- // this variable must be set for the CompileShadowVolume code
+ // this variable must be set for the CompileShadowVolume/CompileShadowMap code
r_shadow_compilingrtlight = rtlight;
R_Shadow_EnlargeLeafSurfaceTrisBuffer(model->brush.num_leafs, model->num_surfaces, model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles, model->surfmesh.num_triangles);
model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs);
memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
if (rtlight->static_numlighttrispvsbytes)
memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
- if (model->CompileShadowVolume && rtlight->shadow)
- model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
+ if (rtlight->shadowmode <= 0)
+ {
+ if (model->CompileShadowVolume && rtlight->shadow)
+ model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
+ }
+ else
+ {
+ if (model->CompileShadowMap && rtlight->shadow)
+ model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
+ }
// now we're done compiling the rtlight
r_shadow_compilingrtlight = NULL;
}
if (rtlight->static_meshchain_shadow_zfail)
Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
rtlight->static_meshchain_shadow_zfail = NULL;
+ if (rtlight->static_meshchain_shadow_shadowmap)
+ Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
+ rtlight->static_meshchain_shadow_shadowmap = NULL;
// these allocations are grouped
if (rtlight->static_surfacelist)
Mem_Free(rtlight->static_surfacelist);
#endif
}
+void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
+{
+ shadowmesh_t *mesh;
+
+ RSurf_ActiveWorldEntity();
+
+ if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
+ {
+ CHECKGLERROR
+ GL_CullFace(GL_NONE);
+ mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
+ for (;mesh;mesh = mesh->next)
+ {
+ if (!mesh->sidetotals[r_shadow_shadowmapside])
+ continue;
+ r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
+ R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
+ R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
+ }
+ CHECKGLERROR
+ }
+ else if (r_refdef.scene.worldentity->model)
+ r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
+
+ rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
+}
+
void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
{
qboolean zpass;
msurface_t *surface;
RSurf_ActiveWorldEntity();
- if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
- {
- if (r_refdef.scene.worldentity->model)
- r_refdef.scene.worldmodel->DrawShadowMap(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
- rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
- return;
- }
if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
{
relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
- ent->model->DrawShadowMap(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
+ {
+ vec3_t radius, worldorigin, lightorigin;
+ VectorSubtract(ent->maxs, ent->mins, radius);
+ VectorScale(radius, 0.5f, radius);
+ VectorAdd(ent->mins, radius, worldorigin);
+ Matrix4x4_Transform(&rsurface.rtlight->matrix_worldtolight, worldorigin, lightorigin);
+ if (R_Shadow_CalcSphereSideMask(lightorigin, VectorLength(radius) / relativeshadowradius, r_shadow_shadowmapborder / (float)(r_shadow_shadowmapsize - r_shadow_shadowmapborder)) & (1 << r_shadow_shadowmapside))
+ ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
+ }
else
ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
}
-/*
-{{ 0, 0, 0}, "px", true, true, true},
-{{ 0, 90, 0}, "py", false, true, false},
-{{ 0, 180, 0}, "nx", false, false, true},
-{{ 0, 270, 0}, "ny", true, false, false},
-{{-90, 180, 0}, "pz", false, false, true},
-{{ 90, 180, 0}, "nz", false, false, true}
-*/
-
-static const double shadowviewmat16[6][4][4] =
-{
- {
- {-1, 0, 0, 0},
- { 0, -1, 0, 0},
- { 0, 0, 1, 0},
- { 0, 0, 0, 1},
- },
- {
- { 0, -1, 0, 0},
- {-1, 0, 0, 0},
- { 0, 0, 1, 0},
- { 0, 0, 0, 1},
- },
- {
- {-1, 0, 0, 0},
- { 0, -1, 0, 0},
- { 0, 0, 1, 0},
- { 0, 0, 0, 1},
- },
- {
- { 0, -1, 0, 0},
- {-1, 0, 0, 0},
- { 0, 0, 1, 0},
- { 0, 0, 0, 1},
- },
- {
- { 0, 0, 1, 0},
- { 0, -1, 0, 0},
- { 1, 0, 0, 0},
- { 0, 0, 0, 1},
- },
- {
- { 0, 0, -1, 0},
- { 0, -1, 0, 0},
- {-1, 0, 0, 0},
- { 0, 0, 0, 1},
- },
-};
-
void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
{
int i;
// all at once at the start of a level, not when it stalls gameplay.
// (especially important to benchmarks)
// compile light
- if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
+ if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
+ {
+ if (rtlight->compiled)
+ R_RTLight_Uncompile(rtlight);
R_RTLight_Compile(rtlight);
+ }
+
// load cubemap
rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
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_shadowmapping_maxsize.integer);
- if (castshadows && r_shadow_shadowmapping.integer >= 1 && r_shadow_shadowmapping.integer <= 3 && r_glsl.integer && gl_support_fragment_shader)
+ if (castshadows && r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 3 && r_glsl.integer && gl_support_fragment_shader)
{
int side;
int size;
if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
r_shadow_shadowmaplod = i;
- size = lodlinear;
- if (r_shadow_shadowmapping.integer == 3)
- size = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) >> r_shadow_shadowmaplod;
+ size = r_shadow_shadowmode == 3 ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
size = bound(1, size, 2048);
//Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
{
R_Shadow_RenderMode_ShadowMap(side, true, size);
if (numsurfaces)
- R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
+ R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs);
for (i = 0;i < numshadowentities;i++)
R_Shadow_DrawEntityShadow(shadowentities[i]);
}
R_Shadow_RenderMode_ShadowMap(side, false, size);
for (i = 0;i < numshadowentities_noselfshadow;i++)
R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
-#if 0
- if (r_shadow_shadowmapping.integer == 1)
- {
- int w = R_TextureWidth(r_shadow_shadowmap2dtexture);
- int h = R_TextureHeight(r_shadow_shadowmap2dtexture);
- static int once = true;
- if (once)
- {
- unsigned char *blah = Z_Malloc(w*h*4);
- qglReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, blah);CHECKGLERROR
- FS_WriteFile("testshadowmap.bin", blah, w*h*4);
- Z_Free(blah);
- }
- once = false;
- }
-#endif
}
// render lighting using the depth texture as shadowmap
{
// draw stencil shadow volumes to mask off pixels that are in shadow
// so that they won't receive lighting
+ GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
R_Shadow_ClearStencil();
if (numsurfaces)
R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
dlight_t *light;
size_t range;
+ if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) ||
+ (r_shadow_shadowmode != 0) != (r_shadow_shadowmapping.integer != 0) ||
+ r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
+ r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
+ r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
+ r_shadow_shadowmapprecision != r_shadow_shadowmapping_precision.integer ||
+ r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
+ R_Shadow_FreeShadowMaps();
+
if (r_editlights.integer)
R_Shadow_DrawLightSprites();
R_Shadow_RenderMode_End();
}
+extern const float r_screenvertex3f[12];
extern void R_SetupView(qboolean allowwaterclippingplane);
+extern void R_ResetViewRendering3D(void);
+extern void R_ResetViewRendering2D(void);
extern cvar_t r_shadows;
extern cvar_t r_shadows_darken;
-extern cvar_t r_shadows_drawafterrtlightning;
+extern cvar_t r_shadows_drawafterrtlighting;
extern cvar_t r_shadows_castfrombmodels;
extern cvar_t r_shadows_throwdistance;
extern cvar_t r_shadows_throwdirection;
vec3_t relativelightdirection;
vec3_t relativeshadowmins, relativeshadowmaxs;
vec3_t tmp, shadowdir;
- float vertex3f[12];
- r_viewport_t viewport;
if (!r_drawentities.integer || !gl_stencil)
return;
CHECKGLERROR
- GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
-
- r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
-
- if (gl_ext_separatestencil.integer)
- {
- r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
- r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
- }
- else if (gl_ext_stenciltwoside.integer)
- {
- r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
- r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
- }
- else
- {
- r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
- r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
- }
+ R_ResetViewRendering3D();
+ //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();
+ R_Shadow_RenderMode_ActiveLight(NULL);
+ r_shadow_lightscissor[0] = r_refdef.view.x;
+ r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
+ r_shadow_lightscissor[2] = r_refdef.view.width;
+ r_shadow_lightscissor[3] = r_refdef.view.height;
+ R_Shadow_RenderMode_StencilShadowVolumes(false);
// get shadow dir
if (r_shadows.integer == 2)
}
// not really the right mode, but this will disable any silly stencil features
- R_Shadow_RenderMode_VisibleLighting(true, true);
-
- // vertex coordinates for a quad that covers the screen exactly
- vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
- vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
- vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
- vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
+ R_Shadow_RenderMode_End();
// set up ortho view for rendering this pass
- R_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, 0, 0, 1, 1, -10, 100, NULL);
- R_SetViewport(&viewport);
- GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
- GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
- GL_ScissorTest(true);
- R_Mesh_Matrix(&identitymatrix);
- R_Mesh_ResetTextureState();
- R_Mesh_VertexPointer(vertex3f, 0, 0);
+ //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
+ //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
+ //GL_ScissorTest(true);
+ //R_Mesh_Matrix(&identitymatrix);
+ //R_Mesh_ResetTextureState();
+ R_ResetViewRendering2D();
+ R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
R_Mesh_ColorPointer(NULL, 0, 0);
+ R_SetupGenericShader(false);
// set up a darkening blend on shadowed areas
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- GL_DepthRange(0, 1);
- GL_DepthTest(false);
- GL_DepthMask(false);
- GL_PolygonOffset(0, 0);CHECKGLERROR
+ //GL_DepthRange(0, 1);
+ //GL_DepthTest(false);
+ //GL_DepthMask(false);
+ //GL_PolygonOffset(0, 0);CHECKGLERROR
GL_Color(0, 0, 0, r_shadows_darken.value);
- GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
- qglDepthFunc(GL_ALWAYS);CHECKGLERROR
+ //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
+ //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
qglEnable(GL_STENCIL_TEST);CHECKGLERROR
qglStencilMask(~0);CHECKGLERROR
qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
R_SetViewport(&r_refdef.view.viewport);
// restore other state to normal
- R_Shadow_RenderMode_End();
+ //R_Shadow_RenderMode_End();
}
void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
else
{
// FIXME: these traces should scan all render entities instead of cl.world
- if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
+ if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
return;
}
VectorScale(rtlight->color, cscale, color);
if (rating >= 0.95)
{
rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
- if (bestrating < rating && CL_Move(light->origin, vec3_origin, vec3_origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
+ if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
{
bestrating = rating;
best = light;
vec3_t dest, endpos;
trace_t trace;
VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
- trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
+ trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
if (trace.fraction < 1)
{
dist = trace.fraction * r_editlights_cursordistance.value;
light = r_refdef.scene.lights[i];
Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
f = 1 - VectorLength2(v);
- if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
+ if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
}
}