1 //**************************************************************************
2 //**
3 //**	##   ##    ##    ##   ##   ####     ####   ###     ###
4 //**	##   ##  ##  ##  ##   ##  ##  ##   ##  ##  ####   ####
5 //**	 ## ##  ##    ##  ## ##  ##    ## ##    ## ## ## ## ##
6 //**	 ## ##  ########  ## ##  ##    ## ##    ## ##  ###  ##
7 //**	  ###   ##    ##   ###    ##  ##   ##  ##  ##       ##
8 //**	   #    ##    ##    #      ####     ####   ##       ##
9 //**
10 //**	$Id: r_light.cpp 4220 2010-04-24 15:24:35Z 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 // HEADER FILES ------------------------------------------------------------
27 
28 #include "gamedefs.h"
29 #include "r_local.h"
30 
31 // MACROS ------------------------------------------------------------------
32 
33 // TYPES -------------------------------------------------------------------
34 
35 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
36 
37 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
38 
39 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
40 
41 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
42 
43 // PUBLIC DATA DEFINITIONS -------------------------------------------------
44 
45 extern VCvarI				r_darken;
46 
47 // PRIVATE DATA DEFINITIONS ------------------------------------------------
48 
49 static subsector_t*		r_sub;
50 static sec_region_t*	r_region;
51 static VCvarF			r_lights_radius("r_lights_radius", "4096", CVAR_Archive);
52 
53 // CODE --------------------------------------------------------------------
54 
55 //==========================================================================
56 //
57 //	VAdvancedRenderLevel::PushDlights
58 //
59 //==========================================================================
60 
PushDlights()61 void VAdvancedRenderLevel::PushDlights()
62 {
63 	r_dlightframecount = 1;
64 }
65 
66 //==========================================================================
67 //
68 //	VAdvancedRenderLevel::LightPoint
69 //
70 //==========================================================================
71 
LightPoint(const TVec & p)72 vuint32 VAdvancedRenderLevel::LightPoint(const TVec &p)
73 {
74 	guard(VAdvancedRenderLevel::LightPoint);
75 	subsector_t		*sub;
76 	subregion_t		*reg;
77 	float			l, lr, lg, lb, d, add;
78 	int				i;
79 	int				leafnum;
80 	linetrace_t		Trace;
81 
82 	if (FixedLight)
83 	{
84 		return FixedLight | (FixedLight << 8) | (FixedLight << 16) | (FixedLight << 24);
85 	}
86 
87 	sub = Level->PointInSubsector(p);
88 	vuint8* dyn_facevis = Level->LeafPVS(sub);
89 	reg = sub->regions;
90 	while (reg->next)
91 	{
92 		d = DotProduct(p, reg->floor->secplane->normal) - reg->floor->secplane->dist;
93 
94 		if (d >= 0.0)
95 		{
96 			break;
97 		}
98 
99 		reg = reg->next;
100 	}
101 
102 	//	Region's base light
103 	l = reg->secregion->params->lightlevel + ExtraLight;
104 	if (r_darken)
105 	{
106 		l = light_remap[MIN(255, (int)l)];
107 	}
108 	l = MIN(255, l);
109 	int SecLightColour = reg->secregion->params->LightColour;
110 	lr = ((SecLightColour >> 16) & 255) * l / 255.0;
111 	lg = ((SecLightColour >> 8) & 255) * l / 255.0;
112 	lb = (SecLightColour & 255) * l / 255.0;
113 
114 	//	Add static lights
115 	for (i = 0; i < Lights.Num(); i++)
116 	{
117 /*		leafnum = Level->PointInSubsector(Lights[i].origin) -
118 			Level->Subsectors;*/
119 
120 		if (!Lights[i].radius)
121 		{
122 			continue;
123 		}
124 
125 		// Check potential visibility
126 		if (!(dyn_facevis[Lights[i].leafnum >> 3] & (1 << (Lights[i].leafnum & 7))))
127 		{
128 			continue;
129 		}
130 
131 		if (!Level->TraceLine(Trace, Lights[i].origin, p, SPF_NOBLOCKSIGHT))
132 		{
133 			// ray was blocked
134 			continue;
135 		}
136 
137 		add = Lights[i].radius - Length(p - Lights[i].origin);
138 		if (add > 0)
139 		{
140 			l += add;
141 			lr += add * ((Lights[i].colour >> 16) & 0xff) / 255.0;
142 			lg += add * ((Lights[i].colour >> 8) & 0xff) / 255.0;
143 			lb += add * (Lights[i].colour & 0xff) / 255.0;
144 		}
145 	}
146 
147 	//	Add dynamic lights
148 	for (i = 0; i < MAX_DLIGHTS; i++)
149 	{
150 		if (DLights[i].die < Level->Time || !DLights[i].radius)
151 			continue;
152 
153 		leafnum = Level->PointInSubsector(DLights[i].origin) -
154 			Level->Subsectors;
155 
156 		// Check potential visibility
157 		if (!(dyn_facevis[leafnum >> 3] & (1 << (leafnum & 7))))
158 		{
159 			continue;
160 		}
161 
162 		add = (DLights[i].radius - DLights[i].minlight) - Length(p - DLights[i].origin);
163 		if (add > 0)
164 		{
165 			l += add;
166 			lr += add * ((DLights[i].colour >> 16) & 0xff) / 255.0;
167 			lg += add * ((DLights[i].colour >> 8) & 0xff) / 255.0;
168 			lb += add * (DLights[i].colour & 0xff) / 255.0;
169 		}
170 	}
171 
172 	if (l > 255)
173 		l = 255;
174 	if (lr > 255)
175 		lr = 255;
176 	if (lg > 255)
177 		lg = 255;
178 	if (lb > 255)
179 		lb = 255;
180 
181 	return ((int)l << 24) | ((int)lr << 16) | ((int)lg << 8) | ((int)lb);
182 	unguard;
183 }
184 
185 //==========================================================================
186 //
187 //	VAdvancedRenderLevel::LightPointAmbient
188 //
189 //==========================================================================
190 
LightPointAmbient(const TVec & p)191 vuint32 VAdvancedRenderLevel::LightPointAmbient(const TVec &p)
192 {
193 	guard(VAdvancedRenderLevel::LightPointAmbient);
194 	subsector_t		*sub;
195 	subregion_t		*reg;
196 	float			l, lr, lg, lb, d;
197 	linetrace_t		Trace;
198 
199 	if (FixedLight)
200 	{
201 		return FixedLight | (FixedLight << 8) | (FixedLight << 16) | (FixedLight << 24);
202 	}
203 
204 	sub = Level->PointInSubsector(p);
205 	reg = sub->regions;
206 	while (reg->next)
207 	{
208 		d = DotProduct(p, reg->floor->secplane->normal) - reg->floor->secplane->dist;
209 
210 		if (d >= 0.0)
211 		{
212 			break;
213 		}
214 
215 		reg = reg->next;
216 	}
217 
218 	//	Region's base light
219 	l = reg->secregion->params->lightlevel + ExtraLight;
220 	if (r_darken)
221 	{
222 		l = light_remap[MIN(255, (int)l)];
223 	}
224 	l = MIN(255, l);
225 	int SecLightColour = reg->secregion->params->LightColour;
226 	lr = ((SecLightColour >> 16) & 255) * l / 255.0;
227 	lg = ((SecLightColour >> 8) & 255) * l / 255.0;
228 	lb = (SecLightColour & 255) * l / 255.0;
229 
230 	return ((int)l << 24) | ((int)lr << 16) | ((int)lg << 8) | ((int)lb);
231 	unguard;
232 }
233 
234 //==========================================================================
235 //
236 //	VAdvancedRenderLevel::BuildLightMap
237 //
238 //==========================================================================
239 
BuildLightMap(surface_t * surf,int shift)240 bool VAdvancedRenderLevel::BuildLightMap(surface_t *surf, int shift)
241 {
242 	return true;
243 }
244 
245 //==========================================================================
246 //
247 //	VAdvancedRenderLevel::BuildLightVis
248 //
249 //==========================================================================
250 
BuildLightVis(int bspnum,float * bbox)251 void VAdvancedRenderLevel::BuildLightVis(int bspnum, float* bbox)
252 {
253 	guard(VAdvancedRenderLevel::BuildLightVis);
254 	if (LightClip.ClipIsFull())
255 	{
256 		return;
257 	}
258 
259 	if (!LightClip.ClipIsBBoxVisible(bbox))
260 	{
261 		return;
262 	}
263 
264 	// Found a subsector?
265 	if (bspnum & NF_SUBSECTOR)
266 	{
267 		int SubNum = bspnum == -1 ? 0 : bspnum & (~NF_SUBSECTOR);
268 		subsector_t* Sub = &Level->Subsectors[SubNum];
269 		if (!Sub->sector->linecount)
270 		{
271 			//	Skip sectors containing original polyobjs
272 			return;
273 		}
274 
275 		if (!LightClip.ClipCheckSubsector(Sub))
276 		{
277 			return;
278 		}
279 
280 		LightVis[SubNum >> 3] |= 1 << (SubNum & 7);
281 		LightClip.ClipAddSubsectorSegs(Sub);
282 		return;
283 	}
284 
285 	node_t* bsp = &Level->Nodes[bspnum];
286 
287 	// Decide which side the view point is on.
288 	float Dist = DotProduct(CurrLightPos, bsp->normal) - bsp->dist;
289 	if (Dist >= CurrLightRadius)
290 	{
291 		//	Light is completely on front side.
292 		BuildLightVis(bsp->children[0], bsp->bbox[0]);
293 	}
294 	else if (Dist <= -CurrLightRadius)
295 	{
296 		//	Light is completely on back side.
297 		BuildLightVis(bsp->children[1], bsp->bbox[1]);
298 	}
299 	else
300 	{
301 		int side = Dist < 0;
302 
303 		// Recursively divide front space.
304 		BuildLightVis(bsp->children[side], bsp->bbox[side]);
305 
306 		// Divide back space.
307 		BuildLightVis(bsp->children[side ^ 1], bsp->bbox[side ^ 1]);
308 	}
309 	unguard;
310 }
311 
312 //==========================================================================
313 //
314 //	VAdvancedRenderLevel::DrawShadowSurfaces
315 //
316 //==========================================================================
317 
DrawShadowSurfaces(surface_t * InSurfs,texinfo_t * texinfo,bool CheckSkyBoxAlways)318 void VAdvancedRenderLevel::DrawShadowSurfaces(surface_t* InSurfs, texinfo_t *texinfo,
319 	bool CheckSkyBoxAlways)
320 {
321 	guard(VAdvancedRenderLevel::DrawShadowSurfaces);
322 	surface_t* surfs = InSurfs;
323 	if (!surfs)
324 	{
325 		return;
326 	}
327 
328 	if (texinfo->Tex->Type == TEXTYPE_Null)
329 	{
330 		return;
331 	}
332 	if (texinfo->Alpha < 1.0)
333 	{
334 		return;
335 	}
336 
337 	do
338 	{
339 		Drawer->RenderSurfaceShadowVolume(surfs, CurrLightPos, CurrLightRadius);
340 		surfs = surfs->next;
341 	} while (surfs);
342 	unguard;
343 }
344 
345 //==========================================================================
346 //
347 //	VAdvancedRenderLevel::RenderShadowLine
348 //
349 // 	Clips the given segment and adds any visible pieces to the line list.
350 //
351 //==========================================================================
352 
RenderShadowLine(drawseg_t * dseg)353 void VAdvancedRenderLevel::RenderShadowLine(drawseg_t* dseg)
354 {
355 	guard(VAdvancedRenderLevel::RenderShadowLine);
356 	seg_t *line = dseg->seg;
357 
358 	if (!line->linedef)
359 	{
360 		//	Miniseg
361 		return;
362 	}
363 
364 	float dist = DotProduct(CurrLightPos, line->normal) - line->dist;
365 	if (dist <= 0)
366 	{
367 		//	Light is in back side or on plane
368 		return;
369 	}
370 
371 	float a1 = LightClip.PointToClipAngle(*line->v2);
372 	float a2 = LightClip.PointToClipAngle(*line->v1);
373 	if (!LightClip.IsRangeVisible(a1, a2))
374 	{
375 		return;
376 	}
377 
378 	line_t *linedef = line->linedef;
379 	side_t *sidedef = line->sidedef;
380 
381 	if (!line->backsector)
382 	{
383 		// single sided line
384 		DrawShadowSurfaces(dseg->mid->surfs, &dseg->mid->texinfo, false);
385 		DrawShadowSurfaces(dseg->topsky->surfs, &dseg->topsky->texinfo, false);
386 	}
387 	else
388 	{
389 		// two sided line
390 		DrawShadowSurfaces(dseg->top->surfs, &dseg->top->texinfo, false);
391 		DrawShadowSurfaces(dseg->topsky->surfs, &dseg->topsky->texinfo, false);
392 		DrawShadowSurfaces(dseg->bot->surfs, &dseg->bot->texinfo, false);
393 		DrawShadowSurfaces(dseg->mid->surfs, &dseg->mid->texinfo, false);
394 		for (segpart_t *sp = dseg->extra; sp; sp = sp->next)
395 		{
396 			DrawShadowSurfaces(sp->surfs, &sp->texinfo, false);
397 		}
398 	}
399 	unguard;
400 }
401 
402 //==========================================================================
403 //
404 //	VAdvancedRenderLevel::RenderShadowSecSurface
405 //
406 //==========================================================================
407 
RenderShadowSecSurface(sec_surface_t * ssurf,VEntity * SkyBox)408 void VAdvancedRenderLevel::RenderShadowSecSurface(sec_surface_t* ssurf, VEntity* SkyBox)
409 {
410 	guard(VAdvancedRenderLevel::RenderShadowSecSurface);
411 	sec_plane_t& plane = *ssurf->secplane;
412 
413 	if (!plane.pic)
414 	{
415 		return;
416 	}
417 
418 	float dist = DotProduct(CurrLightPos, plane.normal) - plane.dist;
419 	if (dist <= 0)
420 	{
421 		//	Light is in back side or on plane
422 		return;
423 	}
424 
425 	DrawShadowSurfaces(ssurf->surfs, &ssurf->texinfo, true);
426 	unguard;
427 }
428 
429 //==========================================================================
430 //
431 //	VAdvancedRenderLevel::RenderShadowSubRegion
432 //
433 // 	Determine floor/ceiling planes.
434 // 	Draw one or more line segments.
435 //
436 //==========================================================================
437 
RenderShadowSubRegion(subregion_t * region)438 void VAdvancedRenderLevel::RenderShadowSubRegion(subregion_t* region)
439 {
440 	guard(VAdvancedRenderLevel::RenderShadowSubRegion);
441 	int				count;
442 	int 			polyCount;
443 	seg_t**			polySeg;
444 	float			d;
445 
446 	d = DotProduct(CurrLightPos, region->floor->secplane->normal) -
447 		region->floor->secplane->dist;
448 	if (region->next && d <= 0.0)
449 	{
450 		RenderShadowSubRegion(region->next);
451 	}
452 
453 	r_region = region->secregion;
454 
455 	if (r_sub->poly)
456 	{
457 		//	Render the polyobj in the subsector first
458 		polyCount = r_sub->poly->numsegs;
459 		polySeg = r_sub->poly->segs;
460 		while (polyCount--)
461 		{
462 			RenderShadowLine((*polySeg)->drawsegs);
463 			polySeg++;
464 		}
465 	}
466 
467 	count = r_sub->numlines;
468 	drawseg_t *ds = region->lines;
469 	while (count--)
470 	{
471 		RenderShadowLine(ds);
472 		ds++;
473 	}
474 
475 	RenderShadowSecSurface(region->floor, r_region->floor->SkyBox);
476 	RenderShadowSecSurface(region->ceil, r_region->ceiling->SkyBox);
477 
478 	if (region->next && d > 0.0)
479 	{
480 		RenderShadowSubRegion(region->next);
481 	}
482 	unguard;
483 }
484 
485 //==========================================================================
486 //
487 //	VAdvancedRenderLevel::RenderShadowSubsector
488 //
489 //==========================================================================
490 
RenderShadowSubsector(int num)491 void VAdvancedRenderLevel::RenderShadowSubsector(int num)
492 {
493 	guard(VAdvancedRenderLevel::RenderShadowSubsector);
494 	subsector_t* Sub = &Level->Subsectors[num];
495 	r_sub = Sub;
496 
497 	if (!(LightVis[num >> 3] & (1 << (num & 7))))
498 	{
499 		return;
500 	}
501 
502 	if (!Sub->sector->linecount)
503 	{
504 		//	Skip sectors containing original polyobjs
505 		return;
506 	}
507 
508 	RenderShadowSubRegion(Sub->regions);
509 
510 	//	Add subsector's segs to the clipper. Clipping against mirror
511 	// is done only for vertical mirror planes.
512 	LightClip.ClipAddSubsectorSegs(Sub);
513 	unguard;
514 }
515 
516 //==========================================================================
517 //
518 //	VAdvancedRenderLevel::RenderShadowBSPNode
519 //
520 //	Renders all subsectors below a given node, traversing subtree
521 // recursively. Just call with BSP root.
522 //
523 //==========================================================================
524 
RenderShadowBSPNode(int bspnum,float * bbox)525 void VAdvancedRenderLevel::RenderShadowBSPNode(int bspnum, float* bbox)
526 {
527 	guard(VAdvancedRenderLevel::RenderShadowBSPNode);
528 	if (LightClip.ClipIsFull())
529 	{
530 		return;
531 	}
532 
533 	if (!LightClip.ClipIsBBoxVisible(bbox))
534 	{
535 		return;
536 	}
537 
538 	// Found a subsector?
539 	if (bspnum & NF_SUBSECTOR)
540 	{
541 		if (bspnum == -1)
542 		{
543 			RenderShadowSubsector(0);
544 		}
545 		else
546 		{
547 			RenderShadowSubsector(bspnum & (~NF_SUBSECTOR));
548 		}
549 		return;
550 	}
551 
552 	node_t* bsp = &Level->Nodes[bspnum];
553 
554 	/*if (bsp->VisFrame != r_visframecount)
555 	{
556 		return;
557 	}*/
558 
559 	// Decide which side the light is on.
560 	float Dist = DotProduct(CurrLightPos, bsp->normal) - bsp->dist;
561 	if (Dist >= CurrLightRadius)
562 	{
563 		//	Light is completely on front side.
564 		RenderShadowBSPNode(bsp->children[0], bsp->bbox[0]);
565 	}
566 	else if (Dist <= -CurrLightRadius)
567 	{
568 		//	Light is completely on back side.
569 		RenderShadowBSPNode(bsp->children[1], bsp->bbox[1]);
570 	}
571 	else
572 	{
573 		int side = Dist < 0;
574 
575 		// Recursively divide front space.
576 		RenderShadowBSPNode(bsp->children[side], bsp->bbox[side]);
577 
578 		// Divide back space.
579 		RenderShadowBSPNode(bsp->children[side ^ 1], bsp->bbox[side ^ 1]);
580 	}
581 	unguard;
582 }
583 
584 //==========================================================================
585 //
586 //	VAdvancedRenderLevel::DrawLightSurfaces
587 //
588 //==========================================================================
589 
DrawLightSurfaces(surface_t * InSurfs,texinfo_t * texinfo,VEntity * SkyBox,bool CheckSkyBoxAlways)590 void VAdvancedRenderLevel::DrawLightSurfaces(surface_t* InSurfs, texinfo_t *texinfo,
591 	VEntity* SkyBox, bool CheckSkyBoxAlways)
592 {
593 	guard(VAdvancedRenderLevel::DrawLightSurfaces);
594 	surface_t* surfs = InSurfs;
595 	if (!surfs)
596 	{
597 		return;
598 	}
599 
600 	if (texinfo->Tex->Type == TEXTYPE_Null)
601 	{
602 		return;
603 	}
604 	if (texinfo->Alpha < 1.0)
605 	{
606 		return;
607 	}
608 
609 	if (SkyBox && (SkyBox->EntityFlags & VEntity::EF_FixedModel))
610 	{
611 		SkyBox = NULL;
612 	}
613 	bool IsStack = SkyBox && SkyBox->eventSkyBoxGetAlways();
614 	if (texinfo->Tex == GTextureManager[skyflatnum] ||
615 		(IsStack && CheckSkyBoxAlways))
616 	{
617 		return;
618 	}
619 
620 	do
621 	{
622 		Drawer->DrawSurfaceLight(surfs);
623 		surfs = surfs->next;
624 	} while (surfs);
625 	unguard;
626 }
627 
628 //==========================================================================
629 //
630 //	VAdvancedRenderLevel::RenderLightLine
631 //
632 // 	Clips the given segment and adds any visible pieces to the line list.
633 //
634 //==========================================================================
635 
RenderLightLine(drawseg_t * dseg)636 void VAdvancedRenderLevel::RenderLightLine(drawseg_t* dseg)
637 {
638 	guard(VAdvancedRenderLevel::RenderLightLine);
639 	seg_t *line = dseg->seg;
640 
641 	if (!line->linedef)
642 	{
643 		//	Miniseg
644 		return;
645 	}
646 
647 	float dist = DotProduct(vieworg, line->normal) - line->dist;
648 	if (dist <= 0)
649 	{
650 		//	Viewer is in back side or on plane
651 		return;
652 	}
653 	dist = DotProduct(CurrLightPos, line->normal) - line->dist;
654 	if (dist < 0 || dist >= CurrLightRadius)
655 	{
656 		//	Light is in back side or on plane or too far away
657 		return;
658 	}
659 
660 	float a1 = LightClip.PointToClipAngle(*line->v2);
661 	float a2 = LightClip.PointToClipAngle(*line->v1);
662 	if (!LightClip.IsRangeVisible(a1, a2))
663 	{
664 		return;
665 	}
666 
667 	line_t *linedef = line->linedef;
668 	side_t *sidedef = line->sidedef;
669 
670 	if (!line->backsector)
671 	{
672 		// single sided line
673 		DrawLightSurfaces(dseg->mid->surfs, &dseg->mid->texinfo,
674 			r_region->ceiling->SkyBox, false);
675 		DrawLightSurfaces(dseg->topsky->surfs, &dseg->topsky->texinfo,
676 			r_region->ceiling->SkyBox, false);
677 	}
678 	else
679 	{
680 		// two sided line
681 		DrawLightSurfaces(dseg->top->surfs, &dseg->top->texinfo,
682 			r_region->ceiling->SkyBox, false);
683 		DrawLightSurfaces(dseg->topsky->surfs, &dseg->topsky->texinfo,
684 			r_region->ceiling->SkyBox, false);
685 		DrawLightSurfaces(dseg->bot->surfs, &dseg->bot->texinfo,
686 			r_region->ceiling->SkyBox, false);
687 		DrawLightSurfaces(dseg->mid->surfs, &dseg->mid->texinfo,
688 			r_region->ceiling->SkyBox, false);
689 		for (segpart_t *sp = dseg->extra; sp; sp = sp->next)
690 		{
691 			DrawLightSurfaces(sp->surfs, &sp->texinfo,
692 				r_region->ceiling->SkyBox, false);
693 		}
694 	}
695 	unguard;
696 }
697 
698 //==========================================================================
699 //
700 //	VAdvancedRenderLevel::RenderLightSecSurface
701 //
702 //==========================================================================
703 
RenderLightSecSurface(sec_surface_t * ssurf,VEntity * SkyBox)704 void VAdvancedRenderLevel::RenderLightSecSurface(sec_surface_t* ssurf, VEntity* SkyBox)
705 {
706 	guard(VAdvancedRenderLevel::RenderLightSecSurface);
707 	sec_plane_t& plane = *ssurf->secplane;
708 
709 	if (!plane.pic)
710 	{
711 		return;
712 	}
713 
714 	float dist = DotProduct(vieworg, plane.normal) - plane.dist;
715 	if (dist <= 0)
716 	{
717 		//	Viewer is in back side or on plane
718 		return;
719 	}
720 	dist = DotProduct(CurrLightPos, plane.normal) - plane.dist;
721 	if (dist < 0 || dist >= CurrLightRadius)
722 	{
723 		//	Light is in back side or on plane or too far away
724 		return;
725 	}
726 
727 	DrawLightSurfaces(ssurf->surfs, &ssurf->texinfo, SkyBox, true);
728 	unguard;
729 }
730 
731 //==========================================================================
732 //
733 //	VAdvancedRenderLevel::RenderLightSubRegion
734 //
735 // 	Determine floor/ceiling planes.
736 // 	Draw one or more line segments.
737 //
738 //==========================================================================
739 
RenderLightSubRegion(subregion_t * region)740 void VAdvancedRenderLevel::RenderLightSubRegion(subregion_t* region)
741 {
742 	guard(VAdvancedRenderLevel::RenderLightSubRegion);
743 	int				count;
744 	int 			polyCount;
745 	seg_t**			polySeg;
746 	float			d;
747 
748 	d = DotProduct(vieworg, region->floor->secplane->normal) -
749 		region->floor->secplane->dist;
750 	if (region->next && d <= 0.0)
751 	{
752 		RenderLightSubRegion(region->next);
753 	}
754 
755 	r_region = region->secregion;
756 
757 	if (r_sub->poly)
758 	{
759 		//	Render the polyobj in the subsector first
760 		polyCount = r_sub->poly->numsegs;
761 		polySeg = r_sub->poly->segs;
762 		while (polyCount--)
763 		{
764 			RenderLightLine((*polySeg)->drawsegs);
765 			polySeg++;
766 		}
767 	}
768 
769 	count = r_sub->numlines;
770 	drawseg_t *ds = region->lines;
771 	while (count--)
772 	{
773 		RenderLightLine(ds);
774 		ds++;
775 	}
776 
777 	RenderLightSecSurface(region->floor, r_region->floor->SkyBox);
778 	RenderLightSecSurface(region->ceil, r_region->ceiling->SkyBox);
779 
780 	if (region->next && d > 0.0)
781 	{
782 		RenderLightSubRegion(region->next);
783 	}
784 	unguard;
785 }
786 
787 //==========================================================================
788 //
789 //	VAdvancedRenderLevel::RenderLightSubsector
790 //
791 //==========================================================================
792 
RenderLightSubsector(int num)793 void VAdvancedRenderLevel::RenderLightSubsector(int num)
794 {
795 	guard(VAdvancedRenderLevel::RenderLightSubsector);
796 	subsector_t* Sub = &Level->Subsectors[num];
797 	r_sub = Sub;
798 
799 	if (!(LightBspVis[num >> 3] & (1 << (num & 7))))
800 	{
801 		return;
802 	}
803 
804 	if (!Sub->sector->linecount)
805 	{
806 		//	Skip sectors containing original polyobjs
807 		return;
808 	}
809 
810 	RenderLightSubRegion(Sub->regions);
811 
812 	//	Add subsector's segs to the clipper. Clipping against mirror
813 	// is done only for vertical mirror planes.
814 	LightClip.ClipAddSubsectorSegs(Sub);
815 	unguard;
816 }
817 
818 //==========================================================================
819 //
820 //	VAdvancedRenderLevel::RenderLightBSPNode
821 //
822 //	Renders all subsectors below a given node, traversing subtree
823 // recursively. Just call with BSP root.
824 //
825 //==========================================================================
826 
RenderLightBSPNode(int bspnum,float * bbox)827 void VAdvancedRenderLevel::RenderLightBSPNode(int bspnum, float* bbox)
828 {
829 	guard(VAdvancedRenderLevel::RenderLightBSPNode);
830 	if (LightClip.ClipIsFull())
831 	{
832 		return;
833 	}
834 
835 	if (!LightClip.ClipIsBBoxVisible(bbox))
836 	{
837 		return;
838 	}
839 
840 	// Found a subsector?
841 	if (bspnum & NF_SUBSECTOR)
842 	{
843 		if (bspnum == -1)
844 		{
845 			RenderLightSubsector(0);
846 		}
847 		else
848 		{
849 			RenderLightSubsector(bspnum & (~NF_SUBSECTOR));
850 		}
851 		return;
852 	}
853 
854 	node_t* bsp = &Level->Nodes[bspnum];
855 
856 	// Decide which side the light is on.
857 	float Dist = DotProduct(CurrLightPos, bsp->normal) - bsp->dist;
858 	if (Dist >= CurrLightRadius)
859 	{
860 		//	Light is completely on front side.
861 		RenderLightBSPNode(bsp->children[0], bsp->bbox[0]);
862 	}
863 	else if (Dist <= -CurrLightRadius)
864 	{
865 		//	Light is completely on back side.
866 		RenderLightBSPNode(bsp->children[1], bsp->bbox[1]);
867 	}
868 	else
869 	{
870 		int side = Dist < 0;
871 
872 		// Recursively divide front space.
873 		RenderLightBSPNode(bsp->children[side], bsp->bbox[side]);
874 
875 		// Divide back space.
876 		RenderLightBSPNode(bsp->children[side ^ 1], bsp->bbox[side ^ 1]);
877 	}
878 	unguard;
879 }
880 
881 //==========================================================================
882 //
883 //	VAdvancedRenderLevel::RenderLightShadows
884 //
885 //==========================================================================
886 
RenderLightShadows(const refdef_t * RD,const VViewClipper * Range,TVec & Pos,float Radius,vuint32 Colour)887 void VAdvancedRenderLevel::RenderLightShadows(const refdef_t* RD,
888 	const VViewClipper* Range, TVec& Pos, float Radius, vuint32 Colour)
889 {
890 	guard(VAdvancedRenderLevel::RenderLightShadows);
891 	//	Don't do lights that are too far away.
892 	if ((Pos - vieworg).Length() > r_lights_radius + Radius)
893 	{
894 		return;
895 	}
896 
897 	float	dummy_bbox[6] = {-99999, -99999, -99999, 99999, 99999, 99999};
898 
899 	//	Clip against frustrum.
900 	for (int i = 0; i < (MirrorClip ? 5 : 4); i++)
901 	{
902 		float d = DotProduct(Pos, view_clipplanes[i].normal);
903 		d -= view_clipplanes[i].dist;
904 		if (d <= -Radius)
905 		{
906 			return;
907 		}
908 	}
909 
910 	CurrLightPos = Pos;
911 	CurrLightRadius = Radius;
912 	CurrLightColour = Colour;
913 
914 	//	Build vis data for light.
915 	LightClip.ClearClipNodes(CurrLightPos, Level);
916 	memset(LightVis, 0, VisSize);
917 	BuildLightVis(Level->NumNodes - 1, dummy_bbox);
918 
919 	//	Create combined light and view visibility.
920 	bool HaveIntersect = false;
921 	for (int i = 0; i < VisSize; i++)
922 	{
923 		LightBspVis[i] = BspVis[i] & LightVis[i];
924 		if (LightBspVis[i])
925 		{
926 			HaveIntersect = true;
927 		}
928 	}
929 	if (!HaveIntersect)
930 	{
931 		return;
932 	}
933 
934 	//	Do shadow volumes.
935 	Drawer->BeginLightShadowVolumes();
936 	LightClip.ClearClipNodes(CurrLightPos, Level);
937 	RenderShadowBSPNode(Level->NumNodes - 1, dummy_bbox);
938 	Drawer->BeginModelsShadowsPass(CurrLightPos, CurrLightRadius);
939 	RenderMobjsShadow();
940 
941 	//	Draw light.
942 	Drawer->BeginLightPass(CurrLightPos, CurrLightRadius, Colour);
943 	LightClip.ClearClipNodes(CurrLightPos, Level);
944 	RenderLightBSPNode(Level->NumNodes - 1, dummy_bbox);
945 	Drawer->BeginModelsLightPass(CurrLightPos, CurrLightRadius, Colour);
946 	RenderMobjsLight();
947 	unguard;
948 }
949