1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: r_bsp.cpp 4706 2014-03-28 15:25:42Z dr_sean $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Copyright (C) 2006-2014 by The Odamex Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // DESCRIPTION:
20 // BSP traversal, handling of LineSegs for rendering.
21 //
22 //-----------------------------------------------------------------------------
23
24 #include <math.h>
25 #include "m_alloc.h"
26 #include "doomdef.h"
27 #include "m_bbox.h"
28 #include "i_system.h"
29 #include "r_main.h"
30 #include "r_plane.h"
31 #include "r_draw.h"
32 #include "r_things.h"
33 #include "p_local.h"
34 #include "m_vectors.h"
35
36 // State.
37 #include "doomstat.h"
38 #include "r_state.h"
39 #include "v_palette.h"
40
41 EXTERN_CVAR (r_particles)
42
43 seg_t* curline;
44 side_t* sidedef;
45 line_t* linedef;
46 sector_t* frontsector;
47 sector_t* backsector;
48
49 // killough 4/7/98: indicates doors closed wrt automap bugfix:
50 bool doorclosed;
51
52 bool r_fakingunderwater;
53 bool r_underwater;
54
55 // Floor and ceiling heights at the end points of a seg_t
56 fixed_t rw_backcz1, rw_backcz2;
57 fixed_t rw_backfz1, rw_backfz2;
58 fixed_t rw_frontcz1, rw_frontcz2;
59 fixed_t rw_frontfz1, rw_frontfz2;
60
61 int rw_start, rw_stop;
62
63 static BYTE FakeSide;
64
65 const fixed_t NEARCLIP = 2*FRACUNIT;
66
67 drawseg_t* ds_p;
68 drawseg_t* drawsegs;
69 unsigned maxdrawsegs;
70
71 // CPhipps -
72 // Instead of clipsegs, let's try using an array with one entry for each column,
73 // indicating whether it's blocked by a solid wall yet or not.
74 // e6y: resolution limitation is removed
75 byte *solidcol;
76
77 //
78 // R_ClearClipSegs
79 //
R_ClearClipSegs(void)80 void R_ClearClipSegs (void)
81 {
82 memset(solidcol, 0, viewwidth);
83 }
84
85 //
86 // R_ReallocDrawSegs
87 //
88 // [SL] From prboom-plus. Moved out of R_StoreWallRange()
R_ReallocDrawSegs(void)89 void R_ReallocDrawSegs(void)
90 {
91 if (ds_p == drawsegs+maxdrawsegs) // killough 1/98 -- fix 2s line HOM
92 {
93 unsigned pos = ds_p - drawsegs; // jff 8/9/98 fix from ZDOOM1.14a
94 unsigned newmax = maxdrawsegs ? maxdrawsegs*2 : 128; // killough
95 drawsegs = (drawseg_t*)realloc(drawsegs, newmax*sizeof(*drawsegs));
96 ds_p = drawsegs + pos; // jff 8/9/98 fix from ZDOOM1.14a
97 maxdrawsegs = newmax;
98 DPrintf("MaxDrawSegs increased to %d\n", maxdrawsegs);
99 }
100 }
101
102 //
103 // R_ClearDrawSegs
104 //
R_ClearDrawSegs(void)105 void R_ClearDrawSegs(void)
106 {
107 ds_p = drawsegs;
108 }
109
110 //
111 // R_ClipWallSegment
112 //
113 // [SL] From prboom-plus. Modified for clarity.
114 //
115 // Calls R_StoreWallRange for each span of non-solid range of columns that
116 // is within the range of first to (and including) last. Non-solid columns
117 // are those which have not yet had a 1s lineseg drawn to them. If makesolid
118 // is specified, any range of non-solid columns found will be marked as solid.
119 //
R_ClipWallSegment(int first,int last,bool makesolid)120 static void R_ClipWallSegment(int first, int last, bool makesolid)
121 {
122 while (first <= last)
123 {
124 if (solidcol[first])
125 {
126 // find the first remaining non-solid column
127 // if all columns remaining are solid, we're done
128 byte* p = (byte*)memchr(solidcol + first, 0, last - first + 1);
129 if (p == NULL)
130 return;
131
132 first = p - solidcol;
133 }
134 else
135 {
136 int to;
137 // find where the span of non-solid columns ends
138 byte* p = (byte*)memchr(solidcol + first, 1, last - first + 1);
139 if (p == NULL)
140 to = last;
141 else
142 to = p - solidcol - 1;
143
144 // set the range for this wall to the range of non-solid columns
145 R_StoreWallRange(first, to);
146
147 // mark the columns as solid
148 if (makesolid)
149 memset(solidcol + first, 1, to - first + 1);
150
151 first = to + 1;
152 }
153 }
154 }
155
CopyPlaneIfValid(plane_t * dest,const plane_t * source,const plane_t * opp)156 bool CopyPlaneIfValid (plane_t *dest, const plane_t *source, const plane_t *opp)
157 {
158 bool copy = false;
159
160 // If the planes do not have matching slopes, then always copy them
161 // because clipping would require creating new sectors.
162 if (source->a != dest->a || source->b != dest->b || source->c != dest->c)
163 {
164 copy = true;
165 }
166 else if (opp->a != -dest->a || opp->b != -dest->b || opp->c != -dest->c)
167 {
168 if (source->d < dest->d)
169 {
170 copy = true;
171 }
172 }
173 else if (source->d < dest->d && source->d > -opp->d)
174 {
175 copy = true;
176 }
177
178 if (copy)
179 {
180 memcpy(dest, source, sizeof(plane_t));
181 }
182
183 return copy;
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
R_FakeFlat(sector_t * sec,sector_t * tempsec,int * floorlightlevel,int * ceilinglightlevel,bool back)199 sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec,
200 int *floorlightlevel, int *ceilinglightlevel,
201 bool back)
202 {
203 // [RH] allow per-plane lighting
204 if (floorlightlevel != NULL)
205 {
206 *floorlightlevel = sec->floorlightsec == NULL ?
207 sec->lightlevel : sec->floorlightsec->lightlevel;
208 }
209
210 if (ceilinglightlevel != NULL)
211 {
212 *ceilinglightlevel = sec->ceilinglightsec == NULL ? // killough 4/11/98
213 sec->lightlevel : sec->ceilinglightsec->lightlevel;
214 }
215
216 FakeSide = FAKED_Center;
217
218 if (!sec->heightsec || sec->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC)
219 return sec;
220 if (!camera || !camera->subsector || !camera->subsector->sector)
221 return sec;
222
223 const sector_t* s = sec->heightsec;
224 sector_t *heightsec = camera->subsector->sector->heightsec;
225
226 bool underwater = r_fakingunderwater ||
227 (heightsec && viewz <= P_FloorHeight(viewx, viewy, heightsec));
228 bool doorunderwater = false;
229 int diffTex = (s->MoreFlags & SECF_CLIPFAKEPLANES);
230
231 // Replace sector being drawn with a copy to be hacked
232 *tempsec = *sec;
233
234 // Replace floor and ceiling height with control sector's heights.
235 if (diffTex)
236 {
237 if (CopyPlaneIfValid (&tempsec->floorplane, &s->floorplane, &sec->ceilingplane))
238 tempsec->floorpic = s->floorpic;
239 else if (s->MoreFlags & SECF_FAKEFLOORONLY)
240 {
241 if (underwater)
242 {
243 tempsec->floorcolormap = s->floorcolormap;
244 tempsec->ceilingcolormap = s->ceilingcolormap;
245
246 if (!(s->MoreFlags & SECF_NOFAKELIGHT))
247 {
248 tempsec->lightlevel = s->lightlevel;
249
250 if (floorlightlevel != NULL)
251 {
252 *floorlightlevel = s->floorlightsec == NULL ?
253 s->lightlevel : s->floorlightsec->lightlevel;
254 }
255
256 if (ceilinglightlevel != NULL)
257 {
258 *ceilinglightlevel = s->ceilinglightsec == NULL ?
259 s->lightlevel : s->ceilinglightsec->lightlevel;
260 }
261 }
262
263 FakeSide = FAKED_BelowFloor;
264 return tempsec;
265 }
266 return sec;
267 }
268 }
269 else
270 {
271 tempsec->floorplane = s->floorplane;
272 }
273
274 if (!(s->MoreFlags & SECF_FAKEFLOORONLY))
275 {
276 if (diffTex)
277 {
278 if (CopyPlaneIfValid (&tempsec->ceilingplane, &s->ceilingplane, &sec->floorplane))
279 tempsec->ceilingpic = s->ceilingpic;
280 }
281 else
282 {
283 tempsec->ceilingplane = s->ceilingplane;
284 }
285 }
286
287 fixed_t refceilz = P_CeilingHeight(viewx, viewy, s);
288 fixed_t orgceilz = P_CeilingHeight(viewx, viewy, sec);
289
290 // [RH] Allow viewing underwater areas through doors/windows that
291 // are underwater but not in a water sector themselves.
292 // Only works if you cannot see the top surface of any deep water
293 // sectors at the same time.
294
295 if (back && !r_fakingunderwater && curline->frontsector->heightsec == NULL)
296 {
297 fixed_t fcz1 = P_CeilingHeight(curline->v1->x, curline->v1->y, frontsector);
298 fixed_t fcz2 = P_CeilingHeight(curline->v2->x, curline->v2->y, frontsector);
299
300 if (fcz1 <= P_FloorHeight(curline->v1->x, curline->v1->y, s) &&
301 fcz2 <= P_FloorHeight(curline->v2->x, curline->v2->y, s))
302 {
303 // will any columns of this window be visible or will they be blocked
304 // by 1s lines and closed doors?
305 if (memchr(solidcol + rw_start, 0, rw_stop - rw_start + 1) != NULL)
306 {
307 doorunderwater = true;
308 r_fakingunderwater = true;
309 }
310 }
311 }
312
313 if (underwater || doorunderwater)
314 {
315 tempsec->floorplane = sec->floorplane;
316 tempsec->ceilingplane = s->floorplane;
317 P_InvertPlane(&tempsec->ceilingplane);
318 P_ChangeCeilingHeight(tempsec, -1);
319 tempsec->floorcolormap = s->floorcolormap;
320 tempsec->ceilingcolormap = s->ceilingcolormap;
321 }
322
323 // killough 11/98: prevent sudden light changes from non-water sectors:
324 if ((underwater && !back) || doorunderwater)
325 { // head-below-floor hack
326 tempsec->floorpic = diffTex ? sec->floorpic : s->floorpic;
327 tempsec->floor_xoffs = s->floor_xoffs;
328 tempsec->floor_yoffs = s->floor_yoffs;
329 tempsec->floor_xscale = s->floor_xscale;
330 tempsec->floor_yscale = s->floor_yscale;
331 tempsec->floor_angle = s->floor_angle;
332 tempsec->base_floor_angle = s->base_floor_angle;
333 tempsec->base_floor_yoffs = s->base_floor_yoffs;
334
335 tempsec->ceilingplane = s->floorplane;
336 P_InvertPlane(&tempsec->ceilingplane);
337 P_ChangeCeilingHeight(tempsec, -1);
338 if (s->ceilingpic == skyflatnum)
339 {
340 tempsec->floorplane = tempsec->ceilingplane;
341 P_InvertPlane(&tempsec->floorplane);
342 P_ChangeFloorHeight(tempsec, +1);
343 tempsec->ceilingpic = tempsec->floorpic;
344 tempsec->ceiling_xoffs = tempsec->floor_xoffs;
345 tempsec->ceiling_yoffs = tempsec->floor_yoffs;
346 tempsec->ceiling_xscale = tempsec->floor_xscale;
347 tempsec->ceiling_yscale = tempsec->floor_yscale;
348 tempsec->ceiling_angle = tempsec->floor_angle;
349 tempsec->base_ceiling_angle = tempsec->base_floor_angle;
350 tempsec->base_ceiling_yoffs = tempsec->base_floor_yoffs;
351 }
352 else
353 {
354 tempsec->ceilingpic = diffTex ? s->floorpic : s->ceilingpic;
355 tempsec->ceiling_xoffs = s->ceiling_xoffs;
356 tempsec->ceiling_yoffs = s->ceiling_yoffs;
357 tempsec->ceiling_xscale = s->ceiling_xscale;
358 tempsec->ceiling_yscale = s->ceiling_yscale;
359 tempsec->ceiling_angle = s->ceiling_angle;
360 tempsec->base_ceiling_angle = s->base_ceiling_angle;
361 tempsec->base_ceiling_yoffs = s->base_ceiling_yoffs;
362 }
363
364 if (!(s->MoreFlags & SECF_NOFAKELIGHT))
365 {
366 tempsec->lightlevel = s->lightlevel;
367
368 if (floorlightlevel != NULL)
369 {
370 *floorlightlevel = s->floorlightsec == NULL ?
371 s->lightlevel : s->floorlightsec->lightlevel;
372 }
373
374 if (ceilinglightlevel != NULL)
375 {
376 *ceilinglightlevel = s->ceilinglightsec == NULL ?
377 s->lightlevel : s->ceilinglightsec->lightlevel;
378 }
379 }
380 FakeSide = FAKED_BelowFloor;
381 }
382 else if (heightsec && viewz >= P_CeilingHeight(viewx, viewy, heightsec) &&
383 orgceilz > refceilz && !(s->MoreFlags & SECF_FAKEFLOORONLY))
384 { // Above-ceiling hack
385 tempsec->ceilingplane = s->ceilingplane;
386 tempsec->floorplane = s->ceilingplane;
387 P_InvertPlane(&tempsec->floorplane);
388 P_ChangeFloorHeight(tempsec, +1);
389
390 tempsec->ceilingcolormap = s->ceilingcolormap;
391 tempsec->floorcolormap = s->floorcolormap;
392
393 tempsec->ceilingpic = diffTex ? sec->ceilingpic : s->ceilingpic;
394 tempsec->floorpic = s->ceilingpic;
395 tempsec->floor_xoffs = tempsec->ceiling_xoffs = s->ceiling_xoffs;
396 tempsec->floor_yoffs = tempsec->ceiling_yoffs = s->ceiling_yoffs;
397 tempsec->floor_xscale = tempsec->ceiling_xscale = s->ceiling_xscale;
398 tempsec->floor_yscale = tempsec->ceiling_yscale = s->ceiling_yscale;
399 tempsec->floor_angle = tempsec->ceiling_angle = s->ceiling_angle;
400 tempsec->base_floor_angle = tempsec->base_ceiling_angle = s->base_ceiling_angle;
401 tempsec->base_floor_yoffs = tempsec->base_ceiling_yoffs = s->base_ceiling_yoffs;
402
403 if (s->floorpic != skyflatnum)
404 {
405 tempsec->ceilingplane = sec->ceilingplane;
406 tempsec->floorpic = s->floorpic;
407 tempsec->floor_xoffs = s->floor_xoffs;
408 tempsec->floor_yoffs = s->floor_yoffs;
409 tempsec->floor_xscale = s->floor_xscale;
410 tempsec->floor_yscale = s->floor_yscale;
411 tempsec->floor_angle = s->floor_angle;
412 }
413
414 if (!(s->MoreFlags & SECF_NOFAKELIGHT))
415 {
416 tempsec->lightlevel = s->lightlevel;
417
418 if (floorlightlevel != NULL)
419 {
420 *floorlightlevel = s->floorlightsec == NULL ?
421 s->lightlevel : s->floorlightsec->lightlevel;
422 }
423
424 if (ceilinglightlevel != NULL)
425 {
426 *ceilinglightlevel = s->ceilinglightsec == NULL ?
427 s->lightlevel : s->ceilinglightsec->lightlevel;
428 }
429 }
430 FakeSide = FAKED_AboveCeiling;
431 }
432 sec = tempsec; // Use other sector
433
434 return sec;
435 }
436
437
438 //
439 // R_AddLine
440 // Clips the given segment
441 // and adds any visible pieces to the line list.
442 //
R_AddLine(seg_t * line)443 void R_AddLine (seg_t *line)
444 {
445 curline = line;
446
447 // skip this line if it's not facing the camera
448 if (R_PointOnSegSide(viewx, viewy, line) != 0)
449 return;
450
451 dcol.color = ((line - segs) & 31) * 4; // [RH] Color if not texturing line
452
453 // translate the line seg endpoints from world-space to camera-space
454 // and store in (t1.x, t1.y) and (t2.x, t2.y)
455 v2fixed_t t1, t2;
456 R_RotatePoint(line->v1->x - viewx, line->v1->y - viewy, ANG90 - viewangle, t1.x, t1.y);
457 R_RotatePoint(line->v2->x - viewx, line->v2->y - viewy, ANG90 - viewangle, t2.x, t2.y);
458
459 // Clip the line seg to the viewing window
460 int32_t lclip, rclip;
461 if (!R_ClipLineToFrustum(&t1, &t2, NEARCLIP, lclip, rclip))
462 return;
463
464 // apply the view frustum clipping to t1 & t2
465 R_ClipLine(&t1, &t2, lclip, rclip, &t1, &t2);
466
467 // project the line endpoints to determine which columns the line seg occupies
468 int x1 = R_ProjectPointX(t1.x, t1.y);
469 int x2 = R_ProjectPointX(t2.x, t2.y) - 1;
470 if (!R_CheckProjectionX(x1, x2))
471 return;
472
473 rw_start = x1;
474 rw_stop = x2;
475
476 // clip the line seg endpoints in world-space
477 // and store in (w1.x, w1.y) and (w2.x, w2.y)
478 v2fixed_t w1, w2;
479 R_ClipLine(line->v1, line->v2, lclip, rclip, &w1, &w2);
480
481 // killough 3/8/98, 4/4/98: hack for invisible ceilings / deep water
482 static sector_t tempsec;
483 backsector = line->backsector ? R_FakeFlat(line->backsector, &tempsec, NULL, NULL, true) : NULL;
484
485 R_PrepWall(w1.x, w1.y, w2.x, w2.y, t1.y, t2.y, x1, x2);
486
487 // [SL] Check for single-sided line, closed doors or other scenarios that
488 // would make this line seg solid.
489 //
490 // This fixes the automap floor height bug -- killough 1/18/98:
491 // killough 4/7/98: optimize: save result in doorclosed for use in r_segs.c
492
493 if (!backsector || !(line->linedef->flags & ML_TWOSIDED) ||
494 (rw_backcz1 <= rw_frontfz1 && rw_backcz2 <= rw_frontfz2) ||
495 (rw_backfz1 >= rw_frontcz1 && rw_backfz2 >= rw_frontcz2) ||
496
497 // if door is closed because back is shut:
498 ((rw_backcz1 <= rw_backfz1 && rw_backcz2 <= rw_backfz2) &&
499
500 // preserve a kind of transparent door/lift special effect:
501 ((rw_backcz1 >= rw_frontcz1 && rw_backcz2 >= rw_frontcz2) ||
502 line->sidedef->toptexture) &&
503
504 ((rw_backfz1 <= rw_frontfz1 && rw_backfz2 <= rw_frontfz2) ||
505 line->sidedef->bottomtexture) &&
506
507 // properly render skies (consider door "open" if both ceilings are sky):
508 (backsector->ceilingpic !=skyflatnum || frontsector->ceilingpic!=skyflatnum)))
509 {
510 doorclosed = true;
511 R_ClipWallSegment(x1, x2, true);
512 return;
513 }
514
515 // Reject empty lines used for triggers and special events.
516 // Identical floor and ceiling on both sides,
517 // identical light levels on both sides, and no middle texture.
518 if (P_IdenticalPlanes(&frontsector->ceilingplane, &backsector->ceilingplane)
519 && P_IdenticalPlanes(&frontsector->floorplane, &backsector->floorplane)
520 && backsector->lightlevel == frontsector->lightlevel
521 && backsector->floorpic == frontsector->floorpic
522 && backsector->ceilingpic == frontsector->ceilingpic
523 && curline->sidedef->midtexture == 0
524
525 // killough 3/7/98: Take flats offsets into account:
526 && backsector->floor_xoffs == frontsector->floor_xoffs
527 && (backsector->floor_yoffs + backsector->base_floor_yoffs) == (frontsector->floor_yoffs + backsector->base_floor_yoffs)
528 && backsector->ceiling_xoffs == frontsector->ceiling_xoffs
529 && (backsector->ceiling_yoffs + backsector->base_ceiling_yoffs) == (frontsector->ceiling_yoffs + frontsector->base_ceiling_yoffs)
530
531 // killough 4/16/98: consider altered lighting
532 && backsector->floorlightsec == frontsector->floorlightsec
533 && backsector->ceilinglightsec == frontsector->ceilinglightsec
534
535 // [RH] Also consider colormaps
536 && backsector->floorcolormap == frontsector->floorcolormap
537 && backsector->ceilingcolormap == frontsector->ceilingcolormap
538
539 // [RH] and scaling
540 && backsector->floor_xscale == frontsector->floor_xscale
541 && backsector->floor_yscale == frontsector->floor_yscale
542 && backsector->ceiling_xscale == frontsector->ceiling_xscale
543 && backsector->ceiling_yscale == frontsector->ceiling_yscale
544
545 // [RH] and rotation
546 && (backsector->floor_angle + backsector->base_floor_angle) == (frontsector->floor_angle + frontsector->base_floor_angle)
547 && (backsector->ceiling_angle + backsector->base_ceiling_angle) == (frontsector->ceiling_angle + frontsector->base_ceiling_angle)
548 )
549 {
550 return;
551 }
552
553 doorclosed = false;
554 R_ClipWallSegment(x1, x2, false);
555 }
556
557
558 static const int checkcoord[12][4] = // killough -- static const
559 {
560 {3,0,2,1},
561 {3,0,2,0},
562 {3,1,2,0},
563 {0},
564 {2,0,2,1},
565 {0,0,0,0},
566 {3,1,3,0},
567 {0},
568 {2,0,3,1},
569 {2,1,3,1},
570 {2,1,3,0}
571 };
572
573 //
574 // R_CheckBBox
575 //
576 // Checks BSP node/subtree bounding box.
577 // Returns true if some part of the bbox might be visible.
578 //
579 // killough 1/28/98: static
580 // CPhipps - const parameter, reformatted
581 // [SL] Rewritten to use R_ClipLineToFrustum to determine if any part of the
582 // bbox's two diagonals would be drawn in a non-solid screen column.
583 //
R_CheckBBox(const fixed_t * bspcoord)584 static bool R_CheckBBox(const fixed_t *bspcoord)
585 {
586 const fixed_t clipdist = 0;
587 v2fixed_t t1, t2;
588
589 // Find the corners of the box that define the edges from current viewpoint
590 int boxpos = (viewx <= bspcoord[BOXLEFT] ? 0 : viewx < bspcoord[BOXRIGHT ] ? 1 : 2) +
591 (viewy >= bspcoord[BOXTOP ] ? 0 : viewy > bspcoord[BOXBOTTOM] ? 4 : 8);
592
593 if (boxpos == 5)
594 return true;
595
596 fixed_t xl = bspcoord[checkcoord[boxpos][0]];
597 fixed_t yl = bspcoord[checkcoord[boxpos][1]];
598 fixed_t xh = bspcoord[checkcoord[boxpos][2]];
599 fixed_t yh = bspcoord[checkcoord[boxpos][3]];
600
601 // translate the bounding box vertices from world-space to camera-space
602 // and store in (t1.x, t1.y) and (t2.x, t2.y)
603 R_RotatePoint(xl - viewx, yl - viewy, ANG90 - viewangle, t1.x, t1.y);
604 R_RotatePoint(xh - viewx, yh - viewy, ANG90 - viewangle, t2.x, t2.y);
605
606 v2fixed_t box_pts[4][2];
607 // top line of box
608 box_pts[0][0].x = t1.x; box_pts[0][0].y = t1.y; box_pts[0][1].x = t2.x; box_pts[0][1].y = t1.y;
609 // bottom line of box
610 box_pts[1][0].x = t1.x; box_pts[1][0].y = t2.y; box_pts[1][1].x = t2.x; box_pts[1][1].y = t2.y;
611 // left line of box;
612 box_pts[2][0].x = t1.x; box_pts[2][0].y = t1.y; box_pts[2][1].x = t1.x; box_pts[2][1].y = t2.y;
613 // right line of box
614 box_pts[3][0].x = t2.x; box_pts[3][0].y = t1.y; box_pts[3][1].x = t2.x; box_pts[3][1].y = t2.y;
615
616 // Check each of the four sides of the bounding box to see if
617 // any part is visible. Find the maximum range of columns the bounding box
618 // will project onto the screen.
619 for (int i = 0; i < 4; i++)
620 {
621 v2fixed_t p1 = box_pts[i][0];
622 v2fixed_t p2 = box_pts[i][1];
623
624 if (R_PointOnLine(0, 0, p1.x, p1.y, p2.x, p2.y))
625 return true;
626
627 int32_t lclip, rclip;
628 if (R_ClipLineToFrustum(&p1, &p2, clipdist, lclip, rclip))
629 {
630 R_ClipLine(&p1, &p2, lclip, rclip, &p1, &p2);
631 int x1 = R_ProjectPointX(p1.x, p1.y);
632 int x2 = R_ProjectPointX(p2.x, p2.y) - 1;
633 if (R_CheckProjectionX(x1, x2))
634 {
635 if (memchr(solidcol + x1, 0, x2 - x1 + 1) != NULL)
636 return true;
637 }
638 }
639 }
640
641 return false;
642 }
643
644 //
645 // R_Subsector
646 // Determine floor/ceiling planes.
647 // Add sprites of things in sector.
648 // Draw one or more line segments.
649 //
R_Subsector(int num)650 void R_Subsector (int num)
651 {
652 int count;
653 seg_t* line;
654 subsector_t *sub;
655 sector_t tempsec; // killough 3/7/98: deep water hack
656 int floorlightlevel; // killough 3/16/98: set floor lightlevel
657 int ceilinglightlevel; // killough 4/11/98
658
659 #ifdef RANGECHECK
660 if (num>=numsubsectors)
661 I_Error ("R_Subsector: ss %i with numss = %i",
662 num,
663 numsubsectors);
664 #endif
665
666 sub = &subsectors[num];
667 frontsector = sub->sector;
668 count = sub->numlines;
669 line = &segs[sub->firstline];
670
671 // killough 3/8/98, 4/4/98: Deep water / fake ceiling effect
672 frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel,
673 &ceilinglightlevel, false); // killough 4/11/98
674
675 basecolormap = frontsector->ceilingcolormap->maps;
676
677 ceilingplane = P_CeilingHeight(camera) > viewz ||
678 frontsector->ceilingpic == skyflatnum ||
679 (frontsector->heightsec &&
680 !(frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) &&
681 frontsector->heightsec->floorpic == skyflatnum) ?
682 R_FindPlane(frontsector->ceilingplane, // killough 3/8/98
683 frontsector->ceilingpic == skyflatnum && // killough 10/98
684 frontsector->sky & PL_SKYFLAT ? frontsector->sky :
685 frontsector->ceilingpic,
686 ceilinglightlevel, // killough 4/11/98
687 frontsector->ceiling_xoffs, // killough 3/7/98
688 frontsector->ceiling_yoffs + frontsector->base_ceiling_yoffs,
689 frontsector->ceiling_xscale,
690 frontsector->ceiling_yscale,
691 frontsector->ceiling_angle + frontsector->base_ceiling_angle
692 ) : NULL;
693
694 basecolormap = frontsector->floorcolormap->maps; // [RH] set basecolormap
695
696 // killough 3/7/98: Add (x,y) offsets to flats, add deep water check
697 // killough 3/16/98: add floorlightlevel
698 // killough 10/98: add support for skies transferred from sidedefs
699 floorplane = P_FloorHeight(camera) < viewz || // killough 3/7/98
700 (frontsector->heightsec &&
701 !(frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) &&
702 frontsector->heightsec->ceilingpic == skyflatnum) ?
703 R_FindPlane(frontsector->floorplane,
704 frontsector->floorpic == skyflatnum && // killough 10/98
705 frontsector->sky & PL_SKYFLAT ? frontsector->sky :
706 frontsector->floorpic,
707 floorlightlevel, // killough 3/16/98
708 frontsector->floor_xoffs, // killough 3/7/98
709 frontsector->floor_yoffs + frontsector->base_floor_yoffs,
710 frontsector->floor_xscale,
711 frontsector->floor_yscale,
712 frontsector->floor_angle + frontsector->base_floor_angle
713 ) : NULL;
714
715 // [RH] set foggy flag
716 foggy = level.fadeto || frontsector->floorcolormap->fade
717 || frontsector->ceilingcolormap->fade;
718
719 // killough 9/18/98: Fix underwater slowdown, by passing real sector
720 // instead of fake one. Improve sprite lighting by basing sprite
721 // lightlevels on floor & ceiling lightlevels in the surrounding area.
722 R_AddSprites (sub->sector, (floorlightlevel + ceilinglightlevel) / 2, FakeSide);
723
724 // [RH] Add particles
725 if (r_particles)
726 {
727 for (WORD i = ParticlesInSubsec[num]; i != NO_PARTICLE; i = Particles[i].nextinsubsector)
728 R_ProjectParticle(Particles + i, subsectors[num].sector, FakeSide);
729 }
730
731 if (sub->poly)
732 { // Render the polyobj in the subsector first
733 int polyCount = sub->poly->numsegs;
734 seg_t **polySeg = sub->poly->segs;
735 while (polyCount--)
736 R_AddLine (*polySeg++);
737 }
738
739 while (count--)
740 R_AddLine (line++);
741 }
742
743
744 //
745 // RenderBSPNode
746 //
747 // Renders all subsectors below a given node, traversing subtree recursively.
748 // Just call with BSP root.
749 // killough 5/2/98: reformatted, removed tail recursion
750 //
R_RenderBSPNode(int bspnum)751 void R_RenderBSPNode (int bspnum)
752 {
753 while (!(bspnum & NF_SUBSECTOR)) // Found a subsector?
754 {
755 node_t *bsp = &nodes[bspnum];
756
757 // Decide which side the view point is on.
758 int frontside = R_PointOnSide(viewx, viewy, bsp);
759 int backside = frontside ^ 1;
760
761 // Recursively divide front space.
762 R_RenderBSPNode(bsp->children[frontside]);
763
764 // Possibly divide back space.
765 if (!R_CheckBBox(bsp->bbox[backside]))
766 return;
767
768 bspnum = bsp->children[backside];
769 }
770
771 R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR);
772 }
773
774
775 VERSION_CONTROL (r_bsp_cpp, "$Id: r_bsp.cpp 4706 2014-03-28 15:25:42Z dr_sean $")
776
777