1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id:$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
11 //
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15 // for more details.
16 //
17 // DESCRIPTION:
18 // BSP traversal, handling of LineSegs for rendering.
19 //
20 // This file contains some code from the Build Engine.
21 //
22 // "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
23 // Ken Silverman's official web site: "http://www.advsys.net/ken"
24 // See the included license file "BUILDLIC.TXT" for license info.
25 //
26 //-----------------------------------------------------------------------------
27
28
29 #include <stdlib.h>
30
31 #include "templates.h"
32
33 #include "doomdef.h"
34
35 #include "m_bbox.h"
36
37 #include "i_system.h"
38 #include "p_lnspec.h"
39 #include "p_setup.h"
40
41 #include "r_main.h"
42 #include "r_plane.h"
43 #include "r_draw.h"
44 #include "r_things.h"
45 #include "r_3dfloors.h"
46 #include "a_sharedglobal.h"
47 #include "g_level.h"
48 #include "p_effect.h"
49
50 // State.
51 #include "doomstat.h"
52 #include "r_state.h"
53 #include "r_bsp.h"
54 #include "r_segs.h"
55 #include "v_palette.h"
56 #include "r_sky.h"
57 #include "po_man.h"
58 #include "r_data/colormaps.h"
59
60 seg_t* curline;
61 side_t* sidedef;
62 line_t* linedef;
63 sector_t* frontsector;
64 sector_t* backsector;
65
66 // killough 4/7/98: indicates doors closed wrt automap bugfix:
67 int doorclosed;
68
69 bool r_fakingunderwater;
70
71 extern bool rw_prepped;
72 extern bool rw_havehigh, rw_havelow;
73 extern int rw_floorstat, rw_ceilstat;
74 extern bool rw_mustmarkfloor, rw_mustmarkceiling;
75 extern short walltop[MAXWIDTH]; // [RH] record max extents of wall
76 extern short wallbottom[MAXWIDTH];
77 extern short wallupper[MAXWIDTH];
78 extern short walllower[MAXWIDTH];
79
80 fixed_t rw_backcz1, rw_backcz2;
81 fixed_t rw_backfz1, rw_backfz2;
82 fixed_t rw_frontcz1, rw_frontcz2;
83 fixed_t rw_frontfz1, rw_frontfz2;
84
85
86 size_t MaxDrawSegs;
87 drawseg_t *drawsegs;
88 drawseg_t* firstdrawseg;
89 drawseg_t* ds_p;
90
91 size_t FirstInterestingDrawseg;
92 TArray<size_t> InterestingDrawsegs;
93
94 FWallCoords WallC;
95 FWallTmapVals WallT;
96
97 static BYTE FakeSide;
98
99 int WindowLeft, WindowRight;
100 WORD MirrorFlags;
101 seg_t *ActiveWallMirror;
102 TArray<size_t> WallMirrors;
103
104 static subsector_t *InSubsector;
105
106 CVAR (Bool, r_drawflat, false, 0) // [RH] Don't texture segs?
107
108
109 void R_StoreWallRange (int start, int stop);
110
111 //
112 // R_ClearDrawSegs
113 //
R_ClearDrawSegs(void)114 void R_ClearDrawSegs (void)
115 {
116 if (drawsegs == NULL)
117 {
118 MaxDrawSegs = 256; // [RH] Default. Increased as needed.
119 firstdrawseg = drawsegs = (drawseg_t *)M_Malloc (MaxDrawSegs * sizeof(drawseg_t));
120 }
121 FirstInterestingDrawseg = 0;
122 InterestingDrawsegs.Clear ();
123 ds_p = drawsegs;
124 }
125
126
127
128 //
129 // ClipWallSegment
130 // Clips the given range of columns
131 // and includes it in the new clip list.
132 //
133 //
134 // 1/11/98 killough: Since a type "short" is sufficient, we
135 // should use it, since smaller arrays fit better in cache.
136 //
137
138 struct cliprange_t
139 {
140 short first, last; // killough
141 };
142
143
144 // newend is one past the last valid seg
145 static cliprange_t *newend;
146 static cliprange_t solidsegs[MAXWIDTH/2+2];
147
148
149
150 //==========================================================================
151 //
152 // R_ClipWallSegment
153 //
154 // Clips the given range of columns, possibly including it in the clip list.
155 // Handles both windows (e.g. LineDefs with upper and lower textures) and
156 // solid walls (e.g. single sided LineDefs [middle texture]) that entirely
157 // block the view.
158 //
159 //==========================================================================
160
R_ClipWallSegment(int first,int last,bool solid)161 bool R_ClipWallSegment (int first, int last, bool solid)
162 {
163 cliprange_t *next, *start;
164 int i, j;
165 bool res = false;
166
167 // Find the first range that touches the range
168 // (adjacent pixels are touching).
169 start = solidsegs;
170 while (start->last < first)
171 start++;
172
173 if (first < start->first)
174 {
175 res = true;
176 if (last <= start->first)
177 {
178 // Post is entirely visible (above start).
179 R_StoreWallRange (first, last);
180 if (fake3D & FAKE3D_FAKEMASK)
181 {
182 return true;
183 }
184
185 // Insert a new clippost for solid walls.
186 if (solid)
187 {
188 if (last == start->first)
189 {
190 start->first = first;
191 }
192 else
193 {
194 next = newend;
195 newend++;
196 while (next != start)
197 {
198 *next = *(next-1);
199 next--;
200 }
201 next->first = first;
202 next->last = last;
203 }
204 }
205 return true;
206 }
207
208 // There is a fragment above *start.
209 R_StoreWallRange (first, start->first);
210
211 // Adjust the clip size for solid walls
212 if (solid && !(fake3D & FAKE3D_FAKEMASK))
213 {
214 start->first = first;
215 }
216 }
217
218 // Bottom contained in start?
219 if (last <= start->last)
220 return res;
221
222 next = start;
223 while (last >= (next+1)->first)
224 {
225 // There is a fragment between two posts.
226 R_StoreWallRange (next->last, (next+1)->first);
227 next++;
228
229 if (last <= next->last)
230 {
231 // Bottom is contained in next.
232 last = next->last;
233 goto crunch;
234 }
235 }
236
237 // There is a fragment after *next.
238 R_StoreWallRange (next->last, last);
239
240 crunch:
241 if (fake3D & FAKE3D_FAKEMASK)
242 {
243 return true;
244 }
245 if (solid)
246 {
247 // Adjust the clip size.
248 start->last = last;
249
250 if (next != start)
251 {
252 // Remove start+1 to next from the clip list,
253 // because start now covers their area.
254 for (i = 1, j = (int)(newend - next); j > 0; i++, j--)
255 {
256 start[i] = next[i];
257 }
258 newend = start+i;
259 }
260 }
261 return true;
262 }
263
R_CheckClipWallSegment(int first,int last)264 bool R_CheckClipWallSegment (int first, int last)
265 {
266 cliprange_t *start;
267
268 // Find the first range that touches the range
269 // (adjacent pixels are touching).
270 start = solidsegs;
271 while (start->last < first)
272 start++;
273
274 if (first < start->first)
275 {
276 return true;
277 }
278
279 // Bottom contained in start?
280 if (last > start->last)
281 {
282 return true;
283 }
284
285 return false;
286 }
287
288
289
290 //
291 // R_ClearClipSegs
292 //
R_ClearClipSegs(short left,short right)293 void R_ClearClipSegs (short left, short right)
294 {
295 solidsegs[0].first = -0x7fff; // new short limit -- killough
296 solidsegs[0].last = left;
297 solidsegs[1].first = right;
298 solidsegs[1].last = 0x7fff; // new short limit -- killough
299 newend = solidsegs+2;
300 }
301
302
303 //
304 // killough 3/7/98: Hack floor/ceiling heights for deep water etc.
305 //
306 // If player's view height is underneath fake floor, lower the
307 // drawn ceiling to be just under the floor height, and replace
308 // the drawn floor and ceiling textures, and light level, with
309 // the control sector's.
310 //
311 // Similar for ceiling, only reflected.
312 //
313 // killough 4/11/98, 4/13/98: fix bugs, add 'back' parameter
314 //
315
R_FakeFlat(sector_t * sec,sector_t * tempsec,int * floorlightlevel,int * ceilinglightlevel,bool back)316 sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec,
317 int *floorlightlevel, int *ceilinglightlevel,
318 bool back)
319 {
320 // [RH] allow per-plane lighting
321 if (floorlightlevel != NULL)
322 {
323 *floorlightlevel = sec->GetFloorLight ();
324 }
325
326 if (ceilinglightlevel != NULL)
327 {
328 *ceilinglightlevel = sec->GetCeilingLight ();
329 }
330
331 FakeSide = FAKED_Center;
332
333 const sector_t *s = sec->GetHeightSec();
334 if (s != NULL)
335 {
336 sector_t *heightsec = viewsector->heightsec;
337 bool underwater = r_fakingunderwater ||
338 (heightsec && heightsec->floorplane.PointOnSide(viewx, viewy, viewz) <= 0);
339 bool doorunderwater = false;
340 int diffTex = (s->MoreFlags & SECF_CLIPFAKEPLANES);
341
342 // Replace sector being drawn with a copy to be hacked
343 *tempsec = *sec;
344
345 // Replace floor and ceiling height with control sector's heights.
346 if (diffTex)
347 {
348 if (s->floorplane.CopyPlaneIfValid (&tempsec->floorplane, &sec->ceilingplane))
349 {
350 tempsec->SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false);
351 }
352 else if (s->MoreFlags & SECF_FAKEFLOORONLY)
353 {
354 if (underwater)
355 {
356 tempsec->ColorMap = s->ColorMap;
357 if (!(s->MoreFlags & SECF_NOFAKELIGHT))
358 {
359 tempsec->lightlevel = s->lightlevel;
360
361 if (floorlightlevel != NULL)
362 {
363 *floorlightlevel = s->GetFloorLight ();
364 }
365
366 if (ceilinglightlevel != NULL)
367 {
368 *ceilinglightlevel = s->GetCeilingLight ();
369 }
370 }
371 FakeSide = FAKED_BelowFloor;
372 return tempsec;
373 }
374 return sec;
375 }
376 }
377 else
378 {
379 tempsec->floorplane = s->floorplane;
380 }
381
382 if (!(s->MoreFlags & SECF_FAKEFLOORONLY))
383 {
384 if (diffTex)
385 {
386 if (s->ceilingplane.CopyPlaneIfValid (&tempsec->ceilingplane, &sec->floorplane))
387 {
388 tempsec->SetTexture(sector_t::ceiling, s->GetTexture(sector_t::ceiling), false);
389 }
390 }
391 else
392 {
393 tempsec->ceilingplane = s->ceilingplane;
394 }
395 }
396
397 fixed_t refceilz = s->ceilingplane.ZatPoint (viewx, viewy);
398 fixed_t orgceilz = sec->ceilingplane.ZatPoint (viewx, viewy);
399
400 #if 1
401 // [RH] Allow viewing underwater areas through doors/windows that
402 // are underwater but not in a water sector themselves.
403 // Only works if you cannot see the top surface of any deep water
404 // sectors at the same time.
405 if (back && !r_fakingunderwater && curline->frontsector->heightsec == NULL)
406 {
407 if (rw_frontcz1 <= s->floorplane.ZatPoint (curline->v1->x, curline->v1->y) &&
408 rw_frontcz2 <= s->floorplane.ZatPoint (curline->v2->x, curline->v2->y))
409 {
410 // Check that the window is actually visible
411 for (int z = WallC.sx1; z < WallC.sx2; ++z)
412 {
413 if (floorclip[z] > ceilingclip[z])
414 {
415 doorunderwater = true;
416 r_fakingunderwater = true;
417 break;
418 }
419 }
420 }
421 }
422 #endif
423
424 if (underwater || doorunderwater)
425 {
426 tempsec->floorplane = sec->floorplane;
427 tempsec->ceilingplane = s->floorplane;
428 tempsec->ceilingplane.FlipVert ();
429 tempsec->ceilingplane.ChangeHeight (-1);
430 tempsec->ColorMap = s->ColorMap;
431 }
432
433 // killough 11/98: prevent sudden light changes from non-water sectors:
434 if ((underwater && !back) || doorunderwater)
435 { // head-below-floor hack
436 tempsec->SetTexture(sector_t::floor, diffTex ? sec->GetTexture(sector_t::floor) : s->GetTexture(sector_t::floor), false);
437 tempsec->planes[sector_t::floor].xform = s->planes[sector_t::floor].xform;
438
439 tempsec->ceilingplane = s->floorplane;
440 tempsec->ceilingplane.FlipVert ();
441 tempsec->ceilingplane.ChangeHeight (-1);
442 if (s->GetTexture(sector_t::ceiling) == skyflatnum)
443 {
444 tempsec->floorplane = tempsec->ceilingplane;
445 tempsec->floorplane.FlipVert ();
446 tempsec->floorplane.ChangeHeight (+1);
447 tempsec->SetTexture(sector_t::ceiling, tempsec->GetTexture(sector_t::floor), false);
448 tempsec->planes[sector_t::ceiling].xform = tempsec->planes[sector_t::floor].xform;
449 }
450 else
451 {
452 tempsec->SetTexture(sector_t::ceiling, diffTex ? s->GetTexture(sector_t::floor) : s->GetTexture(sector_t::ceiling), false);
453 tempsec->planes[sector_t::ceiling].xform = s->planes[sector_t::ceiling].xform;
454 }
455
456 if (!(s->MoreFlags & SECF_NOFAKELIGHT))
457 {
458 tempsec->lightlevel = s->lightlevel;
459
460 if (floorlightlevel != NULL)
461 {
462 *floorlightlevel = s->GetFloorLight ();
463 }
464
465 if (ceilinglightlevel != NULL)
466 {
467 *ceilinglightlevel = s->GetCeilingLight ();
468 }
469 }
470 FakeSide = FAKED_BelowFloor;
471 }
472 else if (heightsec && heightsec->ceilingplane.PointOnSide(viewx, viewy, viewz) <= 0 &&
473 orgceilz > refceilz && !(s->MoreFlags & SECF_FAKEFLOORONLY))
474 { // Above-ceiling hack
475 tempsec->ceilingplane = s->ceilingplane;
476 tempsec->floorplane = s->ceilingplane;
477 tempsec->floorplane.FlipVert ();
478 tempsec->floorplane.ChangeHeight (+1);
479 tempsec->ColorMap = s->ColorMap;
480 tempsec->ColorMap = s->ColorMap;
481
482 tempsec->SetTexture(sector_t::ceiling, diffTex ? sec->GetTexture(sector_t::ceiling) : s->GetTexture(sector_t::ceiling), false);
483 tempsec->SetTexture(sector_t::floor, s->GetTexture(sector_t::ceiling), false);
484 tempsec->planes[sector_t::ceiling].xform = tempsec->planes[sector_t::floor].xform = s->planes[sector_t::ceiling].xform;
485
486 if (s->GetTexture(sector_t::floor) != skyflatnum)
487 {
488 tempsec->ceilingplane = sec->ceilingplane;
489 tempsec->SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false);
490 tempsec->planes[sector_t::floor].xform = s->planes[sector_t::floor].xform;
491 }
492
493 if (!(s->MoreFlags & SECF_NOFAKELIGHT))
494 {
495 tempsec->lightlevel = s->lightlevel;
496
497 if (floorlightlevel != NULL)
498 {
499 *floorlightlevel = s->GetFloorLight ();
500 }
501
502 if (ceilinglightlevel != NULL)
503 {
504 *ceilinglightlevel = s->GetCeilingLight ();
505 }
506 }
507 FakeSide = FAKED_AboveCeiling;
508 }
509 sec = tempsec; // Use other sector
510 }
511 return sec;
512 }
513
514
515 //
516 // R_AddLine
517 // Clips the given segment
518 // and adds any visible pieces to the line list.
519 //
520
R_AddLine(seg_t * line)521 void R_AddLine (seg_t *line)
522 {
523 static sector_t tempsec; // killough 3/8/98: ceiling/water hack
524 bool solid;
525 fixed_t tx1, tx2, ty1, ty2;
526
527 curline = line;
528
529 // [RH] Color if not texturing line
530 dc_color = (((int)(line - segs) * 8) + 4) & 255;
531
532 tx1 = line->v1->x - viewx;
533 tx2 = line->v2->x - viewx;
534 ty1 = line->v1->y - viewy;
535 ty2 = line->v2->y - viewy;
536
537 // Reject lines not facing viewer
538 if (DMulScale32 (ty1, tx1-tx2, tx1, ty2-ty1) >= 0)
539 return;
540
541 if (WallC.Init(tx1, ty1, tx2, ty2, 32))
542 return;
543
544 if (WallC.sx1 >= WindowRight || WallC.sx2 <= WindowLeft)
545 return;
546
547 if (line->linedef == NULL)
548 {
549 if (R_CheckClipWallSegment (WallC.sx1, WallC.sx2))
550 {
551 InSubsector->flags |= SSECF_DRAWN;
552 }
553 return;
554 }
555
556 vertex_t *v1, *v2;
557
558 v1 = line->linedef->v1;
559 v2 = line->linedef->v2;
560
561 if ((v1 == line->v1 && v2 == line->v2) || (v2 == line->v1 && v1 == line->v2))
562 { // The seg is the entire wall.
563 WallT.InitFromWallCoords(&WallC);
564 }
565 else
566 { // The seg is only part of the wall.
567 if (line->linedef->sidedef[0] != line->sidedef)
568 {
569 swapvalues (v1, v2);
570 }
571 WallT.InitFromLine(v1->x - viewx, v1->y - viewy, v2->x - viewx, v2->y - viewy);
572 }
573
574 if (!(fake3D & FAKE3D_FAKEBACK))
575 {
576 backsector = line->backsector;
577 }
578 rw_frontcz1 = frontsector->ceilingplane.ZatPoint (line->v1->x, line->v1->y);
579 rw_frontfz1 = frontsector->floorplane.ZatPoint (line->v1->x, line->v1->y);
580 rw_frontcz2 = frontsector->ceilingplane.ZatPoint (line->v2->x, line->v2->y);
581 rw_frontfz2 = frontsector->floorplane.ZatPoint (line->v2->x, line->v2->y);
582
583 rw_mustmarkfloor = rw_mustmarkceiling = false;
584 rw_havehigh = rw_havelow = false;
585
586 // Single sided line?
587 if (backsector == NULL)
588 {
589 solid = true;
590 }
591 else
592 {
593 // kg3D - its fake, no transfer_heights
594 if (!(fake3D & FAKE3D_FAKEBACK))
595 { // killough 3/8/98, 4/4/98: hack for invisible ceilings / deep water
596 backsector = R_FakeFlat (backsector, &tempsec, NULL, NULL, true);
597 }
598 doorclosed = 0; // killough 4/16/98
599
600 rw_backcz1 = backsector->ceilingplane.ZatPoint (line->v1->x, line->v1->y);
601 rw_backfz1 = backsector->floorplane.ZatPoint (line->v1->x, line->v1->y);
602 rw_backcz2 = backsector->ceilingplane.ZatPoint (line->v2->x, line->v2->y);
603 rw_backfz2 = backsector->floorplane.ZatPoint (line->v2->x, line->v2->y);
604
605 // Cannot make these walls solid, because it can result in
606 // sprite clipping problems for sprites near the wall
607 if (rw_frontcz1 > rw_backcz1 || rw_frontcz2 > rw_backcz2)
608 {
609 rw_havehigh = true;
610 WallMost (wallupper, backsector->ceilingplane, &WallC);
611 }
612 if (rw_frontfz1 < rw_backfz1 || rw_frontfz2 < rw_backfz2)
613 {
614 rw_havelow = true;
615 WallMost (walllower, backsector->floorplane, &WallC);
616 }
617
618 // Closed door.
619 if ((rw_backcz1 <= rw_frontfz1 && rw_backcz2 <= rw_frontfz2) ||
620 (rw_backfz1 >= rw_frontcz1 && rw_backfz2 >= rw_frontcz2))
621 {
622 solid = true;
623 }
624 else if (
625 // properly render skies (consider door "open" if both ceilings are sky):
626 (backsector->GetTexture(sector_t::ceiling) != skyflatnum || frontsector->GetTexture(sector_t::ceiling) != skyflatnum)
627
628 // if door is closed because back is shut:
629 && rw_backcz1 <= rw_backfz1 && rw_backcz2 <= rw_backfz2
630
631 // preserve a kind of transparent door/lift special effect:
632 && ((rw_backcz1 >= rw_frontcz1 && rw_backcz2 >= rw_frontcz2) || line->sidedef->GetTexture(side_t::top).isValid())
633 && ((rw_backfz1 <= rw_frontfz1 && rw_backfz2 <= rw_frontfz2) || line->sidedef->GetTexture(side_t::bottom).isValid()))
634 {
635 // killough 1/18/98 -- This function is used to fix the automap bug which
636 // showed lines behind closed doors simply because the door had a dropoff.
637 //
638 // It assumes that Doom has already ruled out a door being closed because
639 // of front-back closure (e.g. front floor is taller than back ceiling).
640
641 // This fixes the automap floor height bug -- killough 1/18/98:
642 // killough 4/7/98: optimize: save result in doorclosed for use in r_segs.c
643 doorclosed = true;
644 solid = true;
645 }
646 else if (frontsector->ceilingplane != backsector->ceilingplane ||
647 frontsector->floorplane != backsector->floorplane)
648 {
649 // Window.
650 solid = false;
651 }
652 else if (backsector->lightlevel != frontsector->lightlevel
653 || backsector->GetTexture(sector_t::floor) != frontsector->GetTexture(sector_t::floor)
654 || backsector->GetTexture(sector_t::ceiling) != frontsector->GetTexture(sector_t::ceiling)
655 || curline->sidedef->GetTexture(side_t::mid).isValid()
656
657 // killough 3/7/98: Take flats offsets into account:
658 || backsector->GetXOffset(sector_t::floor) != frontsector->GetXOffset(sector_t::floor)
659 || backsector->GetYOffset(sector_t::floor) != frontsector->GetYOffset(sector_t::floor)
660 || backsector->GetXOffset(sector_t::ceiling) != frontsector->GetXOffset(sector_t::ceiling)
661 || backsector->GetYOffset(sector_t::ceiling) != frontsector->GetYOffset(sector_t::ceiling)
662
663 || backsector->GetPlaneLight(sector_t::floor) != frontsector->GetPlaneLight(sector_t::floor)
664 || backsector->GetPlaneLight(sector_t::ceiling) != frontsector->GetPlaneLight(sector_t::ceiling)
665 || backsector->GetFlags(sector_t::floor) != frontsector->GetFlags(sector_t::floor)
666 || backsector->GetFlags(sector_t::ceiling) != frontsector->GetFlags(sector_t::ceiling)
667
668 // [RH] Also consider colormaps
669 || backsector->ColorMap != frontsector->ColorMap
670
671 // [RH] and scaling
672 || backsector->GetXScale(sector_t::floor) != frontsector->GetXScale(sector_t::floor)
673 || backsector->GetYScale(sector_t::floor) != frontsector->GetYScale(sector_t::floor)
674 || backsector->GetXScale(sector_t::ceiling) != frontsector->GetXScale(sector_t::ceiling)
675 || backsector->GetYScale(sector_t::ceiling) != frontsector->GetYScale(sector_t::ceiling)
676
677 // [RH] and rotation
678 || backsector->GetAngle(sector_t::floor) != frontsector->GetAngle(sector_t::floor)
679 || backsector->GetAngle(sector_t::ceiling) != frontsector->GetAngle(sector_t::ceiling)
680
681 // kg3D - and fake lights
682 || (frontsector->e && frontsector->e->XFloor.lightlist.Size())
683 || (backsector->e && backsector->e->XFloor.lightlist.Size())
684 )
685 {
686 solid = false;
687 }
688 else
689 {
690 // Reject empty lines used for triggers and special events.
691 // Identical floor and ceiling on both sides, identical light levels
692 // on both sides, and no middle texture.
693
694 // When using GL nodes, do a clipping test for these lines so we can
695 // mark their subsectors as visible for automap texturing.
696 if (hasglnodes && !(InSubsector->flags & SSECF_DRAWN))
697 {
698 if (R_CheckClipWallSegment(WallC.sx1, WallC.sx2))
699 {
700 InSubsector->flags |= SSECF_DRAWN;
701 }
702 }
703 return;
704 }
705 }
706
707 rw_prepped = false;
708
709 if (line->linedef->special == Line_Horizon)
710 {
711 // Be aware: Line_Horizon does not work properly with sloped planes
712 clearbufshort (walltop+WallC.sx1, WallC.sx2 - WallC.sx1, centery);
713 clearbufshort (wallbottom+WallC.sx1, WallC.sx2 - WallC.sx1, centery);
714 }
715 else
716 {
717 rw_ceilstat = WallMost (walltop, frontsector->ceilingplane, &WallC);
718 rw_floorstat = WallMost (wallbottom, frontsector->floorplane, &WallC);
719
720 // [RH] treat off-screen walls as solid
721 #if 0 // Maybe later...
722 if (!solid)
723 {
724 if (rw_ceilstat == 12 && line->sidedef->GetTexture(side_t::top) != 0)
725 {
726 rw_mustmarkceiling = true;
727 solid = true;
728 }
729 if (rw_floorstat == 3 && line->sidedef->GetTexture(side_t::bottom) != 0)
730 {
731 rw_mustmarkfloor = true;
732 solid = true;
733 }
734 }
735 #endif
736 }
737
738 if (R_ClipWallSegment (WallC.sx1, WallC.sx2, solid))
739 {
740 InSubsector->flags |= SSECF_DRAWN;
741 }
742 }
743
744 //
745 // FWallCoords :: Init
746 //
747 // Transform and clip coordinates. Returns true if it was clipped away
748 //
Init(int x1,int y1,int x2,int y2,int too_close)749 bool FWallCoords::Init(int x1, int y1, int x2, int y2, int too_close)
750 {
751 tx1 = DMulScale20(x1, viewsin, -y1, viewcos);
752 tx2 = DMulScale20(x2, viewsin, -y2, viewcos);
753
754 ty1 = DMulScale20(x1, viewtancos, y1, viewtansin);
755 ty2 = DMulScale20(x2, viewtancos, y2, viewtansin);
756
757 if (MirrorFlags & RF_XFLIP)
758 {
759 int t = 256 - tx1;
760 tx1 = 256 - tx2;
761 tx2 = t;
762 swapvalues(ty1, ty2);
763 }
764
765 if (tx1 >= -ty1)
766 {
767 if (tx1 > ty1) return true; // left edge is off the right side
768 if (ty1 == 0) return true;
769 sx1 = (centerxfrac + Scale(tx1, centerxfrac, ty1)) >> FRACBITS;
770 if (tx1 >= 0) sx1 = MIN(viewwidth, sx1+1); // fix for signed divide
771 sz1 = ty1;
772 }
773 else
774 {
775 if (tx2 < -ty2) return true; // wall is off the left side
776 fixed_t den = tx1 - tx2 - ty2 + ty1;
777 if (den == 0) return true;
778 sx1 = 0;
779 sz1 = ty1 + Scale(ty2 - ty1, tx1 + ty1, den);
780 }
781
782 if (sz1 < too_close)
783 return true;
784
785 if (tx2 <= ty2)
786 {
787 if (tx2 < -ty2) return true; // right edge is off the left side
788 if (ty2 == 0) return true;
789 sx2 = (centerxfrac + Scale(tx2, centerxfrac, ty2)) >> FRACBITS;
790 if (tx2 >= 0) sx2 = MIN(viewwidth, sx2+1); // fix for signed divide
791 sz2 = ty2;
792 }
793 else
794 {
795 if (tx1 > ty1) return true; // wall is off the right side
796 fixed_t den = ty2 - ty1 - tx2 + tx1;
797 if (den == 0) return true;
798 sx2 = viewwidth;
799 sz2 = ty1 + Scale(ty2 - ty1, tx1 - ty1, den);
800 }
801
802 if (sz2 < too_close || sx2 <= sx1)
803 return true;
804
805 return false;
806 }
807
InitFromWallCoords(const FWallCoords * wallc)808 void FWallTmapVals::InitFromWallCoords(const FWallCoords *wallc)
809 {
810 if (MirrorFlags & RF_XFLIP)
811 {
812 UoverZorg = (float)wallc->tx2 * centerx;
813 UoverZstep = (float)(-wallc->ty2);
814 InvZorg = (float)(wallc->tx2 - wallc->tx1) * centerx;
815 InvZstep = (float)(wallc->ty1 - wallc->ty2);
816 }
817 else
818 {
819 UoverZorg = (float)wallc->tx1 * centerx;
820 UoverZstep = (float)(-wallc->ty1);
821 InvZorg = (float)(wallc->tx1 - wallc->tx2) * centerx;
822 InvZstep = (float)(wallc->ty2 - wallc->ty1);
823 }
824 }
825
InitFromLine(int tx1,int ty1,int tx2,int ty2)826 void FWallTmapVals::InitFromLine(int tx1, int ty1, int tx2, int ty2)
827 { // Coordinates should have already had viewx,viewy subtracted
828 fixed_t fullx1 = DMulScale20 (tx1, viewsin, -ty1, viewcos);
829 fixed_t fullx2 = DMulScale20 (tx2, viewsin, -ty2, viewcos);
830 fixed_t fully1 = DMulScale20 (tx1, viewtancos, ty1, viewtansin);
831 fixed_t fully2 = DMulScale20 (tx2, viewtancos, ty2, viewtansin);
832
833 if (MirrorFlags & RF_XFLIP)
834 {
835 fullx1 = -fullx1;
836 fullx2 = -fullx2;
837 }
838
839 UoverZorg = (float)fullx1 * centerx;
840 UoverZstep = (float)(-fully1);
841 InvZorg = (float)(fullx1 - fullx2) * centerx;
842 InvZstep = (float)(fully2 - fully1);
843 }
844
845 //
846 // R_CheckBBox
847 // Checks BSP node/subtree bounding box.
848 // Returns true if some part of the bbox might be visible.
849 //
850 extern "C" const int checkcoord[12][4] =
851 {
852 {3,0,2,1},
853 {3,0,2,0},
854 {3,1,2,0},
855 {0},
856 {2,0,2,1},
857 {0,0,0,0},
858 {3,1,3,0},
859 {0},
860 {2,0,3,1},
861 {2,1,3,1},
862 {2,1,3,0}
863 };
864
865
R_CheckBBox(fixed_t * bspcoord)866 static bool R_CheckBBox (fixed_t *bspcoord) // killough 1/28/98: static
867 {
868 int boxx;
869 int boxy;
870 int boxpos;
871
872 fixed_t x1, y1, x2, y2;
873 fixed_t rx1, ry1, rx2, ry2;
874 int sx1, sx2;
875
876 cliprange_t* start;
877
878 // Find the corners of the box
879 // that define the edges from current viewpoint.
880 if (viewx <= bspcoord[BOXLEFT])
881 boxx = 0;
882 else if (viewx < bspcoord[BOXRIGHT])
883 boxx = 1;
884 else
885 boxx = 2;
886
887 if (viewy >= bspcoord[BOXTOP])
888 boxy = 0;
889 else if (viewy > bspcoord[BOXBOTTOM])
890 boxy = 1;
891 else
892 boxy = 2;
893
894 boxpos = (boxy<<2)+boxx;
895 if (boxpos == 5)
896 return true;
897
898 x1 = bspcoord[checkcoord[boxpos][0]] - viewx;
899 y1 = bspcoord[checkcoord[boxpos][1]] - viewy;
900 x2 = bspcoord[checkcoord[boxpos][2]] - viewx;
901 y2 = bspcoord[checkcoord[boxpos][3]] - viewy;
902
903 // check clip list for an open space
904
905 // Sitting on a line?
906 if (DMulScale32 (y1, x1-x2, x1, y2-y1) >= 0)
907 return true;
908
909 rx1 = DMulScale20 (x1, viewsin, -y1, viewcos);
910 rx2 = DMulScale20 (x2, viewsin, -y2, viewcos);
911 ry1 = DMulScale20 (x1, viewtancos, y1, viewtansin);
912 ry2 = DMulScale20 (x2, viewtancos, y2, viewtansin);
913
914 if (MirrorFlags & RF_XFLIP)
915 {
916 int t = 256-rx1;
917 rx1 = 256-rx2;
918 rx2 = t;
919 swapvalues (ry1, ry2);
920 }
921
922 if (rx1 >= -ry1)
923 {
924 if (rx1 > ry1) return false; // left edge is off the right side
925 if (ry1 == 0) return false;
926 sx1 = (centerxfrac + Scale (rx1, centerxfrac, ry1)) >> FRACBITS;
927 if (rx1 >= 0) sx1 = MIN<int> (viewwidth, sx1+1); // fix for signed divide
928 }
929 else
930 {
931 if (rx2 < -ry2) return false; // wall is off the left side
932 if (rx1 - rx2 - ry2 + ry1 == 0) return false; // wall does not intersect view volume
933 sx1 = 0;
934 }
935
936 if (rx2 <= ry2)
937 {
938 if (rx2 < -ry2) return false; // right edge is off the left side
939 if (ry2 == 0) return false;
940 sx2 = (centerxfrac + Scale (rx2, centerxfrac, ry2)) >> FRACBITS;
941 if (rx2 >= 0) sx2 = MIN<int> (viewwidth, sx2+1); // fix for signed divide
942 }
943 else
944 {
945 if (rx1 > ry1) return false; // wall is off the right side
946 if (ry2 - ry1 - rx2 + rx1 == 0) return false; // wall does not intersect view volume
947 sx2 = viewwidth;
948 }
949
950 // Find the first clippost that touches the source post
951 // (adjacent pixels are touching).
952
953 // Does not cross a pixel.
954 if (sx2 <= sx1)
955 return false;
956
957 start = solidsegs;
958 while (start->last < sx2)
959 start++;
960
961 if (sx1 >= start->first && sx2 <= start->last)
962 {
963 // The clippost contains the new span.
964 return false;
965 }
966
967 return true;
968 }
969
970
971 void R_Subsector (subsector_t *sub);
R_AddPolyobjs(subsector_t * sub)972 static void R_AddPolyobjs(subsector_t *sub)
973 {
974 if (sub->BSP == NULL || sub->BSP->bDirty)
975 {
976 sub->BuildPolyBSP();
977 }
978 if (sub->BSP->Nodes.Size() == 0)
979 {
980 R_Subsector(&sub->BSP->Subsectors[0]);
981 }
982 else
983 {
984 R_RenderBSPNode(&sub->BSP->Nodes.Last());
985 }
986 }
987
988 // kg3D - add fake segs, never rendered
R_FakeDrawLoop(subsector_t * sub)989 void R_FakeDrawLoop(subsector_t *sub)
990 {
991 int count;
992 seg_t* line;
993
994 count = sub->numlines;
995 line = sub->firstline;
996
997 while (count--)
998 {
999 if ((line->sidedef) && !(line->sidedef->Flags & WALLF_POLYOBJ))
1000 {
1001 R_AddLine (line);
1002 }
1003 line++;
1004 }
1005 }
1006
1007 //
1008 // R_Subsector
1009 // Determine floor/ceiling planes.
1010 // Add sprites of things in sector.
1011 // Draw one or more line segments.
1012 //
R_Subsector(subsector_t * sub)1013 void R_Subsector (subsector_t *sub)
1014 {
1015 int count;
1016 seg_t* line;
1017 sector_t tempsec; // killough 3/7/98: deep water hack
1018 int floorlightlevel; // killough 3/16/98: set floor lightlevel
1019 int ceilinglightlevel; // killough 4/11/98
1020 bool outersubsector;
1021 int fll, cll, position;
1022 ASkyViewpoint *skybox;
1023
1024 // kg3D - fake floor stuff
1025 visplane_t *backupfp;
1026 visplane_t *backupcp;
1027 //secplane_t templane;
1028 lightlist_t *light;
1029
1030 if (InSubsector != NULL)
1031 { // InSubsector is not NULL. This means we are rendering from a mini-BSP.
1032 outersubsector = false;
1033 }
1034 else
1035 {
1036 outersubsector = true;
1037 InSubsector = sub;
1038 }
1039
1040 #ifdef RANGECHECK
1041 if (outersubsector && sub - subsectors >= (ptrdiff_t)numsubsectors)
1042 I_Error ("R_Subsector: ss %ti with numss = %i", sub - subsectors, numsubsectors);
1043 #endif
1044
1045 assert(sub->sector != NULL);
1046
1047 if (sub->polys)
1048 { // Render the polyobjs in the subsector first
1049 R_AddPolyobjs(sub);
1050 if (outersubsector)
1051 {
1052 InSubsector = NULL;
1053 }
1054 return;
1055 }
1056
1057 frontsector = sub->sector;
1058 frontsector->MoreFlags |= SECF_DRAWN;
1059 count = sub->numlines;
1060 line = sub->firstline;
1061
1062 // killough 3/8/98, 4/4/98: Deep water / fake ceiling effect
1063 frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel,
1064 &ceilinglightlevel, false); // killough 4/11/98
1065
1066 fll = floorlightlevel;
1067 cll = ceilinglightlevel;
1068
1069 // [RH] set foggy flag
1070 foggy = level.fadeto || frontsector->ColorMap->Fade || (level.flags & LEVEL_HASFADETABLE);
1071 r_actualextralight = foggy ? 0 : extralight << 4;
1072
1073 // kg3D - fake lights
1074 if (fixedlightlev < 0 && frontsector->e && frontsector->e->XFloor.lightlist.Size())
1075 {
1076 light = P_GetPlaneLight(frontsector, &frontsector->ceilingplane, false);
1077 basecolormap = light->extra_colormap;
1078 // If this is the real ceiling, don't discard plane lighting R_FakeFlat()
1079 // accounted for.
1080 if (light->p_lightlevel != &frontsector->lightlevel)
1081 {
1082 ceilinglightlevel = *light->p_lightlevel;
1083 }
1084 }
1085 else
1086 {
1087 basecolormap = frontsector->ColorMap;
1088 }
1089
1090 skybox = frontsector->GetSkyBox(sector_t::ceiling);
1091
1092 ceilingplane = frontsector->ceilingplane.PointOnSide(viewx, viewy, viewz) > 0 ||
1093 frontsector->GetTexture(sector_t::ceiling) == skyflatnum ||
1094 (skybox != NULL && skybox->bAlways) ||
1095 (frontsector->heightsec &&
1096 !(frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) &&
1097 frontsector->heightsec->GetTexture(sector_t::floor) == skyflatnum) ?
1098 R_FindPlane(frontsector->ceilingplane, // killough 3/8/98
1099 frontsector->GetTexture(sector_t::ceiling),
1100 ceilinglightlevel + r_actualextralight, // killough 4/11/98
1101 frontsector->GetAlpha(sector_t::ceiling),
1102 !!(frontsector->GetFlags(sector_t::ceiling) & PLANEF_ADDITIVE),
1103 frontsector->GetXOffset(sector_t::ceiling), // killough 3/7/98
1104 frontsector->GetYOffset(sector_t::ceiling), // killough 3/7/98
1105 frontsector->GetXScale(sector_t::ceiling),
1106 frontsector->GetYScale(sector_t::ceiling),
1107 frontsector->GetAngle(sector_t::ceiling),
1108 frontsector->sky,
1109 skybox
1110 ) : NULL;
1111
1112 if (fixedlightlev < 0 && frontsector->e && frontsector->e->XFloor.lightlist.Size())
1113 {
1114 light = P_GetPlaneLight(frontsector, &frontsector->floorplane, false);
1115 basecolormap = light->extra_colormap;
1116 // If this is the real floor, don't discard plane lighting R_FakeFlat()
1117 // accounted for.
1118 if (light->p_lightlevel != &frontsector->lightlevel)
1119 {
1120 floorlightlevel = *light->p_lightlevel;
1121 }
1122 }
1123 else
1124 {
1125 basecolormap = frontsector->ColorMap;
1126 }
1127
1128 // killough 3/7/98: Add (x,y) offsets to flats, add deep water check
1129 // killough 3/16/98: add floorlightlevel
1130 // killough 10/98: add support for skies transferred from sidedefs
1131 skybox = frontsector->GetSkyBox(sector_t::floor);
1132 floorplane = frontsector->floorplane.PointOnSide(viewx, viewy, viewz) > 0 || // killough 3/7/98
1133 frontsector->GetTexture(sector_t::floor) == skyflatnum ||
1134 (skybox != NULL && skybox->bAlways) ||
1135 (frontsector->heightsec &&
1136 !(frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) &&
1137 frontsector->heightsec->GetTexture(sector_t::ceiling) == skyflatnum) ?
1138 R_FindPlane(frontsector->floorplane,
1139 frontsector->GetTexture(sector_t::floor),
1140 floorlightlevel + r_actualextralight, // killough 3/16/98
1141 frontsector->GetAlpha(sector_t::floor),
1142 !!(frontsector->GetFlags(sector_t::floor) & PLANEF_ADDITIVE),
1143 frontsector->GetXOffset(sector_t::floor), // killough 3/7/98
1144 frontsector->GetYOffset(sector_t::floor), // killough 3/7/98
1145 frontsector->GetXScale(sector_t::floor),
1146 frontsector->GetYScale(sector_t::floor),
1147 frontsector->GetAngle(sector_t::floor),
1148 frontsector->sky,
1149 skybox
1150 ) : NULL;
1151
1152 // kg3D - fake planes rendering
1153 if (r_3dfloors && frontsector->e && frontsector->e->XFloor.ffloors.Size())
1154 {
1155 backupfp = floorplane;
1156 backupcp = ceilingplane;
1157 // first check all floors
1158 for (int i = 0; i < (int)frontsector->e->XFloor.ffloors.Size(); i++)
1159 {
1160 fakeFloor = frontsector->e->XFloor.ffloors[i];
1161 if (!(fakeFloor->flags & FF_EXISTS)) continue;
1162 if (!fakeFloor->model) continue;
1163 if (fakeFloor->bottom.plane->a || fakeFloor->bottom.plane->b) continue;
1164 if (!(fakeFloor->flags & FF_NOSHADE) || (fakeFloor->flags & (FF_RENDERPLANES|FF_RENDERSIDES)))
1165 {
1166 R_3D_AddHeight(fakeFloor->top.plane, frontsector);
1167 }
1168 if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
1169 if (fakeFloor->alpha == 0) continue;
1170 if (fakeFloor->flags & FF_THISINSIDE && fakeFloor->flags & FF_INVERTSECTOR) continue;
1171 fakeAlpha = MIN(Scale(fakeFloor->alpha, OPAQUE, 255), OPAQUE);
1172 if (fakeFloor->validcount != validcount)
1173 {
1174 fakeFloor->validcount = validcount;
1175 R_3D_NewClip();
1176 }
1177 fakeHeight = fakeFloor->top.plane->ZatPoint(frontsector->soundorg[0], frontsector->soundorg[0]);
1178 if (fakeHeight < viewz &&
1179 fakeHeight > frontsector->floorplane.ZatPoint(frontsector->soundorg[0], frontsector->soundorg[1]))
1180 {
1181 fake3D = FAKE3D_FAKEFLOOR;
1182 tempsec = *fakeFloor->model;
1183 tempsec.floorplane = *fakeFloor->top.plane;
1184 tempsec.ceilingplane = *fakeFloor->bottom.plane;
1185 if (!(fakeFloor->flags & FF_THISINSIDE) && !(fakeFloor->flags & FF_INVERTSECTOR))
1186 {
1187 tempsec.SetTexture(sector_t::floor, tempsec.GetTexture(sector_t::ceiling));
1188 position = sector_t::ceiling;
1189 } else position = sector_t::floor;
1190 frontsector = &tempsec;
1191
1192 if (fixedlightlev < 0 && sub->sector->e->XFloor.lightlist.Size())
1193 {
1194 light = P_GetPlaneLight(sub->sector, &frontsector->floorplane, false);
1195 basecolormap = light->extra_colormap;
1196 floorlightlevel = *light->p_lightlevel;
1197 }
1198
1199 ceilingplane = NULL;
1200 floorplane = R_FindPlane(frontsector->floorplane,
1201 frontsector->GetTexture(sector_t::floor),
1202 floorlightlevel + r_actualextralight, // killough 3/16/98
1203 frontsector->GetAlpha(sector_t::floor),
1204 !!(fakeFloor->flags & FF_ADDITIVETRANS),
1205 frontsector->GetXOffset(position), // killough 3/7/98
1206 frontsector->GetYOffset(position), // killough 3/7/98
1207 frontsector->GetXScale(position),
1208 frontsector->GetYScale(position),
1209 frontsector->GetAngle(position),
1210 frontsector->sky,
1211 NULL);
1212
1213 R_FakeDrawLoop(sub);
1214 fake3D = 0;
1215 frontsector = sub->sector;
1216 }
1217 }
1218 // and now ceilings
1219 for (unsigned int i = 0; i < frontsector->e->XFloor.ffloors.Size(); i++)
1220 {
1221 fakeFloor = frontsector->e->XFloor.ffloors[i];
1222 if (!(fakeFloor->flags & FF_EXISTS)) continue;
1223 if (!fakeFloor->model) continue;
1224 if (fakeFloor->top.plane->a || fakeFloor->top.plane->b) continue;
1225 if (!(fakeFloor->flags & FF_NOSHADE) || (fakeFloor->flags & (FF_RENDERPLANES|FF_RENDERSIDES)))
1226 {
1227 R_3D_AddHeight(fakeFloor->bottom.plane, frontsector);
1228 }
1229 if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
1230 if (fakeFloor->alpha == 0) continue;
1231 if (!(fakeFloor->flags & FF_THISINSIDE) && (fakeFloor->flags & (FF_SWIMMABLE|FF_INVERTSECTOR)) == (FF_SWIMMABLE|FF_INVERTSECTOR)) continue;
1232 fakeAlpha = MIN(Scale(fakeFloor->alpha, OPAQUE, 255), OPAQUE);
1233
1234 if (fakeFloor->validcount != validcount)
1235 {
1236 fakeFloor->validcount = validcount;
1237 R_3D_NewClip();
1238 }
1239 fakeHeight = fakeFloor->bottom.plane->ZatPoint(frontsector->soundorg[0], frontsector->soundorg[1]);
1240 if (fakeHeight > viewz &&
1241 fakeHeight < frontsector->ceilingplane.ZatPoint(frontsector->soundorg[0], frontsector->soundorg[1]))
1242 {
1243 fake3D = FAKE3D_FAKECEILING;
1244 tempsec = *fakeFloor->model;
1245 tempsec.floorplane = *fakeFloor->top.plane;
1246 tempsec.ceilingplane = *fakeFloor->bottom.plane;
1247 if ((!(fakeFloor->flags & FF_THISINSIDE) && !(fakeFloor->flags & FF_INVERTSECTOR)) ||
1248 (fakeFloor->flags & FF_THISINSIDE && fakeFloor->flags & FF_INVERTSECTOR))
1249 {
1250 tempsec.SetTexture(sector_t::ceiling, tempsec.GetTexture(sector_t::floor));
1251 position = sector_t::floor;
1252 } else position = sector_t::ceiling;
1253 frontsector = &tempsec;
1254
1255 tempsec.ceilingplane.ChangeHeight(-1);
1256 if (fixedlightlev < 0 && sub->sector->e->XFloor.lightlist.Size())
1257 {
1258 light = P_GetPlaneLight(sub->sector, &frontsector->ceilingplane, false);
1259 basecolormap = light->extra_colormap;
1260 ceilinglightlevel = *light->p_lightlevel;
1261 }
1262 tempsec.ceilingplane.ChangeHeight(1);
1263
1264 floorplane = NULL;
1265 ceilingplane = R_FindPlane(frontsector->ceilingplane, // killough 3/8/98
1266 frontsector->GetTexture(sector_t::ceiling),
1267 ceilinglightlevel + r_actualextralight, // killough 4/11/98
1268 frontsector->GetAlpha(sector_t::ceiling),
1269 !!(fakeFloor->flags & FF_ADDITIVETRANS),
1270 frontsector->GetXOffset(position), // killough 3/7/98
1271 frontsector->GetYOffset(position), // killough 3/7/98
1272 frontsector->GetXScale(position),
1273 frontsector->GetYScale(position),
1274 frontsector->GetAngle(position),
1275 frontsector->sky,
1276 NULL);
1277
1278 R_FakeDrawLoop(sub);
1279 fake3D = 0;
1280 frontsector = sub->sector;
1281 }
1282 }
1283 fakeFloor = NULL;
1284 floorplane = backupfp;
1285 ceilingplane = backupcp;
1286 }
1287
1288 basecolormap = frontsector->ColorMap;
1289 floorlightlevel = fll;
1290 ceilinglightlevel = cll;
1291
1292 // killough 9/18/98: Fix underwater slowdown, by passing real sector
1293 // instead of fake one. Improve sprite lighting by basing sprite
1294 // lightlevels on floor & ceiling lightlevels in the surrounding area.
1295 // [RH] Handle sprite lighting like Duke 3D: If the ceiling is a sky, sprites are lit by
1296 // it, otherwise they are lit by the floor.
1297 R_AddSprites (sub->sector, frontsector->GetTexture(sector_t::ceiling) == skyflatnum ?
1298 ceilinglightlevel : floorlightlevel, FakeSide);
1299
1300 // [RH] Add particles
1301 if ((unsigned int)(sub - subsectors) < (unsigned int)numsubsectors)
1302 { // Only do it for the main BSP.
1303 int shade = LIGHT2SHADE((floorlightlevel + ceilinglightlevel)/2 + r_actualextralight);
1304 for (WORD i = ParticlesInSubsec[(unsigned int)(sub-subsectors)]; i != NO_PARTICLE; i = Particles[i].snext)
1305 {
1306 R_ProjectParticle (Particles + i, subsectors[sub-subsectors].sector, shade, FakeSide);
1307 }
1308 }
1309
1310 count = sub->numlines;
1311 line = sub->firstline;
1312
1313 while (count--)
1314 {
1315 if (!outersubsector || line->sidedef == NULL || !(line->sidedef->Flags & WALLF_POLYOBJ))
1316 {
1317 // kg3D - fake planes bounding calculation
1318 if (r_3dfloors && line->backsector && frontsector->e && line->backsector->e->XFloor.ffloors.Size())
1319 {
1320 backupfp = floorplane;
1321 backupcp = ceilingplane;
1322 floorplane = NULL;
1323 ceilingplane = NULL;
1324 for (unsigned int i = 0; i < line->backsector->e->XFloor.ffloors.Size(); i++)
1325 {
1326 fakeFloor = line->backsector->e->XFloor.ffloors[i];
1327 if (!(fakeFloor->flags & FF_EXISTS)) continue;
1328 if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
1329 if (!fakeFloor->model) continue;
1330 fake3D = FAKE3D_FAKEBACK;
1331 tempsec = *fakeFloor->model;
1332 tempsec.floorplane = *fakeFloor->top.plane;
1333 tempsec.ceilingplane = *fakeFloor->bottom.plane;
1334 backsector = &tempsec;
1335 if (fakeFloor->validcount != validcount)
1336 {
1337 fakeFloor->validcount = validcount;
1338 R_3D_NewClip();
1339 }
1340 if (frontsector->CenterFloor() >= backsector->CenterFloor())
1341 {
1342 fake3D |= FAKE3D_CLIPBOTFRONT;
1343 }
1344 if (frontsector->CenterCeiling() <= backsector->CenterCeiling())
1345 {
1346 fake3D |= FAKE3D_CLIPTOPFRONT;
1347 }
1348 R_AddLine(line); // fake
1349 }
1350 fakeFloor = NULL;
1351 fake3D = 0;
1352 floorplane = backupfp;
1353 ceilingplane = backupcp;
1354 }
1355 R_AddLine (line); // now real
1356 }
1357 line++;
1358 }
1359 if (outersubsector)
1360 {
1361 InSubsector = NULL;
1362 }
1363 }
1364
1365 //
1366 // RenderBSPNode
1367 // Renders all subsectors below a given node, traversing subtree recursively.
1368 // Just call with BSP root and -1.
1369 // killough 5/2/98: reformatted, removed tail recursion
1370
R_RenderBSPNode(void * node)1371 void R_RenderBSPNode (void *node)
1372 {
1373 if (numnodes == 0)
1374 {
1375 R_Subsector (subsectors);
1376 return;
1377 }
1378 while (!((size_t)node & 1)) // Keep going until found a subsector
1379 {
1380 node_t *bsp = (node_t *)node;
1381
1382 // Decide which side the view point is on.
1383 int side = R_PointOnSide (viewx, viewy, bsp);
1384
1385 // Recursively divide front space (toward the viewer).
1386 R_RenderBSPNode (bsp->children[side]);
1387
1388 // Possibly divide back space (away from the viewer).
1389 side ^= 1;
1390 if (!R_CheckBBox (bsp->bbox[side]))
1391 return;
1392
1393 node = bsp->children[side];
1394 }
1395 R_Subsector ((subsector_t *)((BYTE *)node - 1));
1396 }
1397