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