X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=r_shadow.c;h=c7dc780fbc46853752808ed2b45b58043abee87f;hb=dbc428d618fb980cd4e4baba4706dd328b08847b;hp=8151870717d2e1d8d039313d09ebb3ed7875acaf;hpb=96a91bc930e06aa41e3d9d9df6fb1617e6b5830a;p=xonotic%2Fdarkplaces.git diff --git a/r_shadow.c b/r_shadow.c index 81518707..c7dc780f 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -171,17 +171,23 @@ r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_N qboolean r_shadow_usingshadowmaprect; qboolean r_shadow_usingshadowmap2d; qboolean r_shadow_usingshadowmapcube; -float r_shadow_shadowmap_texturescale[4]; +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_shadowmapvsdct; +int r_shadow_shadowmapfilterquality; +int r_shadow_shadowmaptexturetype; +int r_shadow_shadowmapprecision; int r_shadow_shadowmapmaxsize; -int r_shadow_shadowmapfilter; +qboolean r_shadow_shadowmapvsdct; +qboolean r_shadow_shadowmapsampler; +int r_shadow_shadowmappcf; int r_shadow_shadowmapborder; int r_shadow_lightscissor[4]; @@ -197,6 +203,11 @@ int *shadowmark; int *shadowmarklist; int shadowmarkcount; +int maxshadowsides; +int numshadowsides; +unsigned char *shadowsides; +int *shadowsideslist; + int maxvertexupdate; int *vertexupdate; int *vertexremap; @@ -224,7 +235,7 @@ rtexture_t *r_shadow_lightcorona; rtexture_t *r_shadow_shadowmaprectangletexture; rtexture_t *r_shadow_shadowmap2dtexture; rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS]; -rtexture_t *r_shadow_shadowmapcubeprojectiontexture[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 @@ -263,7 +274,9 @@ cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compi 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", "512", "shadowmap size limit"}; @@ -338,18 +351,73 @@ cachepic_t *r_editlights_sprcubemaplight; cachepic_t *r_editlights_sprcubemapnoshadowlight; cachepic_t *r_editlights_sprselection; -void R_Shadow_FreeShadowMaps(void) +void R_Shadow_SetShadowMode(void) { - int i; - r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048); - r_shadow_shadowmode = r_shadow_shadowmapping.integer; - r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer; - r_shadow_shadowmapfilter = r_shadow_shadowmapping_filterquality.integer; + 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(); - CHECKGLERROR if (r_shadow_fborectangle) qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle); r_shadow_fborectangle = 0; @@ -378,10 +446,9 @@ void R_Shadow_FreeShadowMaps(void) R_FreeTexture(r_shadow_shadowmapcubetexture[i]); memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture)); - for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++) - if (r_shadow_shadowmapcubeprojectiontexture[i]) - R_FreeTexture(r_shadow_shadowmapcubeprojectiontexture[i]); - memset(r_shadow_shadowmapcubeprojectiontexture, 0, sizeof(r_shadow_shadowmapcubeprojectiontexture)); + if (r_shadow_shadowmapvsdcttexture) + R_FreeTexture(r_shadow_shadowmapvsdcttexture); + r_shadow_shadowmapvsdcttexture = NULL; CHECKGLERROR } @@ -397,12 +464,16 @@ void r_shadow_start(void) r_shadow_shadowmaprectangletexture = NULL; r_shadow_shadowmap2dtexture = NULL; memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture)); - memset(r_shadow_shadowmapcubeprojectiontexture, 0, sizeof(r_shadow_shadowmapcubeprojectiontexture)); + r_shadow_shadowmapvsdcttexture = NULL; r_shadow_shadowmapmaxsize = 0; r_shadow_shadowmapsize = 0; r_shadow_shadowmaplod = 0; - r_shadow_shadowmapvsdct = 0; - r_shadow_shadowmapfilter = 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; r_shadow_fbo2d = 0; memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside)); @@ -426,6 +497,10 @@ void r_shadow_start(void) 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; @@ -477,6 +552,14 @@ void r_shadow_shutdown(void) 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); @@ -575,7 +658,9 @@ void R_Shadow_Init(void) 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); @@ -614,6 +699,10 @@ void R_Shadow_Init(void) 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; @@ -646,15 +735,17 @@ matrix4x4_t matrix_attenuationz = } }; -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) @@ -662,7 +753,7 @@ void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles) 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])); } } @@ -735,6 +826,21 @@ void R_Shadow_PrepareShadowMark(int numtris) 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; @@ -1130,8 +1236,8 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, 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) { @@ -1203,32 +1309,199 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, } } -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) @@ -1374,6 +1647,7 @@ void R_Shadow_RenderMode_Begin(void) 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) @@ -1407,6 +1681,7 @@ void R_Shadow_RenderMode_Reset(void) 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); @@ -1475,6 +1750,26 @@ void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass) } } +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; @@ -1489,15 +1784,18 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size) 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_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod]) - r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod] = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection", 2, 4, size, r_shadow_shadowmapborder); + 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", maxsize*2, maxsize*4, r_shadow_shadowmapfilter == 1 || r_shadow_shadowmapfilter == 2); + 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 @@ -1524,22 +1822,22 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size) 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_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 / 2) * (1.0f - r_shadow_shadowmapborder / (float)size); - r_shadow_shadowmap_parameters[1] = (0.5f / 4) * (1.0f - r_shadow_shadowmapborder / (float)size); + 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_shadowmode == 2) { // complex unrolled cube approach (more flexible) - if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod]) - r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod] = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection", 2, 3, size, r_shadow_shadowmapborder); + 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", maxsize*2, maxsize*3, r_shadow_shadowmapfilter == 1 || r_shadow_shadowmapfilter == 2); + 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 @@ -1567,10 +1865,10 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size) qglClearColor(1,1,1,1);CHECKGLERROR } R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL); - r_shadow_shadowmap_texturescale[0] = 2*size; - r_shadow_shadowmap_texturescale[1] = 3*size; + 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] = size; + r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size; r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE; } else if (r_shadow_shadowmode == 3) @@ -1579,7 +1877,7 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size) if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) { #if 1 - r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", bound(1, maxsize >> r_shadow_shadowmaplod, 2048), r_shadow_shadowmapfilter == 1 || r_shadow_shadowmapfilter == 2); + 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++) { @@ -1616,12 +1914,15 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size) r_shadow_shadowmap_parameters[1] = 1.0f; r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE; } - r_shadow_shadowmap_texturescale[2] = 1.0f / r_shadow_shadowmap_texturescale[0]; - r_shadow_shadowmap_texturescale[3] = 1.0f / r_shadow_shadowmap_texturescale[1]; 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); @@ -1678,7 +1979,7 @@ void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qb if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect)) { - R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod])); + R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture)); CHECKGLERROR } } @@ -3005,6 +3306,7 @@ void R_RTLight_Compile(rtlight_t *rtlight) // 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; @@ -3020,7 +3322,7 @@ void R_RTLight_Compile(rtlight_t *rtlight) 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); @@ -3048,8 +3350,16 @@ void R_RTLight_Compile(rtlight_t *rtlight) 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; } @@ -3095,6 +3405,9 @@ void R_RTLight_Uncompile(rtlight_t *rtlight) 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); @@ -3292,6 +3605,33 @@ void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight) #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; @@ -3301,13 +3641,6 @@ void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned 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) { @@ -3377,7 +3710,15 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent) 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 @@ -3429,55 +3770,6 @@ void R_Shadow_DrawEntityLight(entity_render_t *ent) 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; @@ -3507,8 +3799,13 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) // 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; @@ -3716,7 +4013,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear) r_shadow_shadowmaplod = i; - size = r_shadow_shadowmapvsdct || r_shadow_shadowmode ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear; + 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); @@ -3726,7 +4023,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) { 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]); } @@ -3821,7 +4118,13 @@ void R_ShadowVolumeLighting(qboolean visible) dlight_t *light; size_t range; - if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) || r_shadow_shadowmode != r_shadow_shadowmapping.integer || r_shadow_shadowmapvsdct != r_shadow_shadowmapping_vsdct.integer || r_shadow_shadowmapfilter != r_shadow_shadowmapping_filterquality.integer || r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16)) + 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) @@ -4035,7 +4338,7 @@ void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale) 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); @@ -4416,7 +4719,7 @@ void R_Shadow_SelectLightInView(void) 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; @@ -4862,7 +5165,7 @@ void R_Shadow_SetCursorLocationForView(void) 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; @@ -5536,7 +5839,7 @@ void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffu 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); } }