X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=r_shadow.c;h=3f570a5d0b3da8d4f543cb457450eeebe3ede192;hb=fb846a34ee193c8bf32132f7b6f165c52aa2d619;hp=1e6966133d9a483cc2dba76a75da374d2ba82e03;hpb=6f77dd97d9abe654f6a7c7a5a872a4ddc79b5737;p=xonotic%2Fdarkplaces.git diff --git a/r_shadow.c b/r_shadow.c index 1e696613..3f570a5d 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -146,6 +146,7 @@ typedef enum r_shadow_rendermode_e { R_SHADOW_RENDERMODE_NONE, R_SHADOW_RENDERMODE_STENCIL, + R_SHADOW_RENDERMODE_SEPARATESTENCIL, R_SHADOW_RENDERMODE_STENCILTWOSIDE, R_SHADOW_RENDERMODE_LIGHT_VERTEX, R_SHADOW_RENDERMODE_LIGHT_DOT3, @@ -184,6 +185,10 @@ int r_shadow_buffer_numsurfacepvsbytes; unsigned char *r_shadow_buffer_surfacepvs; int *r_shadow_buffer_surfacelist; +// current light's cull box (copied out of an rtlight or calculated by GetLightInfo) +vec3_t r_shadow_rtlight_cullmins; +vec3_t r_shadow_rtlight_cullmaxs; + rtexturepool_t *r_shadow_texturepool; rtexture_t *r_shadow_attenuation2dtexture; rtexture_t *r_shadow_attenuation3dtexture; @@ -198,26 +203,30 @@ cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"}; cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"}; cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"}; -cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25", "how bright the forced flat gloss should look if r_shadow_gloss is 2"}; -cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"}; +cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"}; +cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "2", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"}; +cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"}; cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5", "changes attenuation texture generation (does not affect r_glsl lighting)"}; cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_glsl lighting)"}; cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"}; cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"}; cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"}; +cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"}; cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"}; cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"}; -cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal culling optimizations on dynamic lights (slow! you probably don't want this!)"}; +cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"}; cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"}; cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1", "enables shadows from dynamic lights when using full world lighting"}; cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"}; cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"}; cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"}; cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"}; +cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp 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_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"}; cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"}; cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_glsl lighting)"}; +cvar_t gl_ext_separatestencil = {0, "gl_ext_separatetencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"}; cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"}; cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"}; cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"}; @@ -359,7 +368,6 @@ void R_Shadow_Help_f(void) "r_shadow_projectdistance : shadow volume projection distance\n" "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n" "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n" -"r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n" "r_shadow_realtime_world : use high quality world lighting mode\n" "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n" "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n" @@ -385,24 +393,28 @@ void R_Shadow_Init(void) Cvar_RegisterVariable(&r_shadow_gloss); Cvar_RegisterVariable(&r_shadow_gloss2intensity); Cvar_RegisterVariable(&r_shadow_glossintensity); + Cvar_RegisterVariable(&r_shadow_glossexponent); Cvar_RegisterVariable(&r_shadow_lightattenuationpower); Cvar_RegisterVariable(&r_shadow_lightattenuationscale); Cvar_RegisterVariable(&r_shadow_lightintensityscale); Cvar_RegisterVariable(&r_shadow_portallight); Cvar_RegisterVariable(&r_shadow_projectdistance); + Cvar_RegisterVariable(&r_shadow_frontsidecasting); Cvar_RegisterVariable(&r_shadow_realtime_dlight); Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows); - Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling); + Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling); Cvar_RegisterVariable(&r_shadow_realtime_world); Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows); Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps); Cvar_RegisterVariable(&r_shadow_realtime_world_shadows); Cvar_RegisterVariable(&r_shadow_realtime_world_compile); Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow); + Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp); Cvar_RegisterVariable(&r_shadow_scissor); Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor); Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset); Cvar_RegisterVariable(&r_shadow_texture3d); + Cvar_RegisterVariable(&gl_ext_separatestencil); Cvar_RegisterVariable(&gl_ext_stenciltwoside); if (gamemode == GAME_TENEBRAE) { @@ -524,12 +536,18 @@ void R_Shadow_PrepareShadowMark(int numtris) numshadowmark = 0; } -int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris) +int R_Shadow_ConstructShadowVolume(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; int outtriangles = 0, outvertices = 0; const int *element; const float *vertex; + float ratio, direction[3], projectvector[3]; + + if (projectdirection) + VectorScale(projectdirection, projectdistance, projectvector); + else + VectorClear(projectvector); if (maxvertexupdate < innumvertices) { @@ -553,91 +571,183 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int * for (i = 0;i < numshadowmarktris;i++) shadowmark[shadowmarktris[i]] = shadowmarkcount; - for (i = 0;i < numshadowmarktris;i++) + // create the vertices + if (projectdirection) { - element = inelement3i + shadowmarktris[i] * 3; - // make sure the vertices are created - for (j = 0;j < 3;j++) + for (i = 0;i < numshadowmarktris;i++) { - if (vertexupdate[element[j]] != vertexupdatenum) + element = inelement3i + shadowmarktris[i] * 3; + for (j = 0;j < 3;j++) { - float ratio, direction[3]; - vertexupdate[element[j]] = vertexupdatenum; - vertexremap[element[j]] = outvertices; - vertex = invertex3f + element[j] * 3; - // project one copy of the vertex to the sphere radius of the light - // (FIXME: would projecting it to the light box be better?) - VectorSubtract(vertex, projectorigin, direction); - ratio = projectdistance / VectorLength(direction); - VectorCopy(vertex, outvertex3f); - VectorMA(projectorigin, ratio, direction, (outvertex3f + 3)); - outvertex3f += 6; - outvertices += 2; + if (vertexupdate[element[j]] != vertexupdatenum) + { + vertexupdate[element[j]] = vertexupdatenum; + vertexremap[element[j]] = outvertices; + vertex = invertex3f + element[j] * 3; + // project one copy of the vertex according to projectvector + VectorCopy(vertex, outvertex3f); + VectorAdd(vertex, projectvector, (outvertex3f + 3)); + outvertex3f += 6; + outvertices += 2; + } } } } - - for (i = 0;i < numshadowmarktris;i++) + else { - int remappedelement[3]; - int markindex; - const int *neighbortriangle; - - markindex = shadowmarktris[i] * 3; - element = inelement3i + markindex; - neighbortriangle = inneighbor3i + markindex; - // output the front and back triangles - outelement3i[0] = vertexremap[element[0]]; - outelement3i[1] = vertexremap[element[1]]; - outelement3i[2] = vertexremap[element[2]]; - outelement3i[3] = vertexremap[element[2]] + 1; - outelement3i[4] = vertexremap[element[1]] + 1; - outelement3i[5] = vertexremap[element[0]] + 1; - - outelement3i += 6; - outtriangles += 2; - // output the sides (facing outward from this triangle) - if (shadowmark[neighbortriangle[0]] != shadowmarkcount) - { - remappedelement[0] = vertexremap[element[0]]; - remappedelement[1] = vertexremap[element[1]]; - outelement3i[0] = remappedelement[1]; - outelement3i[1] = remappedelement[0]; - outelement3i[2] = remappedelement[0] + 1; - outelement3i[3] = remappedelement[1]; - outelement3i[4] = remappedelement[0] + 1; - outelement3i[5] = remappedelement[1] + 1; - - outelement3i += 6; - outtriangles += 2; + for (i = 0;i < numshadowmarktris;i++) + { + element = inelement3i + shadowmarktris[i] * 3; + for (j = 0;j < 3;j++) + { + if (vertexupdate[element[j]] != vertexupdatenum) + { + vertexupdate[element[j]] = vertexupdatenum; + vertexremap[element[j]] = outvertices; + vertex = invertex3f + element[j] * 3; + // project one copy of the vertex to the sphere radius of the light + // (FIXME: would projecting it to the light box be better?) + VectorSubtract(vertex, projectorigin, direction); + ratio = projectdistance / VectorLength(direction); + VectorCopy(vertex, outvertex3f); + VectorMA(projectorigin, ratio, direction, (outvertex3f + 3)); + outvertex3f += 6; + outvertices += 2; + } + } } - if (shadowmark[neighbortriangle[1]] != shadowmarkcount) + } + + if (r_shadow_frontsidecasting.integer) + { + for (i = 0;i < numshadowmarktris;i++) { - remappedelement[1] = vertexremap[element[1]]; - remappedelement[2] = vertexremap[element[2]]; - outelement3i[0] = remappedelement[2]; - outelement3i[1] = remappedelement[1]; - outelement3i[2] = remappedelement[1] + 1; - outelement3i[3] = remappedelement[2]; - outelement3i[4] = remappedelement[1] + 1; - outelement3i[5] = remappedelement[2] + 1; + int remappedelement[3]; + int markindex; + const int *neighbortriangle; + + markindex = shadowmarktris[i] * 3; + element = inelement3i + markindex; + neighbortriangle = inneighbor3i + markindex; + // output the front and back triangles + outelement3i[0] = vertexremap[element[0]]; + outelement3i[1] = vertexremap[element[1]]; + outelement3i[2] = vertexremap[element[2]]; + outelement3i[3] = vertexremap[element[2]] + 1; + outelement3i[4] = vertexremap[element[1]] + 1; + outelement3i[5] = vertexremap[element[0]] + 1; outelement3i += 6; outtriangles += 2; + // output the sides (facing outward from this triangle) + if (shadowmark[neighbortriangle[0]] != shadowmarkcount) + { + remappedelement[0] = vertexremap[element[0]]; + remappedelement[1] = vertexremap[element[1]]; + outelement3i[0] = remappedelement[1]; + outelement3i[1] = remappedelement[0]; + outelement3i[2] = remappedelement[0] + 1; + outelement3i[3] = remappedelement[1]; + outelement3i[4] = remappedelement[0] + 1; + outelement3i[5] = remappedelement[1] + 1; + + outelement3i += 6; + outtriangles += 2; + } + if (shadowmark[neighbortriangle[1]] != shadowmarkcount) + { + remappedelement[1] = vertexremap[element[1]]; + remappedelement[2] = vertexremap[element[2]]; + outelement3i[0] = remappedelement[2]; + outelement3i[1] = remappedelement[1]; + outelement3i[2] = remappedelement[1] + 1; + outelement3i[3] = remappedelement[2]; + outelement3i[4] = remappedelement[1] + 1; + outelement3i[5] = remappedelement[2] + 1; + + outelement3i += 6; + outtriangles += 2; + } + if (shadowmark[neighbortriangle[2]] != shadowmarkcount) + { + remappedelement[0] = vertexremap[element[0]]; + remappedelement[2] = vertexremap[element[2]]; + outelement3i[0] = remappedelement[0]; + outelement3i[1] = remappedelement[2]; + outelement3i[2] = remappedelement[2] + 1; + outelement3i[3] = remappedelement[0]; + outelement3i[4] = remappedelement[2] + 1; + outelement3i[5] = remappedelement[0] + 1; + + outelement3i += 6; + outtriangles += 2; + } } - if (shadowmark[neighbortriangle[2]] != shadowmarkcount) + } + else + { + for (i = 0;i < numshadowmarktris;i++) { - remappedelement[0] = vertexremap[element[0]]; - remappedelement[2] = vertexremap[element[2]]; - outelement3i[0] = remappedelement[0]; - outelement3i[1] = remappedelement[2]; - outelement3i[2] = remappedelement[2] + 1; - outelement3i[3] = remappedelement[0]; - outelement3i[4] = remappedelement[2] + 1; - outelement3i[5] = remappedelement[0] + 1; + int remappedelement[3]; + int markindex; + const int *neighbortriangle; + + markindex = shadowmarktris[i] * 3; + element = inelement3i + markindex; + neighbortriangle = inneighbor3i + markindex; + // output the front and back triangles + outelement3i[0] = vertexremap[element[2]]; + outelement3i[1] = vertexremap[element[1]]; + outelement3i[2] = vertexremap[element[0]]; + outelement3i[3] = vertexremap[element[0]] + 1; + outelement3i[4] = vertexremap[element[1]] + 1; + outelement3i[5] = vertexremap[element[2]] + 1; outelement3i += 6; outtriangles += 2; + // output the sides (facing outward from this triangle) + if (shadowmark[neighbortriangle[0]] != shadowmarkcount) + { + remappedelement[0] = vertexremap[element[0]]; + remappedelement[1] = vertexremap[element[1]]; + outelement3i[0] = remappedelement[0]; + outelement3i[1] = remappedelement[1]; + outelement3i[2] = remappedelement[1] + 1; + outelement3i[3] = remappedelement[0]; + outelement3i[4] = remappedelement[1] + 1; + outelement3i[5] = remappedelement[0] + 1; + + outelement3i += 6; + outtriangles += 2; + } + if (shadowmark[neighbortriangle[1]] != shadowmarkcount) + { + remappedelement[1] = vertexremap[element[1]]; + remappedelement[2] = vertexremap[element[2]]; + outelement3i[0] = remappedelement[1]; + outelement3i[1] = remappedelement[2]; + outelement3i[2] = remappedelement[2] + 1; + outelement3i[3] = remappedelement[1]; + outelement3i[4] = remappedelement[2] + 1; + outelement3i[5] = remappedelement[1] + 1; + + outelement3i += 6; + outtriangles += 2; + } + if (shadowmark[neighbortriangle[2]] != shadowmarkcount) + { + remappedelement[0] = vertexremap[element[0]]; + remappedelement[2] = vertexremap[element[2]]; + outelement3i[0] = remappedelement[2]; + outelement3i[1] = remappedelement[0]; + outelement3i[2] = remappedelement[0] + 1; + outelement3i[3] = remappedelement[2]; + outelement3i[4] = remappedelement[0] + 1; + outelement3i[5] = remappedelement[2] + 1; + + outelement3i += 6; + outtriangles += 2; + } } } if (outnumvertices) @@ -645,12 +755,12 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int * return outtriangles; } -void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, int nummarktris, const int *marktris) +void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris) { int tris, outverts; if (projectdistance < 0.1) { - Con_Printf("R_Shadow_Volume: projectdistance %f\n"); + Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance); return; } if (!numverts || !nummarktris) @@ -658,16 +768,17 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, // make sure shadowelements is big enough for this volume if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts) R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255); - tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdistance, nummarktris, marktris); + tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris); r_refdef.stats.lights_dynamicshadowtriangles += tris; R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements); } -void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs) +void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, 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 t, tend; const int *e; const float *v[3]; + float normal[3]; if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs)) return; tend = firsttriangle + numtris; @@ -676,26 +787,59 @@ void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *inv && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2]) { // surface box entirely inside light box, no box cull - for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) - if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3)) - shadowmarklist[numshadowmark++] = t; + if (projectdirection) + { + for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + { + TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal); + if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)) + shadowmarklist[numshadowmark++] = t; + } + } + else + { + for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3)) + shadowmarklist[numshadowmark++] = t; + } } else { // surface box not entirely inside light box, cull each triangle - for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + if (projectdirection) { - v[0] = invertex3f + e[0] * 3; - v[1] = invertex3f + e[1] * 3; - v[2] = invertex3f + e[2] * 3; - if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]) - && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) - && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) - && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) - && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) - && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) - && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2]))) - shadowmarklist[numshadowmark++] = t; + 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) + && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) + && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) + && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) + && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) + && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) + && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2]))) + shadowmarklist[numshadowmark++] = 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]) + && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) + && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) + && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) + && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) + && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) + && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2]))) + shadowmarklist[numshadowmark++] = t; + } } } } @@ -715,11 +859,11 @@ void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *verte if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL) { // decrement stencil if backface is behind depthbuffer - qglCullFace(GL_BACK);CHECKGLERROR // quake is backwards, this culls front faces + GL_CullFace(GL_BACK); // quake is backwards, this culls front faces qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR R_Mesh_Draw(0, numvertices, numtriangles, element3i); // increment stencil if frontface is behind depthbuffer - qglCullFace(GL_FRONT);CHECKGLERROR // quake is backwards, this culls back faces + GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR } R_Mesh_Draw(0, numvertices, numtriangles, element3i); @@ -788,6 +932,8 @@ void R_Shadow_ValidateCvars(void) { if (r_shadow_texture3d.integer && !gl_texture3d) Cvar_SetValueQuick(&r_shadow_texture3d, 0); + if (gl_ext_separatestencil.integer && !gl_support_separatestencil) + Cvar_SetValueQuick(&gl_ext_separatestencil, 0); if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside) Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0); } @@ -820,16 +966,16 @@ void R_Shadow_RenderMode_Begin(void) R_Mesh_ColorPointer(NULL); R_Mesh_ResetTextureState(); GL_BlendFunc(GL_ONE, GL_ZERO); - GL_DepthMask(false); GL_DepthTest(true); + GL_DepthMask(false); GL_Color(0, 0, 0, 1); - qglCullFace(GL_FRONT);CHECKGLERROR // quake is backwards, this culls back faces - qglEnable(GL_CULL_FACE);CHECKGLERROR GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height); r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE; - if (gl_ext_stenciltwoside.integer) + if (gl_ext_separatestencil.integer) + r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL; + else if (gl_ext_stenciltwoside.integer) r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE; else r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL; @@ -860,26 +1006,38 @@ void R_Shadow_RenderMode_Reset(void) } R_Mesh_ColorPointer(NULL); R_Mesh_ResetTextureState(); + GL_DepthTest(true); + GL_DepthMask(false); + qglDepthFunc(GL_LEQUAL);CHECKGLERROR + qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR + qglDisable(GL_STENCIL_TEST);CHECKGLERROR + qglStencilMask(~0);CHECKGLERROR + qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR + qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR + GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces + GL_Color(1, 1, 1, 1); + GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1); + GL_BlendFunc(GL_ONE, GL_ZERO); } void R_Shadow_RenderMode_StencilShadowVolumes(void) { CHECKGLERROR R_Shadow_RenderMode_Reset(); - GL_Color(1, 1, 1, 1); GL_ColorMask(0, 0, 0, 0); - GL_BlendFunc(GL_ONE, GL_ZERO); - GL_DepthMask(false); - GL_DepthTest(true); qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR qglDepthFunc(GL_LESS);CHECKGLERROR - qglCullFace(GL_FRONT);CHECKGLERROR // quake is backwards, this culls back faces qglEnable(GL_STENCIL_TEST);CHECKGLERROR - qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR r_shadow_rendermode = r_shadow_shadowingrendermode; - if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE) + if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL) { - qglDisable(GL_CULL_FACE);CHECKGLERROR + GL_CullFace(GL_NONE); + qglStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR // quake is backwards, this is front faces + qglStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR // quake is backwards, this is back faces + } + else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE) + { + GL_CullFace(GL_NONE); qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces qglStencilMask(~0);CHECKGLERROR @@ -888,13 +1046,6 @@ void R_Shadow_RenderMode_StencilShadowVolumes(void) qglStencilMask(~0);CHECKGLERROR qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR } - else - { - qglEnable(GL_CULL_FACE);CHECKGLERROR - qglStencilMask(~0);CHECKGLERROR - // this is changed by every shadow render so its value here is unimportant - qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR - } GL_Clear(GL_STENCIL_BUFFER_BIT); r_refdef.stats.lights_clears++; } @@ -904,35 +1055,17 @@ void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent) CHECKGLERROR R_Shadow_RenderMode_Reset(); GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); - GL_DepthMask(false); - GL_DepthTest(true); - qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR - //qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR - GL_Color(1, 1, 1, 1); - GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1); - if (transparent) - { - qglDepthFunc(GL_LEQUAL);CHECKGLERROR - } - else + if (!transparent) { qglDepthFunc(GL_EQUAL);CHECKGLERROR } - qglCullFace(GL_FRONT);CHECKGLERROR // quake is backwards, this culls back faces - qglEnable(GL_CULL_FACE);CHECKGLERROR if (stenciltest) { qglEnable(GL_STENCIL_TEST);CHECKGLERROR + // only draw light where this geometry was already rendered AND the + // stencil is 128 (values other than this mean shadow) + qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR } - else - { - qglDisable(GL_STENCIL_TEST);CHECKGLERROR - } - qglStencilMask(~0);CHECKGLERROR - qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR - // only draw light where this geometry was already rendered AND the - // stencil is 128 (values other than this mean shadow) - qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR r_shadow_rendermode = r_shadow_lightingrendermode; // do global setup needed for the chosen lighting mode if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL) @@ -959,15 +1092,10 @@ void R_Shadow_RenderMode_VisibleShadowVolumes(void) CHECKGLERROR R_Shadow_RenderMode_Reset(); GL_BlendFunc(GL_ONE, GL_ONE); - GL_DepthMask(false); - GL_DepthTest(!r_showdisabledepthtest.integer); - qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR + GL_DepthTest(r_showshadowvolumes.integer < 2); GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1); - GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1); - qglDepthFunc(GL_GEQUAL);CHECKGLERROR - qglCullFace(GL_FRONT);CHECKGLERROR // this culls back - qglDisable(GL_CULL_FACE);CHECKGLERROR - qglDisable(GL_STENCIL_TEST);CHECKGLERROR + qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR + GL_CullFace(GL_NONE); r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES; } @@ -976,28 +1104,16 @@ void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transpar CHECKGLERROR R_Shadow_RenderMode_Reset(); GL_BlendFunc(GL_ONE, GL_ONE); - GL_DepthMask(false); - GL_DepthTest(!r_showdisabledepthtest.integer); - qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR + GL_DepthTest(r_showlighting.integer < 2); GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1); - GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1); - if (transparent) - { - qglDepthFunc(GL_LEQUAL);CHECKGLERROR - } - else + if (!transparent) { qglDepthFunc(GL_EQUAL);CHECKGLERROR } - qglCullFace(GL_FRONT);CHECKGLERROR // this culls back - qglEnable(GL_CULL_FACE);CHECKGLERROR if (stenciltest) { qglEnable(GL_STENCIL_TEST);CHECKGLERROR - } - else - { - qglDisable(GL_STENCIL_TEST);CHECKGLERROR + qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR } r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING; } @@ -1007,25 +1123,8 @@ void R_Shadow_RenderMode_End(void) CHECKGLERROR R_Shadow_RenderMode_Reset(); R_Shadow_RenderMode_ActiveLight(NULL); - GL_BlendFunc(GL_ONE, GL_ZERO); GL_DepthMask(true); - GL_DepthTest(true); - qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR - //qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR - GL_Color(1, 1, 1, 1); - GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1); GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height); - qglDepthFunc(GL_LEQUAL);CHECKGLERROR - qglCullFace(GL_FRONT);CHECKGLERROR // quake is backwards, this culls back faces - qglEnable(GL_CULL_FACE);CHECKGLERROR - qglDisable(GL_STENCIL_TEST);CHECKGLERROR - qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR - if (gl_support_stenciltwoside) - { - qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR - } - qglStencilMask(~0);CHECKGLERROR - qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE; } @@ -1625,6 +1724,7 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(int numsurfac static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale) { + float glossexponent; rmeshstate_t m; // FIXME: detect blendsquare! //if (!gl_support_blendsquare) @@ -1653,12 +1753,8 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(int numsurfa R_Mesh_ResetTextureState(); // square alpha in framebuffer a few times to make it shiny GL_BlendFunc(GL_ZERO, GL_DST_ALPHA); - // these comments are a test run through this math for intensity 0.5 - // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier) - // 0.25 * 0.25 = 0.0625 (this is another pass) - // 0.0625 * 0.0625 = 0.00390625 (this is another pass) - RSurf_DrawBatch_Simple(numsurfaces, surfacelist); - RSurf_DrawBatch_Simple(numsurfaces, surfacelist); + for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2) + RSurf_DrawBatch_Simple(numsurfaces, surfacelist); GL_LockArrays(0, 0); // fourth pass @@ -1705,12 +1801,8 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(int numsurfa R_Mesh_ResetTextureState(); // square alpha in framebuffer a few times to make it shiny GL_BlendFunc(GL_ZERO, GL_DST_ALPHA); - // these comments are a test run through this math for intensity 0.5 - // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier) - // 0.25 * 0.25 = 0.0625 (this is another pass) - // 0.0625 * 0.0625 = 0.00390625 (this is another pass) - RSurf_DrawBatch_Simple(numsurfaces, surfacelist); - RSurf_DrawBatch_Simple(numsurfaces, surfacelist); + for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2) + RSurf_DrawBatch_Simple(numsurfaces, surfacelist); GL_LockArrays(0, 0); // fourth pass @@ -1744,12 +1836,8 @@ static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(int numsurfa R_Mesh_ResetTextureState(); // square alpha in framebuffer a few times to make it shiny GL_BlendFunc(GL_ZERO, GL_DST_ALPHA); - // these comments are a test run through this math for intensity 0.5 - // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier) - // 0.25 * 0.25 = 0.0625 (this is another pass) - // 0.0625 * 0.0625 = 0.00390625 (this is another pass) - RSurf_DrawBatch_Simple(numsurfaces, surfacelist); - RSurf_DrawBatch_Simple(numsurfaces, surfacelist); + for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2) + RSurf_DrawBatch_Simple(numsurfaces, surfacelist); GL_LockArrays(0, 0); // fourth pass @@ -1981,18 +2069,12 @@ void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist) lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha; if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * rsurface_texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f)) return; - if ((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) - { - qglDisable(GL_CULL_FACE);CHECKGLERROR - } - else - { - qglEnable(GL_CULL_FACE);CHECKGLERROR - } + GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST)); + GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces if (rsurface_texture->colormapping) { - qboolean dopants = rsurface_texture->skin.pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f); - qboolean doshirt = rsurface_texture->skin.shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f); + qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f); + qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f); if (dopants) { lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0]; @@ -2012,16 +2094,17 @@ void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist) switch (r_shadow_rendermode) { case R_SHADOW_RENDERMODE_VISIBLELIGHTING: - R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->skin.pants, rsurface_texture->skin.shirt, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt); + GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer); + R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt); break; case R_SHADOW_RENDERMODE_LIGHT_GLSL: - R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->skin.pants, rsurface_texture->skin.shirt, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt); + R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt); break; case R_SHADOW_RENDERMODE_LIGHT_DOT3: - R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->skin.pants, rsurface_texture->skin.shirt, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt); + R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt); break; case R_SHADOW_RENDERMODE_LIGHT_VERTEX: - R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->skin.pants, rsurface_texture->skin.shirt, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt); + R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt); break; default: Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode); @@ -2033,16 +2116,17 @@ void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist) switch (r_shadow_rendermode) { case R_SHADOW_RENDERMODE_VISIBLELIGHTING: - R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false); + GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer); + R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false); break; case R_SHADOW_RENDERMODE_LIGHT_GLSL: - R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false); + R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false); break; case R_SHADOW_RENDERMODE_LIGHT_DOT3: - R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false); + R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false); break; case R_SHADOW_RENDERMODE_LIGHT_VERTEX: - R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false); + R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false); break; default: Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode); @@ -2136,7 +2220,7 @@ void R_RTLight_Compile(rtlight_t *rtlight) if (numsurfaces) memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist)); if (model->CompileShadowVolume && rtlight->shadow) - model->CompileShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist); + model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist); // now we're done compiling the rtlight r_shadow_compilingrtlight = NULL; } @@ -2209,11 +2293,11 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfa if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL) { // decrement stencil if backface is behind depthbuffer - qglCullFace(GL_BACK);CHECKGLERROR // quake is backwards, this culls front faces + GL_CullFace(GL_BACK); // quake is backwards, this culls front faces qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i); // increment stencil if frontface is behind depthbuffer - qglCullFace(GL_FRONT);CHECKGLERROR // quake is backwards, this culls back faces + GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR } R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i); @@ -2224,7 +2308,7 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfa else if (numsurfaces) { R_Mesh_Matrix(&ent->matrix); - model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs); + model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs); } } else @@ -2238,7 +2322,7 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfa relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius; relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius; R_Mesh_Matrix(&ent->matrix); - model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs); + model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs); } } @@ -2311,6 +2395,9 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs)) return; + VectorCopy(rtlight->cullmins, r_shadow_rtlight_cullmins); + VectorCopy(rtlight->cullmaxs, r_shadow_rtlight_cullmaxs); + if (rtlight->compiled && r_shadow_realtime_world_compile.integer) { // compiled light, world available and can receive realtime lighting @@ -2326,12 +2413,12 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) // dynamic light, world available and can receive realtime lighting // calculate lit surfaces and leafs R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces); - r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, 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_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces); leaflist = r_shadow_buffer_leaflist; leafpvs = r_shadow_buffer_leafpvs; surfacelist = r_shadow_buffer_surfacelist; // if the reduced leaf bounds are offscreen, skip it - if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs)) + if (R_CullBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs)) return; } else @@ -2353,7 +2440,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) return; } // set up a scissor rectangle for this light - if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs)) + if (R_Shadow_ScissorForBBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs)) return; // make a list of lit entities and shadow casting entities @@ -2372,7 +2459,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) { model_t *model; entity_render_t *ent = r_refdef.entities[i]; - if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs) + if (BoxesOverlap(ent->mins, ent->maxs, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs) && (model = ent->model) && !(ent->flags & RENDER_TRANSPARENT) && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))) @@ -2470,6 +2557,94 @@ void R_ShadowVolumeLighting(qboolean visible) R_Shadow_RenderMode_End(); } +extern void R_SetupView(const matrix4x4_t *matrix); +extern cvar_t r_shadows_throwdistance; +void R_DrawModelShadows(void) +{ + int i; + float relativethrowdistance; + entity_render_t *ent; + vec3_t relativelightorigin; + vec3_t relativelightdirection; + vec3_t relativeshadowmins, relativeshadowmaxs; + float vertex3f[12]; + + if (!r_drawentities.integer || !gl_stencil) + return; + + CHECKGLERROR + GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height); + + r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE; + + if (gl_ext_separatestencil.integer) + r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL; + else if (gl_ext_stenciltwoside.integer) + r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE; + else + r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL; + + R_Shadow_RenderMode_StencilShadowVolumes(); + + for (i = 0;i < r_refdef.numentities;i++) + { + ent = r_refdef.entities[i]; + // cast shadows from anything that is not a submodel of the map + if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW)) + { + relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix); + VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance); + VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance); + VectorNegate(ent->modellight_lightdir, relativelightdirection); + VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin); + R_Mesh_Matrix(&ent->matrix); + ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs); + } + } + + // 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; + + // set up ortho view for rendering this pass + GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100); + GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height); + GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1); + GL_ScissorTest(true); + R_Mesh_Matrix(&identitymatrix); + R_Mesh_ResetTextureState(); + R_Mesh_VertexPointer(vertex3f); + R_Mesh_ColorPointer(NULL); + + // set up a 50% darkening blend on shadowed areas + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL_DepthTest(false); + GL_DepthMask(false); + qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR + GL_Color(0, 0, 0, 0.5); + GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1); + qglDepthFunc(GL_ALWAYS);CHECKGLERROR + qglEnable(GL_STENCIL_TEST);CHECKGLERROR + qglStencilMask(~0);CHECKGLERROR + qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR + qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR + + // apply the blend to the shadowed areas + R_Mesh_Draw(0, 4, 2, polygonelements); + + // restoring the perspective view is done by R_RenderScene + //R_SetupView(&r_view.matrix); + + // restore other state to normal + R_Shadow_RenderMode_End(); +} + + //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"}; typedef struct suffixinfo_s {