fix crashes when recursing portals on maps with some bogus leafs (where
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 18 Aug 2008 17:50:21 +0000 (17:50 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 18 Aug 2008 17:50:21 +0000 (17:50 +0000)
infinite recursion loops can occur, alternating between two leafs), such
as cmc.bsp for prozactf coop

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@8455 d7cf8633-e32d-0410-b094-e92efae38249

gl_rsurf.c
model_shared.h
portals.c
portals.h
r_shadow.c

index 3998249..21f5e4c 100644 (file)
@@ -604,6 +604,7 @@ typedef struct r_q1bsp_getlightinfo_s
        int *outleaflist;
        unsigned char *outleafpvs;
        int outnumleafs;
+       unsigned char *visitingleafpvs;
        int *outsurfacelist;
        unsigned char *outsurfacepvs;
        unsigned char *tempsurfacepvs;
@@ -882,7 +883,7 @@ void R_Q1BSP_CallRecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, qboolean us
        }
 }
 
-void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer, unsigned char *outshadowtrispvs, unsigned char *outlighttrispvs)
+void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer, unsigned char *outshadowtrispvs, unsigned char *outlighttrispvs, unsigned char *visitingleafpvs)
 {
        r_q1bsp_getlightinfo_t info;
        VectorCopy(relativelightorigin, info.relativelightorigin);
@@ -905,6 +906,7 @@ void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, floa
        info.outleaflist = outleaflist;
        info.outleafpvs = outleafpvs;
        info.outnumleafs = 0;
+       info.visitingleafpvs = visitingleafpvs;
        info.outsurfacelist = outsurfacelist;
        info.outsurfacepvs = outsurfacepvs;
        info.outshadowtrispvs = outshadowtrispvs;
@@ -912,6 +914,7 @@ void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, floa
        info.outnumsurfaces = 0;
        VectorCopy(info.relativelightorigin, info.outmins);
        VectorCopy(info.relativelightorigin, info.outmaxs);
+       memset(visitingleafpvs, 0, (info.model->brush.num_leafs + 7) >> 3);
        memset(outleafpvs, 0, (info.model->brush.num_leafs + 7) >> 3);
        memset(outsurfacepvs, 0, (info.model->nummodelsurfaces + 7) >> 3);
        if (info.model->brush.shadowmesh)
@@ -928,12 +931,12 @@ void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, floa
        if (r_shadow_frontsidecasting.integer && r_shadow_compilingrtlight && r_shadow_realtime_world_compileportalculling.integer && info.model->brush.data_portals)
        {
                // use portal recursion for exact light volume culling, and exact surface checking
-               Portal_Visibility(info.model, info.relativelightorigin, info.outleaflist, info.outleafpvs, &info.outnumleafs, info.outsurfacelist, info.outsurfacepvs, &info.outnumsurfaces, NULL, 0, true, info.lightmins, info.lightmaxs, info.outmins, info.outmaxs, info.outshadowtrispvs, info.outlighttrispvs);
+               Portal_Visibility(info.model, info.relativelightorigin, info.outleaflist, info.outleafpvs, &info.outnumleafs, info.outsurfacelist, info.outsurfacepvs, &info.outnumsurfaces, NULL, 0, true, info.lightmins, info.lightmaxs, info.outmins, info.outmaxs, info.outshadowtrispvs, info.outlighttrispvs, info.visitingleafpvs);
        }
        else if (r_shadow_frontsidecasting.integer && r_shadow_realtime_dlight_portalculling.integer && info.model->brush.data_portals)
        {
                // use portal recursion for exact light volume culling, but not the expensive exact surface checking
-               Portal_Visibility(info.model, info.relativelightorigin, info.outleaflist, info.outleafpvs, &info.outnumleafs, info.outsurfacelist, info.outsurfacepvs, &info.outnumsurfaces, NULL, 0, r_shadow_realtime_dlight_portalculling.integer >= 2, info.lightmins, info.lightmaxs, info.outmins, info.outmaxs, info.outshadowtrispvs, info.outlighttrispvs);
+               Portal_Visibility(info.model, info.relativelightorigin, info.outleaflist, info.outleafpvs, &info.outnumleafs, info.outsurfacelist, info.outsurfacepvs, &info.outnumsurfaces, NULL, 0, r_shadow_realtime_dlight_portalculling.integer >= 2, info.lightmins, info.lightmaxs, info.outmins, info.outmaxs, info.outshadowtrispvs, info.outlighttrispvs, info.visitingleafpvs);
        }
        else
        {
index 2302383..bd939d6 100644 (file)
@@ -858,7 +858,7 @@ typedef struct model_s
        // draw any enabled debugging effects on this model (such as showing triangles, normals, collision brushes...)
        void(*DrawDebug)(struct entity_render_s *ent);
        // gathers info on which clusters and surfaces are lit by light, as well as calculating a bounding box
-       void(*GetLightInfo)(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer, unsigned char *outshadowtrispvs, unsigned char *outlighttrispvs);
+       void(*GetLightInfo)(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer, unsigned char *outshadowtrispvs, unsigned char *outlighttrispvs, unsigned char *visitingleafpvs);
        // compile a shadow volume for the model based on light source
        void(*CompileShadowVolume)(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist);
        // draw a shadow volume for the model based on light source
@@ -966,7 +966,7 @@ void R_Q1BSP_DrawSky(struct entity_render_s *ent);
 void R_Q1BSP_Draw(struct entity_render_s *ent);
 void R_Q1BSP_DrawDepth(struct entity_render_s *ent);
 void R_Q1BSP_DrawDebug(struct entity_render_s *ent);
-void R_Q1BSP_GetLightInfo(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer, unsigned char *outshadowtrispvs, unsigned char *outlighttrispvs);
+void R_Q1BSP_GetLightInfo(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer, unsigned char *outshadowtrispvs, unsigned char *outlighttrispvs, unsigned char *visitingleafpvs);
 void R_Q1BSP_CompileShadowVolume(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist);
 void R_Q1BSP_DrawShadowVolume(struct entity_render_s *ent, const vec3_t relativelightorigin, const vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs);
 void R_Q1BSP_DrawLight(struct entity_render_s *ent, int numsurfaces, const int *surfacelist, const unsigned char *trispvs);
index 8e2b579..3b770f9 100644 (file)
--- a/portals.c
+++ b/portals.c
@@ -273,6 +273,7 @@ typedef struct portalrecursioninfo_s
        int *surfacelist;
        unsigned char *surfacepvs;
        int numleafs;
+       unsigned char *visitingleafpvs; // used to prevent infinite loops
        int *leaflist;
        unsigned char *leafpvs;
        unsigned char *shadowtrispvs;
@@ -291,6 +292,12 @@ static void Portal_RecursiveFlow (portalrecursioninfo_t *info, mleaf_t *leaf, in
        float dist;
        vec3_t center;
        tinyplane_t *newplanes;
+       int leafindex = leaf - info->model->brush.data_leafs;
+
+       if (CHECKPVSBIT(info->visitingleafpvs, leafindex))
+               return; // recursive loop of leafs (cmc.bsp for megatf coop)
+
+       SETPVSBIT(info->visitingleafpvs, leafindex);
 
        for (i = 0;i < 3;i++)
        {
@@ -301,7 +308,6 @@ static void Portal_RecursiveFlow (portalrecursioninfo_t *info, mleaf_t *leaf, in
 
        if (info->leafpvs)
        {
-               int leafindex = leaf - info->model->brush.data_leafs;
                if (!CHECKPVSBIT(info->leafpvs, leafindex))
                {
                        SETPVSBIT(info->leafpvs, leafindex);
@@ -391,6 +397,8 @@ static void Portal_RecursiveFlow (portalrecursioninfo_t *info, mleaf_t *leaf, in
                        }
                }
        }
+
+       CLEARPVSBIT(info->visitingleafpvs, leafindex);
 }
 
 static void Portal_RecursiveFindLeafForFlow(portalrecursioninfo_t *info, mnode_t *node)
@@ -411,7 +419,7 @@ static void Portal_RecursiveFindLeafForFlow(portalrecursioninfo_t *info, mnode_t
        }
 }
 
-void Portal_Visibility(dp_model_t *model, const vec3_t eye, int *leaflist, unsigned char *leafpvs, int *numleafspointer, int *surfacelist, unsigned char *surfacepvs, int *numsurfacespointer, const mplane_t *frustumplanes, int numfrustumplanes, int exact, const float *boxmins, const float *boxmaxs, float *updateleafsmins, float *updateleafsmaxs, unsigned char *shadowtrispvs, unsigned char *lighttrispvs)
+void Portal_Visibility(dp_model_t *model, const vec3_t eye, int *leaflist, unsigned char *leafpvs, int *numleafspointer, int *surfacelist, unsigned char *surfacepvs, int *numsurfacespointer, const mplane_t *frustumplanes, int numfrustumplanes, int exact, const float *boxmins, const float *boxmaxs, float *updateleafsmins, float *updateleafsmaxs, unsigned char *shadowtrispvs, unsigned char *lighttrispvs, unsigned char *visitingleafpvs)
 {
        int i;
        portalrecursioninfo_t info;
@@ -446,6 +454,7 @@ void Portal_Visibility(dp_model_t *model, const vec3_t eye, int *leaflist, unsig
        info.surfacelist = surfacelist;
        info.surfacepvs = surfacepvs;
        info.numleafs = 0;
+       info.visitingleafpvs = visitingleafpvs;
        info.leaflist = leaflist;
        info.leafpvs = leafpvs;
        info.model = model;
index 5843c0a..fb61328 100644 (file)
--- a/portals.h
+++ b/portals.h
@@ -4,7 +4,7 @@
 
 int Portal_CheckPolygon(dp_model_t *model, vec3_t eye, float *polypoints, int numpoints);
 int Portal_CheckBox(dp_model_t *model, vec3_t eye, vec3_t a, vec3_t b);
-void Portal_Visibility(dp_model_t *model, const vec3_t eye, int *leaflist, unsigned char *leafpvs, int *numleafspointer, int *surfacelist, unsigned char *surfacepvs, int *numsurfacespointer, const mplane_t *frustumplanes, int numfrustumplanes, int exact, const float *boxmins, const float *boxmaxs, float *updateleafsmins, float *updateleafsmaxs, unsigned char *shadowtrispvs, unsigned char *lighttrispvs);
+void Portal_Visibility(dp_model_t *model, const vec3_t eye, int *leaflist, unsigned char *leafpvs, int *numleafspointer, int *surfacelist, unsigned char *surfacepvs, int *numsurfacespointer, const mplane_t *frustumplanes, int numfrustumplanes, int exact, const float *boxmins, const float *boxmaxs, float *updateleafsmins, float *updateleafsmaxs, unsigned char *shadowtrispvs, unsigned char *lighttrispvs, unsigned char *visitingleafpvs);
 
 #endif
 
index 22bb891..067910e 100644 (file)
@@ -178,6 +178,7 @@ int *vertexremap;
 int vertexupdatenum;
 
 int r_shadow_buffer_numleafpvsbytes;
+unsigned char *r_shadow_buffer_visitingleafpvs;
 unsigned char *r_shadow_buffer_leafpvs;
 int *r_shadow_buffer_leaflist;
 
@@ -318,6 +319,7 @@ void r_shadow_start(void)
        shadowmarklist = NULL;
        shadowmarkcount = 0;
        r_shadow_buffer_numleafpvsbytes = 0;
+       r_shadow_buffer_visitingleafpvs = NULL;
        r_shadow_buffer_leafpvs = NULL;
        r_shadow_buffer_leaflist = NULL;
        r_shadow_buffer_numsurfacepvsbytes = 0;
@@ -363,6 +365,9 @@ void r_shadow_shutdown(void)
        shadowmarklist = NULL;
        shadowmarkcount = 0;
        r_shadow_buffer_numleafpvsbytes = 0;
+       if (r_shadow_buffer_visitingleafpvs)
+               Mem_Free(r_shadow_buffer_visitingleafpvs);
+       r_shadow_buffer_visitingleafpvs = NULL;
        if (r_shadow_buffer_leafpvs)
                Mem_Free(r_shadow_buffer_leafpvs);
        r_shadow_buffer_leafpvs = NULL;
@@ -484,6 +489,7 @@ void R_Shadow_Init(void)
        shadowmarklist = NULL;
        shadowmarkcount = 0;
        r_shadow_buffer_numleafpvsbytes = 0;
+       r_shadow_buffer_visitingleafpvs = NULL;
        r_shadow_buffer_leafpvs = NULL;
        r_shadow_buffer_leaflist = NULL;
        r_shadow_buffer_numsurfacepvsbytes = 0;
@@ -542,11 +548,14 @@ static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces,
        int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
        if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
        {
+               if (r_shadow_buffer_visitingleafpvs)
+                       Mem_Free(r_shadow_buffer_visitingleafpvs);
                if (r_shadow_buffer_leafpvs)
                        Mem_Free(r_shadow_buffer_leafpvs);
                if (r_shadow_buffer_leaflist)
                        Mem_Free(r_shadow_buffer_leaflist);
                r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
+               r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
                r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
                r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
        }
@@ -2468,7 +2477,7 @@ void R_RTLight_Compile(rtlight_t *rtlight)
                // this variable must be set for the CompileShadowVolume code
                r_shadow_compilingrtlight = rtlight;
                R_Shadow_EnlargeLeafSurfaceTrisBuffer(model->brush.num_leafs, model->num_surfaces, model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles, model->surfmesh.num_triangles);
-               model->GetLightInfo(ent, 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_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs);
+               model->GetLightInfo(ent, 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_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs);
                numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
                numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
                numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
@@ -2909,7 +2918,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                // dynamic light, world available and can receive realtime lighting
                // calculate lit surfaces and leafs
                R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
-               r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs);
+               r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs);
                leaflist = r_shadow_buffer_leaflist;
                leafpvs = r_shadow_buffer_leafpvs;
                surfacelist = r_shadow_buffer_surfacelist;