123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665 |
- /* Emacs style mode select -*- C++ -*-
- *-----------------------------------------------------------------------------
- *
- *
- * PrBoom: a Doom port merged with LxDoom and LSDLDoom
- * based on BOOM, a modified and improved DOOM engine
- * Copyright (C) 1999 by
- * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
- * Copyright (C) 1999-2000 by
- * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
- * Copyright 2005, 2006 by
- * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * DESCRIPTION:
- * BSP traversal, handling of LineSegs for rendering.
- *
- *-----------------------------------------------------------------------------*/
- #include "doomstat.h"
- #include "m_bbox.h"
- #include "r_main.h"
- #include "r_segs.h"
- #include "r_plane.h"
- #include "r_things.h"
- #include "r_bsp.h" // cph - sanity checking
- #include "v_video.h"
- #include "lprintf.h"
- seg_t *curline;
- side_t *sidedef;
- line_t *linedef;
- sector_t *frontsector;
- sector_t *backsector;
- drawseg_t *ds_p;
- // killough 4/7/98: indicates doors closed wrt automap bugfix:
- // cph - replaced by linedef rendering flags - int doorclosed;
- // killough: New code which removes 2s linedef limit
- drawseg_t *drawsegs;
- unsigned maxdrawsegs;
- // drawseg_t drawsegs[MAXDRAWSEGS]; // old code -- killough
- //
- // R_ClearDrawSegs
- //
- void R_ClearDrawSegs(void)
- {
- ds_p = drawsegs;
- }
- // CPhipps -
- // Instead of clipsegs, let's try using an array with one entry for each column,
- // indicating whether it's blocked by a solid wall yet or not.
- byte solidcol[MAX_SCREENWIDTH];
- // CPhipps -
- // R_ClipWallSegment
- //
- // Replaces the old R_Clip*WallSegment functions. It draws bits of walls in those
- // columns which aren't solid, and updates the solidcol[] array appropriately
- static void R_ClipWallSegment(int first, int last, boolean solid)
- {
- byte *p;
- while (first < last) {
- if (solidcol[first]) {
- if (!(p = memchr(solidcol+first, 0, last-first))) return; // All solid
- first = p - solidcol;
- } else {
- int to;
- if (!(p = memchr(solidcol+first, 1, last-first))) to = last;
- else to = p - solidcol;
- R_StoreWallRange(first, to-1);
- if (solid) {
- memset(solidcol+first,1,to-first);
- }
- first = to;
- }
- }
- }
- //
- // R_ClearClipSegs
- //
- void R_ClearClipSegs (void)
- {
- memset(solidcol, 0, SCREENWIDTH);
- }
- // killough 1/18/98 -- This function is used to fix the automap bug which
- // showed lines behind closed doors simply because the door had a dropoff.
- //
- // cph - converted to R_RecalcLineFlags. This recalculates all the flags for
- // a line, including closure and texture tiling.
- static void R_RecalcLineFlags(void)
- {
- linedef->r_validcount = gametic;
- /* First decide if the line is closed, normal, or invisible */
- if (!(linedef->flags & ML_TWOSIDED)
- || backsector->ceilingheight <= frontsector->floorheight
- || backsector->floorheight >= frontsector->ceilingheight
- || (
- // if door is closed because back is shut:
- backsector->ceilingheight <= backsector->floorheight
- // preserve a kind of transparent door/lift special effect:
- && (backsector->ceilingheight >= frontsector->ceilingheight ||
- curline->sidedef->toptexture)
- && (backsector->floorheight <= frontsector->floorheight ||
- curline->sidedef->bottomtexture)
- // properly render skies (consider door "open" if both ceilings are sky):
- && (backsector->ceilingpic !=skyflatnum ||
- frontsector->ceilingpic!=skyflatnum)
- )
- )
- linedef->r_flags = RF_CLOSED;
- else {
- // Reject empty lines used for triggers
- // and special events.
- // Identical floor and ceiling on both sides,
- // identical light levels on both sides,
- // and no middle texture.
- // CPhipps - recode for speed, not certain if this is portable though
- if (backsector->ceilingheight != frontsector->ceilingheight
- || backsector->floorheight != frontsector->floorheight
- || curline->sidedef->midtexture
- || memcmp(&backsector->floor_xoffs, &frontsector->floor_xoffs,
- sizeof(frontsector->floor_xoffs) + sizeof(frontsector->floor_yoffs) +
- sizeof(frontsector->ceiling_xoffs) + sizeof(frontsector->ceiling_yoffs) +
- sizeof(frontsector->ceilingpic) + sizeof(frontsector->floorpic) +
- sizeof(frontsector->lightlevel) + sizeof(frontsector->floorlightsec) +
- sizeof(frontsector->ceilinglightsec))) {
- linedef->r_flags = 0; return;
- } else
- linedef->r_flags = RF_IGNORE;
- }
- /* cph - I'm too lazy to try and work with offsets in this */
- if (curline->sidedef->rowoffset) return;
- /* Now decide on texture tiling */
- if (linedef->flags & ML_TWOSIDED) {
- int c;
- /* Does top texture need tiling */
- if ((c = frontsector->ceilingheight - backsector->ceilingheight) > 0 &&
- (textureheight[texturetranslation[curline->sidedef->toptexture]] > c))
- linedef->r_flags |= RF_TOP_TILE;
- /* Does bottom texture need tiling */
- if ((c = frontsector->floorheight - backsector->floorheight) > 0 &&
- (textureheight[texturetranslation[curline->sidedef->bottomtexture]] > c))
- linedef->r_flags |= RF_BOT_TILE;
- } else {
- int c;
- /* Does middle texture need tiling */
- if ((c = frontsector->ceilingheight - frontsector->floorheight) > 0 &&
- (textureheight[texturetranslation[curline->sidedef->midtexture]] > c))
- linedef->r_flags |= RF_MID_TILE;
- }
- }
- //
- // killough 3/7/98: Hack floor/ceiling heights for deep water etc.
- //
- // If player's view height is underneath fake floor, lower the
- // drawn ceiling to be just under the floor height, and replace
- // the drawn floor and ceiling textures, and light level, with
- // the control sector's.
- //
- // Similar for ceiling, only reflected.
- //
- // killough 4/11/98, 4/13/98: fix bugs, add 'back' parameter
- //
- sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec,
- int *floorlightlevel, int *ceilinglightlevel,
- boolean back)
- {
- if (floorlightlevel)
- *floorlightlevel = sec->floorlightsec == -1 ?
- sec->lightlevel : sectors[sec->floorlightsec].lightlevel;
- if (ceilinglightlevel)
- *ceilinglightlevel = sec->ceilinglightsec == -1 ? // killough 4/11/98
- sec->lightlevel : sectors[sec->ceilinglightsec].lightlevel;
- if (sec->heightsec != -1)
- {
- const sector_t *s = §ors[sec->heightsec];
- int heightsec = viewplayer->mo->subsector->sector->heightsec;
- int underwater = heightsec!=-1 && viewz<=sectors[heightsec].floorheight;
- // Replace sector being drawn, with a copy to be hacked
- *tempsec = *sec;
- // Replace floor and ceiling height with other sector's heights.
- tempsec->floorheight = s->floorheight;
- tempsec->ceilingheight = s->ceilingheight;
- // killough 11/98: prevent sudden light changes from non-water sectors:
- if (underwater && (tempsec-> floorheight = sec->floorheight,
- tempsec->ceilingheight = s->floorheight-1, !back))
- { // head-below-floor hack
- tempsec->floorpic = s->floorpic;
- tempsec->floor_xoffs = s->floor_xoffs;
- tempsec->floor_yoffs = s->floor_yoffs;
- if (underwater) {
- if (s->ceilingpic == skyflatnum) {
- tempsec->floorheight = tempsec->ceilingheight+1;
- tempsec->ceilingpic = tempsec->floorpic;
- tempsec->ceiling_xoffs = tempsec->floor_xoffs;
- tempsec->ceiling_yoffs = tempsec->floor_yoffs;
- } else {
- tempsec->ceilingpic = s->ceilingpic;
- tempsec->ceiling_xoffs = s->ceiling_xoffs;
- tempsec->ceiling_yoffs = s->ceiling_yoffs;
- }
- }
- tempsec->lightlevel = s->lightlevel;
- if (floorlightlevel)
- *floorlightlevel = s->floorlightsec == -1 ? s->lightlevel :
- sectors[s->floorlightsec].lightlevel; // killough 3/16/98
- if (ceilinglightlevel)
- *ceilinglightlevel = s->ceilinglightsec == -1 ? s->lightlevel :
- sectors[s->ceilinglightsec].lightlevel; // killough 4/11/98
- }
- else
- if (heightsec != -1 && viewz >= sectors[heightsec].ceilingheight &&
- sec->ceilingheight > s->ceilingheight)
- { // Above-ceiling hack
- tempsec->ceilingheight = s->ceilingheight;
- tempsec->floorheight = s->ceilingheight + 1;
- tempsec->floorpic = tempsec->ceilingpic = s->ceilingpic;
- tempsec->floor_xoffs = tempsec->ceiling_xoffs = s->ceiling_xoffs;
- tempsec->floor_yoffs = tempsec->ceiling_yoffs = s->ceiling_yoffs;
- if (s->floorpic != skyflatnum)
- {
- tempsec->ceilingheight = sec->ceilingheight;
- tempsec->floorpic = s->floorpic;
- tempsec->floor_xoffs = s->floor_xoffs;
- tempsec->floor_yoffs = s->floor_yoffs;
- }
- tempsec->lightlevel = s->lightlevel;
- if (floorlightlevel)
- *floorlightlevel = s->floorlightsec == -1 ? s->lightlevel :
- sectors[s->floorlightsec].lightlevel; // killough 3/16/98
- if (ceilinglightlevel)
- *ceilinglightlevel = s->ceilinglightsec == -1 ? s->lightlevel :
- sectors[s->ceilinglightsec].lightlevel; // killough 4/11/98
- }
- sec = tempsec; // Use other sector
- }
- return sec;
- }
- //
- // R_AddLine
- // Clips the given segment
- // and adds any visible pieces to the line list.
- //
- static void R_AddLine (seg_t *line)
- {
- int x1;
- int x2;
- angle_t angle1;
- angle_t angle2;
- angle_t span;
- angle_t tspan;
- static sector_t tempsec; // killough 3/8/98: ceiling/water hack
- curline = line;
- angle1 = R_PointToAngle (line->v1->x, line->v1->y);
- angle2 = R_PointToAngle (line->v2->x, line->v2->y);
- // Clip to view edges.
- span = angle1 - angle2;
- // Back side, i.e. backface culling
- if (span >= ANG180)
- return;
- // Global angle needed by segcalc.
- rw_angle1 = angle1;
- angle1 -= viewangle;
- angle2 -= viewangle;
- tspan = angle1 + clipangle;
- if (tspan > 2*clipangle)
- {
- tspan -= 2*clipangle;
- // Totally off the left edge?
- if (tspan >= span)
- return;
- angle1 = clipangle;
- }
- tspan = clipangle - angle2;
- if (tspan > 2*clipangle)
- {
- tspan -= 2*clipangle;
- // Totally off the left edge?
- if (tspan >= span)
- return;
- angle2 = 0-clipangle;
- }
- // The seg is in the view range,
- // but not necessarily visible.
- angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT;
- angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT;
- // killough 1/31/98: Here is where "slime trails" can SOMETIMES occur:
- x1 = viewangletox[angle1];
- x2 = viewangletox[angle2];
- #ifdef GL_DOOM
- // proff 11/99: we have to add these segs to avoid gaps in OpenGL
- if (x1 >= x2) // killough 1/31/98 -- change == to >= for robustness
- {
- if (V_GetMode() == VID_MODEGL)
- {
- if (ds_p == drawsegs+maxdrawsegs) // killough 1/98 -- fix 2s line HOM
- {
- unsigned pos = ds_p - drawsegs; // jff 8/9/98 fix from ZDOOM1.14a
- unsigned newmax = maxdrawsegs ? maxdrawsegs*2 : 128; // killough
- drawsegs = realloc(drawsegs,newmax*sizeof(*drawsegs));
- //ds_p = drawsegs+maxdrawsegs;
- ds_p = drawsegs + pos; // jff 8/9/98 fix from ZDOOM1.14a
- maxdrawsegs = newmax;
- }
- ds_p->curline = curline;
- ds_p++;
- gld_AddWall(curline);
- return;
- }
- else
- return;
- }
- #else
- // Does not cross a pixel?
- if (x1 >= x2) // killough 1/31/98 -- change == to >= for robustness
- return;
- #endif
- backsector = line->backsector;
- // Single sided line?
- if (backsector)
- // killough 3/8/98, 4/4/98: hack for invisible ceilings / deep water
- backsector = R_FakeFlat(backsector, &tempsec, NULL, NULL, true);
- /* cph - roll up linedef properties in flags */
- if ((linedef = curline->linedef)->r_validcount != gametic)
- R_RecalcLineFlags();
- if (linedef->r_flags & RF_IGNORE)
- {
- return;
- }
- else
- R_ClipWallSegment (x1, x2, linedef->r_flags & RF_CLOSED);
- }
- //
- // R_CheckBBox
- // Checks BSP node/subtree bounding box.
- // Returns true
- // if some part of the bbox might be visible.
- //
- static const int checkcoord[12][4] = // killough -- static const
- {
- {3,0,2,1},
- {3,0,2,0},
- {3,1,2,0},
- {0},
- {2,0,2,1},
- {0,0,0,0},
- {3,1,3,0},
- {0},
- {2,0,3,1},
- {2,1,3,1},
- {2,1,3,0}
- };
- // killough 1/28/98: static // CPhipps - const parameter, reformatted
- static boolean R_CheckBBox(const fixed_t *bspcoord)
- {
- angle_t angle1, angle2;
- {
- int boxpos;
- const int* check;
- // Find the corners of the box
- // that define the edges from current viewpoint.
- boxpos = (viewx <= bspcoord[BOXLEFT] ? 0 : viewx < bspcoord[BOXRIGHT ] ? 1 : 2) +
- (viewy >= bspcoord[BOXTOP ] ? 0 : viewy > bspcoord[BOXBOTTOM] ? 4 : 8);
- if (boxpos == 5)
- return true;
- check = checkcoord[boxpos];
- angle1 = R_PointToAngle (bspcoord[check[0]], bspcoord[check[1]]) - viewangle;
- angle2 = R_PointToAngle (bspcoord[check[2]], bspcoord[check[3]]) - viewangle;
- }
- // cph - replaced old code, which was unclear and badly commented
- // Much more efficient code now
- if ((signed)angle1 < (signed)angle2) { /* it's "behind" us */
- /* Either angle1 or angle2 is behind us, so it doesn't matter if we
- * change it to the corect sign
- */
- if ((angle1 >= ANG180) && (angle1 < ANG270))
- angle1 = INT_MAX; /* which is ANG180-1 */
- else
- angle2 = INT_MIN;
- }
- if ((signed)angle2 >= (signed)clipangle) return false; // Both off left edge
- if ((signed)angle1 <= -(signed)clipangle) return false; // Both off right edge
- if ((signed)angle1 >= (signed)clipangle) angle1 = clipangle; // Clip at left edge
- if ((signed)angle2 <= -(signed)clipangle) angle2 = 0-clipangle; // Clip at right edge
- // Find the first clippost
- // that touches the source post
- // (adjacent pixels are touching).
- angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT;
- angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT;
- {
- int sx1 = viewangletox[angle1];
- int sx2 = viewangletox[angle2];
- // const cliprange_t *start;
- // Does not cross a pixel.
- if (sx1 == sx2)
- return false;
- if (!memchr(solidcol+sx1, 0, sx2-sx1)) return false;
- // All columns it covers are already solidly covered
- }
- return true;
- }
- //
- // R_Subsector
- // Determine floor/ceiling planes.
- // Add sprites of things in sector.
- // Draw one or more line segments.
- //
- // killough 1/31/98 -- made static, polished
- // JDC: removed static so it won't be inlined in R_RenderBSPNode, which bloats the recursive stack
- /* static */ void R_Subsector(int num)
- {
- int count;
- seg_t *line;
- subsector_t *sub;
- sector_t tempsec; // killough 3/7/98: deep water hack
- int floorlightlevel; // killough 3/16/98: set floor lightlevel
- int ceilinglightlevel; // killough 4/11/98
- #ifdef GL_DOOM
- visplane_t dummyfloorplane;
- visplane_t dummyceilingplane;
- #endif
- #ifdef RANGECHECK
- if (num>=numsubsectors)
- I_Error ("R_Subsector: ss %i with numss = %i", num, numsubsectors);
- #endif
- sub = &subsectors[num];
- frontsector = sub->sector;
- count = sub->numlines;
- line = &segs[sub->firstline];
- // killough 3/8/98, 4/4/98: Deep water / fake ceiling effect
- frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel,
- &ceilinglightlevel, false); // killough 4/11/98
- // killough 3/7/98: Add (x,y) offsets to flats, add deep water check
- // killough 3/16/98: add floorlightlevel
- // killough 10/98: add support for skies transferred from sidedefs
- floorplane = frontsector->floorheight < viewz || // killough 3/7/98
- (frontsector->heightsec != -1 &&
- sectors[frontsector->heightsec].ceilingpic == skyflatnum) ?
- R_FindPlane(frontsector->floorheight,
- frontsector->floorpic == skyflatnum && // kilough 10/98
- frontsector->sky & PL_SKYFLAT ? frontsector->sky :
- frontsector->floorpic,
- floorlightlevel, // killough 3/16/98
- frontsector->floor_xoffs, // killough 3/7/98
- frontsector->floor_yoffs
- ) : NULL;
- ceilingplane = frontsector->ceilingheight > viewz ||
- frontsector->ceilingpic == skyflatnum ||
- (frontsector->heightsec != -1 &&
- sectors[frontsector->heightsec].floorpic == skyflatnum) ?
- R_FindPlane(frontsector->ceilingheight, // killough 3/8/98
- frontsector->ceilingpic == skyflatnum && // kilough 10/98
- frontsector->sky & PL_SKYFLAT ? frontsector->sky :
- frontsector->ceilingpic,
- ceilinglightlevel, // killough 4/11/98
- frontsector->ceiling_xoffs, // killough 3/7/98
- frontsector->ceiling_yoffs
- ) : NULL;
- #ifdef GL_DOOM
- // check if the sector is faked
- if ((frontsector==sub->sector) && (V_GetMode() == VID_MODEGL))
- {
- // if the sector has bottomtextures, then the floorheight will be set to the
- // highest surounding floorheight
- if ((frontsector->no_bottomtextures) || (!floorplane))
- {
- int i=frontsector->linecount;
- dummyfloorplane.height=INT_MIN;
- while (i--)
- {
- line_t *tmpline=frontsector->lines[i];
- if (tmpline->backsector)
- if (tmpline->backsector != frontsector)
- if (tmpline->backsector->floorheight>dummyfloorplane.height)
- {
- dummyfloorplane.height=tmpline->backsector->floorheight;
- dummyfloorplane.lightlevel=tmpline->backsector->lightlevel;
- }
- if (tmpline->frontsector)
- if (tmpline->frontsector != frontsector)
- if (tmpline->frontsector->floorheight>dummyfloorplane.height)
- {
- dummyfloorplane.height=tmpline->frontsector->floorheight;
- dummyfloorplane.lightlevel=tmpline->frontsector->lightlevel;
- }
- }
- if (dummyfloorplane.height!=INT_MIN)
- floorplane=&dummyfloorplane;
- }
- // the same for ceilings. they will be set to the lowest ceilingheight
- if ((frontsector->no_toptextures) || (!ceilingplane))
- {
- int i=frontsector->linecount;
- dummyceilingplane.height=INT_MAX;
- while (i--)
- {
- line_t *tmpline=frontsector->lines[i];
- if (tmpline->backsector)
- if (tmpline->backsector != frontsector)
- if (tmpline->backsector->ceilingheight<dummyceilingplane.height)
- {
- dummyceilingplane.height=tmpline->backsector->ceilingheight;
- dummyceilingplane.lightlevel=tmpline->backsector->lightlevel;
- }
- if (tmpline->frontsector)
- if (tmpline->frontsector != frontsector)
- if (tmpline->frontsector->ceilingheight<dummyceilingplane.height)
- {
- dummyceilingplane.height=tmpline->frontsector->ceilingheight;
- dummyceilingplane.lightlevel=tmpline->frontsector->lightlevel;
- }
- }
- if (dummyceilingplane.height!=INT_MAX)
- ceilingplane=&dummyceilingplane;
- }
- }
- #endif
- // killough 9/18/98: Fix underwater slowdown, by passing real sector
- // instead of fake one. Improve sprite lighting by basing sprite
- // lightlevels on floor & ceiling lightlevels in the surrounding area.
- //
- // 10/98 killough:
- //
- // NOTE: TeamTNT fixed this bug incorrectly, messing up sprite lighting!!!
- // That is part of the 242 effect!!! If you simply pass sub->sector to
- // the old code you will not get correct lighting for underwater sprites!!!
- // Either you must pass the fake sector and handle validcount here, on the
- // real sector, or you must account for the lighting in some other way,
- // like passing it as an argument.
- R_AddSprites(sub, (floorlightlevel+ceilinglightlevel)/2);
- while (count--)
- {
- if (line->miniseg == false)
- R_AddLine (line);
- line++;
- curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so R_ColourMap doesn't try using it for other things */
- }
- #ifdef GL_DOOM
- if (V_GetMode() == VID_MODEGL)
- gld_AddPlane(num, floorplane, ceilingplane);
- #endif
- }
- //
- // RenderBSPNode
- // Renders all subsectors below a given node,
- // traversing subtree recursively.
- // Just call with BSP root.
- //
- // killough 5/2/98: reformatted, removed tail recursion
- void R_RenderBSPNode(int bspnum)
- {
- while (!(bspnum & NF_SUBSECTOR)) // Found a subsector?
- {
- const node_t *bsp = &nodes[bspnum];
- // Decide which side the view point is on.
- int side = R_PointOnSide(viewx, viewy, bsp);
- // Recursively divide front space.
- R_RenderBSPNode(bsp->children[side]);
- // Possibly divide back space.
- if (!R_CheckBBox(bsp->bbox[side^1]))
- return;
- bspnum = bsp->children[side^1];
- }
- R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR);
- }
|