cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
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_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
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_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", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
+cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
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_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_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_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
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_shadow_glsl lighting)"};
-cvar_t r_shadow_glsl = {0, "r_shadow_glsl", "1", "enables use of OpenGL 2.0 pixel shaders for lighting"};
-cvar_t r_shadow_glsl_offsetmapping = {0, "r_shadow_glsl_offsetmapping", "0", "enables offset mapping effect (also known as parallax mapping or sometimes as virtual displacement mapping, not as good as relief mapping or silohuette mapping but much faster), can cause strange artifacts on many textures, requires bumpmaps for depth information (normalmaps can have depth information as alpha channel, but most do not)"};
-cvar_t r_shadow_glsl_offsetmapping_scale = {0, "r_shadow_glsl_offsetmapping_scale", "-0.04", "how deep the offset mapping effect is, and whether it is inward or outward"};
-cvar_t r_shadow_glsl_offsetmapping_bias = {0, "r_shadow_glsl_offsetmapping_bias", "0.04", "pushes the effect closer/further"};
-cvar_t r_shadow_glsl_usehalffloat = {0, "r_shadow_glsl_usehalffloat", "0", "use half and hvec variables in GLSL shader for a speed gain (NVIDIA only)"};
-cvar_t r_shadow_glsl_surfacenormalize = {0, "r_shadow_glsl_surfacenormalize", "1", "normalize bumpmap texels in GLSL shader, produces a more rounded look on small bumps and dents"};
+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_separatestencil", "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)"};
Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
-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)
- 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)
@@ -950,143+813,158 @@ 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)
- for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+}
+
+static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, float r, float g, float b)
+void R_Shadow_RenderLighting_Light_Vertex_Pass(const model_t *model, int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, vec3_t diffusecolor2, vec3_t ambientcolor2)
{
int renders;
- const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
+void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)