]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
reduced size of viewblend triangle from 64000 units to 64 units, in hopes of curing...
[xonotic/darkplaces.git] / r_shadow.c
index 1826d96cceeaa2a90ff3c1d1f00d6fcc17482daf..11e62aae756f97efb7489603adb7f137f931483d 100644 (file)
@@ -14,7 +14,16 @@ did not intersect the visible geometry, suitable as a stencil mask for
 rendering lighting everywhere but shadow.
 
 In our case we use a biased stencil clear of 128 to avoid requiring the
-stencil wrap extension (but probably should support it).
+stencil wrap extension (but probably should support it), and to address
+Creative's patent on this sort of technology we also draw the frontfaces
+first, and backfaces second (decrement, increment).
+
+Patent warning:
+This algorithm may be covered by Creative's patent (US Patent #6384822)
+on Carmack's Reverse paper (which I have not read), however that patent
+seems to be about drawing a stencil shadow from a model in an otherwise
+unshadowed scene, where as realtime lighting technology draws light where
+shadows do not lie.
 
 
 
@@ -151,12 +160,14 @@ cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
-cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "0"};
+cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0"};
+cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1"};
 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "10000"};
 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
-cvar_t r_shadow_shadows = {CVAR_SAVE, "r_shadow_shadows", "1"};
+cvar_t r_shadow_worldshadows = {0, "r_shadow_worldshadows", "1"};
+cvar_t r_shadow_dlightshadows = {CVAR_SAVE, "r_shadow_dlightshadows", "1"};
 cvar_t r_shadow_showtris = {0, "r_shadow_showtris", "0"};
 
 int c_rt_lights, c_rt_clears, c_rt_scissored;
@@ -240,12 +251,14 @@ void R_Shadow_Help_f(void)
 "r_shadow_scissor : use scissor optimization\n"
 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
+"r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
 "r_shadow_portallight : use portal visibility for static light precomputation\n"
 "r_shadow_projectdistance : shadow volume projection distance\n"
 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
-"r_shadow_shadows : dlight shadows (world always has shadows)\n"
+"r_shadow_worldshadows : enable world shadows\n"
+"r_shadow_dlightshadows : enable dlight shadows\n"
 "Commands:\n"
 "r_shadow_help : this help\n"
        );
@@ -266,12 +279,14 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_scissor);
        Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
        Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
+       Cvar_RegisterVariable(&r_shadow_polygonfactor);
        Cvar_RegisterVariable(&r_shadow_polygonoffset);
        Cvar_RegisterVariable(&r_shadow_portallight);
        Cvar_RegisterVariable(&r_shadow_projectdistance);
        Cvar_RegisterVariable(&r_shadow_texture3d);
        Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
-       Cvar_RegisterVariable(&r_shadow_shadows);
+       Cvar_RegisterVariable(&r_shadow_worldshadows);
+       Cvar_RegisterVariable(&r_shadow_dlightshadows);
        Cvar_RegisterVariable(&r_shadow_showtris);
        Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
        R_Shadow_EditLights_Init();
