1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** $Id: r_light.cpp 4354 2010-12-23 19:48:32Z 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 int r_dlightframecount;
46 bool r_light_add;
47
48 vuint32 blocklights[18 * 18];
49 vuint32 blocklightsr[18 * 18];
50 vuint32 blocklightsg[18 * 18];
51 vuint32 blocklightsb[18 * 18];
52 vuint32 blockaddlightsr[18 * 18];
53 vuint32 blockaddlightsg[18 * 18];
54 vuint32 blockaddlightsb[18 * 18];
55
56 byte light_remap[256];
57 VCvarI r_darken("r_darken", "0", CVAR_Archive);
58 VCvarI r_ambient("r_ambient", "0");
59 int light_mem;
60 VCvarI r_extrasamples("r_extrasamples", "0", CVAR_Archive);
61 VCvarI r_dynamic("r_dynamic", "1", CVAR_Archive);
62 VCvarI r_dynamic_clip("r_dynamic_clip", "0", CVAR_Archive);
63 VCvarI r_static_lights("r_static_lights", "1", CVAR_Archive);
64 VCvarI r_static_add("r_static_add", "0", CVAR_Archive);
65 VCvarF r_specular("r_specular", "0.1", CVAR_Archive);
66
67 // PRIVATE DATA DEFINITIONS ------------------------------------------------
68
69 static TVec smins, smaxs;
70 static TVec worldtotex[2];
71 static TVec textoworld[2];
72 static TVec texorg;
73 static TVec surfpt[18 * 18 * 4];
74 static int numsurfpt;
75 static bool points_calculated;
76 static float lightmap[18 * 18 * 4];
77 static float lightmapr[18 * 18 * 4];
78 static float lightmapg[18 * 18 * 4];
79 static float lightmapb[18 * 18 * 4];
80 static bool light_hit;
81 static byte *facevis;
82 static bool is_coloured;
83
84 static int c_bad;
85
86 // CODE --------------------------------------------------------------------
87
88 //==========================================================================
89 //
90 // VRenderLevelShared::AddStaticLight
91 //
92 //==========================================================================
93
AddStaticLight(const TVec & origin,float radius,vuint32 colour)94 void VRenderLevelShared::AddStaticLight(const TVec &origin, float radius,
95 vuint32 colour)
96 {
97 guard(VRenderLevelShared::AddStaticLight);
98 light_t& L = Lights.Alloc();
99 L.origin = origin;
100 L.radius = radius;
101 L.colour = colour;
102 L.leafnum = Level->PointInSubsector(origin) - Level->Subsectors;
103 unguard;
104 }
105
106 //==========================================================================
107 //
108 // VRenderLevel::CalcMinMaxs
109 //
110 //==========================================================================
111
CalcMinMaxs(surface_t * surf)112 void VRenderLevel::CalcMinMaxs(surface_t *surf)
113 {
114 guard(VRenderLevel::CalcMinMaxs);
115 smins = TVec(99999.0, 99999.0, 99999.0);
116 smaxs = TVec(-999999.0, -999999.0, -999999.0);
117
118 for (int i = 0; i < surf->count; i++)
119 {
120 TVec &v = surf->verts[i];
121 if (smins.x > v.x)
122 smins.x = v.x;
123 if (smins.y > v.y)
124 smins.y = v.y;
125 if (smins.z > v.z)
126 smins.z = v.z;
127 if (smaxs.x < v.x)
128 smaxs.x = v.x;
129 if (smaxs.y < v.y)
130 smaxs.y = v.y;
131 if (smaxs.z < v.z)
132 smaxs.z = v.z;
133 }
134 unguard;
135 }
136
137 //==========================================================================
138 //
139 // VRenderLevel::CastRay
140 //
141 // Returns the distance between the points, or -1 if blocked
142 //
143 //==========================================================================
144
CastRay(const TVec & p1,const TVec & p2,float squaredist)145 float VRenderLevel::CastRay(const TVec &p1, const TVec &p2,
146 float squaredist)
147 {
148 guard(VRenderLevel::CastRay);
149 linetrace_t Trace;
150
151 TVec delta = p2 - p1;
152 float t = DotProduct(delta, delta);
153 if (t > squaredist)
154 return -1; // too far away
155
156 if (!Level->TraceLine(Trace, p1, p2, SPF_NOBLOCKSIGHT))
157 return -1; // ray was blocked
158
159 if (t == 0)
160 t = 1; // don't blow up...
161 return sqrt(t);
162 unguard;
163 }
164
165 //==========================================================================
166 //
167 // VRenderLevel::CalcFaceVectors
168 //
169 // Fills in texorg, worldtotex. and textoworld
170 //
171 //==========================================================================
172
CalcFaceVectors(surface_t * surf)173 void VRenderLevel::CalcFaceVectors(surface_t *surf)
174 {
175 guard(VRenderLevel::CalcFaceVectors);
176 texinfo_t *tex;
177 int i;
178 TVec texnormal;
179 float distscale;
180 float dist, len;
181
182 tex = surf->texinfo;
183
184 // convert from float to vec_t
185 worldtotex[0] = tex->saxis;
186 worldtotex[1] = tex->taxis;
187
188 // Calculate a normal to the texture axis. Points can be moved along
189 // this without changing their S/T
190 texnormal.x = tex->taxis.y * tex->saxis.z
191 - tex->taxis.z * tex->saxis.y;
192 texnormal.y = tex->taxis.z * tex->saxis.x
193 - tex->taxis.x * tex->saxis.z;
194 texnormal.z = tex->taxis.x * tex->saxis.y
195 - tex->taxis.y * tex->saxis.x;
196 texnormal = Normalise(texnormal);
197
198 // flip it towards plane normal
199 distscale = DotProduct(texnormal, surf->plane->normal);
200 if (!distscale)
201 Host_Error("Texture axis perpendicular to face");
202 if (distscale < 0)
203 {
204 distscale = -distscale;
205 texnormal = -texnormal;
206 }
207
208 // distscale is the ratio of the distance along the texture normal to
209 // the distance along the plane normal
210 distscale = 1 / distscale;
211
212 for (i = 0; i < 2; i++)
213 {
214 len = Length(worldtotex[i]);
215 dist = DotProduct(worldtotex[i], surf->plane->normal);
216 dist *= distscale;
217 textoworld[i] = worldtotex[i] - dist * texnormal;
218 textoworld[i] = textoworld[i] * (1 / len) * (1 / len);
219 }
220
221 // calculate texorg on the texture plane
222 for (i = 0; i < 3; i++)
223 texorg[i] = -tex->soffs * textoworld[0][i] - tex->toffs * textoworld[1][i];
224
225 // project back to the face plane
226 dist = DotProduct(texorg, surf->plane->normal) - surf->plane->dist - 1;
227 dist *= distscale;
228 texorg = texorg - dist * texnormal;
229 unguard;
230 }
231
232 //==========================================================================
233 //
234 // VRenderLevel::CalcPoints
235 //
236 // For each texture aligned grid point, back project onto the plane
237 // to get the world xyz value of the sample point
238 //
239 //==========================================================================
240
CalcPoints(surface_t * surf)241 void VRenderLevel::CalcPoints(surface_t *surf)
242 {
243 guard(VRenderLevel::CalcPoints);
244 int i;
245 int s, t;
246 int w, h;
247 int step;
248 float starts, startt, us, ut;
249 float mids, midt;
250 TVec* spt;
251 TVec facemid;
252 linetrace_t Trace;
253
254
255 //
256 // fill in surforg
257 // the points are biased towards the centre of the surface
258 // to help avoid edge cases just inside walls
259 //
260 spt = surfpt;
261 mids = surf->texturemins[0] + surf->extents[0] / 2;
262 midt = surf->texturemins[1] + surf->extents[1] / 2;
263
264 facemid = texorg + textoworld[0] * mids + textoworld[1] * midt;
265
266 if (r_extrasamples)
267 {
268 // extra filtering
269 w = ((surf->extents[0] >> 4) + 1) * 2;
270 h = ((surf->extents[1] >> 4) + 1) * 2;
271 starts = surf->texturemins[0] - 8;
272 startt = surf->texturemins[1] - 8;
273 step = 8;
274 }
275 else
276 {
277 w = (surf->extents[0] >> 4) + 1;
278 h = (surf->extents[1] >> 4) + 1;
279 starts = surf->texturemins[0];
280 startt = surf->texturemins[1];
281 step = 16;
282 }
283
284 numsurfpt = w * h;
285 for (t = 0; t < h; t++)
286 {
287 for (s = 0; s < w; s++, spt++)
288 {
289 us = starts + s * step;
290 ut = startt + t * step;
291
292 // if a line can be traced from surf to facemid, the point is good
293 for (i = 0; i < 6; i++)
294 {
295 // calculate texture point
296 *spt = texorg + textoworld[0] * us + textoworld[1] * ut;
297 if (Level->TraceLine(Trace, facemid, *spt, SPF_NOBLOCKSIGHT))
298 {
299 break; // got it
300 }
301 if (i & 1)
302 {
303 if (us > mids)
304 {
305 us -= 8;
306 if (us < mids)
307 us = mids;
308 }
309 else
310 {
311 us += 8;
312 if (us > mids)
313 us = mids;
314 }
315 }
316 else
317 {
318 if (ut > midt)
319 {
320 ut -= 8;
321 if (ut < midt)
322 ut = midt;
323 }
324 else
325 {
326 ut += 8;
327 if (ut > midt)
328 ut = midt;
329 }
330 }
331
332 // move surf 8 pixels towards the centre
333 *spt += 8 * Normalise(facemid - *spt);
334 }
335 if (i == 2)
336 c_bad++;
337 }
338 }
339 unguard;
340 }
341
342 //==========================================================================
343 //
344 // VRenderLevel::SingleLightFace
345 //
346 //==========================================================================
347
SingleLightFace(light_t * light,surface_t * surf)348 void VRenderLevel::SingleLightFace(light_t *light, surface_t *surf)
349 {
350 guard(VRenderLevel::SingleLightFace);
351 float dist;
352 TVec incoming;
353 float angle;
354 float add;
355 TVec *spt;
356 int c;
357 float squaredist;
358 float rmul, gmul, bmul;
359
360 // Check potential visibility
361 if (!(facevis[light->leafnum >> 3] & (1 << (light->leafnum & 7))))
362 return;
363
364 // Check bounding box
365 if (light->origin.x + light->radius < smins.x ||
366 light->origin.x - light->radius > smaxs.x ||
367 light->origin.y + light->radius < smins.y ||
368 light->origin.y - light->radius > smaxs.y ||
369 light->origin.z + light->radius < smins.z ||
370 light->origin.z - light->radius > smaxs.z)
371 {
372 return;
373 }
374
375 dist = DotProduct(light->origin, surf->plane->normal) - surf->plane->dist;
376
377 // don't bother with lights behind the surface
378 if (dist <= -0.1)
379 return;
380
381 // don't bother with light too far away
382 if (dist > light->radius)
383 {
384 return;
385 }
386
387 // Calc points only when surface may be lit by a light
388 if (!points_calculated)
389 {
390 CalcFaceVectors(surf);
391 CalcPoints(surf);
392
393 memset(lightmap, 0, numsurfpt * 4);
394 memset(lightmapr, 0, numsurfpt * 4);
395 memset(lightmapg, 0, numsurfpt * 4);
396 memset(lightmapb, 0, numsurfpt * 4);
397 points_calculated = true;
398 }
399
400 //
401 // check it for real
402 //
403 spt = surfpt;
404 squaredist = light->radius * light->radius;
405 rmul = ((light->colour >> 16) & 0xff) / 255.0;
406 gmul = ((light->colour >> 8) & 0xff) / 255.0;
407 bmul = (light->colour & 0xff) / 255.0;
408 for (c = 0; c < numsurfpt; c++, spt++)
409 {
410 dist = CastRay(light->origin, *spt, squaredist);
411 if (dist < 0)
412 continue; // light doesn't reach
413
414 incoming = Normalise(light->origin - *spt);
415 angle = DotProduct(incoming, surf->plane->normal);
416
417 angle = 0.5 + 0.5 * angle;
418 add = light->radius - dist;
419 add *= angle;
420 if (add < 0)
421 continue;
422 lightmap[c] += add;
423 lightmapr[c] += add * rmul;
424 lightmapg[c] += add * gmul;
425 lightmapb[c] += add * bmul;
426 if (lightmap[c] > 1) // ignore real tiny lights
427 {
428 light_hit = true;
429 if (light->colour != 0xffffffff)
430 is_coloured = true;
431 }
432 }
433 unguard;
434 }
435
436 //==========================================================================
437 //
438 // VRenderLevel::LightFace
439 //
440 //==========================================================================
441
LightFace(surface_t * surf,subsector_t * leaf)442 void VRenderLevel::LightFace(surface_t *surf, subsector_t *leaf)
443 {
444 guard(VRenderLevel::LightFace);
445 int i, s, t, w, h;
446 float total;
447
448 facevis = Level->LeafPVS(leaf);
449 points_calculated = false;
450 light_hit = false;
451 is_coloured = false;
452
453 //
454 // cast all lights
455 //
456 CalcMinMaxs(surf);
457 if (r_static_lights)
458 {
459 for (i = 0; i < Lights.Num(); i++)
460 {
461 SingleLightFace(&Lights[i], surf);
462 }
463 }
464
465 if (!light_hit)
466 {
467 // no light hitting it
468 if (surf->lightmap)
469 {
470 Z_Free(surf->lightmap);
471 surf->lightmap = NULL;
472 }
473 if (surf->lightmap_rgb)
474 {
475 Z_Free(surf->lightmap_rgb);
476 surf->lightmap_rgb = NULL;
477 }
478 return;
479 }
480
481 w = (surf->extents[0] >> 4) + 1;
482 h = (surf->extents[1] >> 4) + 1;
483
484 // If the surface already has a lightmap, we will reuse it, otherwiese
485 // we must allocate a new block
486 if (is_coloured)
487 {
488 if (surf->lightmap_rgb)
489 {
490 Z_Free(surf->lightmap_rgb);
491 }
492 surf->lightmap_rgb = (rgb_t*)Z_Malloc(w * h * 3);
493 light_mem += w * h * 3;
494
495 i = 0;
496 for (t = 0; t < h; t++)
497 {
498 for (s = 0; s < w; s++, i++)
499 {
500 if (r_extrasamples)
501 {
502 // filtered sample
503 total = lightmapr[t*w*4+s*2] +
504 lightmapr[t*2*w*2+s*2+1] +
505 lightmapr[(t*2+1)*w*2+s*2] +
506 lightmapr[(t*2+1)*w*2+s*2+1];
507 total *= 0.25;
508 }
509 else
510 total = lightmapr[i];
511 if (total > 255)
512 total = 255;
513 if (total < 0)
514 Sys_Error("light < 0");
515 surf->lightmap_rgb[i].r = byte(total);
516
517 if (r_extrasamples)
518 {
519 // filtered sample
520 total = lightmapg[t*w*4+s*2] +
521 lightmapg[t*2*w*2+s*2+1] +
522 lightmapg[(t*2+1)*w*2+s*2] +
523 lightmapg[(t*2+1)*w*2+s*2+1];
524 total *= 0.25;
525 }
526 else
527 total = lightmapg[i];
528 if (total > 255)
529 total = 255;
530 if (total < 0)
531 Sys_Error("light < 0");
532 surf->lightmap_rgb[i].g = byte(total);
533
534 if (r_extrasamples)
535 {
536 // filtered sample
537 total = lightmapb[t*w*4+s*2] +
538 lightmapb[t*2*w*2+s*2+1] +
539 lightmapb[(t*2+1)*w*2+s*2] +
540 lightmapb[(t*2+1)*w*2+s*2+1];
541 total *= 0.25;
542 }
543 else
544 total = lightmapb[i];
545 if (total > 255)
546 total = 255;
547 if (total < 0)
548 Sys_Error("light < 0");
549 surf->lightmap_rgb[i].b = byte(total);
550 }
551 }
552 }
553 else
554 {
555 if (surf->lightmap_rgb)
556 {
557 Z_Free(surf->lightmap_rgb);
558 surf->lightmap_rgb = NULL;
559 }
560 }
561
562 if (surf->lightmap)
563 {
564 Z_Free(surf->lightmap);
565 }
566 surf->lightmap = (byte*)Z_Malloc(w * h);
567 light_mem += w * h;
568
569 i = 0;
570 for (t = 0; t < h; t++)
571 {
572 for (s = 0; s < w; s++, i++)
573 {
574 if (r_extrasamples)
575 {
576 // filtered sample
577 total = lightmap[t*w*4+s*2] +
578 lightmap[t*2*w*2+s*2+1] +
579 lightmap[(t*2+1)*w*2+s*2] +
580 lightmap[(t*2+1)*w*2+s*2+1];
581 total *= 0.25;
582 }
583 else
584 total = lightmap[i];
585 if (total > 255)
586 total = 255;
587 if (total < 0)
588 Sys_Error("light < 0");
589 surf->lightmap[i] = byte(total);
590 }
591 }
592 unguard;
593 }
594
595 //**************************************************************************
596 //**
597 //** DYNAMIC LIGHTS
598 //**
599 //**************************************************************************
600
601 //==========================================================================
602 //
603 // VRenderLevelShared::AllocDlight
604 //
605 //==========================================================================
606
AllocDlight(VThinker * Owner)607 dlight_t* VRenderLevelShared::AllocDlight(VThinker* Owner)
608 {
609 guard(VRenderLevelShared::AllocDlight);
610 int i;
611 dlight_t* dl;
612
613 // first look for an exact key match
614 if (Owner)
615 {
616 dl = DLights;
617 for (i = 0; i < MAX_DLIGHTS; i++, dl++)
618 {
619 if (dl->Owner == Owner)
620 {
621 memset(dl, 0, sizeof(*dl));
622 dl->Owner = Owner;
623 return dl;
624 }
625 }
626 }
627
628 // then look for anything else
629 dl = DLights;
630 for (i = 0; i < MAX_DLIGHTS; i++, dl++)
631 {
632 if (dl->die < Level->Time)
633 {
634 memset(dl, 0, sizeof(*dl));
635 dl->Owner = Owner;
636 return dl;
637 }
638 }
639
640 int bestnum = 0;
641 float bestdist = 0.0;
642 for (i = 0; i < MAX_DLIGHTS; i++, dl++)
643 {
644 float dist = Length(dl->origin - cl->ViewOrg);
645 if (dist > bestdist)
646 {
647 bestnum = i;
648 bestdist = dist;
649 }
650 }
651 dl = &DLights[bestnum];
652 memset(dl, 0, sizeof(*dl));
653 dl->Owner = Owner;
654 return dl;
655 unguard;
656 }
657
658 //==========================================================================
659 //
660 // VRenderLevelShared::DecayLights
661 //
662 //==========================================================================
663
DecayLights(float time)664 void VRenderLevelShared::DecayLights(float time)
665 {
666 guard(VRenderLevelShared::DecayLights);
667 dlight_t* dl = DLights;
668 for (int i = 0; i < MAX_DLIGHTS; i++, dl++)
669 {
670 if (dl->die < Level->Time || !dl->radius)
671 continue;
672
673 dl->radius -= time * dl->decay;
674 if (dl->radius < 0)
675 dl->radius = 0;
676 }
677 unguard;
678 }
679
680 //==========================================================================
681 //
682 // VRenderLevel::MarkLights
683 //
684 //==========================================================================
685
MarkLights(dlight_t * light,int bit,int bspnum)686 void VRenderLevel::MarkLights(dlight_t *light, int bit, int bspnum)
687 {
688 guard(VRenderLevel::MarkLights);
689 int leafnum;
690
691 if (bspnum & NF_SUBSECTOR)
692 {
693 int num;
694
695 if (bspnum == -1)
696 num = 0;
697 else
698 num = bspnum & (~NF_SUBSECTOR);
699 subsector_t *ss = &Level->Subsectors[num];
700
701 if (r_dynamic_clip)
702 {
703 vuint8* dyn_facevis = Level->LeafPVS(ss);
704 leafnum = Level->PointInSubsector(light->origin) -
705 Level->Subsectors;
706
707 // Check potential visibility
708 if (!(dyn_facevis[leafnum >> 3] & (1 << (leafnum & 7))))
709 return;
710 }
711
712 if (ss->dlightframe != r_dlightframecount)
713 {
714 ss->dlightbits = 0;
715 ss->dlightframe = r_dlightframecount;
716 }
717 ss->dlightbits |= bit;
718 }
719 else
720 {
721 node_t* node = &Level->Nodes[bspnum];
722 float dist = DotProduct(light->origin, node->normal) - node->dist;
723
724 if (dist > -light->radius + light->minlight)
725 {
726 MarkLights(light, bit, node->children[0]);
727 }
728 if (dist < light->radius - light->minlight)
729 {
730 MarkLights(light, bit, node->children[1]);
731 }
732 }
733 unguard;
734 }
735
736 //==========================================================================
737 //
738 // VRenderLevel::PushDlights
739 //
740 //==========================================================================
741
PushDlights()742 void VRenderLevel::PushDlights()
743 {
744 guard(VRenderLevel::PushDlights);
745 if (GGameInfo->IsPaused())
746 {
747 return;
748 }
749 r_dlightframecount++;
750
751 if (!r_dynamic)
752 {
753 return;
754 }
755
756 dlight_t* l = DLights;
757 for (int i = 0; i < MAX_DLIGHTS; i++, l++)
758 {
759 if (l->die < Level->Time || !l->radius)
760 continue;
761 MarkLights(l, 1 << i, Level->NumNodes - 1);
762 }
763 unguard;
764 }
765
766 //==========================================================================
767 //
768 // VRenderLevel::LightPoint
769 //
770 //==========================================================================
771
LightPoint(const TVec & p)772 vuint32 VRenderLevel::LightPoint(const TVec &p)
773 {
774 guard(VRenderLevel::LightPoint);
775 subsector_t *sub;
776 subregion_t *reg;
777 float l, lr, lg, lb, d, add;
778 int i, s, t, ds, dt;
779 surface_t *surf;
780 int ltmp;
781 rgb_t *rgbtmp;
782 int leafnum;
783
784
785 if (FixedLight)
786 {
787 return FixedLight | (FixedLight << 8) | (FixedLight << 16) | (FixedLight << 24);
788 }
789
790 sub = Level->PointInSubsector(p);
791 reg = sub->regions;
792 while (reg->next)
793 {
794 d = DotProduct(p, reg->floor->secplane->normal) - reg->floor->secplane->dist;
795
796 if (d >= 0.0)
797 {
798 break;
799 }
800
801 reg = reg->next;
802 }
803
804 // Region's base light
805 l = reg->secregion->params->lightlevel + ExtraLight;
806 if (r_darken)
807 {
808 l = light_remap[MIN(255, (int)l)];
809 }
810 l = MIN(255, l);
811 int SecLightColour = reg->secregion->params->LightColour;
812 lr = ((SecLightColour >> 16) & 255) * l / 255.0;
813 lg = ((SecLightColour >> 8) & 255) * l / 255.0;
814 lb = (SecLightColour & 255) * l / 255.0;
815
816 // Light from floor's lightmap
817 s = (int)(DotProduct(p, reg->floor->texinfo.saxis) + reg->floor->texinfo.soffs);
818 t = (int)(DotProduct(p, reg->floor->texinfo.taxis) + reg->floor->texinfo.toffs);
819 for (surf = reg->floor->surfs; surf; surf = surf->next)
820 {
821 if (!surf->lightmap)
822 {
823 continue;
824 }
825 if (s < surf->texturemins[0] || t < surf->texturemins[1])
826 {
827 continue;
828 }
829
830 ds = s - surf->texturemins[0];
831 dt = t - surf->texturemins[1];
832
833 if (ds > surf->extents[0] || dt > surf->extents[1])
834 {
835 continue;
836 }
837
838 if (surf->lightmap_rgb)
839 {
840 l += surf->lightmap[(ds >> 4) + (dt >> 4) * ((surf->extents[0] >> 4) + 1)];
841 rgbtmp = &surf->lightmap_rgb[(ds >> 4) + (dt >> 4) * ((surf->extents[0] >> 4) + 1)];
842 lr += rgbtmp->r;
843 lg += rgbtmp->g;
844 lb += rgbtmp->b;
845 }
846 else
847 {
848 ltmp = surf->lightmap[(ds >> 4) + (dt >> 4) * ((surf->extents[0] >> 4) + 1)];
849 l += ltmp;
850 lr += ltmp;
851 lg += ltmp;
852 lb += ltmp;
853 }
854 break;
855 }
856
857 // Add dynamic lights
858 if (sub->dlightframe == r_dlightframecount)
859 {
860 for (i = 0; i < MAX_DLIGHTS; i++)
861 {
862 if (!(sub->dlightbits & (1 << i)))
863 continue;
864 if (r_dynamic_clip)
865 {
866 vuint8* dyn_facevis = Level->LeafPVS(sub);
867 leafnum = Level->PointInSubsector(DLights[i].origin) -
868 Level->Subsectors;
869
870 // Check potential visibility
871 if (!(dyn_facevis[leafnum >> 3] & (1 << (leafnum & 7))))
872 continue;
873 }
874
875 add = (DLights[i].radius - DLights[i].minlight) - Length(p - DLights[i].origin);
876
877 if (add > 0)
878 {
879 l += add;
880 lr += add * ((DLights[i].colour >> 16) & 0xff) / 255.0;
881 lg += add * ((DLights[i].colour >> 8) & 0xff) / 255.0;
882 lb += add * (DLights[i].colour & 0xff) / 255.0;
883 }
884 }
885 }
886
887 if (l > 255)
888 l = 255;
889 if (lr > 255)
890 lr = 255;
891 if (lg > 255)
892 lg = 255;
893 if (lb > 255)
894 lb = 255;
895
896 return ((int)l << 24) | ((int)lr << 16) | ((int)lg << 8) | ((int)lb);
897 unguard;
898 }
899
900 //==========================================================================
901 //
902 // VRenderLevel::AddDynamicLights
903 //
904 //==========================================================================
905
AddDynamicLights(surface_t * surf)906 void VRenderLevel::AddDynamicLights(surface_t *surf)
907 {
908 guard(VRenderLevel::AddDynamicLights);
909 int lnum;
910 int sd, td;
911 float dist, rad, minlight, rmul, gmul, bmul;
912 TVec impact, local;
913 int s, t, i;
914 int smax, tmax;
915 texinfo_t *tex;
916 subsector_t *sub;
917 int leafnum;
918
919
920 smax = (surf->extents[0] >> 4) + 1;
921 tmax = (surf->extents[1] >> 4) + 1;
922 tex = surf->texinfo;
923
924 for (lnum = 0; lnum < MAX_DLIGHTS; lnum++)
925 {
926 if (!(surf->dlightbits & (1<<lnum)))
927 continue; // not lit by this light
928
929 rad = DLights[lnum].radius;
930 dist = DotProduct(DLights[lnum].origin, surf->plane->normal) -
931 surf->plane->dist;
932 if (r_dynamic_clip)
933 {
934 if (dist <= -0.1)
935 continue;
936 }
937
938 rad -= fabs(dist);
939 minlight = DLights[lnum].minlight;
940 if (rad < minlight)
941 continue;
942 minlight = rad - minlight;
943
944 impact = DLights[lnum].origin - surf->plane->normal * dist;
945
946 if (r_dynamic_clip)
947 {
948 sub = Level->PointInSubsector(*surf->verts);
949 vuint8* dyn_facevis = Level->LeafPVS(sub);
950 leafnum = Level->PointInSubsector(DLights[lnum].origin) -
951 Level->Subsectors;
952
953 // Check potential visibility
954 if (!(dyn_facevis[leafnum >> 3] & (1 << (leafnum & 7))))
955 continue;
956 }
957
958 rmul = (DLights[lnum].colour >> 16) & 0xff;
959 gmul = (DLights[lnum].colour >> 8) & 0xff;
960 bmul = DLights[lnum].colour & 0xff;
961
962 local.x = DotProduct(impact, tex->saxis) + tex->soffs;
963 local.y = DotProduct(impact, tex->taxis) + tex->toffs;
964
965 local.x -= surf->texturemins[0];
966 local.y -= surf->texturemins[1];
967
968 for (t = 0; t < tmax; t++)
969 {
970 td = (int)local.y - t * 16;
971 if (td < 0)
972 td = -td;
973 for (s = 0; s < smax; s++)
974 {
975 sd = (int)local.x - s * 16;
976 if (sd < 0)
977 sd = -sd;
978 if (sd > td)
979 dist = sd + (td >> 1);
980 else
981 dist = td + (sd >> 1);
982
983 if (dist < minlight)
984 {
985 i = t * smax + s;
986 blocklights[i] += (vuint32)((rad - dist) * 256);
987 blocklightsr[i] += (vuint32)((rad - dist) * rmul);
988 blocklightsg[i] += (vuint32)((rad - dist) * gmul);
989 blocklightsb[i] += (vuint32)((rad - dist) * bmul);
990 if (DLights[lnum].colour != 0xffffffff)
991 is_coloured = true;
992 }
993 }
994 }
995 }
996 unguard;
997 }
998
999 //==========================================================================
1000 //
1001 // VRenderLevel::BuildLightMap
1002 //
1003 // Combine and scale multiple lightmaps into the 8.8 format in blocklights
1004 //
1005 //==========================================================================
1006
BuildLightMap(surface_t * surf,int shift)1007 bool VRenderLevel::BuildLightMap(surface_t *surf, int shift)
1008 {
1009 guard(VRenderLevel::BuildLightMap);
1010 int smax, tmax;
1011 int t;
1012 int i, size;
1013 byte *lightmap;
1014 rgb_t *lightmap_rgb;
1015
1016 is_coloured = false;
1017 r_light_add = false;
1018 smax = (surf->extents[0] >> 4) + 1;
1019 tmax = (surf->extents[1] >> 4) + 1;
1020 size = smax*tmax;
1021 lightmap = surf->lightmap;
1022 lightmap_rgb = surf->lightmap_rgb;
1023
1024 // clear to ambient
1025 t = surf->Light >> 24;
1026 t = MAX(t, r_ambient);
1027 t <<= 8;
1028 int tR = ((surf->Light >> 16) & 255) * t / 255;
1029 int tG = ((surf->Light >> 8) & 255) * t / 255;
1030 int tB = (surf->Light & 255) * t / 255;
1031 if (tR != tG || tR != tB)
1032 is_coloured = true;
1033 for (i = 0; i < size; i++)
1034 {
1035 blocklights[i] = t;
1036 blocklightsr[i] = tR;
1037 blocklightsg[i] = tG;
1038 blocklightsb[i] = tB;
1039 blockaddlightsr[i] = 0;
1040 blockaddlightsg[i] = 0;
1041 blockaddlightsb[i] = 0;
1042 }
1043
1044 // add lightmap
1045 if (lightmap_rgb)
1046 {
1047 if (!lightmap)
1048 {
1049 Sys_Error("RGB lightmap without uncoloured lightmap");
1050 }
1051 is_coloured = true;
1052 for (i = 0; i < size; i++)
1053 {
1054 blocklights[i] += lightmap[i] << 8;
1055 blocklightsr[i] += lightmap_rgb[i].r << 8;
1056 blocklightsg[i] += lightmap_rgb[i].g << 8;
1057 blocklightsb[i] += lightmap_rgb[i].b << 8;
1058 if (!r_static_add)
1059 {
1060 if (blocklightsr[i] > 0xffff)
1061 blocklightsr[i] = 0xffff;
1062 if (blocklightsg[i] > 0xffff)
1063 blocklightsg[i] = 0xffff;
1064 if (blocklightsb[i] > 0xffff)
1065 blocklightsb[i] = 0xffff;
1066 }
1067 }
1068 }
1069 else if (lightmap)
1070 {
1071 for (i = 0; i < size; i++)
1072 {
1073 t = lightmap[i] << 8;
1074 blocklights[i] += t;
1075 blocklightsr[i] += t;
1076 blocklightsg[i] += t;
1077 blocklightsb[i] += t;
1078 if (!r_static_add)
1079 {
1080 if (blocklightsr[i] > 0xffff)
1081 blocklightsr[i] = 0xffff;
1082 if (blocklightsg[i] > 0xffff)
1083 blocklightsg[i] = 0xffff;
1084 if (blocklightsb[i] > 0xffff)
1085 blocklightsb[i] = 0xffff;
1086 }
1087 }
1088 }
1089
1090 // add all the dynamic lights
1091 if (surf->dlightframe == r_dlightframecount)
1092 AddDynamicLights(surf);
1093
1094 // Calc additive light. This must be done before lightmap procesing
1095 // because it will clamp all lights
1096 if (!shift)
1097 {
1098 for (i = 0; i < size; i++)
1099 {
1100 t = blocklightsr[i] - 0x10000;
1101 if (t > 0)
1102 {
1103 t = int(r_specular * t);
1104 if (t > 0xffff)
1105 t = 0xffff;
1106 blockaddlightsr[i] = t;
1107 r_light_add = true;
1108 }
1109
1110 t = blocklightsg[i] - 0x10000;
1111 if (t > 0)
1112 {
1113 t = int(r_specular * t);
1114 if (t > 0xffff)
1115 t = 0xffff;
1116 blockaddlightsg[i] = t;
1117 r_light_add = true;
1118 }
1119
1120 t = blocklightsb[i] - 0x10000;
1121 if (t > 0)
1122 {
1123 t = int(r_specular * t);
1124 if (t > 0xffff)
1125 t = 0xffff;
1126 blockaddlightsb[i] = t;
1127 r_light_add = true;
1128 }
1129 }
1130 }
1131
1132 // bound, invert, and shift
1133 int minlight = 1 << (8 - shift);
1134 for (i = 0; i < size; i++)
1135 {
1136 t = (255 * 256 - (int)blocklights[i]) >> shift;
1137 if (t < minlight)
1138 t = minlight;
1139 blocklights[i] = t;
1140
1141 t = (255 * 256 - (int)blocklightsr[i]) >> shift;
1142 if (t < minlight)
1143 t = minlight;
1144 blocklightsr[i] = t;
1145
1146 t = (255 * 256 - (int)blocklightsg[i]) >> shift;
1147 if (t < minlight)
1148 t = minlight;
1149 blocklightsg[i] = t;
1150
1151 t = (255 * 256 - (int)blocklightsb[i]) >> shift;
1152 if (t < minlight)
1153 t = minlight;
1154 blocklightsb[i] = t;
1155 }
1156
1157 return is_coloured;
1158 unguard;
1159 }
1160
1161 //==========================================================================
1162 //
1163 // VRenderLevel::FlushCaches
1164 //
1165 //==========================================================================
1166
FlushCaches()1167 void VRenderLevel::FlushCaches()
1168 {
1169 guard(VRenderLevel::FlushCaches);
1170 memset(blockbuf, 0, sizeof(blockbuf));
1171 freeblocks = NULL;
1172 for (int i = 0; i < NUM_CACHE_BLOCKS; i++)
1173 {
1174 blockbuf[i].chain = freeblocks;
1175 freeblocks = &blockbuf[i];
1176 }
1177 for (int i = 0; i < NUM_BLOCK_SURFS; i++)
1178 {
1179 cacheblocks[i] = freeblocks;
1180 freeblocks = freeblocks->chain;
1181 cacheblocks[i]->width = BLOCK_WIDTH;
1182 cacheblocks[i]->height = BLOCK_HEIGHT;
1183 cacheblocks[i]->blocknum = i;
1184 }
1185 unguard;
1186 }
1187
1188 //==========================================================================
1189 //
1190 // VRenderLevel::FlushOldCaches
1191 //
1192 //==========================================================================
1193
FlushOldCaches()1194 void VRenderLevel::FlushOldCaches()
1195 {
1196 guard(VRenderLevel::FlushOldCaches);
1197 int i;
1198 surfcache_t *blines;
1199 surfcache_t *block;
1200
1201 for (i = 0; i < NUM_BLOCK_SURFS; i++)
1202 {
1203 for (blines = cacheblocks[i]; blines; blines = blines->bnext)
1204 {
1205 for (block = blines; block; block = block->lnext)
1206 {
1207 if (block->owner && cacheframecount != block->lastframe)
1208 {
1209 block = FreeBlock(block, false);
1210 }
1211 }
1212 if (!blines->owner && !blines->lprev && !blines->lnext)
1213 {
1214 blines = FreeBlock(blines, true);
1215 }
1216 }
1217 }
1218 if (!freeblocks)
1219 {
1220 Sys_Error("No more free blocks");
1221 }
1222 unguard;
1223 }
1224
1225 //==========================================================================
1226 //
1227 // VRenderLevel::AllocBlock
1228 //
1229 //==========================================================================
1230
AllocBlock(int width,int height)1231 surfcache_t* VRenderLevel::AllocBlock(int width, int height)
1232 {
1233 guard(VRenderLevel::AllocBlock);
1234 int i;
1235 surfcache_t* blines;
1236 surfcache_t* block;
1237 surfcache_t* other;
1238
1239 for (i = 0; i < NUM_BLOCK_SURFS; i++)
1240 {
1241 for (blines = cacheblocks[i]; blines; blines = blines->bnext)
1242 {
1243 if (blines->height != height)
1244 {
1245 continue;
1246 }
1247 for (block = blines; block; block = block->lnext)
1248 {
1249 if (block->owner)
1250 {
1251 continue;
1252 }
1253 if (block->width < width)
1254 {
1255 continue;
1256 }
1257 if (block->width > width)
1258 {
1259 if (!freeblocks)
1260 {
1261 FlushOldCaches();
1262 }
1263 other = freeblocks;
1264 freeblocks = other->chain;
1265 other->s = block->s + width;
1266 other->t = block->t;
1267 other->width = block->width - width;
1268 other->height = block->height;
1269 other->lnext = block->lnext;
1270 if (other->lnext)
1271 {
1272 other->lnext->lprev = other;
1273 }
1274 block->lnext = other;
1275 other->lprev = block;
1276 block->width = width;
1277 other->owner = NULL;
1278 other->blocknum = i;
1279 }
1280 return block;
1281 }
1282 }
1283 }
1284
1285 for (i = 0; i < NUM_BLOCK_SURFS; i++)
1286 {
1287 for (blines = cacheblocks[i]; blines; blines = blines->bnext)
1288 {
1289 if (blines->height < height)
1290 {
1291 continue;
1292 }
1293 if (blines->lnext)
1294 {
1295 continue;
1296 }
1297
1298 block = blines;
1299 if (block->height > height)
1300 {
1301 if (!freeblocks)
1302 {
1303 FlushOldCaches();
1304 }
1305 other = freeblocks;
1306 freeblocks = other->chain;
1307 other->s = 0;
1308 other->t = block->t + height;
1309 other->width = block->width;
1310 other->height = block->height - height;
1311 other->lnext = NULL;
1312 other->lprev = NULL;
1313 other->bnext = block->bnext;
1314 if (other->bnext)
1315 {
1316 other->bnext->bprev = other;
1317 }
1318 block->bnext = other;
1319 other->bprev = block;
1320 block->height = height;
1321 other->owner = NULL;
1322 other->blocknum = i;
1323 }
1324
1325 if (!freeblocks)
1326 {
1327 FlushOldCaches();
1328 }
1329 other = freeblocks;
1330 freeblocks = other->chain;
1331 other->s = block->s + width;
1332 other->t = block->t;
1333 other->width = block->width - width;
1334 other->height = block->height;
1335 other->lnext = NULL;
1336 block->lnext = other;
1337 other->lprev = block;
1338 block->width = width;
1339 other->owner = NULL;
1340 other->blocknum = i;
1341
1342 return block;
1343 }
1344 }
1345
1346 Sys_Error("overflow");
1347 return NULL;
1348 unguard;
1349 }
1350
1351 //==========================================================================
1352 //
1353 // VRenderLevel::FreeBlock
1354 //
1355 //==========================================================================
1356
FreeBlock(surfcache_t * block,bool check_lines)1357 surfcache_t* VRenderLevel::FreeBlock(surfcache_t *block, bool check_lines)
1358 {
1359 guard(VRenderLevel::FreeBlock);
1360 surfcache_t *other;
1361
1362 if (block->owner)
1363 {
1364 *block->owner = NULL;
1365 block->owner = NULL;
1366 }
1367 if (block->lnext && !block->lnext->owner)
1368 {
1369 other = block->lnext;
1370 block->width += other->width;
1371 block->lnext = other->lnext;
1372 if (block->lnext)
1373 {
1374 block->lnext->lprev = block;
1375 }
1376 other->chain = freeblocks;
1377 freeblocks = other;
1378 }
1379 if (block->lprev && !block->lprev->owner)
1380 {
1381 other = block;
1382 block = block->lprev;
1383 block->width += other->width;
1384 block->lnext = other->lnext;
1385 if (block->lnext)
1386 {
1387 block->lnext->lprev = block;
1388 }
1389 other->chain = freeblocks;
1390 freeblocks = other;
1391 }
1392
1393 if (block->lprev || block->lnext || !check_lines)
1394 {
1395 return block;
1396 }
1397
1398 if (block->bnext && !block->bnext->lnext)
1399 {
1400 other = block->bnext;
1401 block->height += other->height;
1402 block->bnext = other->bnext;
1403 if (block->bnext)
1404 {
1405 block->bnext->bprev = block;
1406 }
1407 other->chain = freeblocks;
1408 freeblocks = other;
1409 }
1410 if (block->bprev && !block->bprev->lnext)
1411 {
1412 other = block;
1413 block = block->bprev;
1414 block->height += other->height;
1415 block->bnext = other->bnext;
1416 if (block->bnext)
1417 {
1418 block->bnext->bprev = block;
1419 }
1420 other->chain = freeblocks;
1421 freeblocks = other;
1422 }
1423 return block;
1424 unguard;
1425 }
1426
1427 //==========================================================================
1428 //
1429 // VRenderLevel::FreeSurfCache
1430 //
1431 //==========================================================================
1432
FreeSurfCache(surfcache_t * block)1433 void VRenderLevel::FreeSurfCache(surfcache_t *block)
1434 {
1435 guard(VRenderLevel::FreeSurfCache);
1436 FreeBlock(block, true);
1437 unguard;
1438 }
1439
1440 //==========================================================================
1441 //
1442 // VRenderLevelShared::FreeSurfCache
1443 //
1444 //==========================================================================
1445
FreeSurfCache(surfcache_t *)1446 void VRenderLevelShared::FreeSurfCache(surfcache_t*)
1447 {
1448 }
1449
1450 //==========================================================================
1451 //
1452 // VRenderLevel::CacheSurface
1453 //
1454 //==========================================================================
1455
CacheSurface(surface_t * surface)1456 void VRenderLevel::CacheSurface(surface_t *surface)
1457 {
1458 guard(VRenderLevel::CacheSurface);
1459 surfcache_t *cache;
1460 int smax, tmax;
1461 int i, j, bnum;
1462
1463 //
1464 // see if the cache holds appropriate data
1465 //
1466 cache = surface->CacheSurf;
1467
1468 if (cache && !cache->dlight && surface->dlightframe != r_dlightframecount
1469 && cache->Light == surface->Light)
1470 {
1471 bnum = cache->blocknum;
1472 cache->chain = light_chain[bnum];
1473 light_chain[bnum] = cache;
1474 cache->lastframe = cacheframecount;
1475 return;
1476 }
1477
1478 //
1479 // determine shape of surface
1480 //
1481 smax = (surface->extents[0] >> 4) + 1;
1482 tmax = (surface->extents[1] >> 4) + 1;
1483
1484 //
1485 // allocate memory if needed
1486 //
1487 if (!cache) // if a texture just animated, don't reallocate it
1488 {
1489 cache = AllocBlock(smax, tmax);
1490 surface->CacheSurf = cache;
1491 cache->owner = &surface->CacheSurf;
1492 cache->surf = surface;
1493 }
1494
1495 if (surface->dlightframe == r_dlightframecount)
1496 cache->dlight = 1;
1497 else
1498 cache->dlight = 0;
1499 cache->Light = surface->Light;
1500
1501 // calculate the lightings
1502 BuildLightMap(surface, 0);
1503 bnum = cache->blocknum;
1504 block_changed[bnum] = true;
1505
1506 for (j = 0; j < tmax; j++)
1507 {
1508 for (i = 0; i < smax; i++)
1509 {
1510 rgba_t &lb = light_block[bnum][(j + cache->t) * BLOCK_WIDTH +
1511 i + cache->s];
1512 lb.r = 255 - byte(blocklightsr[j * smax + i] >> 8);
1513 lb.g = 255 - byte(blocklightsg[j * smax + i] >> 8);
1514 lb.b = 255 - byte(blocklightsb[j * smax + i] >> 8);
1515 lb.a = 255;
1516 }
1517 }
1518 cache->chain = light_chain[bnum];
1519 light_chain[bnum] = cache;
1520 cache->lastframe = cacheframecount;
1521
1522 // specular highlights
1523 for (j = 0; j < tmax; j++)
1524 {
1525 for (i = 0; i < smax; i++)
1526 {
1527 rgba_t &lb = add_block[bnum][(j + cache->t) * BLOCK_WIDTH +
1528 i + cache->s];
1529 lb.r = byte(blockaddlightsr[j * smax + i] >> 8);
1530 lb.g = byte(blockaddlightsg[j * smax + i] >> 8);
1531 lb.b = byte(blockaddlightsb[j * smax + i] >> 8);
1532 lb.a = 255;
1533 }
1534 }
1535 if (r_light_add)
1536 {
1537 cache->addchain = add_chain[bnum];
1538 add_chain[bnum] = cache;
1539 add_changed[bnum] = true;
1540 }
1541 unguard;
1542 }
1543