UFO: Alien Invasion
Loading...
Searching...
No Matches
lightmap.cpp
Go to the documentation of this file.
1
4
5/*
6Copyright (C) 1997-2001 Id Software, Inc.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23*/
24
25#include "lighting.h"
26#include "bsp.h"
27
28#define sun_angles config.sun_angles[config.compile_for_day]
29#define sun_normal config.sun_normal[config.compile_for_day]
30#define sun_color config.sun_color[config.compile_for_day]
31#define sun_intensity config.sun_intensity[config.compile_for_day]
32#define sun_ambient_color config.sun_ambient_color[config.compile_for_day]
33
35
57
59typedef struct extents_s {
63} extents_t;
64
66
72static void BuildFaceExtents (void)
73{
74 for (int k = 0; k < curTile->numfaces; k++) {
75 const dBspSurface_t* s = &curTile->faces[k];
76 const dBspTexinfo_t* tex = &curTile->texinfo[s->texinfo];
77
78 float* mins = face_extents[k].mins;
79 float* maxs = face_extents[k].maxs;
80
81 float* center = face_extents[k].center;
82
83 float* stmins = face_extents[k].stmins;
84 float* stmaxs = face_extents[k].stmaxs;
85 int i;
86
87 VectorSet(mins, 999999, 999999, 999999);
88 VectorSet(maxs, -999999, -999999, -999999);
89
90 stmins[0] = stmins[1] = 999999;
91 stmaxs[0] = stmaxs[1] = -999999;
92
93 for (i = 0; i < s->numedges; i++) {
94 const int e = curTile->surfedges[s->firstedge + i];
95 const dBspVertex_t* v;
96 int j;
97
98 if (e >= 0)
99 v = curTile->vertexes + curTile->edges[e].v[0];
100 else
101 v = curTile->vertexes + curTile->edges[-e].v[1];
102
103 for (j = 0; j < 3; j++) { /* calculate mins, maxs */
104 if (v->point[j] > maxs[j])
105 maxs[j] = v->point[j];
106 if (v->point[j] < mins[j])
107 mins[j] = v->point[j];
108 }
109
110 for (j = 0; j < 2; j++) { /* calculate stmins, stmaxs */
111 const float offset = tex->vecs[j][3];
112 const float val = DotProduct(v->point, tex->vecs[j]) + offset;
113 if (val < stmins[j])
114 stmins[j] = val;
115 if (val > stmaxs[j])
116 stmaxs[j] = val;
117 }
118 }
119
120 for (i = 0; i < 3; i++)
121 center[i] = (mins[i] + maxs[i]) / 2.0f;
122 }
123}
124
129{
130 const dBspSurface_t* s;
131 float* stmins, *stmaxs;
132 vec2_t lm_mins, lm_maxs;
133 const int luxelScale = (1 << config.lightquant);
134
135 s = l->face;
136
137 stmins = face_extents[s - curTile->faces].stmins;
138 stmaxs = face_extents[s - curTile->faces].stmaxs;
139
140 for (int i = 0; i < 2; i++) {
141 lm_mins[i] = floor(stmins[i] / luxelScale);
142 lm_maxs[i] = ceil(stmaxs[i] / luxelScale);
143
144 l->texmins[i] = lm_mins[i];
145 l->texsize[i] = lm_maxs[i] - lm_mins[i] + 1;
146 }
147
148 if (l->texsize[0] * l->texsize[1] > MAX_MAP_LIGHTMAP)
149 Sys_Error("Surface too large to light (%dx%d)", l->texsize[0], l->texsize[1]);
150}
151
156{
157 const dBspTexinfo_t* tex;
158 int i;
159 vec3_t texnormal;
160 vec_t distscale, dist;
161
162 tex = &curTile->texinfo[l->face->texinfo];
163
164 for (i = 0; i < 2; i++)
165 VectorCopy(tex->vecs[i], l->worldtotex[i]);
166
167 /* calculate a normal to the texture axis. points can be moved along this
168 * without changing their S/T */
169 texnormal[0] = tex->vecs[1][1] * tex->vecs[0][2]
170 - tex->vecs[1][2] * tex->vecs[0][1];
171 texnormal[1] = tex->vecs[1][2] * tex->vecs[0][0]
172 - tex->vecs[1][0] * tex->vecs[0][2];
173 texnormal[2] = tex->vecs[1][0] * tex->vecs[0][1]
174 - tex->vecs[1][1] * tex->vecs[0][0];
175 VectorNormalize(texnormal);
176
177 /* flip it towards plane normal */
178 distscale = DotProduct(texnormal, l->facenormal);
179 if (!distscale) {
180 Verb_Printf(VERB_EXTRA, "WARNING: Texture axis perpendicular to face\n");
181 distscale = 1.0;
182 }
183 if (distscale < 0.0) {
184 distscale = -distscale;
185 VectorSubtract(vec3_origin, texnormal, texnormal);
186 }
187
188 /* distscale is the ratio of the distance along the texture normal to
189 * the distance along the plane normal */
190 distscale = 1.0 / distscale;
191
192 for (i = 0; i < 2; i++) {
193 const vec_t len = VectorLength(l->worldtotex[i]);
194 const vec_t distance = DotProduct(l->worldtotex[i], l->facenormal) * distscale;
195 VectorMA(l->worldtotex[i], -distance, texnormal, l->textoworld[i]);
196 VectorScale(l->textoworld[i], (1.0f / len) * (1.0f / len), l->textoworld[i]);
197 }
198
199 /* calculate texorg on the texture plane */
200 for (i = 0; i < 3; i++)
201 l->texorg[i] =
202 -tex->vecs[0][3] * l->textoworld[0][i] -
203 tex->vecs[1][3] * l->textoworld[1][i];
204
205 /* project back to the face plane */
206 dist = DotProduct(l->texorg, l->facenormal) - l->facedist - 1;
207 dist *= distscale;
208 VectorMA(l->texorg, -dist, texnormal, l->texorg);
209
210 /* compensate for org'd bmodels */
211 VectorAdd(l->texorg, l->modelorg, l->texorg);
212
213 /* total sample count */
214 l->numsurfpt = l->texsize[0] * l->texsize[1];
216 if (!l->surfpt)
217 Sys_Error("Surface too large to light (" UFO_SIZE_T ")", l->numsurfpt * sizeof(*l->surfpt));
218
219 /* distance between samples */
220 l->step = 1 << config.lightquant;
221}
222
230static void CalcPoints (lightinfo_t* l, float sofs, float tofs)
231{
232 /* fill in surforg
233 * the points are biased towards the center of the surfaces
234 * to help avoid edge cases just inside walls */
235 vec_t* surf = l->surfpt[0];
236
237 int h = l->texsize[1];
238 int w = l->texsize[0];
239
240 int step = l->step;
241 vec_t starts = l->texmins[0] * step;
242 vec_t startt = l->texmins[1] * step;
243
244 for (int t = 0; t < h; t++) {
245 for (int s = 0; s < w; s++, surf += 3) {
246 const vec_t us = starts + (s + sofs) * step;
247 const vec_t ut = startt + (t + tofs) * step;
248
249 /* calculate texture point */
250 for (int j = 0; j < 3; j++)
251 surf[j] = l->texorg[j] + l->textoworld[0][j] * us +
252 l->textoworld[1][j] * ut;
253 }
254 }
255}
256
258typedef struct facelight_s {
263
265
272
274typedef struct light_s {
275 struct light_s* next;
277
278 float intensity;
279 vec3_t origin;
282 float stopdot;
283} light_t;
284
287
293void BuildLights (void)
294{
295 int i;
296 light_t* l;
297
298 /* surfaces */
299 for (i = 0; i < MAX_MAP_FACES; i++) {
300 /* iterate subdivided patches */
301 for(const patch_t* p = face_patches[i]; p; p = p->next) {
302 if (VectorEmpty(p->light))
303 continue;
304
305 numlights[config.compile_for_day]++;
307
308 VectorCopy(p->origin, l->origin);
309
310 l->next = lights[config.compile_for_day];
311 lights[config.compile_for_day] = l;
312
313 l->type = emit_surface;
314
315 l->intensity = ColorNormalize(p->light, l->color);
316 l->intensity *= p->area * config.surface_scale;
317 }
318 }
319
320 /* entities (skip the world) */
321 for (i = 1; i < num_entities; i++) {
322 float intensity;
323 const char* color;
324 const char* target;
325 const entity_t* e = &entities[i];
326 const char* name = ValueForKey(e, "classname");
327 if (!Q_strstart(name, "light"))
328 continue;
329
330 /* remove those lights that are only for the night version */
331 if (config.compile_for_day) {
332 const int spawnflags = atoi(ValueForKey(e, "spawnflags"));
333 if (!(spawnflags & 1)) /* day */
334 continue;
335 }
336
337 numlights[config.compile_for_day]++;
339
340 GetVectorForKey(e, "origin", l->origin);
341
342 /* link in */
343 l->next = lights[config.compile_for_day];
344 lights[config.compile_for_day] = l;
345
346 intensity = FloatForKey(e, "light");
347 if (!intensity)
348 intensity = 300.0;
349 color = ValueForKey(e, "_color");
350 if (color && color[0] != '\0'){
351 if (sscanf(color, "%f %f %f", &l->color[0], &l->color[1], &l->color[2]) != 3)
352 Sys_Error("Invalid _color entity property given: %s", color);
353 ColorNormalize(l->color, l->color);
354 } else
355 VectorSet(l->color, 1.0, 1.0, 1.0);
356 l->intensity = intensity * config.entity_scale;
357 l->type = emit_point;
358
359 target = ValueForKey(e, "target");
360 if (target[0] != '\0' || Q_streq(name, "light_spot")) {
361 l->type = emit_spotlight;
362 l->stopdot = FloatForKey(e, "_cone");
363 if (!l->stopdot)
364 l->stopdot = 10;
365 l->stopdot = cos(l->stopdot * torad);
366 if (target[0] != '\0') { /* point towards target */
367 entity_t* e2 = FindTargetEntity(target);
368 if (!e2)
369 Com_Printf("WARNING: light at (%i %i %i) has missing target '%s' - e.g. create an info_null that has a 'targetname' set to '%s'\n",
370 (int)l->origin[0], (int)l->origin[1], (int)l->origin[2], target, target);
371 else {
372 vec3_t dest;
373 GetVectorForKey(e2, "origin", dest);
376 }
377 } else { /* point down angle */
378 const float angle = FloatForKey(e, "angle");
379 if (angle == ANGLE_UP) {
380 l->normal[0] = l->normal[1] = 0.0;
381 l->normal[2] = 1.0;
382 } else if (angle == ANGLE_DOWN) {
383 l->normal[0] = l->normal[1] = 0.0;
384 l->normal[2] = -1.0;
385 } else {
386 l->normal[2] = 0;
387 l->normal[0] = cos(angle * torad);
388 l->normal[1] = sin(angle * torad);
389 }
390 }
391 }
392 }
393
394 /* handle worldspawn light settings */
395 {
396 const entity_t* e = &entities[0];
397 const char* ambient, *light, *angles, *color;
398 float f;
399 int i;
400
401 if (config.compile_for_day) {
402 ambient = ValueForKey(e, "ambient_day");
403 light = ValueForKey(e, "light_day");
404 angles = ValueForKey(e, "angles_day");
405 color = ValueForKey(e, "color_day");
406 } else {
407 ambient = ValueForKey(e, "ambient_night");
408 light = ValueForKey(e, "light_night");
409 angles = ValueForKey(e, "angles_night");
410 color = ValueForKey(e, "color_night");
411 }
412
413 if (light[0] != '\0')
414 sun_intensity = atoi(light);
415
416 if (angles[0] != '\0') {
418 if (sscanf(angles, "%f %f", &sun_angles[0], &sun_angles[1]) != 2)
419 Sys_Error("wrong angles values given: '%s'", angles);
420 AngleVectors(sun_angles, sun_normal, nullptr, nullptr);
421 }
422
423 if (color[0] != '\0') {
426 }
427
428 if (ambient[0] != '\0')
430
431 /* optionally pull brightness from worldspawn */
432 f = FloatForKey(e, "brightness");
433 if (f > 0.0)
434 config.brightness = f;
435
436 /* saturation as well */
437 f = FloatForKey(e, "saturation");
438 if (f > 0.0)
439 config.saturation = f;
440 else
441 Verb_Printf(VERB_EXTRA, "Invalid saturation setting (%f) in worldspawn found\n", f);
442
443 f = FloatForKey(e, "contrast");
444 if (f > 0.0)
445 config.contrast = f;
446 else
447 Verb_Printf(VERB_EXTRA, "Invalid contrast setting (%f) in worldspawn found\n", f);
448
449 /* lightmap resolution downscale (e.g. 4 = 1 << 4) */
450 i = atoi(ValueForKey(e, "quant"));
451 if (i >= 1 && i <= 6)
452 config.lightquant = i;
453 else
454 Verb_Printf(VERB_EXTRA, "Invalid quant setting (%i) in worldspawn found\n", i);
455 }
456
457 Verb_Printf(VERB_EXTRA, "light settings:\n * intensity: %i\n * sun_angles: pitch %f yaw %f\n * sun_color: %f:%f:%f\n * sun_ambient_color: %f:%f:%f\n",
459 Verb_Printf(VERB_NORMAL, "%i direct lights for %s lightmap\n", numlights[config.compile_for_day], (config.compile_for_day ? "day" : "night"));
460}
461
471static bool TR_TestLineSingleTile (const vec3_t start, const vec3_t stop, int* headhint)
472{
473 static int shared_lastthead = 0;
474 int lastthead = *headhint;
475
476 if (!lastthead) {
477 lastthead = shared_lastthead;
478 *headhint = lastthead;
479 }
480
481 assert(mapTiles.numTiles == 1);
482
483 /* ufo2map does many traces to the same endpoint.
484 * Often an occluding node will be found in the same thead
485 * as the last trace, so test that one first. */
486 if (curTile->theadlevel[lastthead] <= LEVEL_LASTLIGHTBLOCKING
487 && TR_TestLine_r(curTile, curTile->thead[lastthead], start, stop))
488 return true;
489
490 for (int i = 0; i < curTile->numtheads; i++) {
491 const int level = curTile->theadlevel[i];
492 if (i == lastthead)
493 continue;
495 continue;
496 if (TR_TestLine_r(curTile, curTile->thead[i], start, stop)) {
497 shared_lastthead = *headhint = i;
498 return true;
499 }
500 }
501 return false;
502}
503
507static void GatherSampleSunlight (const vec3_t pos, const vec3_t normal, float* sample, float* direction, float scale, int* headhint)
508{
509 vec3_t delta;
510 float dot, light;
511
512 if (!sun_intensity)
513 return;
514
515 dot = DotProduct(sun_normal, normal);
516 if (dot <= 0.001)
517 return; /* wrong direction */
518
519 /* don't use only 512 (which would be the 8 level max unit) but a
520 * higher value - because the light angle is not fixed at 90 degree */
521 VectorMA(pos, 8192, sun_normal, delta);
522
523 if (TR_TestLineSingleTile(pos, delta, headhint))
524 return; /* occluded */
525
526 light = sun_intensity * dot;
527 if (light > 255)
528 light = 255;
529 light *= scale;
530
531 /* add some light to it */
532 VectorMA(sample, light, sun_color, sample);
533
534 /* and accumulate the direction */
535 VectorMix(normal, sun_normal, light / sun_intensity, delta);
536 VectorMA(direction, light * scale, delta, direction);
537}
538
539
548static void GatherSampleLight (vec3_t pos, const vec3_t normal, float* sample, float* direction, float scale, int* headhints)
549{
550 light_t* l;
551 vec3_t delta;
552 int* headhint;
553
554 for (l = lights[config.compile_for_day], headhint = headhints; l; l = l->next, headhint++) {
555 float light = 0.0;
556 float dot2;
557
558 /* Com_Printf("Looking with next hint.\n"); */
559
560 VectorSubtract(l->origin, pos, delta);
561 float dist = VectorNormalize(delta);
562
563 float dot = DotProduct(delta, normal);
564 if (dot <= 0.001)
565 continue; /* behind sample surface */
566
567 switch (l->type) {
568 case emit_point:
569 /* linear falloff */
570 light = (l->intensity - dist) * dot;
571 break;
572
573 case emit_surface:
574 /* exponential falloff */
575 light = (l->intensity / (dist * dist)) * dot;
576 break;
577
578 case emit_spotlight:
579 /* linear falloff with cone */
580 dot2 = -DotProduct(delta, l->normal);
581 if (dot2 > l->stopdot) {
582 /* inside the cone */
583 light = (l->intensity - dist) * dot;
584 } else {
585 /* outside the cone */
586 light = (l->intensity * (dot2 / l->stopdot) - dist) * dot;
587 }
588 break;
589 default:
590 Sys_Error("Bad l->type");
591 }
592
593 if (light <= 0.5) /* almost no light */
594 continue;
595
596 if (TR_TestLineSingleTile(pos, l->origin, headhint))
597 continue; /* occluded */
598
599 if (light > 255)
600 light = 255;
601 /* add some light to it */
602 VectorMA(sample, light * scale, l->color, sample);
603
604 /* and add some direction */
605 VectorMix(normal, delta, 2.0 * light / l->intensity, delta);
606 VectorMA(direction, light * scale, delta, direction);
607 }
608
609 /* Com_Printf("Looking with last hint.\n"); */
610 GatherSampleSunlight(pos, normal, sample, direction, scale, headhint);
611}
612
613#define SAMPLE_NUDGE 0.25
614
619static inline void NudgeSamplePosition (const vec3_t in, const vec3_t normal, const vec3_t center, vec3_t out)
620{
621 vec3_t dir;
622
623 VectorCopy(in, out);
624
625 /* move into the level using the normal and surface center */
626 VectorSubtract(out, center, dir);
627 VectorNormalize(dir);
628
629 VectorMA(out, SAMPLE_NUDGE, dir, out);
630 VectorMA(out, SAMPLE_NUDGE, normal, out);
631}
632
633#define MAX_VERT_FACES 256
634
641static void FacesWithVert (int vert, int* faces, int* nfaces)
642{
643 int k = 0;
644 for (int i = 0; i < curTile->numfaces; i++) {
645 const dBspSurface_t* face = &curTile->faces[i];
646 const dBspTexinfo_t* tex = &curTile->texinfo[face->texinfo];
647
648 /* only build vertex normals for phong shaded surfaces */
649 if (!(tex->surfaceFlags & SURF_PHONG))
650 continue;
651
652 for (int j = 0; j < face->numedges; j++) {
653 const int e = curTile->surfedges[face->firstedge + j];
654 const int v = e >= 0 ? curTile->edges[e].v[0] : curTile->edges[-e].v[1];
655
656 /* face references vert */
657 if (v == vert) {
658 faces[k++] = i;
659 if (k == MAX_VERT_FACES)
660 Sys_Error("MAX_VERT_FACES");
661 break;
662 }
663 }
664 }
665 *nfaces = k;
666}
667
674{
675 int vert_faces[MAX_VERT_FACES];
676 int num_vert_faces;
677
679
680 for (int i = 0; i < curTile->numvertexes; i++) {
681 VectorClear(curTile->normals[i].normal);
682
683 FacesWithVert(i, vert_faces, &num_vert_faces);
684 if (!num_vert_faces) /* rely on plane normal only */
685 continue;
686
687 for (int j = 0; j < num_vert_faces; j++) {
688 const dBspSurface_t* face = &curTile->faces[vert_faces[j]];
689 const dBspPlane_t* plane = &curTile->planes[face->planenum];
690 extents_t* extends = &face_extents[vert_faces[j]];
691
692 /* scale the contribution of each face based on size */
693 vec3_t norm, delta;
694 VectorSubtract(extends->maxs, extends->mins, delta);
695 float scale = VectorLength(delta);
696
697 if (face->side)
698 VectorScale(plane->normal, -scale, norm);
699 else
700 VectorScale(plane->normal, scale, norm);
701
702 VectorAdd(curTile->normals[i].normal, norm, curTile->normals[i].normal);
703 }
704 VectorNormalize(curTile->normals[i].normal);
705 }
706}
707
708
714static void SampleNormal (const lightinfo_t* l, const vec3_t pos, vec3_t normal)
715{
716 float dist[MAX_VERT_FACES];
717
718 float nearest = 9999.0;
719 int nearv = 0;
720
721 /* calculate the distance to each vertex */
722 for (int i = 0; i < l->face->numedges; i++) { /* find nearest and farthest verts */
723 int v;
724 const int e = curTile->surfedges[l->face->firstedge + i];
725 if (e >= 0)
726 v = curTile->edges[e].v[0];
727 else
728 v = curTile->edges[-e].v[1];
729
730 vec3_t temp;
731 VectorSubtract(pos, curTile->vertexes[v].point, temp);
732 dist[i] = VectorLength(temp);
733 if (dist[i] < nearest) {
734 nearest = dist[i];
735 nearv = v;
736 }
737 }
738 VectorCopy(curTile->normals[nearv].normal, normal);
739}
740
741
742#define MAX_SAMPLES 5
743#define SOFT_SAMPLES 4
744static const float sampleofs[2][MAX_SAMPLES][2] = {
745 {{0.0, 0.0}, {-0.125, -0.125}, {0.125, -0.125}, {0.125, 0.125}, {-0.125, 0.125}},
746 {{-0.66, 0.33}, {-0.33, -0.66}, {0.33, 0.66}, {0.66, -0.33},{0.0,0.0}}
747};
748
753void BuildFacelights (unsigned int facenum)
754{
755 if (facenum >= MAX_MAP_FACES) {
756 Com_Printf("MAX_MAP_FACES hit\n");
757 return;
758 }
759
760 dBspSurface_t* face = &curTile->faces[facenum];
761 dBspPlane_t* plane = &curTile->planes[face->planenum];
762 dBspTexinfo_t* tex = &curTile->texinfo[face->texinfo];
763
764 if (tex->surfaceFlags & SURF_WARP)
765 return; /* non-lit texture */
766
767 float* sdir = tex->vecs[0];
768 float* tdir = tex->vecs[1];
769
770 /* lighting -extra antialiasing */
771 int numsamples;
772 if (config.extrasamples)
773 numsamples = config.soft ? SOFT_SAMPLES : MAX_SAMPLES;
774 else
775 numsamples = 1;
776
777 lightinfo_t li;
778 OBJZERO(li);
779
780 float scale = 1.0 / numsamples; /* each sample contributes this much */
781
782 li.face = face;
783 li.facedist = plane->dist;
784 VectorCopy(plane->normal, li.facenormal);
785 /* negate the normal and dist */
786 if (face->side) {
788 li.facedist = -li.facedist;
789 }
790
791 /* get the origin offset for rotating bmodels */
792 VectorCopy(face_offset[facenum], li.modelorg);
793
794 /* calculate lightmap texture mins and maxs */
796
797 /* and the lightmap texture vectors */
799
800 /* now generate all of the sample points */
801 CalcPoints(&li, 0, 0);
802
803 facelight_t* fl = &facelight[config.compile_for_day][facenum];
804 fl->numsamples = li.numsurfpt;
807
808 float* center = face_extents[facenum].center; /* center of the face */
809
810 /* Also setup the hints. Each hint is specific to each light source, including sunlight. */
811 int* headhints = Mem_AllocTypeN(int, (numlights[config.compile_for_day] + 1));
812
813
814 /* calculate light for each sample */
815 int i;
816 for (i = 0; i < fl->numsamples; i++) {
817 float* const sample = fl->samples[i]; /* accumulate lighting here */
818 float* const direction = fl->directions[i]; /* accumulate direction here */
819 vec3_t normal, binormal;
820 vec4_t tangent;
821
822 if (tex->surfaceFlags & SURF_PHONG)
823 /* interpolated normal */
824 SampleNormal(&li, li.surfpt[i], normal);
825 else
826 /* or just plane normal */
827 VectorCopy(li.facenormal, normal);
828
829 const int grid_type = config.soft ? 1 : 0;
830 for (int j = 0; j < numsamples; j++) { /* with antialiasing */
831 vec3_t pos;
832
833 /* add offset for supersampling */
834 VectorMA(li.surfpt[i], sampleofs[grid_type][j][0] * li.step, li.textoworld[0], pos);
835 VectorMA(pos, sampleofs[grid_type][j][1] * li.step, li.textoworld[1], pos);
836
837 NudgeSamplePosition(pos, normal, center, pos);
838
839 GatherSampleLight(pos, normal, sample, direction, scale, headhints);
840 }
841 if (VectorNotEmpty(direction)) {
842 vec3_t dir;
843
844 /* normalize it */
845 VectorNormalize(direction);
846
847 /* finalize the lighting direction for the sample */
848 TangentVectors(normal, sdir, tdir, tangent, binormal);
849
850 dir[0] = DotProduct(direction, tangent);
851 dir[1] = DotProduct(direction, binormal);
852 dir[2] = DotProduct(direction, normal);
853
854 VectorCopy(dir, direction);
855 }
856 }
857
858 /* Free the hints. */
859 Mem_Free(headhints);
860
861 for (i = 0; i < fl->numsamples; i++) { /* pad them */
862 float* const direction = fl->directions[i];
863 if (VectorEmpty(direction))
864 VectorSet(direction, 0.0, 0.0, 1.0);
865 }
866
867 /* free the sample positions for the face */
868 Mem_Free(li.surfpt);
869}
870
871#define TGA_HEADER_SIZE 18
872static void WriteTGA24 (const char* filename, const byte* data, int width, int height, int offset)
873{
874 const int size = width * height * 3;
875 /* allocate a buffer and set it up */
876 byte* buffer = Mem_AllocTypeN(byte, size + TGA_HEADER_SIZE);
877 memset(buffer, 0, TGA_HEADER_SIZE);
878 buffer[2] = 2;
879 buffer[12] = width & 255;
880 buffer[13] = width >> 8;
881 buffer[14] = height & 255;
882 buffer[15] = height >> 8;
883 buffer[16] = 24;
884 /* create top-down TGA */
885 buffer[17] = 32;
886
887 /* swap rgb to bgr */
888 for (int i = 0; i < size; i += 3) {
889 buffer[i + TGA_HEADER_SIZE] = data[i*2 + offset + 2]; /* blue */
890 buffer[i + TGA_HEADER_SIZE + 1] = data[i*2 + offset + 1]; /* green */
891 buffer[i + TGA_HEADER_SIZE + 2] = data[i*2 + offset + 0]; /* red */
892 }
893
894 /* write it and free the buffer */
895 ScopedFile file;
896 if (FS_OpenFile(filename, &file, FILE_WRITE) > 0)
897 Sys_Error("Unable to open %s for writing", filename);
898
899 FS_Write(buffer, size + TGA_HEADER_SIZE, &file);
900
901 /* close the file */
902 Mem_Free(buffer);
903}
904
912static void CalcTextureSize (const dBspSurface_t* s, vec2_t texsize, int scale)
913{
914 const float* stmins = face_extents[s - curTile->faces].stmins;
915 const float* stmaxs = face_extents[s - curTile->faces].stmaxs;
916
917 for (int i = 0; i < 2; i++) {
918 const float mins = floor(stmins[i] / scale);
919 const float maxs = ceil(stmaxs[i] / scale);
920
921 texsize[i] = maxs - mins + 1;
922 }
923}
924
931static void ExportLightmap (const char* path, const char* name, bool day)
932{
933 const int lightmapIndex = day ? 1 : 0;
934 const byte* bspLightBytes = curTile->lightdata[lightmapIndex];
935 const byte quant = *bspLightBytes;
936 const int scale = 1 << quant;
937
938 for (int i = 0; i < curTile->numfaces; i++) {
939 const dBspSurface_t* face = &curTile->faces[i];
940 const byte* lightmap = bspLightBytes + face->lightofs[lightmapIndex];
941 vec2_t texSize;
942
943 CalcTextureSize(face, texSize, scale);
944
945 /* write a tga image out */
946 if (Vector2NotEmpty(texSize)) {
947 char filename[MAX_QPATH];
948 Com_sprintf(filename, sizeof(filename), "%s/%s_lightmap_%04d%c.tga", path, name, i, day ? 'd' : 'n');
949 Com_Printf("Writing %s (%.0fx%.0f)\n", filename, texSize[0], texSize[1]);
950 WriteTGA24(filename, lightmap, texSize[0], texSize[1], 0);
951 Com_sprintf(filename, sizeof(filename), "%s/%s_direction_%04d%c.tga", path, name, i, day ? 'd' : 'n');
952 Com_Printf("Writing %s (%.0fx%.0f)\n", filename, texSize[0], texSize[1]);
953 WriteTGA24(filename, lightmap, texSize[0], texSize[1], 3);
954 }
955 }
956}
957
963void ExportLightmaps (const char* bspFileName)
964{
965 char path[MAX_QPATH], lightmapName[MAX_QPATH];
966 const char* fileName = Com_SkipPath(bspFileName);
967
968 Com_FilePath(bspFileName, path, sizeof(path));
969 Com_StripExtension(fileName, lightmapName, sizeof(lightmapName));
970
971 /* note it */
972 Com_Printf("--- ExportLightmaps ---\n");
973
975
976 ExportLightmap(path, lightmapName, true);
977 ExportLightmap(path, lightmapName, false);
978}
979
980static const vec3_t luminosity = {0.2125, 0.7154, 0.0721};
981
987void FinalLightFace (unsigned int facenum)
988{
989 dBspSurface_t* f = &curTile->faces[facenum];
990 facelight_t* fl = &facelight[config.compile_for_day][facenum];
991
992 /* none-lit texture */
993 if (curTile->texinfo[f->texinfo].surfaceFlags & SURF_WARP)
994 return;
995
996 ThreadLock();
997
998 f->lightofs[config.compile_for_day] = curTile->lightdatasize[config.compile_for_day];
999 curTile->lightdatasize[config.compile_for_day] += fl->numsamples * 3;
1000 /* account for light direction data as well */
1001 curTile->lightdatasize[config.compile_for_day] += fl->numsamples * 3;
1002
1003 if (curTile->lightdatasize[config.compile_for_day] > MAX_MAP_LIGHTING)
1004 Sys_Error("MAX_MAP_LIGHTING (%i exceeded %i) - try to reduce the brush size (%s)",
1005 curTile->lightdatasize[config.compile_for_day], MAX_MAP_LIGHTING,
1006 curTile->texinfo[f->texinfo].texture);
1007
1008 ThreadUnlock();
1009
1010 /* write it out */
1011 byte* dest = &curTile->lightdata[config.compile_for_day][f->lightofs[config.compile_for_day]];
1012
1013 for (int j = 0; j < fl->numsamples; j++) {
1014 int k;
1015 vec3_t temp;
1016
1017 /* start with raw sample data */
1018 VectorCopy(fl->samples[j], temp);
1019
1020 /* convert to float */
1021 VectorScale(temp, 1.0 / 255.0, temp);
1022
1023 /* add an ambient term if desired */
1024 VectorAdd(temp, sun_ambient_color, temp);
1025
1026 /* apply global scale factor */
1027 VectorScale(temp, config.brightness, temp);
1028
1029 float max = 0.0;
1030
1031 /* find the brightest component */
1032 for (k = 0; k < 3; k++) {
1033 /* enforcing positive values */
1034 if (temp[k] < 0.0)
1035 temp[k] = 0.0;
1036
1037 if (temp[k] > max)
1038 max = temp[k];
1039 }
1040
1041 if (max > 255.0) /* clamp without changing hue */
1042 VectorScale(temp, 255.0 / max, temp);
1043
1044 for (k = 0; k < 3; k++) { /* apply contrast */
1045 temp[k] -= 0.5; /* normalize to -0.5 through 0.5 */
1046
1047 temp[k] *= config.contrast; /* scale */
1048
1049 temp[k] += 0.5;
1050
1051 if (temp[k] > 1.0) /* clamp */
1052 temp[k] = 1.0;
1053 else if (temp[k] < 0)
1054 temp[k] = 0;
1055 }
1056
1057 /* apply saturation */
1058 float d = DotProduct(temp, luminosity);
1059
1060 vec3_t intensity;
1061 VectorSet(intensity, d, d, d);
1062 VectorMix(intensity, temp, config.saturation, temp);
1063
1064 for (k = 0; k < 3; k++) {
1065 temp[k] *= 255.0; /* back to byte */
1066
1067 if (temp[k] > 255.0) /* clamp */
1068 temp[k] = 255.0;
1069 else if (temp[k] < 0.0)
1070 temp[k] = 0.0;
1071
1072 *dest++ = (byte)temp[k];
1073 }
1074
1075 /* also write the directional data */
1076 vec3_t dir;
1077 VectorCopy(fl->directions[j], dir);
1078 for (k = 0; k < 3; k++)
1079 *dest++ = (byte)((dir[k] + 1.0f) * 127.0f);
1080 }
1081}
void GetVectorFromString(const char *value, vec3_t vec)
Converts a string into a vec3_t.
Definition bspfile.cpp:575
void GetVectorForKey(const entity_t *ent, const char *key, vec3_t vec)
Converts the value of a entity parameter into a vec3_t.
Definition bspfile.cpp:592
vec_t FloatForKey(const entity_t *ent, const char *key)
Definition bspfile.cpp:566
int num_entities
Definition bspfile.cpp:394
entity_t entities[MAX_MAP_ENTITIES]
Definition bspfile.cpp:395
const char * ValueForKey(const entity_t *ent, const char *key)
Definition bspfile.cpp:558
entity_t * FindTargetEntity(const char *target)
Searches the entities array for an entity with the parameter targetname that matches the searched tar...
Definition map.cpp:911
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
#define MAX_MAP_LIGHTMAP
Definition defines.h:386
#define ANGLE_DOWN
Definition defines.h:206
#define LIGHTMAP_MAX
Definition defines.h:365
#define SURF_PHONG
Definition defines.h:263
#define MAX_MAP_FACES
Definition defines.h:144
#define SURF_WARP
Definition defines.h:256
#define LEVEL_LASTLIGHTBLOCKING
Definition defines.h:350
#define MAX_MAP_LIGHTING
Definition defines.h:148
#define ANGLE_UP
Definition defines.h:205
int FS_Write(const void *buffer, int len, qFILE *f)
Properly handles partial writes.
Definition files.cpp:1513
int FS_OpenFile(const char *filename, qFILE *file, filemode_t mode)
Finds and opens the file in the search path.
Definition files.cpp:162
#define MAX_QPATH
Definition filesys.h:40
@ FILE_WRITE
Definition filesys.h:111
level_locals_t level
Definition g_main.cpp:38
void Sys_Error(const char *error,...)
Definition g_main.cpp:421
voidpf void uLong size
Definition ioapi.h:42
const char * filename
Definition ioapi.h:41
voidpf uLong offset
Definition ioapi.h:45
vec3_t face_offset[MAX_MAP_FACES]
Definition lightmap.cpp:34
patch_t * face_patches[MAX_MAP_FACES]
Definition patches.cpp:30
static void SampleNormal(const lightinfo_t *l, const vec3_t pos, vec3_t normal)
For Phong-shaded samples, interpolate the vertex normals for the surface in question,...
Definition lightmap.cpp:714
void BuildVertexNormals(void)
Calculate per-vertex (instead of per-plane) normal vectors. This is done by finding all of the faces ...
Definition lightmap.cpp:673
emittype_t
Different types of sources emitting light.
Definition lightmap.cpp:267
@ emit_point
Definition lightmap.cpp:269
@ emit_surface
Definition lightmap.cpp:268
@ emit_spotlight
Definition lightmap.cpp:270
void BuildLights(void)
Create lights out of patches and entity lights.
Definition lightmap.cpp:293
#define sun_normal
Definition lightmap.cpp:29
#define SOFT_SAMPLES
Definition lightmap.cpp:743
#define SAMPLE_NUDGE
Definition lightmap.cpp:613
static void ExportLightmap(const char *path, const char *name, bool day)
Export all the faces for one particular lightmap (day or night).
Definition lightmap.cpp:931
static void GatherSampleSunlight(const vec3_t pos, const vec3_t normal, float *sample, float *direction, float scale, int *headhint)
A follow-up to GatherSampleLight, simply trace along the sun normal, adding sunlight.
Definition lightmap.cpp:507
void FinalLightFace(unsigned int facenum)
Add the indirect lighting on top of the direct lighting and save into final map format.
Definition lightmap.cpp:987
void BuildFacelights(unsigned int facenum)
Definition lightmap.cpp:753
static void CalcLightinfoExtents(lightinfo_t *l)
Definition lightmap.cpp:128
static light_t * lights[LIGHTMAP_MAX]
Definition lightmap.cpp:285
static void CalcLightinfoVectors(lightinfo_t *l)
Fills in texorg, worldtotex. and textoworld.
Definition lightmap.cpp:155
static void CalcPoints(lightinfo_t *l, float sofs, float tofs)
For each texture aligned grid point, back project onto the plane to get the world xyz value of the sa...
Definition lightmap.cpp:230
static bool TR_TestLineSingleTile(const vec3_t start, const vec3_t stop, int *headhint)
Checks traces against a single-tile map, optimized for ufo2map. This trace is only for visible levels...
Definition lightmap.cpp:471
#define sun_angles
Definition lightmap.cpp:28
void ExportLightmaps(const char *bspFileName)
Export the day and night lightmap and direction data for the given map.
Definition lightmap.cpp:963
static void WriteTGA24(const char *filename, const byte *data, int width, int height, int offset)
Definition lightmap.cpp:872
#define TGA_HEADER_SIZE
Definition lightmap.cpp:871
#define sun_intensity
Definition lightmap.cpp:31
#define MAX_SAMPLES
Definition lightmap.cpp:742
static facelight_t facelight[LIGHTMAP_MAX][MAX_MAP_FACES]
Definition lightmap.cpp:264
static void FacesWithVert(int vert, int *faces, int *nfaces)
Populate faces with indexes of all dBspFace_t's referencing the specified edge.
Definition lightmap.cpp:641
static const float sampleofs[2][MAX_SAMPLES][2]
Definition lightmap.cpp:744
static int numlights[LIGHTMAP_MAX]
Definition lightmap.cpp:286
#define sun_color
Definition lightmap.cpp:30
#define MAX_VERT_FACES
Definition lightmap.cpp:633
static extents_t face_extents[MAX_MAP_FACES]
Definition lightmap.cpp:65
static void BuildFaceExtents(void)
Populates face_extents for all dBspSurface_t, prior to light creation. This is done so that sample po...
Definition lightmap.cpp:72
static void CalcTextureSize(const dBspSurface_t *s, vec2_t texsize, int scale)
Calculates the texture width for the lightmap texture. This depends on the surface mins and maxs and ...
Definition lightmap.cpp:912
static void GatherSampleLight(vec3_t pos, const vec3_t normal, float *sample, float *direction, float scale, int *headhints)
Definition lightmap.cpp:548
#define sun_ambient_color
Definition lightmap.cpp:32
static void NudgeSamplePosition(const vec3_t in, const vec3_t normal, const vec3_t center, vec3_t out)
Move the incoming sample position towards the surface center and along the surface normal to reduce f...
Definition lightmap.cpp:619
static const vec3_t luminosity
Definition lightmap.cpp:980
vec_t VectorNormalize(vec3_t v)
Calculate unit vector for a given vec3_t.
Definition mathlib.cpp:745
vec_t VectorLength(const vec3_t v)
Calculate the length of a vector.
Definition mathlib.cpp:434
void VectorMA(const vec3_t veca, const float scale, const vec3_t vecb, vec3_t outVector)
Sets vector_out (vc) to vevtor1 (va) + scale * vector2 (vb).
Definition mathlib.cpp:261
const vec3_t vec3_origin
Definition mathlib.cpp:35
void VectorMix(const vec3_t v1, const vec3_t v2, float mix, vec3_t out)
Calculate a position on v1 v2 line.
Definition mathlib.cpp:447
vec_t ColorNormalize(const vec3_t in, vec3_t out)
Definition mathlib.cpp:190
void AngleVectors(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
Create the rotation matrix in order to rotate something.
Definition mathlib.cpp:631
void TangentVectors(const vec3_t normal, const vec3_t sdir, const vec3_t tdir, vec4_t tangent, vec3_t binormal)
Projects the normalized directional vectors on to the normal's plane. The fourth component of the res...
Definition mathlib.cpp:1057
#define torad
Definition mathlib.h:50
#define Mem_Free(ptr)
Definition mem.h:35
#define Mem_AllocTypeN(type, n)
Definition mem.h:38
#define Mem_AllocType(type)
Definition mem.h:39
QGL_EXTERN GLuint GLchar GLuint * len
Definition r_gl.h:99
QGL_EXTERN GLenum GLuint * dest
Definition r_gl.h:101
QGL_EXTERN int GLboolean GLfloat * v
Definition r_gl.h:120
QGL_EXTERN GLsizei const GLvoid * data
Definition r_gl.h:89
QGL_EXTERN GLfloat f
Definition r_gl.h:114
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
#define Q_streq(a, b)
Definition shared.h:136
#define OBJZERO(obj)
Definition shared.h:178
void Com_StripExtension(const char *in, char *out, const size_t size)
Removes the file extension from a filename.
Definition shared.cpp:259
const char * Com_SkipPath(const char *pathname)
Returns just the filename from a given path.
Definition shared.cpp:37
void Com_FilePath(const char *in, char *out, size_t size)
Returns the path up to, but not including the last /.
Definition shared.cpp:319
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition shared.cpp:587
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
vec3_t normal
Definition typedefs.h:373
float dist
Definition typedefs.h:374
int lightofs[LIGHTMAP_MAX]
Definition typedefs.h:412
short texinfo
Definition typedefs.h:409
short numedges
Definition typedefs.h:408
uint16_t planenum
Definition typedefs.h:404
uint32_t surfaceFlags
Definition typedefs.h:390
float vecs[2][4]
Definition typedefs.h:389
face extents
Definition lightmap.cpp:59
vec3_t mins
Definition lightmap.cpp:60
vec3_t center
Definition lightmap.cpp:61
vec3_t maxs
Definition lightmap.cpp:60
vec2_t stmins
Definition lightmap.cpp:62
vec2_t stmaxs
Definition lightmap.cpp:62
buckets for sample accumulation - clipped by the surface
Definition lightmap.cpp:258
vec3_t * directions
Definition lightmap.cpp:261
vec3_t * samples
Definition lightmap.cpp:260
a light source
Definition r_light.h:29
vec3_t normal
Definition lightmap.cpp:281
vec4_t color
Definition r_light.h:31
float stopdot
Definition lightmap.cpp:282
vec3_t origin
Definition r_light.h:30
emittype_t type
Definition lightmap.cpp:276
float intensity
Definition lightmap.cpp:278
struct light_s * next
Definition lightmap.cpp:275
lightinfo is a temporary bucket for lighting calculations
Definition lightmap.cpp:37
vec3_t texorg
Definition lightmap.cpp:46
vec3_t facenormal
Definition lightmap.cpp:39
int texsize[2]
Definition lightmap.cpp:51
vec3_t modelorg
Definition lightmap.cpp:44
int texmins[2]
Definition lightmap.cpp:50
dBspSurface_t * face
Definition lightmap.cpp:55
vec3_t worldtotex[2]
Definition lightmap.cpp:47
vec3_t * surfpt
Definition lightmap.cpp:42
vec_t facedist
Definition lightmap.cpp:38
vec3_t textoworld[2]
Definition lightmap.cpp:48
static config_t config
Definition test_all.cpp:43
static mapTiles_t mapTiles
dMapTile_t * curTile
Definition bsp.cpp:32
void ThreadUnlock(void)
Release the lock on the shared data.
Definition threads.cpp:126
void Verb_Printf(const verbosityLevel_t importance, const char *format,...) __attribute__((format(__printf__
@ VERB_NORMAL
Definition shared.h:45
@ VERB_EXTRA
Definition shared.h:46
void ThreadLock(void)
Lock the shared data by the calling thread.
Definition threads.cpp:112
int TR_TestLine_r(TR_TILE_TYPE *tile, int32_t nodenum, const vec3_t start, const vec3_t end)
Definition tracing.cpp:209
float vec_t
Definition ufotypes.h:37
vec_t vec3_t[3]
Definition ufotypes.h:39
vec_t vec4_t[4]
Definition ufotypes.h:40
uint8_t byte
Definition ufotypes.h:34
#define UFO_SIZE_T
Definition ufotypes.h:89
vec_t vec2_t[2]
Definition ufotypes.h:38
static const vec3_t scale
#define Vector2NotEmpty(a)
Definition vector.h:75
#define VectorClear(a)
Definition vector.h:55
#define VectorNegate(src, dest)
Definition vector.h:58
#define VectorNotEmpty(a)
Definition vector.h:72
#define VectorSubtract(a, b, dest)
Definition vector.h:45
#define VectorCopy(src, dest)
Definition vector.h:51
#define VectorEmpty(a)
Definition vector.h:73
#define VectorAdd(a, b, dest)
Definition vector.h:47
#define DotProduct(x, y)
Returns the distance between two 3-dimensional vectors.
Definition vector.h:44
#define VectorSet(v, x, y, z)
Definition vector.h:59
#define VectorScale(in, scale, out)
Definition vector.h:79