-
- viewleaf = model->brushq1.PointInLeaf(model, r_vieworigin);
- if (!viewleaf)
- return;
-
- memset(r_worldsurfacevisible, 0, r_refdef.worldmodel->brush.num_surfaces);
- if (viewleaf->clusterindex < 0 || r_surfaceworldnode.integer)
- {
- // equivilant to quake's RecursiveWorldNode but faster and more effective
- for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++)
- {
- if (CHECKPVSBIT(r_pvsbits, leaf->clusterindex) && !R_CullBox (leaf->mins, leaf->maxs))
- {
- c_leafs++;
- if (leaf->numleafsurfaces)
- for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
- r_worldsurfacevisible[*mark] = true;
- }
- }
+ // portal method:
+ // follows portals leading outward from viewleaf, does not venture
+ // offscreen or into leafs that are not visible, faster than Quake's
+ // RecursiveWorldNode and vastly better in unvised maps, often culls a
+ // lot of surface that pvs alone would miss
+ leafstack[0] = viewleaf;
+ leafstackpos = 1;
+ memset(leafvisited, 0, model->brush.num_leafs);
+ while (leafstackpos)
+ {
+ c_leafs++;
+ leaf = leafstack[--leafstackpos];
+ leafvisited[leaf - model->brush.data_leafs] = 1;
+ // mark any surfaces bounding this leaf
+ if (leaf->numleafsurfaces)
+ for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
+ r_worldsurfacevisible[*mark] = true;
+ // follow portals into other leafs
+ // the checks are:
+ // if viewer is behind portal (portal faces outward into the scene)
+ // and the portal polygon's bounding box is on the screen
+ // and the leaf has not been visited yet
+ // and the leaf is visible in the pvs
+ // (the first two checks won't cause as many cache misses as the leaf checks)
+ for (p = leaf->portals;p;p = p->next)
+ if (DotProduct(r_vieworigin, p->plane.normal) < (p->plane.dist + 1) && !R_CullBox(p->mins, p->maxs) && !leafvisited[p->past - model->brush.data_leafs] && CHECKPVSBIT(r_pvsbits, p->past->clusterindex))
+ leafstack[leafstackpos++] = p->past;