@@ -626,15 +641,15 @@ void R_Shadow_Volume(int numverts, int numtris, const float *invertex3f, int *el
                GL_VertexPointer(varray_vertex3f2);
                if (r_shadowstage == SHADOWSTAGE_STENCIL)
                {
-                       // increment stencil if backface is behind depthbuffer
-                       qglCullFace(GL_BACK); // quake is backwards, this culls front faces
-                       qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
-                       R_Mesh_Draw(outverts, tris, shadowelements);
-                       c_rt_shadowmeshes++;
-                       c_rt_shadowtris += numtris;
                        // decrement stencil if frontface is behind depthbuffer
                        qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
                        qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
+                       R_Mesh_Draw(outverts, tris, shadowelements);
+                       c_rt_shadowmeshes++;
+                       c_rt_shadowtris += numtris;
+                       // increment stencil if backface is behind depthbuffer
+                       qglCullFace(GL_BACK); // quake is backwards, this culls front faces
+                       qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
                }
                R_Mesh_Draw(outverts, tris, shadowelements);
                c_rt_shadowmeshes++;
@@ -647,9 +662,9 @@ void R_Shadow_RenderShadowMeshVolume(shadowmesh_t *firstmesh)
        shadowmesh_t *mesh;
        if (r_shadowstage == SHADOWSTAGE_STENCIL)
        {
-               // increment stencil if backface is behind depthbuffer
-               qglCullFace(GL_BACK); // quake is backwards, this culls front faces
-               qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
+               // decrement stencil if frontface is behind depthbuffer
+               qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
+               qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
                for (mesh = firstmesh;mesh;mesh = mesh->next)
                {
                        GL_VertexPointer(mesh->vertex3f);
@@ -657,9 +672,9 @@ void R_Shadow_RenderShadowMeshVolume(shadowmesh_t *firstmesh)
                        c_rtcached_shadowmeshes++;
                        c_rtcached_shadowtris += mesh->numtriangles;
                }
-               // decrement stencil if frontface is behind depthbuffer
-               qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
-               qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
+               // increment stencil if backface is behind depthbuffer
+               qglCullFace(GL_BACK); // quake is backwards, this culls front faces
+               qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
        }
        for (mesh = firstmesh;mesh;mesh = mesh->next)
        {
@@ -818,6 +833,7 @@ void R_Shadow_Stage_Begin(void)
        GL_DepthTest(true);
        R_Mesh_State_Texture(&m);
        GL_Color(0, 0, 0, 1);
+       qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
        qglDisable(GL_SCISSOR_TEST);
        r_shadowstage = SHADOWSTAGE_NONE;
 
@@ -852,14 +868,16 @@ void R_Shadow_Stage_ShadowVolumes(void)
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthMask(false);
        GL_DepthTest(true);
-       if (r_shadow_polygonoffset.value != 0)
-       {
-               qglPolygonOffset(1.0f, r_shadow_polygonoffset.value);
-               qglEnable(GL_POLYGON_OFFSET_FILL);
-       }
-       else
-               qglDisable(GL_POLYGON_OFFSET_FILL);
+       qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
+       //if (r_shadow_polygonoffset.value != 0)
+       //{
+       //      qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
+       //      qglEnable(GL_POLYGON_OFFSET_FILL);
+       //}
+       //else
+       //      qglDisable(GL_POLYGON_OFFSET_FILL);
        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);
@@ -883,10 +901,12 @@ void R_Shadow_Stage_LightWithoutShadows(void)
        GL_BlendFunc(GL_ONE, GL_ONE);
        GL_DepthMask(false);
        GL_DepthTest(true);
-       qglDisable(GL_POLYGON_OFFSET_FILL);
+       qglPolygonOffset(0, 0);
+       //qglDisable(GL_POLYGON_OFFSET_FILL);
        GL_Color(1, 1, 1, 1);
        qglColorMask(1, 1, 1, 1);
        qglDepthFunc(GL_EQUAL);
+       qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
        qglDisable(GL_STENCIL_TEST);
        qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        qglStencilFunc(GL_EQUAL, 128, 0xFF);
@@ -902,10 +922,12 @@ void R_Shadow_Stage_LightWithShadows(void)
        GL_BlendFunc(GL_ONE, GL_ONE);
        GL_DepthMask(false);
        GL_DepthTest(true);
-       qglDisable(GL_POLYGON_OFFSET_FILL);
+       qglPolygonOffset(0, 0);
+       //qglDisable(GL_POLYGON_OFFSET_FILL);
        GL_Color(1, 1, 1, 1);
        qglColorMask(1, 1, 1, 1);
        qglDepthFunc(GL_EQUAL);
+       qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
        qglEnable(GL_STENCIL_TEST);
        qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        // only draw light where this geometry was already rendered AND the
@@ -923,11 +945,13 @@ void R_Shadow_Stage_End(void)
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthMask(true);
        GL_DepthTest(true);
-       qglDisable(GL_POLYGON_OFFSET_FILL);
+       qglPolygonOffset(0, 0);
+       //qglDisable(GL_POLYGON_OFFSET_FILL);
        GL_Color(1, 1, 1, 1);
        qglColorMask(1, 1, 1, 1);
        qglDisable(GL_SCISSOR_TEST);
        qglDepthFunc(GL_LEQUAL);
+       qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
        qglDisable(GL_STENCIL_TEST);
        qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        qglStencilFunc(GL_ALWAYS, 128, 0xFF);
@@ -1877,12 +1901,12 @@ void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style
                                if (face->lighttemp_castshadow)
                                {
                                        face->lighttemp_castshadow = false;
-                                       if (!(face->texture->renderflags & (Q3MTEXTURERENDERFLAGS_NODRAW | Q3MTEXTURERENDERFLAGS_SKY)))
+                                       if (!(face->texture->surfaceflags & (Q3SURFACEFLAG_NODRAW | Q3SURFACEFLAG_SKY)))
                                        {
                                                if (e->castshadows)
                                                        if (!(face->texture->nativecontents & CONTENTSQ3_TRANSLUCENT))
                                                                Mod_ShadowMesh_AddMesh(r_shadow_mempool, castmesh, NULL, NULL, NULL, face->data_vertex3f, NULL, NULL, NULL, NULL, face->num_triangles, face->data_element3i);
-                                               if (!(face->texture->renderflags & (Q3MTEXTURERENDERFLAGS_SKY)))
+                                               if (!(face->texture->surfaceflags & Q3SURFACEFLAG_SKY))
                                                        Mod_ShadowMesh_AddMesh(r_shadow_mempool, e->meshchain_light, face->texture->skin.base, face->texture->skin.gloss, face->texture->skin.nmap, face->data_vertex3f, face->data_svector3f, face->data_tvector3f, face->data_normal3f, face->data_texcoordtexture2f, face->num_triangles, face->data_element3i);
                                        }
                                }
@@ -2259,7 +2283,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
 {
        int entnum, style, islight;
        char key[256], value[1024];
-       float origin[3], radius, color[3], light, scale, originhack[3], overridecolor[3];
+       float origin[3], radius, color[3], light, fadescale, lightscale, originhack[3], overridecolor[3];
        const char *data;
 
        if (cl.worldmodel == NULL)
@@ -2277,7 +2301,8 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                originhack[0] = originhack[1] = originhack[2] = 0;
                color[0] = color[1] = color[2] = 1;
                overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
-               scale = 1;
+               fadescale = 1;
+               lightscale = 1;
                style = 0;
                islight = false;
                while (1)
@@ -2304,7 +2329,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                        else if (!strcmp("color", key))
                                sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
                        else if (!strcmp("wait", key))
-                               scale = atof(value);
+                               fadescale = atof(value);
                        else if (!strcmp("classname", key))
                        {
                                if (!strncmp(value, "light", 5))
@@ -2377,10 +2402,21 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                        }
                        else if (!strcmp("style", key))
                                style = atoi(value);
+                       else if (cl.worldmodel->type == mod_brushq3)
+                       {
+                               if (!strcmp("scale", key))
+                                       lightscale = atof(value);
+                               if (!strcmp("fade", key))
+                                       fadescale = atof(value);
+                       }
                }
                if (light <= 0 && islight)
                        light = 300;
-               radius = min(light * r_editlights_quakelightsizescale.value / scale, 1048576);
+               if (lightscale <= 0)
+                       lightscale = 1;
+               if (fadescale <= 0)
+                       fadescale = 1;
+               radius = min(light * r_editlights_quakelightsizescale.value * lightscale / fadescale, 1048576);
                light = sqrt(bound(0, light, 1048576)) * (1.0f / 16.0f);
                if (color[0] == 1 && color[1] == 1 && color[2] == 1)
                        VectorCopy(overridecolor, color);