UFO: Alien Invasion
Doxygen documentation generating
lightmap.cpp
Go to the documentation of this file.
1 
5 /*
6 Copyright (C) 1997-2001 Id Software, Inc.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, 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 
37 typedef struct {
40 
41  int numsurfpt;
43 
47  vec3_t worldtotex[2];
48  vec3_t textoworld[2];
50  int texmins[2];
51  int texsize[2];
53  int step;
56 } lightinfo_t;
57 
59 typedef struct extents_s {
60  vec3_t mins, maxs;
62  vec2_t stmins, stmaxs;
63 } extents_t;
64 
66 
72 static 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 
230 static 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 
258 typedef struct facelight_s {
262 } facelight_t;
263 
265 
267 typedef enum {
271 } emittype_t;
272 
274 typedef struct light_s {
275  struct light_s* next;
278  float intensity;
279  vec3_t origin;
282  float stopdot;
283 } light_t;
284 
287 
293 void 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]++;
306  l = Mem_AllocType(light_t);
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]++;
338  l = Mem_AllocType(light_t);
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);
374  VectorSubtract(dest, l->origin, l->normal);
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 
471 static 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 
507 static 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 
548 static 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 
619 static 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 
641 static 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++) {
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 
703  }
705  }
706 }
707 
708 
714 static 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
744 static 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 
753 void 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
872 static 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 */
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 
912 static 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 
931 static 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 
963 void 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 
980 static const vec3_t luminosity = {0.2125, 0.7154, 0.0721};
981 
987 void 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 }
#define Vector2NotEmpty(a)
Definition: vector.h:75
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 VectorLength(const vec3_t v)
Calculate the length of a vector.
Definition: mathlib.cpp:434
vec3_t normal
Definition: typedefs.h:373
static void GatherSampleLight(vec3_t pos, const vec3_t normal, float *sample, float *direction, float scale, int *headhints)
Definition: lightmap.cpp:548
#define LEVEL_LASTLIGHTBLOCKING
Definition: defines.h:350
float intensity
Definition: lightmap.cpp:278
float stopdot
Definition: lightmap.cpp:282
emittype_t type
Definition: lightmap.cpp:276
float vecs[2][4]
Definition: typedefs.h:389
#define VectorCopy(src, dest)
Definition: vector.h:51
#define Mem_AllocTypeN(type, n)
Definition: mem.h:38
vec3_t * surfpt
Definition: lightmap.cpp:42
void Sys_Error(const char *error,...)
Definition: g_main.cpp:421
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
#define VectorSet(v, x, y, z)
Definition: vector.h:59
int surfedges[MAX_MAP_SURFEDGES]
Definition: typedefs.h:506
static void CalcLightinfoExtents(lightinfo_t *l)
Definition: lightmap.cpp:128
#define MAX_MAP_FACES
Definition: defines.h:144
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
char texture[32]
Definition: typedefs.h:392
const char * Com_SkipPath(const char *pathname)
Returns just the filename from a given path.
Definition: shared.cpp:37
a light source
Definition: r_light.h:29
dBspVertex_t vertexes[MAX_MAP_VERTS]
Definition: typedefs.h:481
int FS_OpenFile(const char *filename, qFILE *file, filemode_t mode)
Finds and opens the file in the search path.
Definition: files.cpp:162
vec4_t color
Definition: r_light.h:31
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, weighting them according to their proximity to the sample position.
Definition: lightmap.cpp:714
vec_t ColorNormalize(const vec3_t in, vec3_t out)
Definition: mathlib.cpp:190
face extents
Definition: lightmap.cpp:59
static const vec3_t scale
byte lightdata[LIGHTMAP_MAX][MAX_MAP_LIGHTING]
Definition: typedefs.h:465
void BuildLights(void)
Create lights out of patches and entity lights.
Definition: lightmap.cpp:293
short side
Definition: typedefs.h:405
#define TGA_HEADER_SIZE
Definition: lightmap.cpp:871
voidpf uLong int origin
Definition: ioapi.h:45
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
void Com_StripExtension(const char *in, char *out, const size_t size)
Removes the file extension from a filename.
Definition: shared.cpp:259
#define sun_intensity
Definition: lightmap.cpp:31
const char * filename
Definition: ioapi.h:41
const vec3_t vec3_origin
Definition: mathlib.cpp:35
static const vec3_t luminosity
Definition: lightmap.cpp:980
#define VectorNegate(src, dest)
Definition: vector.h:58
float vec_t
Definition: ufotypes.h: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
vec3_t facenormal
Definition: lightmap.cpp:39
static void WriteTGA24(const char *filename, const byte *data, int width, int height, int offset)
Definition: lightmap.cpp:872
voidpf void uLong size
Definition: ioapi.h:42
vec3_t * samples
Definition: lightmap.cpp:260
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
vec3_t origin
Definition: r_light.h:30
vec3_t maxs
Definition: lightmap.cpp:60
void ExportLightmaps(const char *bspFileName)
Export the day and night lightmap and direction data for the given map.
Definition: lightmap.cpp:963
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
QGL_EXTERN GLsizei const GLvoid * data
Definition: r_gl.h:89
int numtheads
Definition: typedefs.h:449
vec3_t textoworld[2]
Definition: lightmap.cpp:48
int numsamples
Definition: lightmap.cpp:259
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
#define SOFT_SAMPLES
Definition: lightmap.cpp:743
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
entity_t entities[MAX_MAP_ENTITIES]
Definition: bspfile.cpp:395
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
void BuildFacelights(unsigned int facenum)
Definition: lightmap.cpp:753
#define VectorScale(in, scale, out)
Definition: vector.h:79
static light_t * lights[LIGHTMAP_MAX]
Definition: lightmap.cpp:285
static extents_t face_extents[MAX_MAP_FACES]
Definition: lightmap.cpp:65
void ThreadUnlock(void)
Release the lock on the shared data.
Definition: threads.cpp:126
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
int theadlevel[LEVEL_MAX]
Definition: typedefs.h:451
lightinfo is a temporary bucket for lighting calculations
Definition: lightmap.cpp:37
#define DotProduct(x, y)
Returns the distance between two 3-dimensional vectors.
Definition: vector.h:44
#define sun_angles
Definition: lightmap.cpp:28
vec3_t normal
Definition: lightmap.cpp:281
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
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
vec3_t modelorg
Definition: lightmap.cpp:44
uint32_t surfaceFlags
Definition: typedefs.h:390
#define OBJZERO(obj)
Definition: shared.h:178
#define MAX_SAMPLES
Definition: lightmap.cpp:742
vec3_t worldtotex[2]
Definition: lightmap.cpp:47
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&#39;s plane. The fourth component of the res...
Definition: mathlib.cpp:1057
#define sun_normal
Definition: lightmap.cpp:29
static facelight_t facelight[LIGHTMAP_MAX][MAX_MAP_FACES]
Definition: lightmap.cpp:264
vec3_t * directions
Definition: lightmap.cpp:261
static int numlights[LIGHTMAP_MAX]
Definition: lightmap.cpp:286
#define VectorEmpty(a)
Definition: vector.h:73
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition: shared.cpp:587
short texinfo
Definition: typedefs.h:409
int TR_TestLine_r(TR_TILE_TYPE *tile, int32_t nodenum, const vec3_t start, const vec3_t end)
Definition: tracing.cpp:209
vec_t facedist
Definition: lightmap.cpp:38
vec3_t color
Definition: lightmap.cpp:280
int lightdatasize[LIGHTMAP_MAX]
Definition: typedefs.h:464
vec3_t texorg
Definition: lightmap.cpp:46
void GetVectorFromString(const char *value, vec3_t vec)
Converts a string into a vec3_t.
Definition: bspfile.cpp:575
#define SURF_PHONG
Definition: defines.h:263
unsigned short v[2]
Definition: typedefs.h:400
#define SAMPLE_NUDGE
Definition: lightmap.cpp:613
#define VectorNotEmpty(a)
Definition: vector.h:72
dBspTexinfo_t texinfo[MAX_MAP_TEXINFO]
Definition: typedefs.h:487
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
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
QGL_EXTERN GLenum GLuint * dest
Definition: r_gl.h:101
void Verb_Printf(const verbosityLevel_t importance, const char *format,...) __attribute__((format(__printf__
patch_t * face_patches[MAX_MAP_FACES]
Definition: patches.cpp:30
int numvertexes
Definition: typedefs.h:480
dBspSurface_t faces[MAX_MAP_FACES]
Definition: typedefs.h:490
static config_t config
Definition: test_all.cpp:43
#define MAX_MAP_LIGHTING
Definition: defines.h:148
struct light_s * next
Definition: lightmap.cpp:275
dMapTile_t * curTile
Definition: bsp.cpp:32
vec3_t center
Definition: lightmap.cpp:61
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
#define VectorClear(a)
Definition: vector.h:55
dBspEdge_t edges[MAX_MAP_EDGES]
Definition: typedefs.h:493
#define VectorAdd(a, b, dest)
Definition: vector.h:47
void ThreadLock(void)
Lock the shared data by the calling thread.
Definition: threads.cpp:112
int thead[LEVEL_MAX]
Definition: typedefs.h:450
#define MAX_QPATH
Definition: filesys.h:40
QGL_EXTERN GLint i
Definition: r_gl.h:113
QGL_EXTERN GLuint GLchar GLuint * len
Definition: r_gl.h:99
buckets for sample accumulation - clipped by the surface
Definition: lightmap.cpp:258
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
#define ANGLE_UP
Definition: defines.h:205
vec3_t face_offset[MAX_MAP_FACES]
Definition: lightmap.cpp:34
static void CalcLightinfoVectors(lightinfo_t *l)
Fills in texorg, worldtotex. and textoworld.
Definition: lightmap.cpp:155
vec_t VectorNormalize(vec3_t v)
Calculate unit vector for a given vec3_t.
Definition: mathlib.cpp:745
int numfaces
Definition: typedefs.h:489
uint16_t planenum
Definition: typedefs.h:404
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
int texsize[2]
Definition: lightmap.cpp:51
vec_t FloatForKey(const entity_t *ent, const char *key)
Definition: bspfile.cpp:566
vec3_t mins
Definition: lightmap.cpp:60
float dist
Definition: typedefs.h:374
#define sun_ambient_color
Definition: lightmap.cpp:32
#define Mem_Free(ptr)
Definition: mem.h:35
struct patch_s * next
Definition: lighting.h:43
#define UFO_SIZE_T
Definition: ufotypes.h:89
vec_t vec3_t[3]
Definition: ufotypes.h:39
#define torad
Definition: mathlib.h:50
vec_t vec2_t[2]
Definition: ufotypes.h:38
vec2_t stmins
Definition: lightmap.cpp:62
static void FacesWithVert(int vert, int *faces, int *nfaces)
Populate faces with indexes of all dBspFace_t&#39;s referencing the specified edge.
Definition: lightmap.cpp:641
vec3_t normal
Definition: typedefs.h:366
dBspNormal_t normals[MAX_MAP_VERTS]
Definition: typedefs.h:478
#define Mem_AllocType(type)
Definition: mem.h:39
vec2_t stmaxs
Definition: lightmap.cpp:62
#define Q_streq(a, b)
Definition: shared.h:136
#define LIGHTMAP_MAX
Definition: defines.h:365
int numTiles
Definition: tracing.h:82
const char * ValueForKey(const entity_t *ent, const char *key)
Definition: bspfile.cpp:558
voidpf uLong offset
Definition: ioapi.h:45
float point[3]
Definition: typedefs.h:362
#define SURF_WARP
Definition: defines.h:256
int texmins[2]
Definition: lightmap.cpp:50
int lightofs[LIGHTMAP_MAX]
Definition: typedefs.h:412
dBspPlane_t planes[MAX_MAP_PLANES]
Definition: typedefs.h:475
uint8_t byte
Definition: ufotypes.h:34
QGL_EXTERN int GLboolean GLfloat * v
Definition: r_gl.h:120
int num_entities
Definition: bspfile.cpp:394
#define MAX_VERT_FACES
Definition: lightmap.cpp:633
int numsurfpt
Definition: lightmap.cpp:41
#define ANGLE_DOWN
Definition: defines.h:206
#define VectorSubtract(a, b, dest)
Definition: vector.h:45
static mapTiles_t mapTiles
level_locals_t level
Definition: g_main.cpp:38
#define sun_color
Definition: lightmap.cpp:30
int FS_Write(const void *buffer, int len, qFILE *f)
Properly handles partial writes.
Definition: files.cpp:1513
short numedges
Definition: typedefs.h:408
static const float sampleofs[2][MAX_SAMPLES][2]
Definition: lightmap.cpp:744
vec_t vec4_t[4]
Definition: ufotypes.h:40
#define MAX_MAP_LIGHTMAP
Definition: defines.h:386
dBspSurface_t * face
Definition: lightmap.cpp:55
emittype_t
Different types of sources emitting light.
Definition: lightmap.cpp:267
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