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