#define SHADOWSTAGE_NONE 0
#define SHADOWSTAGE_STENCIL 1
#define SHADOWSTAGE_LIGHT 2
-#define SHADOWSTAGE_ERASESTENCIL 3
+#define SHADOWSTAGE_STENCILTWOSIDE 3
int r_shadowstage = SHADOWSTAGE_NONE;
int r_shadow_reloadlights = false;
cvar_t r_shadow_showtris = {0, "r_shadow_showtris", "0"};
cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
+cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
int c_rt_lights, c_rt_clears, c_rt_scissored;
int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
Cvar_RegisterVariable(&r_shadow_showtris);
Cvar_RegisterVariable(&r_shadow_staticworldlights);
Cvar_RegisterVariable(&r_shadow_cull);
+ Cvar_RegisterVariable(&gl_ext_stenciltwoside);
if (gamemode == GAME_TENEBRAE)
{
Cvar_SetValue("r_shadow_gloss", 2);
if (r_shadow_texture3d.integer && !gl_texture3d)
Cvar_SetValueQuick(&r_shadow_texture3d, 0);
+ if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
+ Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
if (!r_shadow_attenuation2dtexture
|| (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
qglDepthFunc(GL_LESS);
qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
qglEnable(GL_STENCIL_TEST);
- qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- qglStencilFunc(GL_ALWAYS, 128, 0xFF);
- r_shadowstage = SHADOWSTAGE_STENCIL;
+ qglStencilFunc(GL_ALWAYS, 128, ~0);
+ if (gl_ext_stenciltwoside.integer)
+ {
+ r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
+ qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
+ qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
+ qglStencilMask(~0);
+ qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
+ qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
+ qglStencilMask(~0);
+ qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
+ }
+ else
+ {
+ r_shadowstage = SHADOWSTAGE_STENCIL;
+ qglStencilMask(~0);
+ qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ }
GL_Clear(GL_STENCIL_BUFFER_BIT);
c_rt_clears++;
// LordHavoc note: many shadow volumes reside entirely inside the world
qglDepthFunc(GL_EQUAL);
qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
qglDisable(GL_STENCIL_TEST);
+ if (gl_support_stenciltwoside)
+ qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
+ qglStencilMask(~0);
qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
qglStencilFunc(GL_EQUAL, 128, 0xFF);
r_shadowstage = SHADOWSTAGE_LIGHT;
qglDepthFunc(GL_EQUAL);
qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
qglEnable(GL_STENCIL_TEST);
+ if (gl_support_stenciltwoside)
+ qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
+ qglStencilMask(~0);
qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
// only draw light where this geometry was already rendered AND the
// stencil is 128 (values other than this mean shadow)
qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
qglDisable(GL_STENCIL_TEST);
qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ if (gl_support_stenciltwoside)
+ qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
+ qglStencilMask(~0);
qglStencilFunc(GL_ALWAYS, 128, 0xFF);
r_shadowstage = SHADOWSTAGE_NONE;
}
int gl_support_anisotropy = false;
// GL_NV_texture_shader
int gl_textureshader = false;
+// GL_EXT_stencil_two_side
+int gl_support_stenciltwoside = false;
// LordHavoc: if window is hidden, don't update screen
int vid_hidden = true;
void (GLAPIENTRY *qglPolygonOffset)(GLfloat factor, GLfloat units);
+void (GLAPIENTRY *qglActiveStencilFaceEXT)(GLenum);
+
int GL_CheckExtension(const char *name, const dllfunction_t *funcs, const char *disableparm, int silent)
{
int failed = false;
{NULL, NULL}
};
+static dllfunction_t stenciltwosidefuncs[] =
+{
+ {"glActiveStencilFaceEXT", (void **) &qglActiveStencilFaceEXT},
+ {NULL, NULL}
+};
+
void VID_CheckExtensions(void)
{
gl_support_clamptoedge = false;
gl_support_var = false;
gl_support_var2 = false;
+ gl_support_stenciltwoside = false;
if (!GL_CheckExtension("OpenGL 1.1.0", opengl110funcs, NULL, false))
Sys_Error("OpenGL 1.1.0 functions not found\n");
gl_textureshader = GL_CheckExtension("GL_NV_texture_shader", NULL, "-notextureshader", false);
+ gl_support_stenciltwoside = GL_CheckExtension("GL_EXT_stencil_two_side", stenciltwosidefuncs, "-nostenciltwoside", false);
+
// we don't care if it's an extension or not, they are identical functions, so keep it simple in the rendering code
if (qglDrawRangeElements == NULL)
qglDrawRangeElements = qglDrawRangeElementsEXT;