]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
reorganized view rendering setup code a bit to reduce potential for state bugs (more...
[xonotic/darkplaces.git] / r_shadow.c
index be2493433e38be5a026521da26eab4e3bc1fbaa3..3327166042827d7d6f4a72d4b1909e5ae3c61e60 100644 (file)
@@ -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,
@@ -198,8 +199,9 @@ 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.5", "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"};
@@ -218,6 +220,7 @@ cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization
 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"};
@@ -385,6 +388,7 @@ 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);
@@ -403,6 +407,7 @@ void R_Shadow_Init(void)
        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)
        {
@@ -679,7 +684,7 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f,
        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)
@@ -851,6 +856,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);
 }
@@ -883,13 +890,16 @@ void R_Shadow_RenderMode_Begin(void)
        R_Mesh_ColorPointer(NULL);
        R_Mesh_ResetTextureState();
        GL_BlendFunc(GL_ONE, GL_ZERO);
+       GL_DepthTest(true);
        GL_DepthMask(false);
        GL_Color(0, 0, 0, 1);
        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;
@@ -920,22 +930,36 @@ 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);
        qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
        qglDepthFunc(GL_LESS);CHECKGLERROR
        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)
+       {
+               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
@@ -946,13 +970,6 @@ void R_Shadow_RenderMode_StencilShadowVolumes(void)
                qglStencilMask(~0);CHECKGLERROR
                qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
        }
-       else
-       {
-               GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
-               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++;
 }
@@ -962,32 +979,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);
-       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
        }
        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)
@@ -1014,19 +1016,10 @@ void R_Shadow_RenderMode_VisibleShadowVolumes(void)
        CHECKGLERROR
        R_Shadow_RenderMode_Reset();
        GL_BlendFunc(GL_ONE, GL_ONE);
-       GL_DepthMask(false);
-       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);
-       if (r_showshadowvolumes.integer >= 2)
-       {
-               qglDepthFunc(GL_ALWAYS);CHECKGLERROR
-       }
-       else
-       {
-               qglDepthFunc(GL_GEQUAL);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;
 }
 
@@ -1035,19 +1028,9 @@ void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transpar
        CHECKGLERROR
        R_Shadow_RenderMode_Reset();
        GL_BlendFunc(GL_ONE, GL_ONE);
-       GL_DepthMask(false);
-       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 (r_showshadowvolumes.integer >= 2)
-       {
-               qglDepthFunc(GL_ALWAYS);CHECKGLERROR
-       }
-       else if (transparent)
-       {
-               qglDepthFunc(GL_LEQUAL);CHECKGLERROR
-       }
-       else
+       if (!transparent)
        {
                qglDepthFunc(GL_EQUAL);CHECKGLERROR
        }
@@ -1055,10 +1038,6 @@ void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transpar
        {
                qglEnable(GL_STENCIL_TEST);CHECKGLERROR
        }
-       else
-       {
-               qglDisable(GL_STENCIL_TEST);CHECKGLERROR
-       }
        r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
 }
 
@@ -1067,22 +1046,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);
-       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
-       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;
 }
 
@@ -1682,6 +1647,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)
@@ -1710,12 +1676,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
@@ -1762,12 +1724,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
@@ -1801,12 +1759,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
@@ -2543,7 +2497,9 @@ void R_DrawModelShadows(void)
 
        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;
@@ -2561,6 +2517,7 @@ void R_DrawModelShadows(void)
                        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);
                }
        }
@@ -2600,11 +2557,10 @@ void R_DrawModelShadows(void)
        // apply the blend to the shadowed areas
        R_Mesh_Draw(0, 4, 2, polygonelements);
 
-       // restore perspective view
-       R_SetupView(&r_view.matrix);
+       // restoring the perspective view is done by R_RenderScene
+       //R_SetupView(&r_view.matrix);
 
        // restore other state to normal
-       GL_DepthTest(true);
        R_Shadow_RenderMode_End();
 }