aboutsummaryrefslogtreecommitdiff
path: root/src/r_bsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/r_bsp.c')
-rw-r--r--src/r_bsp.c664
1 files changed, 664 insertions, 0 deletions
diff --git a/src/r_bsp.c b/src/r_bsp.c
new file mode 100644
index 0000000..e9ce6c5
--- /dev/null
+++ b/src/r_bsp.c
@@ -0,0 +1,664 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * BSP traversal, handling of LineSegs for rendering.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomstat.h"
35#include "m_bbox.h"
36#include "r_main.h"
37#include "r_segs.h"
38#include "r_plane.h"
39#include "r_things.h"
40#include "r_bsp.h" // cph - sanity checking
41#include "v_video.h"
42#include "lprintf.h"
43
44seg_t *curline;
45side_t *sidedef;
46line_t *linedef;
47sector_t *frontsector;
48sector_t *backsector;
49drawseg_t *ds_p;
50
51// killough 4/7/98: indicates doors closed wrt automap bugfix:
52// cph - replaced by linedef rendering flags - int doorclosed;
53
54// killough: New code which removes 2s linedef limit
55drawseg_t *drawsegs;
56unsigned maxdrawsegs;
57// drawseg_t drawsegs[MAXDRAWSEGS]; // old code -- killough
58
59//
60// R_ClearDrawSegs
61//
62
63void R_ClearDrawSegs(void)
64{
65 ds_p = drawsegs;
66}
67
68// CPhipps -
69// Instead of clipsegs, let's try using an array with one entry for each column,
70// indicating whether it's blocked by a solid wall yet or not.
71
72byte solidcol[MAX_SCREENWIDTH];
73
74// CPhipps -
75// R_ClipWallSegment
76//
77// Replaces the old R_Clip*WallSegment functions. It draws bits of walls in those
78// columns which aren't solid, and updates the solidcol[] array appropriately
79
80static void R_ClipWallSegment(int first, int last, boolean solid)
81{
82 byte *p;
83 while (first < last) {
84 if (solidcol[first]) {
85 if (!(p = memchr(solidcol+first, 0, last-first))) return; // All solid
86 first = p - solidcol;
87 } else {
88 int to;
89 if (!(p = memchr(solidcol+first, 1, last-first))) to = last;
90 else to = p - solidcol;
91 R_StoreWallRange(first, to-1);
92 if (solid) {
93 memset(solidcol+first,1,to-first);
94 }
95 first = to;
96 }
97 }
98}
99
100//
101// R_ClearClipSegs
102//
103
104void R_ClearClipSegs (void)
105{
106 memset(solidcol, 0, SCREENWIDTH);
107}
108
109// killough 1/18/98 -- This function is used to fix the automap bug which
110// showed lines behind closed doors simply because the door had a dropoff.
111//
112// cph - converted to R_RecalcLineFlags. This recalculates all the flags for
113// a line, including closure and texture tiling.
114
115static void R_RecalcLineFlags(void)
116{
117 linedef->r_validcount = gametic;
118
119 /* First decide if the line is closed, normal, or invisible */
120 if (!(linedef->flags & ML_TWOSIDED)
121 || backsector->ceilingheight <= frontsector->floorheight
122 || backsector->floorheight >= frontsector->ceilingheight
123 || (
124 // if door is closed because back is shut:
125 backsector->ceilingheight <= backsector->floorheight
126
127 // preserve a kind of transparent door/lift special effect:
128 && (backsector->ceilingheight >= frontsector->ceilingheight ||
129 curline->sidedef->toptexture)
130
131 && (backsector->floorheight <= frontsector->floorheight ||
132 curline->sidedef->bottomtexture)
133
134 // properly render skies (consider door "open" if both ceilings are sky):
135 && (backsector->ceilingpic !=skyflatnum ||
136 frontsector->ceilingpic!=skyflatnum)
137 )
138 )
139 linedef->r_flags = RF_CLOSED;
140 else {
141 // Reject empty lines used for triggers
142 // and special events.
143 // Identical floor and ceiling on both sides,
144 // identical light levels on both sides,
145 // and no middle texture.
146 // CPhipps - recode for speed, not certain if this is portable though
147 if (backsector->ceilingheight != frontsector->ceilingheight
148 || backsector->floorheight != frontsector->floorheight
149 || curline->sidedef->midtexture
150 || memcmp(&backsector->floor_xoffs, &frontsector->floor_xoffs,
151 sizeof(frontsector->floor_xoffs) + sizeof(frontsector->floor_yoffs) +
152 sizeof(frontsector->ceiling_xoffs) + sizeof(frontsector->ceiling_yoffs) +
153 sizeof(frontsector->ceilingpic) + sizeof(frontsector->floorpic) +
154 sizeof(frontsector->lightlevel) + sizeof(frontsector->floorlightsec) +
155 sizeof(frontsector->ceilinglightsec))) {
156 linedef->r_flags = 0; return;
157 } else
158 linedef->r_flags = RF_IGNORE;
159 }
160
161 /* cph - I'm too lazy to try and work with offsets in this */
162 if (curline->sidedef->rowoffset) return;
163
164 /* Now decide on texture tiling */
165 if (linedef->flags & ML_TWOSIDED) {
166 int c;
167
168 /* Does top texture need tiling */
169 if ((c = frontsector->ceilingheight - backsector->ceilingheight) > 0 &&
170 (textureheight[texturetranslation[curline->sidedef->toptexture]] > c))
171 linedef->r_flags |= RF_TOP_TILE;
172
173 /* Does bottom texture need tiling */
174 if ((c = frontsector->floorheight - backsector->floorheight) > 0 &&
175 (textureheight[texturetranslation[curline->sidedef->bottomtexture]] > c))
176 linedef->r_flags |= RF_BOT_TILE;
177 } else {
178 int c;
179 /* Does middle texture need tiling */
180 if ((c = frontsector->ceilingheight - frontsector->floorheight) > 0 &&
181 (textureheight[texturetranslation[curline->sidedef->midtexture]] > c))
182 linedef->r_flags |= RF_MID_TILE;
183 }
184}
185
186//
187// killough 3/7/98: Hack floor/ceiling heights for deep water etc.
188//
189// If player's view height is underneath fake floor, lower the
190// drawn ceiling to be just under the floor height, and replace
191// the drawn floor and ceiling textures, and light level, with
192// the control sector's.
193//
194// Similar for ceiling, only reflected.
195//
196// killough 4/11/98, 4/13/98: fix bugs, add 'back' parameter
197//
198
199sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec,
200 int *floorlightlevel, int *ceilinglightlevel,
201 boolean back)
202{
203 if (floorlightlevel)
204 *floorlightlevel = sec->floorlightsec == -1 ?
205 sec->lightlevel : sectors[sec->floorlightsec].lightlevel;
206
207 if (ceilinglightlevel)
208 *ceilinglightlevel = sec->ceilinglightsec == -1 ? // killough 4/11/98
209 sec->lightlevel : sectors[sec->ceilinglightsec].lightlevel;
210
211 if (sec->heightsec != -1)
212 {
213 const sector_t *s = &sectors[sec->heightsec];
214 int heightsec = viewplayer->mo->subsector->sector->heightsec;
215 int underwater = heightsec!=-1 && viewz<=sectors[heightsec].floorheight;
216
217 // Replace sector being drawn, with a copy to be hacked
218 *tempsec = *sec;
219
220 // Replace floor and ceiling height with other sector's heights.
221 tempsec->floorheight = s->floorheight;
222 tempsec->ceilingheight = s->ceilingheight;
223
224 // killough 11/98: prevent sudden light changes from non-water sectors:
225 if (underwater && (tempsec-> floorheight = sec->floorheight,
226 tempsec->ceilingheight = s->floorheight-1, !back))
227 { // head-below-floor hack
228 tempsec->floorpic = s->floorpic;
229 tempsec->floor_xoffs = s->floor_xoffs;
230 tempsec->floor_yoffs = s->floor_yoffs;
231
232 if (underwater) {
233 if (s->ceilingpic == skyflatnum) {
234 tempsec->floorheight = tempsec->ceilingheight+1;
235 tempsec->ceilingpic = tempsec->floorpic;
236 tempsec->ceiling_xoffs = tempsec->floor_xoffs;
237 tempsec->ceiling_yoffs = tempsec->floor_yoffs;
238 } else {
239 tempsec->ceilingpic = s->ceilingpic;
240 tempsec->ceiling_xoffs = s->ceiling_xoffs;
241 tempsec->ceiling_yoffs = s->ceiling_yoffs;
242 }
243 }
244
245 tempsec->lightlevel = s->lightlevel;
246
247 if (floorlightlevel)
248 *floorlightlevel = s->floorlightsec == -1 ? s->lightlevel :
249 sectors[s->floorlightsec].lightlevel; // killough 3/16/98
250
251 if (ceilinglightlevel)
252 *ceilinglightlevel = s->ceilinglightsec == -1 ? s->lightlevel :
253 sectors[s->ceilinglightsec].lightlevel; // killough 4/11/98
254 }
255 else
256 if (heightsec != -1 && viewz >= sectors[heightsec].ceilingheight &&
257 sec->ceilingheight > s->ceilingheight)
258 { // Above-ceiling hack
259 tempsec->ceilingheight = s->ceilingheight;
260 tempsec->floorheight = s->ceilingheight + 1;
261
262 tempsec->floorpic = tempsec->ceilingpic = s->ceilingpic;
263 tempsec->floor_xoffs = tempsec->ceiling_xoffs = s->ceiling_xoffs;
264 tempsec->floor_yoffs = tempsec->ceiling_yoffs = s->ceiling_yoffs;
265
266 if (s->floorpic != skyflatnum)
267 {
268 tempsec->ceilingheight = sec->ceilingheight;
269 tempsec->floorpic = s->floorpic;
270 tempsec->floor_xoffs = s->floor_xoffs;
271 tempsec->floor_yoffs = s->floor_yoffs;
272 }
273
274 tempsec->lightlevel = s->lightlevel;
275
276 if (floorlightlevel)
277 *floorlightlevel = s->floorlightsec == -1 ? s->lightlevel :
278 sectors[s->floorlightsec].lightlevel; // killough 3/16/98
279
280 if (ceilinglightlevel)
281 *ceilinglightlevel = s->ceilinglightsec == -1 ? s->lightlevel :
282 sectors[s->ceilinglightsec].lightlevel; // killough 4/11/98
283 }
284 sec = tempsec; // Use other sector
285 }
286 return sec;
287}
288
289//
290// R_AddLine
291// Clips the given segment
292// and adds any visible pieces to the line list.
293//
294
295static void R_AddLine (seg_t *line)
296{
297 int x1;
298 int x2;
299 angle_t angle1;
300 angle_t angle2;
301 angle_t span;
302 angle_t tspan;
303 static sector_t tempsec; // killough 3/8/98: ceiling/water hack
304
305 curline = line;
306
307 angle1 = R_PointToAngle (line->v1->x, line->v1->y);
308 angle2 = R_PointToAngle (line->v2->x, line->v2->y);
309
310 // Clip to view edges.
311 span = angle1 - angle2;
312
313 // Back side, i.e. backface culling
314 if (span >= ANG180)
315 return;
316
317 // Global angle needed by segcalc.
318 rw_angle1 = angle1;
319 angle1 -= viewangle;
320 angle2 -= viewangle;
321
322 tspan = angle1 + clipangle;
323 if (tspan > 2*clipangle)
324 {
325 tspan -= 2*clipangle;
326
327 // Totally off the left edge?
328 if (tspan >= span)
329 return;
330
331 angle1 = clipangle;
332 }
333
334 tspan = clipangle - angle2;
335 if (tspan > 2*clipangle)
336 {
337 tspan -= 2*clipangle;
338
339 // Totally off the left edge?
340 if (tspan >= span)
341 return;
342 angle2 = 0-clipangle;
343 }
344
345 // The seg is in the view range,
346 // but not necessarily visible.
347
348 angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT;
349 angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT;
350
351 // killough 1/31/98: Here is where "slime trails" can SOMETIMES occur:
352 x1 = viewangletox[angle1];
353 x2 = viewangletox[angle2];
354
355#ifdef GL_DOOM
356 // proff 11/99: we have to add these segs to avoid gaps in OpenGL
357 if (x1 >= x2) // killough 1/31/98 -- change == to >= for robustness
358 {
359 if (V_GetMode() == VID_MODEGL)
360 {
361 if (ds_p == drawsegs+maxdrawsegs) // killough 1/98 -- fix 2s line HOM
362 {
363 unsigned pos = ds_p - drawsegs; // jff 8/9/98 fix from ZDOOM1.14a
364 unsigned newmax = maxdrawsegs ? maxdrawsegs*2 : 128; // killough
365 drawsegs = realloc(drawsegs,newmax*sizeof(*drawsegs));
366 //ds_p = drawsegs+maxdrawsegs;
367 ds_p = drawsegs + pos; // jff 8/9/98 fix from ZDOOM1.14a
368 maxdrawsegs = newmax;
369 }
370 ds_p->curline = curline;
371 ds_p++;
372 gld_AddWall(curline);
373 return;
374 }
375 else
376 return;
377 }
378#else
379 // Does not cross a pixel?
380 if (x1 >= x2) // killough 1/31/98 -- change == to >= for robustness
381 return;
382#endif
383
384 backsector = line->backsector;
385
386 // Single sided line?
387 if (backsector)
388 // killough 3/8/98, 4/4/98: hack for invisible ceilings / deep water
389 backsector = R_FakeFlat(backsector, &tempsec, NULL, NULL, true);
390
391 /* cph - roll up linedef properties in flags */
392 if ((linedef = curline->linedef)->r_validcount != gametic)
393 R_RecalcLineFlags();
394
395 if (linedef->r_flags & RF_IGNORE)
396 {
397 return;
398 }
399 else
400 R_ClipWallSegment (x1, x2, linedef->r_flags & RF_CLOSED);
401}
402
403//
404// R_CheckBBox
405// Checks BSP node/subtree bounding box.
406// Returns true
407// if some part of the bbox might be visible.
408//
409
410static const int checkcoord[12][4] = // killough -- static const
411{
412 {3,0,2,1},
413 {3,0,2,0},
414 {3,1,2,0},
415 {0},
416 {2,0,2,1},
417 {0,0,0,0},
418 {3,1,3,0},
419 {0},
420 {2,0,3,1},
421 {2,1,3,1},
422 {2,1,3,0}
423};
424
425// killough 1/28/98: static // CPhipps - const parameter, reformatted
426static boolean R_CheckBBox(const fixed_t *bspcoord)
427{
428 angle_t angle1, angle2;
429
430 {
431 int boxpos;
432 const int* check;
433
434 // Find the corners of the box
435 // that define the edges from current viewpoint.
436 boxpos = (viewx <= bspcoord[BOXLEFT] ? 0 : viewx < bspcoord[BOXRIGHT ] ? 1 : 2) +
437 (viewy >= bspcoord[BOXTOP ] ? 0 : viewy > bspcoord[BOXBOTTOM] ? 4 : 8);
438
439 if (boxpos == 5)
440 return true;
441
442 check = checkcoord[boxpos];
443 angle1 = R_PointToAngle (bspcoord[check[0]], bspcoord[check[1]]) - viewangle;
444 angle2 = R_PointToAngle (bspcoord[check[2]], bspcoord[check[3]]) - viewangle;
445 }
446
447 // cph - replaced old code, which was unclear and badly commented
448 // Much more efficient code now
449 if ((signed)angle1 < (signed)angle2) { /* it's "behind" us */
450 /* Either angle1 or angle2 is behind us, so it doesn't matter if we
451 * change it to the corect sign
452 */
453 if ((angle1 >= ANG180) && (angle1 < ANG270))
454 angle1 = INT_MAX; /* which is ANG180-1 */
455 else
456 angle2 = INT_MIN;
457 }
458
459 if ((signed)angle2 >= (signed)clipangle) return false; // Both off left edge
460 if ((signed)angle1 <= -(signed)clipangle) return false; // Both off right edge
461 if ((signed)angle1 >= (signed)clipangle) angle1 = clipangle; // Clip at left edge
462 if ((signed)angle2 <= -(signed)clipangle) angle2 = 0-clipangle; // Clip at right edge
463
464 // Find the first clippost
465 // that touches the source post
466 // (adjacent pixels are touching).
467 angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT;
468 angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT;
469 {
470 int sx1 = viewangletox[angle1];
471 int sx2 = viewangletox[angle2];
472 // const cliprange_t *start;
473
474 // Does not cross a pixel.
475 if (sx1 == sx2)
476 return false;
477
478 if (!memchr(solidcol+sx1, 0, sx2-sx1)) return false;
479 // All columns it covers are already solidly covered
480 }
481
482 return true;
483}
484
485//
486// R_Subsector
487// Determine floor/ceiling planes.
488// Add sprites of things in sector.
489// Draw one or more line segments.
490//
491// killough 1/31/98 -- made static, polished
492
493static void R_Subsector(int num)
494{
495 int count;
496 seg_t *line;
497 subsector_t *sub;
498 sector_t tempsec; // killough 3/7/98: deep water hack
499 int floorlightlevel; // killough 3/16/98: set floor lightlevel
500 int ceilinglightlevel; // killough 4/11/98
501#ifdef GL_DOOM
502 visplane_t dummyfloorplane;
503 visplane_t dummyceilingplane;
504#endif
505
506#ifdef RANGECHECK
507 if (num>=numsubsectors)
508 I_Error ("R_Subsector: ss %i with numss = %i", num, numsubsectors);
509#endif
510
511 sub = &subsectors[num];
512 frontsector = sub->sector;
513 count = sub->numlines;
514 line = &segs[sub->firstline];
515
516 // killough 3/8/98, 4/4/98: Deep water / fake ceiling effect
517 frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel,
518 &ceilinglightlevel, false); // killough 4/11/98
519
520 // killough 3/7/98: Add (x,y) offsets to flats, add deep water check
521 // killough 3/16/98: add floorlightlevel
522 // killough 10/98: add support for skies transferred from sidedefs
523
524 floorplane = frontsector->floorheight < viewz || // killough 3/7/98
525 (frontsector->heightsec != -1 &&
526 sectors[frontsector->heightsec].ceilingpic == skyflatnum) ?
527 R_FindPlane(frontsector->floorheight,
528 frontsector->floorpic == skyflatnum && // kilough 10/98
529 frontsector->sky & PL_SKYFLAT ? frontsector->sky :
530 frontsector->floorpic,
531 floorlightlevel, // killough 3/16/98
532 frontsector->floor_xoffs, // killough 3/7/98
533 frontsector->floor_yoffs
534 ) : NULL;
535
536 ceilingplane = frontsector->ceilingheight > viewz ||
537 frontsector->ceilingpic == skyflatnum ||
538 (frontsector->heightsec != -1 &&
539 sectors[frontsector->heightsec].floorpic == skyflatnum) ?
540 R_FindPlane(frontsector->ceilingheight, // killough 3/8/98
541 frontsector->ceilingpic == skyflatnum && // kilough 10/98
542 frontsector->sky & PL_SKYFLAT ? frontsector->sky :
543 frontsector->ceilingpic,
544 ceilinglightlevel, // killough 4/11/98
545 frontsector->ceiling_xoffs, // killough 3/7/98
546 frontsector->ceiling_yoffs
547 ) : NULL;
548#ifdef GL_DOOM
549 // check if the sector is faked
550 if ((frontsector==sub->sector) && (V_GetMode() == VID_MODEGL))
551 {
552 // if the sector has bottomtextures, then the floorheight will be set to the
553 // highest surounding floorheight
554 if ((frontsector->no_bottomtextures) || (!floorplane))
555 {
556 int i=frontsector->linecount;
557
558 dummyfloorplane.height=INT_MIN;
559 while (i--)
560 {
561 line_t *tmpline=frontsector->lines[i];
562 if (tmpline->backsector)
563 if (tmpline->backsector != frontsector)
564 if (tmpline->backsector->floorheight>dummyfloorplane.height)
565 {
566 dummyfloorplane.height=tmpline->backsector->floorheight;
567 dummyfloorplane.lightlevel=tmpline->backsector->lightlevel;
568 }
569 if (tmpline->frontsector)
570 if (tmpline->frontsector != frontsector)
571 if (tmpline->frontsector->floorheight>dummyfloorplane.height)
572 {
573 dummyfloorplane.height=tmpline->frontsector->floorheight;
574 dummyfloorplane.lightlevel=tmpline->frontsector->lightlevel;
575 }
576 }
577 if (dummyfloorplane.height!=INT_MIN)
578 floorplane=&dummyfloorplane;
579 }
580 // the same for ceilings. they will be set to the lowest ceilingheight
581 if ((frontsector->no_toptextures) || (!ceilingplane))
582 {
583 int i=frontsector->linecount;
584
585 dummyceilingplane.height=INT_MAX;
586 while (i--)
587 {
588 line_t *tmpline=frontsector->lines[i];
589 if (tmpline->backsector)
590 if (tmpline->backsector != frontsector)
591 if (tmpline->backsector->ceilingheight<dummyceilingplane.height)
592 {
593 dummyceilingplane.height=tmpline->backsector->ceilingheight;
594 dummyceilingplane.lightlevel=tmpline->backsector->lightlevel;
595 }
596 if (tmpline->frontsector)
597 if (tmpline->frontsector != frontsector)
598 if (tmpline->frontsector->ceilingheight<dummyceilingplane.height)
599 {
600 dummyceilingplane.height=tmpline->frontsector->ceilingheight;
601 dummyceilingplane.lightlevel=tmpline->frontsector->lightlevel;
602 }
603 }
604 if (dummyceilingplane.height!=INT_MAX)
605 ceilingplane=&dummyceilingplane;
606 }
607 }
608#endif
609
610 // killough 9/18/98: Fix underwater slowdown, by passing real sector
611 // instead of fake one. Improve sprite lighting by basing sprite
612 // lightlevels on floor & ceiling lightlevels in the surrounding area.
613 //
614 // 10/98 killough:
615 //
616 // NOTE: TeamTNT fixed this bug incorrectly, messing up sprite lighting!!!
617 // That is part of the 242 effect!!! If you simply pass sub->sector to
618 // the old code you will not get correct lighting for underwater sprites!!!
619 // Either you must pass the fake sector and handle validcount here, on the
620 // real sector, or you must account for the lighting in some other way,
621 // like passing it as an argument.
622
623 R_AddSprites(sub, (floorlightlevel+ceilinglightlevel)/2);
624 while (count--)
625 {
626 if (line->miniseg == false)
627 R_AddLine (line);
628 line++;
629 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 */
630 }
631#ifdef GL_DOOM
632 if (V_GetMode() == VID_MODEGL)
633 gld_AddPlane(num, floorplane, ceilingplane);
634#endif
635}
636
637//
638// RenderBSPNode
639// Renders all subsectors below a given node,
640// traversing subtree recursively.
641// Just call with BSP root.
642//
643// killough 5/2/98: reformatted, removed tail recursion
644
645void R_RenderBSPNode(int bspnum)
646{
647 while (!(bspnum & NF_SUBSECTOR)) // Found a subsector?
648 {
649 const node_t *bsp = &nodes[bspnum];
650
651 // Decide which side the view point is on.
652 int side = R_PointOnSide(viewx, viewy, bsp);
653 // Recursively divide front space.
654 R_RenderBSPNode(bsp->children[side]);
655
656 // Possibly divide back space.
657
658 if (!R_CheckBBox(bsp->bbox[side^1]))
659 return;
660
661 bspnum = bsp->children[side^1];
662 }
663 R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR);
664}