1 //**************************************************************************
2 //**
3 //**	##   ##    ##    ##   ##   ####     ####   ###     ###
4 //**	##   ##  ##  ##  ##   ##  ##  ##   ##  ##  ####   ####
5 //**	 ## ##  ##    ##  ## ##  ##    ## ##    ## ## ## ## ##
6 //**	 ## ##  ########  ## ##  ##    ## ##    ## ##  ###  ##
7 //**	  ###   ##    ##   ###    ##  ##   ##  ##  ##       ##
8 //**	   #    ##    ##    #      ####     ####   ##       ##
9 //**
10 //**	$Id: r_bsp.cpp 4350 2010-12-17 15:36:16Z dj_jl $
11 //**
12 //**	Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //**	This program is free software; you can redistribute it and/or
15 //**  modify it under the terms of the GNU General Public License
16 //**  as published by the Free Software Foundation; either version 2
17 //**  of the License, or (at your option) any later version.
18 //**
19 //**	This program is distributed in the hope that it will be useful,
20 //**  but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //**  GNU General Public License for more details.
23 //**
24 //**************************************************************************
25 //**
26 //**	BSP traversal, handling of LineSegs for rendering.
27 //**
28 //**************************************************************************
29 
30 // HEADER FILES ------------------------------------------------------------
31 
32 #include "gamedefs.h"
33 #include "r_local.h"
34 
35 // MACROS ------------------------------------------------------------------
36 
37 #define HORIZON_SURF_SIZE	(sizeof(surface_t) + sizeof(TVec) * 3)
38 
39 // TYPES -------------------------------------------------------------------
40 
41 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
42 
43 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
44 
45 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
46 
47 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
48 
49 // PUBLIC DATA DEFINITIONS -------------------------------------------------
50 
51 // PRIVATE DATA DEFINITIONS ------------------------------------------------
52 
53 static subsector_t*		r_sub;
54 static subregion_t*		r_subregion;
55 static sec_region_t*	r_region;
56 static bool				MirrorClipSegs;
57 
58 static VCvarI			r_maxmirrors("r_maxmirrors", "4", CVAR_Archive);
59 
60 // CODE --------------------------------------------------------------------
61 
62 //==========================================================================
63 //
64 //	VRenderLevelShared::SetUpFrustumIndexes
65 //
66 //==========================================================================
67 
SetUpFrustumIndexes()68 void VRenderLevelShared::SetUpFrustumIndexes()
69 {
70 	guard(VRenderLevelShared::SetUpFrustumIndexes);
71 	for (int i = 0; i < 4; i++)
72 	{
73 		int *pindex = FrustumIndexes[i];
74 		for (int j = 0; j < 3; j++)
75 		{
76 			if (view_clipplanes[i].normal[j] < 0)
77 			{
78 				pindex[j] = j;
79 				pindex[j + 3] = j + 3;
80 			}
81 			else
82 			{
83 				pindex[j] = j + 3;
84 				pindex[j + 3] = j;
85 			}
86 		}
87 	}
88 	unguard;
89 }
90 
91 //==========================================================================
92 //
93 //	VRenderLevel::QueueWorldSurface
94 //
95 //==========================================================================
96 
QueueWorldSurface(surface_t * surf)97 void VRenderLevel::QueueWorldSurface(surface_t* surf)
98 {
99 	guard(VRenderLevel::QueueWorldSurface);
100 	bool lightmaped = surf->lightmap != NULL ||
101 		surf->dlightframe == r_dlightframecount;
102 
103 	if (lightmaped)
104 	{
105 		CacheSurface(surf);
106 		if (Drawer->HaveMultiTexture)
107 		{
108 			return;
109 		}
110 	}
111 
112 	QueueSimpleSurf(surf);
113 	unguard;
114 }
115 
116 //==========================================================================
117 //
118 //	VAdvancedRenderLevel::QueueWorldSurface
119 //
120 //==========================================================================
121 
QueueWorldSurface(surface_t * surf)122 void VAdvancedRenderLevel::QueueWorldSurface(surface_t* surf)
123 {
124 	guard(VAdvancedRenderLevel::QueueWorldSurface);
125 	QueueSimpleSurf(surf);
126 	unguard;
127 }
128 
129 //==========================================================================
130 //
131 //	VRenderLevelShared::DrawSurfaces
132 //
133 //==========================================================================
134 
QueueSimpleSurf(surface_t * surf)135 void VRenderLevelShared::QueueSimpleSurf(surface_t* surf)
136 {
137 	guard(VRenderLevelShared::QueueSimpleSurf);
138 	if (SimpleSurfsTail)
139 	{
140 		SimpleSurfsTail->DrawNext = surf;
141 		SimpleSurfsTail = surf;
142 	}
143 	else
144 	{
145 		SimpleSurfsHead = surf;
146 		SimpleSurfsTail = surf;
147 	}
148 	surf->DrawNext = NULL;
149 	unguard;
150 }
151 
152 //==========================================================================
153 //
154 //	VRenderLevelShared::QueueSkyPortal
155 //
156 //==========================================================================
157 
QueueSkyPortal(surface_t * surf)158 void VRenderLevelShared::QueueSkyPortal(surface_t* surf)
159 {
160 	guard(VRenderLevelShared::QueueSkyPortal);
161 	if (SkyPortalsTail)
162 	{
163 		SkyPortalsTail->DrawNext = surf;
164 		SkyPortalsTail = surf;
165 	}
166 	else
167 	{
168 		SkyPortalsHead = surf;
169 		SkyPortalsTail = surf;
170 	}
171 	surf->DrawNext = NULL;
172 	unguard;
173 }
174 
175 //==========================================================================
176 //
177 //	VRenderLevelShared::QueueHorizonPortal
178 //
179 //==========================================================================
180 
QueueHorizonPortal(surface_t * surf)181 void VRenderLevelShared::QueueHorizonPortal(surface_t* surf)
182 {
183 	guard(VRenderLevelShared::QueueHorizonPortal);
184 	if (HorizonPortalsTail)
185 	{
186 		HorizonPortalsTail->DrawNext = surf;
187 		HorizonPortalsTail = surf;
188 	}
189 	else
190 	{
191 		HorizonPortalsHead = surf;
192 		HorizonPortalsTail = surf;
193 	}
194 	surf->DrawNext = NULL;
195 	unguard;
196 }
197 
198 //==========================================================================
199 //
200 //	VRenderLevelShared::DrawSurfaces
201 //
202 //==========================================================================
203 
DrawSurfaces(surface_t * InSurfs,texinfo_t * texinfo,VEntity * SkyBox,int LightSourceSector,int SideLight,bool AbsSideLight,bool CheckSkyBoxAlways)204 void VRenderLevelShared::DrawSurfaces(surface_t* InSurfs, texinfo_t *texinfo,
205 	VEntity* SkyBox, int LightSourceSector, int SideLight, bool AbsSideLight,
206 	bool CheckSkyBoxAlways)
207 {
208 	guard(VRenderLevelShared::DrawSurfaces);
209 	surface_t* surfs = InSurfs;
210 	if (!surfs)
211 	{
212 		return;
213 	}
214 
215 	if (texinfo->Tex->Type == TEXTYPE_Null)
216 	{
217 		return;
218 	}
219 
220 	sec_params_t* LightParams = LightSourceSector == -1 ? r_region->params :
221 		&Level->Sectors[LightSourceSector].params;
222 	int lLev = (AbsSideLight ? 0 : LightParams->lightlevel) + SideLight;
223 	lLev = FixedLight ? FixedLight : lLev + ExtraLight;
224 	lLev = MID(0, lLev, 255);
225 	if (r_darken)
226 	{
227 		lLev = light_remap[lLev];
228 	}
229 	vuint32 Fade = GetFade(r_region);
230 
231 	if (SkyBox && (SkyBox->EntityFlags & VEntity::EF_FixedModel))
232 	{
233 		SkyBox = NULL;
234 	}
235 	bool IsStack = SkyBox && SkyBox->eventSkyBoxGetAlways();
236 	if (texinfo->Tex == GTextureManager[skyflatnum] ||
237 		IsStack && CheckSkyBoxAlways)
238 	{
239 		VSky* Sky = NULL;
240 		if (!SkyBox && r_sub->sector->Sky & SKY_FROM_SIDE)
241 		{
242 			int Tex;
243 			bool Flip;
244 			if (r_sub->sector->Sky == SKY_FROM_SIDE)
245 			{
246 				Tex = Level->LevelInfo->Sky2Texture;
247 				Flip = true;
248 			}
249 			else
250 			{
251 				side_t* Side = &Level->Sides[(r_sub->sector->Sky &
252 					(SKY_FROM_SIDE - 1)) - 1];
253 				Tex = Side->TopTexture;
254 				Flip = !!Level->Lines[Side->LineNum].arg3;
255 			}
256 			if (GTextureManager[Tex]->Type != TEXTYPE_Null)
257 			{
258 				for (int i = 0; i < SideSkies.Num(); i++)
259 				{
260 					if (SideSkies[i]->SideTex == Tex &&
261 						SideSkies[i]->SideFlip == Flip)
262 					{
263 						Sky = SideSkies[i];
264 						break;
265 					}
266 				}
267 				if (!Sky)
268 				{
269 					Sky = new VSky;
270 					Sky->Init(Tex, Tex, 0, 0, false,
271 						!!(Level->LevelInfo->LevelInfoFlags &
272 						VLevelInfo::LIF_ForceNoSkyStretch), Flip, false);
273 					SideSkies.Append(Sky);
274 				}
275 			}
276 		}
277 		if (!Sky && !SkyBox)
278 		{
279 			InitSky();
280 			Sky = &BaseSky;
281 		}
282 
283 		VPortal* Portal = NULL;
284 		if (SkyBox)
285 		{
286 			for (int i = 0; i < Portals.Num(); i++)
287 			{
288 				if (Portals[i] && Portals[i]->MatchSkyBox(SkyBox))
289 				{
290 					Portal = Portals[i];
291 					break;
292 				}
293 			}
294 			if (!Portal)
295 			{
296 				if (IsStack)
297 				{
298 					Portal = new VSectorStackPortal(this, SkyBox);
299 				}
300 				else
301 				{
302 					Portal = new VSkyBoxPortal(this, SkyBox);
303 				}
304 				Portals.Append(Portal);
305 			}
306 		}
307 		else
308 		{
309 			for (int i = 0; i < Portals.Num(); i++)
310 			{
311 				if (Portals[i] && Portals[i]->MatchSky(Sky))
312 				{
313 					Portal = Portals[i];
314 					break;
315 				}
316 			}
317 			if (!Portal)
318 			{
319 				Portal = new VSkyPortal(this, Sky);
320 				Portals.Append(Portal);
321 			}
322 		}
323 		do
324 		{
325 			Portal->Surfs.Append(surfs);
326 			if (IsStack && CheckSkyBoxAlways &&
327 				SkyBox->eventSkyBoxGetPlaneAlpha())
328 			{
329 				surfs->Light = (lLev << 24) | LightParams->LightColour;
330 				surfs->Fade = Fade;
331 				surfs->dlightframe = r_sub->dlightframe;
332 				surfs->dlightbits = r_sub->dlightbits;
333 				DrawTranslucentPoly(surfs, surfs->verts, surfs->count,
334 					0, SkyBox->eventSkyBoxGetPlaneAlpha(), false, 0,
335 					false, 0, 0, TVec(), 0, TVec(), TVec(), TVec());
336 			}
337 
338 			if (!Drawer->HaveStencil)
339 			{
340 				if (PortalLevel == 0)
341 				{
342 					world_surf_t& S = WorldSurfs.Alloc();
343 					S.Surf = surfs;
344 					S.Type = 1;
345 				}
346 				else
347 				{
348 					QueueSkyPortal(surfs);
349 				}
350 			}
351 
352 			surfs = surfs->next;
353 		} while (surfs);
354 		return;
355 	}
356 
357 	do
358 	{
359 		surfs->Light = (lLev << 24) | LightParams->LightColour;
360 		surfs->Fade = Fade;
361 		surfs->dlightframe = r_sub->dlightframe;
362 		surfs->dlightbits = r_sub->dlightbits;
363 
364 		if (texinfo->Alpha > 1.0)
365 		{
366 			if (PortalLevel == 0)
367 			{
368 				world_surf_t& S = WorldSurfs.Alloc();
369 				S.Surf = surfs;
370 				S.Type = 0;
371 			}
372 			else
373 			{
374 				QueueWorldSurface(surfs);
375 			}
376 		}
377 		else
378 		{
379 			DrawTranslucentPoly(surfs, surfs->verts, surfs->count,
380 				0, texinfo->Alpha, texinfo->Additive, 0, false, 0, 0,
381 				TVec(), 0, TVec(), TVec(), TVec());
382 		}
383 		surfs = surfs->next;
384 	} while (surfs);
385 	unguard;
386 }
387 
388 //==========================================================================
389 //
390 //	VRenderLevelShared::RenderHorizon
391 //
392 //==========================================================================
393 
RenderHorizon(drawseg_t * dseg)394 void VRenderLevelShared::RenderHorizon(drawseg_t* dseg)
395 {
396 	guard(VRenderLevelShared::RenderHorizon);
397 	seg_t* Seg = dseg->seg;
398 
399 	if (!dseg->HorizonTop)
400 	{
401 		dseg->HorizonTop = (surface_t*)Z_Malloc(HORIZON_SURF_SIZE);
402 		dseg->HorizonBot = (surface_t*)Z_Malloc(HORIZON_SURF_SIZE);
403 		memset(dseg->HorizonTop, 0, HORIZON_SURF_SIZE);
404 		memset(dseg->HorizonBot, 0, HORIZON_SURF_SIZE);
405 	}
406 
407 	//	Horizon is not supported in sectors with slopes, so just use TexZ.
408 	float TopZ = r_region->ceiling->TexZ;
409 	float BotZ = r_region->floor->TexZ;
410 	float HorizonZ = vieworg.z;
411 
412 	//	Handle top part.
413 	if (TopZ > HorizonZ)
414 	{
415 		sec_surface_t* Ceil = r_subregion->ceil;
416 
417 		//	Calculate light and fade.
418 		sec_params_t* LightParams = Ceil->secplane->LightSourceSector != -1 ?
419 			&Level->Sectors[Ceil->secplane->LightSourceSector].params :
420 			r_region->params;
421 		int lLev = FixedLight ? FixedLight :
422 			MIN(255, LightParams->lightlevel + ExtraLight);
423 		if (r_darken)
424 		{
425 			lLev = light_remap[lLev];
426 		}
427 		vuint32 Fade = GetFade(r_region);
428 
429 		surface_t* Surf = dseg->HorizonTop;
430 		Surf->plane = dseg->seg;
431 		Surf->texinfo = &Ceil->texinfo;
432 		Surf->HorizonPlane = Ceil->secplane;
433 		Surf->Light = (lLev << 24) | LightParams->LightColour;
434 		Surf->Fade = Fade;
435 		Surf->count = 4;
436 		Surf->verts[0] = *Seg->v1;
437 		Surf->verts[0].z = MAX(BotZ, HorizonZ);
438 		Surf->verts[1] = *Seg->v1;
439 		Surf->verts[1].z = TopZ;
440 		Surf->verts[2] = *Seg->v2;
441 		Surf->verts[2].z = TopZ;
442 		Surf->verts[3] = *Seg->v2;
443 		Surf->verts[3].z = MAX(BotZ, HorizonZ);
444 		if (Ceil->secplane->pic == skyflatnum)
445 		{
446 			//	If it's a sky, render it as a regular sky surface.
447 			DrawSurfaces(Surf, &Ceil->texinfo, r_region->ceiling->SkyBox, -1,
448 				Seg->sidedef->Light, !!(Seg->sidedef->Flags & SDF_ABSLIGHT),
449 				false);
450 		}
451 		else
452 		{
453 			if (PortalLevel == 0)
454 			{
455 				world_surf_t& S = WorldSurfs.Alloc();
456 				S.Surf = Surf;
457 				S.Type = 2;
458 			}
459 			else
460 			{
461 				QueueHorizonPortal(Surf);
462 			}
463 		}
464 	}
465 
466 	//	Handle bottom part.
467 	if (BotZ < HorizonZ)
468 	{
469 		sec_surface_t* Floor = r_subregion->floor;
470 
471 		//	Calculate light and fade.
472 		sec_params_t* LightParams = Floor->secplane->LightSourceSector != -1 ?
473 			&Level->Sectors[Floor->secplane->LightSourceSector].params :
474 			r_region->params;
475 		int lLev = FixedLight ? FixedLight :
476 			MIN(255, LightParams->lightlevel + ExtraLight);
477 		if (r_darken)
478 		{
479 			lLev = light_remap[lLev];
480 		}
481 		vuint32 Fade = GetFade(r_region);
482 
483 		surface_t* Surf = dseg->HorizonBot;
484 		Surf->plane = dseg->seg;
485 		Surf->texinfo = &Floor->texinfo;
486 		Surf->HorizonPlane = Floor->secplane;
487 		Surf->Light = (lLev << 24) | LightParams->LightColour;
488 		Surf->Fade = Fade;
489 		Surf->count = 4;
490 		Surf->verts[0] = *Seg->v1;
491 		Surf->verts[0].z = BotZ;
492 		Surf->verts[1] = *Seg->v1;
493 		Surf->verts[1].z = MIN(TopZ, HorizonZ);
494 		Surf->verts[2] = *Seg->v2;
495 		Surf->verts[2].z = MIN(TopZ, HorizonZ);
496 		Surf->verts[3] = *Seg->v2;
497 		Surf->verts[3].z = BotZ;
498 		if (Floor->secplane->pic == skyflatnum)
499 		{
500 			//	If it's a sky, render it as a regular sky surface.
501 			DrawSurfaces(Surf, &Floor->texinfo, r_region->floor->SkyBox, -1,
502 				Seg->sidedef->Light, !!(Seg->sidedef->Flags & SDF_ABSLIGHT),
503 				false);
504 		}
505 		else
506 		{
507 			if (PortalLevel == 0)
508 			{
509 				world_surf_t& S = WorldSurfs.Alloc();
510 				S.Surf = Surf;
511 				S.Type = 2;
512 			}
513 			else
514 			{
515 				QueueHorizonPortal(Surf);
516 			}
517 		}
518 	}
519 	unguard;
520 }
521 
522 //==========================================================================
523 //
524 //	VRenderLevelShared::RenderMirror
525 //
526 //==========================================================================
527 
RenderMirror(drawseg_t * dseg)528 void VRenderLevelShared::RenderMirror(drawseg_t* dseg)
529 {
530 	guard(VRenderLevelShared::RenderMirror);
531 	seg_t* Seg = dseg->seg;
532 
533 	if (Drawer->HaveStencil && MirrorLevel < r_maxmirrors)
534 	{
535 		VPortal* Portal = NULL;
536 		for (int i = 0; i < Portals.Num(); i++)
537 		{
538 			if (Portals[i] && Portals[i]->MatchMirror(Seg))
539 			{
540 				Portal = Portals[i];
541 				break;
542 			}
543 		}
544 		if (!Portal)
545 		{
546 			Portal = new VMirrorPortal(this, Seg);
547 			Portals.Append(Portal);
548 		}
549 
550 		surface_t* surfs = dseg->mid->surfs;
551 		do
552 		{
553 			Portal->Surfs.Append(surfs);
554 			surfs = surfs->next;
555 		} while (surfs);
556 	}
557 	else
558 	{
559 		DrawSurfaces(dseg->mid->surfs, &dseg->mid->texinfo,
560 			r_region->ceiling->SkyBox, -1, Seg->sidedef->Light,
561 			!!(Seg->sidedef->Flags & SDF_ABSLIGHT), false);
562 	}
563 	unguard;
564 }
565 
566 //==========================================================================
567 //
568 //	VRenderLevelShared::RenderLine
569 //
570 // 	Clips the given segment and adds any visible pieces to the line list.
571 //
572 //==========================================================================
573 
RenderLine(drawseg_t * dseg)574 void VRenderLevelShared::RenderLine(drawseg_t* dseg)
575 {
576 	guard(VRenderLevelShared::RenderLine);
577 	seg_t *line = dseg->seg;
578 
579 	if (!line->linedef)
580 	{
581 		//	Miniseg
582 		return;
583 	}
584 
585 	float dist = DotProduct(vieworg, line->normal) - line->dist;
586 	if (dist <= 0)
587 	{
588 		//	Viewer is in back side or on plane
589 		return;
590 	}
591 
592 	float a1 = ViewClip.PointToClipAngle(*line->v2);
593 	float a2 = ViewClip.PointToClipAngle(*line->v1);
594 	if (!ViewClip.IsRangeVisible(a1, a2))
595 	{
596 		return;
597 	}
598 
599 	if (MirrorClipSegs)
600 	{
601 		//	Clip away segs that are behind mirror.
602 		float Dist1 = DotProduct(*line->v1, view_clipplanes[4].normal) -
603 			view_clipplanes[4].dist;
604 		float Dist2 = DotProduct(*line->v2, view_clipplanes[4].normal) -
605 			view_clipplanes[4].dist;
606 		if (Dist1 <= 0 && Dist2 <= 0)
607 		{
608 			//	Behind mirror.
609 			return;
610 		}
611 	}
612 
613 	line_t *linedef = line->linedef;
614 	side_t *sidedef = line->sidedef;
615 
616 	//FIXME this marks all lines
617 	// mark the segment as visible for auto map
618 	linedef->flags |= ML_MAPPED;
619 
620 	if (!line->backsector)
621 	{
622 		// single sided line
623 		if (line->linedef->special == LNSPEC_LineHorizon)
624 		{
625 			RenderHorizon(dseg);
626 		}
627 		else if (line->linedef->special == LNSPEC_LineMirror)
628 		{
629 			RenderMirror(dseg);
630 		}
631 		else
632 		{
633 			DrawSurfaces(dseg->mid->surfs, &dseg->mid->texinfo,
634 				r_region->ceiling->SkyBox, -1, sidedef->Light,
635 				!!(sidedef->Flags & SDF_ABSLIGHT), false);
636 		}
637 		DrawSurfaces(dseg->topsky->surfs, &dseg->topsky->texinfo,
638 			r_region->ceiling->SkyBox, -1, sidedef->Light,
639 			!!(sidedef->Flags & SDF_ABSLIGHT), false);
640 	}
641 	else
642 	{
643 		// two sided line
644 		DrawSurfaces(dseg->top->surfs, &dseg->top->texinfo,
645 			r_region->ceiling->SkyBox, -1, sidedef->Light,
646 			!!(sidedef->Flags & SDF_ABSLIGHT), false);
647 		DrawSurfaces(dseg->topsky->surfs, &dseg->topsky->texinfo,
648 			r_region->ceiling->SkyBox, -1, sidedef->Light,
649 			!!(sidedef->Flags & SDF_ABSLIGHT), false);
650 		DrawSurfaces(dseg->bot->surfs, &dseg->bot->texinfo,
651 			r_region->ceiling->SkyBox, -1, sidedef->Light,
652 			!!(sidedef->Flags & SDF_ABSLIGHT), false);
653 		DrawSurfaces(dseg->mid->surfs, &dseg->mid->texinfo,
654 			r_region->ceiling->SkyBox, -1, sidedef->Light,
655 			!!(sidedef->Flags & SDF_ABSLIGHT), false);
656 		for (segpart_t *sp = dseg->extra; sp; sp = sp->next)
657 		{
658 			DrawSurfaces(sp->surfs, &sp->texinfo,r_region->ceiling->SkyBox,
659 				-1, sidedef->Light, !!(sidedef->Flags & SDF_ABSLIGHT), false);
660 		}
661 	}
662 	unguard;
663 }
664 
665 //==========================================================================
666 //
667 //	VRenderLevelShared::RenderSecSurface
668 //
669 //==========================================================================
670 
RenderSecSurface(sec_surface_t * ssurf,VEntity * SkyBox)671 void VRenderLevelShared::RenderSecSurface(sec_surface_t* ssurf,
672 	VEntity* SkyBox)
673 {
674 	guard(VRenderLevelShared::RenderSecSurface);
675 	sec_plane_t& plane = *ssurf->secplane;
676 
677 	if (!plane.pic)
678 	{
679 		return;
680 	}
681 
682 	float dist = DotProduct(vieworg, plane.normal) - plane.dist;
683 	if (dist <= 0)
684 	{
685 		//	Viewer is in back side or on plane
686 		return;
687 	}
688 
689 	if (plane.MirrorAlpha < 1.0 && Drawer->HaveStencil &&
690 		MirrorLevel < r_maxmirrors)
691 	{
692 		VPortal* Portal = NULL;
693 		for (int i = 0; i < Portals.Num(); i++)
694 		{
695 			if (Portals[i] && Portals[i]->MatchMirror(&plane))
696 			{
697 				Portal = Portals[i];
698 				break;
699 			}
700 		}
701 		if (!Portal)
702 		{
703 			Portal = new VMirrorPortal(this, &plane);
704 			Portals.Append(Portal);
705 		}
706 
707 		surface_t* surfs = ssurf->surfs;
708 		do
709 		{
710 			Portal->Surfs.Append(surfs);
711 			surfs = surfs->next;
712 		} while (surfs);
713 
714 		if (plane.MirrorAlpha <= 0.0)
715 		{
716 			return;
717 		}
718 		ssurf->texinfo.Alpha = plane.MirrorAlpha;
719 	}
720 
721 	DrawSurfaces(ssurf->surfs, &ssurf->texinfo, SkyBox,
722 		plane.LightSourceSector, 0, false, true);
723 	unguard;
724 }
725 
726 //==========================================================================
727 //
728 //	VRenderLevelShared::RenderSubRegion
729 //
730 // 	Determine floor/ceiling planes.
731 // 	Draw one or more line segments.
732 //
733 //==========================================================================
734 
RenderSubRegion(subregion_t * region)735 void VRenderLevelShared::RenderSubRegion(subregion_t* region)
736 {
737 	guard(VRenderLevelShared::RenderSubRegion);
738 	int				count;
739 	int 			polyCount;
740 	seg_t**			polySeg;
741 	float			d;
742 
743 	d = DotProduct(vieworg, region->floor->secplane->normal) -
744 		region->floor->secplane->dist;
745 	if (region->next && d <= 0.0)
746 	{
747 		RenderSubRegion(region->next);
748 	}
749 
750 	r_subregion = region;
751 	r_region = region->secregion;
752 
753 	if (r_sub->poly)
754 	{
755 		//	Render the polyobj in the subsector first
756 		polyCount = r_sub->poly->numsegs;
757 		polySeg = r_sub->poly->segs;
758 		while (polyCount--)
759 		{
760 			RenderLine((*polySeg)->drawsegs);
761 			polySeg++;
762 		}
763 	}
764 
765 	count = r_sub->numlines;
766 	drawseg_t *ds = region->lines;
767 	while (count--)
768 	{
769 		RenderLine(ds);
770 		ds++;
771 	}
772 
773 	RenderSecSurface(region->floor, r_region->floor->SkyBox);
774 	RenderSecSurface(region->ceil, r_region->ceiling->SkyBox);
775 
776 	if (region->next && d > 0.0)
777 	{
778 		RenderSubRegion(region->next);
779 	}
780 	unguard;
781 }
782 
783 //==========================================================================
784 //
785 //	VRenderLevelShared::RenderSubsector
786 //
787 //==========================================================================
788 
RenderSubsector(int num)789 void VRenderLevelShared::RenderSubsector(int num)
790 {
791 	guard(VRenderLevelShared::RenderSubsector);
792 	subsector_t* Sub = &Level->Subsectors[num];
793 	r_sub = Sub;
794 
795 	if (Sub->VisFrame != r_visframecount)
796 	{
797 		return;
798 	}
799 
800 	if (!Sub->sector->linecount)
801 	{
802 		//	Skip sectors containing original polyobjs
803 		return;
804 	}
805 
806 	if (!ViewClip.ClipCheckSubsector(Sub))
807 	{
808 		return;
809 	}
810 
811 	BspVis[num >> 3] |= 1 << (num & 7);
812 
813 	RenderSubRegion(Sub->regions);
814 
815 	//	Add subsector's segs to the clipper. Clipping against mirror
816 	// is done only for vertical mirror planes.
817 	ViewClip.ClipAddSubsectorSegs(Sub, MirrorClipSegs ? &view_clipplanes[4] :
818 		NULL);
819 	unguard;
820 }
821 
822 //==========================================================================
823 //
824 //	VRenderLevelShared::RenderBSPNode
825 //
826 //	Renders all subsectors below a given node, traversing subtree
827 // recursively. Just call with BSP root.
828 //
829 //==========================================================================
830 
RenderBSPNode(int bspnum,float * bbox,int AClipflags)831 void VRenderLevelShared::RenderBSPNode(int bspnum, float* bbox, int AClipflags)
832 {
833 	guard(VRenderLevelShared::RenderBSPNode);
834 	if (ViewClip.ClipIsFull())
835 	{
836 		return;
837 	}
838 	int clipflags = AClipflags;
839 	// cull the clipping planes if not trivial accept
840 	if (clipflags)
841 	{
842 		for (int i = 0; i < 5; i++)
843 		{
844 			if (!(clipflags & view_clipplanes[i].clipflag))
845 			{
846 				continue;	// don't need to clip against it
847 			}
848 
849 			// generate accept and reject points
850 
851 			int *pindex = FrustumIndexes[i];
852 
853 			TVec rejectpt;
854 
855 			rejectpt[0] = bbox[pindex[0]];
856 			rejectpt[1] = bbox[pindex[1]];
857 			rejectpt[2] = bbox[pindex[2]];
858 
859 			float d;
860 
861 			d = DotProduct(rejectpt, view_clipplanes[i].normal);
862 			d -= view_clipplanes[i].dist;
863 			if (d <= 0)
864 			{
865 				return;
866 			}
867 
868 			TVec acceptpt;
869 
870 			acceptpt[0] = bbox[pindex[3+0]];
871 			acceptpt[1] = bbox[pindex[3+1]];
872 			acceptpt[2] = bbox[pindex[3+2]];
873 
874 			d = DotProduct(acceptpt, view_clipplanes[i].normal);
875 			d -= view_clipplanes[i].dist;
876 
877 			if (d >= 0)
878 			{
879 				clipflags ^= view_clipplanes[i].clipflag;	// node is entirely on screen
880 			}
881 		}
882 	}
883 
884 	if (!ViewClip.ClipIsBBoxVisible(bbox))
885 	{
886 		return;
887 	}
888 
889 	// Found a subsector?
890 	if (bspnum & NF_SUBSECTOR)
891 	{
892 		if (bspnum == -1)
893 		{
894 			RenderSubsector(0);
895 		}
896 		else
897 		{
898 			RenderSubsector(bspnum & (~NF_SUBSECTOR));
899 		}
900 		return;
901 	}
902 
903 	node_t* bsp = &Level->Nodes[bspnum];
904 
905 	if (bsp->VisFrame != r_visframecount)
906 	{
907 		return;
908 	}
909 
910 	// Decide which side the view point is on.
911 	int side = bsp->PointOnSide(vieworg);
912 
913 	// Recursively divide front space.
914 	RenderBSPNode(bsp->children[side], bsp->bbox[side], clipflags);
915 
916 	// Divide back space.
917 	RenderBSPNode(bsp->children[side ^ 1], bsp->bbox[side ^ 1], clipflags);
918 	unguard;
919 }
920 
921 //==========================================================================
922 //
923 //	VRenderLevelShared::RenderBspWorld
924 //
925 //==========================================================================
926 
RenderBspWorld(const refdef_t * rd,const VViewClipper * Range)927 void VRenderLevelShared::RenderBspWorld(const refdef_t* rd, const VViewClipper* Range)
928 {
929 	guard(VRenderLevelShared::RenderBspWorld);
930 	float	dummy_bbox[6] = {-99999, -99999, -99999, 99999, 99999, 99999};
931 
932 	SetUpFrustumIndexes();
933 	ViewClip.ClearClipNodes(vieworg, Level);
934 	ViewClip.ClipInitFrustrumRange(viewangles, viewforward, viewright, viewup,
935 		rd->fovx, rd->fovy);
936 	if (Range)
937 	{
938 		//	Range contains a valid range, so we must clip away holes in it.
939 		ViewClip.ClipToRanges(*Range);
940 	}
941 	memset(BspVis, 0, VisSize);
942 	if (PortalLevel == 0)
943 	{
944 		WorldSurfs.Resize(4096);
945 	}
946 	MirrorClipSegs = MirrorClip && !view_clipplanes[4].normal.z;
947 
948 	// head node is the last node output
949 	RenderBSPNode(Level->NumNodes - 1, dummy_bbox, MirrorClip ? 31 : 15);
950 
951 	if (PortalLevel == 0)
952 	{
953 		guard(Best sky);
954 		//	Draw the most complex sky portal behind the scene first, without
955 		// the need to use stencil buffer.
956 		VPortal* BestSky = NULL;
957 		int BestSkyIndex = -1;
958 		for (int i = 0; i < Portals.Num(); i++)
959 		{
960 			if (Portals[i] && Portals[i]->IsSky() &&
961 				(!BestSky || BestSky->Surfs.Num() < Portals[i]->Surfs.Num()))
962 			{
963 				BestSky = Portals[i];
964 				BestSkyIndex = i;
965 			}
966 		}
967 		if (BestSky)
968 		{
969 			PortalLevel = 1;
970 			BestSky->Draw(false);
971 			delete BestSky;
972 			BestSky = NULL;
973 			Portals.RemoveIndex(BestSkyIndex);
974 			PortalLevel = 0;
975 		}
976 		unguard;
977 
978 		guard(World surfaces);
979 		for (int i = 0; i < WorldSurfs.Num(); i++)
980 		{
981 			switch (WorldSurfs[i].Type)
982 			{
983 			case 0:
984 				QueueWorldSurface(WorldSurfs[i].Surf);
985 				break;
986 			case 1:
987 				QueueSkyPortal(WorldSurfs[i].Surf);
988 				break;
989 			case 2:
990 				QueueHorizonPortal(WorldSurfs[i].Surf);
991 				break;
992 			}
993 		}
994 		WorldSurfs.Clear();
995 		unguard;
996 	}
997 	unguard;
998 }
999 
1000 //==========================================================================
1001 //
1002 //	VRenderLevelShared::RenderPortals
1003 //
1004 //==========================================================================
1005 
RenderPortals()1006 void VRenderLevelShared::RenderPortals()
1007 {
1008 	guard(VRenderLevelShared::RenderPortals);
1009 	PortalLevel++;
1010 	if (Drawer->HaveStencil)
1011 	{
1012 		for (int i = 0; i < Portals.Num(); i++)
1013 		{
1014 			if (Portals[i] && Portals[i]->Level == PortalLevel)
1015 			{
1016 				Portals[i]->Draw(true);
1017 			}
1018 		}
1019 	}
1020 	for (int i = 0; i < Portals.Num(); i++)
1021 	{
1022 		if (Portals[i] && Portals[i]->Level == PortalLevel)
1023 		{
1024 			delete Portals[i];
1025 			Portals[i] = NULL;
1026 		}
1027 	}
1028 	PortalLevel--;
1029 	if (PortalLevel == 0)
1030 	{
1031 		Portals.Clear();
1032 	}
1033 	unguard;
1034 }
1035 
1036 //==========================================================================
1037 //
1038 //	VRenderLevel::RenderWorld
1039 //
1040 //==========================================================================
1041 
RenderWorld(const refdef_t * rd,const VViewClipper * Range)1042 void VRenderLevel::RenderWorld(const refdef_t* rd, const VViewClipper* Range)
1043 {
1044 	guard(VRenderLevel::RenderWorld);
1045 	RenderBspWorld(rd, Range);
1046 
1047 	Drawer->WorldDrawing();
1048 
1049 	RenderPortals();
1050 	unguard;
1051 }
1052 
1053 //==========================================================================
1054 //
1055 //	VAdvancedRenderLevel::RenderWorld
1056 //
1057 //==========================================================================
1058 
RenderWorld(const refdef_t * rd,const VViewClipper * Range)1059 void VAdvancedRenderLevel::RenderWorld(const refdef_t* rd, const VViewClipper* Range)
1060 {
1061 	guard(VAdvancedRenderLevel::RenderWorld);
1062 	RenderBspWorld(rd, Range);
1063 
1064 	Drawer->DrawWorldAmbientPass();
1065 
1066 	RenderPortals();
1067 	unguard;
1068 }
1069