1 /*
2 	gl_lightmap.c
3 
4 	surface-related refresh code
5 
6 	Copyright (C) 1996-1997  Id Software, Inc.
7 	Copyright (C) 2000       Joseph Carter <knghtbrd@debian.org>
8 
9 	This program is free software; you can redistribute it and/or
10 	modify it under the terms of the GNU General Public License
11 	as published by the Free Software Foundation; either version 2
12 	of the License, or (at your option) any later version.
13 
14 	This program is distributed in the hope that it will be useful,
15 	but WITHOUT ANY WARRANTY; without even the implied warranty of
16 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 	See the GNU General Public License for more details.
19 
20 	You should have received a copy of the GNU General Public License
21 	along with this program; if not, write to:
22 
23 		Free Software Foundation, Inc.
24 		59 Temple Place - Suite 330
25 		Boston, MA  02111-1307, USA
26 
27 */
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31 
32 #define NH_DEFINE
33 #include "namehack.h"
34 
35 #ifdef HAVE_STRING_H
36 # include <string.h>
37 #endif
38 #ifdef HAVE_STRINGS_H
39 # include <strings.h>
40 #endif
41 
42 #include <math.h>
43 #include <stdio.h>
44 
45 #include "QF/cvar.h"
46 #include "QF/render.h"
47 #include "QF/sys.h"
48 #include "QF/GL/defines.h"
49 #include "QF/GL/funcs.h"
50 #include "QF/GL/qf_lightmap.h"
51 #include "QF/GL/qf_rmain.h"
52 #include "QF/GL/qf_sky.h"
53 #include "QF/GL/qf_textures.h"
54 #include "QF/GL/qf_vid.h"
55 
56 #include "compat.h"
57 #include "r_internal.h"
58 
59 static int          dlightdivtable[8192];
60 static int			 gl_internalformat;				// 1 or 3
61 static int          lightmap_bytes;				// 1, 3, or 4
62 int          gl_lightmap_textures;
63 
64 // keep lightmap texture data in main memory so texsubimage can update properly
65 // LordHavoc: changed to be allocated at runtime (typically lower memory usage)
66 static byte        *lightmaps[MAX_LIGHTMAPS];
67 
68 static unsigned int blocklights[34 * 34 * 3];	//FIXME make dynamic
69 static int          allocated[MAX_LIGHTMAPS][BLOCK_WIDTH];
70 
71 qboolean	 gl_lightmap_modified[MAX_LIGHTMAPS];
72 instsurf_t	*gl_lightmap_polys[MAX_LIGHTMAPS];
73 glRect_t	 gl_lightmap_rectchange[MAX_LIGHTMAPS];
74 
75 static int	 lmshift = 7;
76 
77 void (*gl_R_BuildLightMap) (msurface_t *surf);
78 
79 extern void gl_multitexture_f (cvar_t *var);
80 
81 
82 void
gl_lightmap_init(void)83 gl_lightmap_init (void)
84 {
85 	int         s;
86 
87 	memset (&lightmaps, 0, sizeof (lightmaps));
88 	dlightdivtable[0] = 1048576 >> 7;
89 	for (s = 1; s < 8192; s++)
90 		dlightdivtable[s] = 1048576 / (s << 7);
91 }
92 /*
93 static void
94 R_RecursiveLightUpdate (mnode_t *node)
95 {
96 	int         c;
97 	msurface_t *surf;
98 
99 	if (node->children[0]->contents >= 0)
100 		R_RecursiveLightUpdate (node->children[0]);
101 	if (node->children[1]->contents >= 0)
102 		R_RecursiveLightUpdate (node->children[1]);
103 	if ((c = node->numsurfaces))
104 		for (surf = r_worldentity.model->surfaces + node->firstsurface; c;
105 			 c--, surf++)
106 			surf->cached_dlight = true;
107 }
108 */
109 static inline void
R_AddDynamicLights_1(msurface_t * surf)110 R_AddDynamicLights_1 (msurface_t *surf)
111 {
112 	float			dist;
113 	unsigned int	maxdist, maxdist2, maxdist3;
114 	int             smax, smax_bytes, tmax,
115 					grey, s, t;
116 	unsigned int	lnum, td, i, j;
117 	unsigned int    sdtable[18];
118 	unsigned int   *bl;
119 	vec3_t			impact, local;
120 
121 	smax = (surf->extents[0] >> 4) + 1;
122 	smax_bytes = smax * gl_internalformat;
123 	tmax = (surf->extents[1] >> 4) + 1;
124 
125 	for (lnum = 0; lnum < r_maxdlights; lnum++) {
126 		if (!(surf->dlightbits[lnum / 32] & (1 << (lnum % 32))))
127 			continue;					// not lit by this light
128 
129 		VectorSubtract (r_dlights[lnum].origin, currententity->origin, local);
130 		dist = DotProduct (local, surf->plane->normal) - surf->plane->dist;
131 		VectorMultSub (r_dlights[lnum].origin, dist, surf->plane->normal,
132 					   impact);
133 
134 		i = DotProduct (impact,	surf->texinfo->vecs[0]) +
135 			surf->texinfo->vecs[0][3] - surf->texturemins[0];
136 
137 		// reduce calculations
138 		t = dist * dist;
139 		for (s = 0; s < smax; s++, i -= 16)
140 			sdtable[s] = i * i + t;
141 
142 		i = DotProduct (impact,	surf->texinfo->vecs[1]) +
143 			surf->texinfo->vecs[1][3] - surf->texturemins[1];
144 
145 		// for comparisons to minimum acceptable light
146 		maxdist = (int) (r_dlights[lnum].radius * r_dlights[lnum].radius);
147 
148 		// clamp radius to avoid exceeding 8192 entry division table
149 		if (maxdist > 1048576)
150 			maxdist = 1048576;
151 		maxdist3 = maxdist - t;
152 
153 		// convert to 8.8 blocklights format
154 		grey = (r_dlights[lnum].color[0] + r_dlights[lnum].color[1] +
155 				r_dlights[lnum].color[2]) * maxdist / 3.0;
156 		bl = blocklights;
157 		for (t = 0; t < tmax; t++, i -= 16) {
158 			td = i * i;
159 			if (td < maxdist3) {		// ensure part is visible on this line
160 				maxdist2 = maxdist - td;
161 				for (s = 0; s < smax; s++) {
162 					if (sdtable[s] < maxdist2) {
163 						j = dlightdivtable[(sdtable[s] + td) >> 7];
164 						*bl++ += (grey * j) >> 7;
165 					} else
166 						bl++;
167 				}
168 			} else
169 				bl += smax_bytes;		// skip line
170 		}
171 	}
172 }
173 
174 static inline void
R_AddDynamicLights_3(msurface_t * surf)175 R_AddDynamicLights_3 (msurface_t *surf)
176 {
177 	float			dist;
178 	unsigned int	maxdist, maxdist2, maxdist3;
179 	int             smax, smax_bytes, tmax,
180 					red, green, blue, s, t;
181 	unsigned int	lnum, td, i, j;
182 	unsigned int    sdtable[18];
183 	unsigned int   *bl;
184 	vec3_t			impact, local;
185 
186 	smax = (surf->extents[0] >> 4) + 1;
187 	smax_bytes = smax * gl_internalformat;
188 	tmax = (surf->extents[1] >> 4) + 1;
189 
190 	for (lnum = 0; lnum < r_maxdlights; lnum++) {
191 		if (!(surf->dlightbits[lnum / 32] & (1 << (lnum % 32))))
192 			continue;					// not lit by this light
193 
194 		VectorSubtract (r_dlights[lnum].origin, currententity->origin, local);
195 		dist = DotProduct (local, surf->plane->normal) - surf->plane->dist;
196 		VectorMultSub (r_dlights[lnum].origin, dist, surf->plane->normal,
197 					   impact);
198 
199 		i = DotProduct (impact,	surf->texinfo->vecs[0]) +
200 			surf->texinfo->vecs[0][3] - surf->texturemins[0];
201 
202 		// reduce calculations
203 		t = dist * dist;
204 		for (s = 0; s < smax; s++, i -= 16)
205 			sdtable[s] = i * i + t;
206 
207 		i = DotProduct (impact,	surf->texinfo->vecs[1]) +
208 			surf->texinfo->vecs[1][3] - surf->texturemins[1];
209 
210 		// for comparisons to minimum acceptable light
211 		maxdist = (int) (r_dlights[lnum].radius * r_dlights[lnum].radius);
212 
213 		// clamp radius to avoid exceeding 8192 entry division table
214 		if (maxdist > 1048576)
215 			maxdist = 1048576;
216 		maxdist3 = maxdist - t;
217 
218 		// convert to 8.8 blocklights format
219 		red = r_dlights[lnum].color[0] * maxdist;
220 		green = r_dlights[lnum].color[1] * maxdist;
221 		blue = r_dlights[lnum].color[2] * maxdist;
222 		bl = blocklights;
223 		for (t = 0; t < tmax; t++, i -= 16) {
224 			td = i * i;
225 			if (td < maxdist3) {		// ensure part is visible on this line
226 				maxdist2 = maxdist - td;
227 				for (s = 0; s < smax; s++) {
228 					if (sdtable[s] < maxdist2) {
229 						j = dlightdivtable[(sdtable[s] + td) >> 7];
230 						*bl++ += (red * j) >> 7;
231 						*bl++ += (green * j) >> 7;
232 						*bl++ += (blue * j) >> 7;
233 					} else
234 						bl += 3;
235 				}
236 			} else
237 				bl += smax_bytes;		// skip line
238 		}
239 	}
240 }
241 
242 static void
R_BuildLightMap_1(msurface_t * surf)243 R_BuildLightMap_1 (msurface_t *surf)
244 {
245 	byte		   *dest;
246 	int				maps, size, stride, smax, tmax, i, j;
247 	unsigned int	scale;
248 	unsigned int   *bl;
249 
250 	surf->cached_dlight = (surf->dlightframe == r_framecount);
251 
252 	smax = (surf->extents[0] >> 4) + 1;
253 	tmax = (surf->extents[1] >> 4) + 1;
254 	size = smax * tmax * gl_internalformat;
255 
256 	// set to full bright if no light data
257 	if (!r_worldentity.model->lightdata) {
258 		memset (&blocklights[0], 0xff, size * sizeof(int));
259 		goto store;
260 	}
261 
262 	// clear to no light
263 	memset (&blocklights[0], 0, size * sizeof(int));
264 
265 	// add all the lightmaps
266 	if (surf->samples) {
267 		byte		   *lightmap;
268 
269 		lightmap = surf->samples;
270 		for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255;
271 			 maps++) {
272 			scale = d_lightstylevalue[surf->styles[maps]];
273 			surf->cached_light[maps] = scale;					// 8.8 fraction
274 			bl = blocklights;
275 			for (i = 0; i < size; i++) {
276 				*bl++ += *lightmap++ * scale;
277 			}
278 		}
279 	}
280 	// add all the dynamic lights
281 	if (surf->dlightframe == r_framecount)
282 		R_AddDynamicLights_1 (surf);
283 
284   store:
285 	// bound and shift
286 	// Also, invert because we're using a diff blendfunc now
287 
288 	stride = (BLOCK_WIDTH - smax) * lightmap_bytes;
289 	bl = blocklights;
290 
291 	dest = lightmaps[surf->lightmaptexturenum]
292 			+ (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes;
293 
294 	for (i = 0; i < tmax; i++, dest += stride) {
295 		for (j = smax; j; j--) {
296 			*dest++ = min (*bl >> lmshift, 255);
297 			bl++;
298 		}
299 	}
300 }
301 
302 static void
R_BuildLightMap_3(msurface_t * surf)303 R_BuildLightMap_3 (msurface_t *surf)
304 {
305 	byte		   *dest;
306 	int				maps, size, stride, smax, tmax, i, j;
307 	unsigned int	scale;
308 	unsigned int   *bl;
309 
310 	surf->cached_dlight = (surf->dlightframe == r_framecount);
311 
312 	smax = (surf->extents[0] >> 4) + 1;
313 	tmax = (surf->extents[1] >> 4) + 1;
314 	size = smax * tmax * gl_internalformat;
315 
316 	// set to full bright if no light data
317 	if (!r_worldentity.model->lightdata) {
318 		memset (&blocklights[0], 0xff, size * sizeof(int));
319 		goto store;
320 	}
321 
322 	// clear to no light
323 	memset (&blocklights[0], 0, size * sizeof(int));
324 
325 	// add all the lightmaps
326 	if (surf->samples) {
327 		byte		   *lightmap;
328 
329 		lightmap = surf->samples;
330 		for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255;
331 			 maps++) {
332 			scale = d_lightstylevalue[surf->styles[maps]];
333 			surf->cached_light[maps] = scale;					// 8.8 fraction
334 			bl = blocklights;
335 			for (i = 0; i < smax * tmax; i++) {
336 				*bl++ += *lightmap++ * scale;
337 				*bl++ += *lightmap++ * scale;
338 				*bl++ += *lightmap++ * scale;
339 			}
340 		}
341 	}
342 	// add all the dynamic lights
343 	if (surf->dlightframe == r_framecount)
344 		R_AddDynamicLights_3 (surf);
345 
346   store:
347 	// bound and shift
348 	// and invert too
349 	stride = (BLOCK_WIDTH - smax) * lightmap_bytes;
350 	bl = blocklights;
351 
352 	dest = lightmaps[surf->lightmaptexturenum]
353 			+ (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes;
354 
355 	for (i = 0; i < tmax; i++, dest += stride) {
356 		for (j = 0; j < smax; j++) {
357 			*dest++ = min (*bl >> lmshift, 255);
358 			bl++;
359 			*dest++ = min (*bl >> lmshift, 255);
360 			bl++;
361 			*dest++ = min (*bl >> lmshift, 255);
362 			bl++;
363 		}
364 	}
365 }
366 
367 static void
R_BuildLightMap_4(msurface_t * surf)368 R_BuildLightMap_4 (msurface_t *surf)
369 {
370 	byte		   *dest;
371 	int				maps, size, smax, tmax, i, j, stride;
372 	unsigned int	scale;
373 	unsigned int   *bl;
374 
375 	surf->cached_dlight = (surf->dlightframe == r_framecount);
376 
377 	smax = (surf->extents[0] >> 4) + 1;
378 	tmax = (surf->extents[1] >> 4) + 1;
379 	size = smax * tmax * gl_internalformat;
380 
381 	// set to full bright if no light data
382 	if (!r_worldentity.model->lightdata) {
383 		memset (&blocklights[0], 0xff, size * sizeof(int));
384 		goto store;
385 	}
386 
387 	// clear to no light
388 	memset (&blocklights[0], 0, size * sizeof(int));
389 
390 	// add all the lightmaps
391 	if (surf->samples) {
392 		byte		   *lightmap;
393 
394 		lightmap = surf->samples;
395 		for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255;
396 			 maps++) {
397 			scale = d_lightstylevalue[surf->styles[maps]];
398 			surf->cached_light[maps] = scale;					// 8.8 fraction
399 			bl = blocklights;
400 			for (i = 0; i < smax * tmax; i++) {
401 				*bl++ += *lightmap++ * scale;
402 				*bl++ += *lightmap++ * scale;
403 				*bl++ += *lightmap++ * scale;
404 			}
405 		}
406 	}
407 	// add all the dynamic lights
408 	if (surf->dlightframe == r_framecount)
409 		R_AddDynamicLights_3 (surf);
410 
411   store:
412 	// bound and shift
413 	// and invert too
414 	stride = (BLOCK_WIDTH - smax) * lightmap_bytes;
415 	bl = blocklights;
416 
417 	dest = lightmaps[surf->lightmaptexturenum]
418 			+ (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes;
419 
420 	for (i = 0; i < tmax; i++, dest += stride) {
421 		for (j = 0; j < smax; j++) {
422 			*dest++ = min (*bl >> lmshift, 255);
423 			bl++;
424 			*dest++ = min (*bl >> lmshift, 255);
425 			bl++;
426 			*dest++ = min (*bl >> lmshift, 255);
427 			bl++;
428 			*dest++ = 255;
429 		}
430 	}
431 }
432 
433 // BRUSH MODELS ===============================================================
434 
435 static inline void
do_subimage_2(int i)436 do_subimage_2 (int i)
437 {
438 	byte       *block, *lm, *b;
439 	int         stride, width;
440 	glRect_t   *rect = &gl_lightmap_rectchange[i];
441 
442 	width = rect->w * lightmap_bytes;
443 	stride = BLOCK_WIDTH * lightmap_bytes;
444 	b = block = Hunk_TempAlloc (rect->h * width);
445 	lm = lightmaps[i] + (rect->t * BLOCK_WIDTH + rect->l) * lightmap_bytes;
446 	for (i = rect->h; i > 0; i--) {
447 		memcpy (b, lm, width);
448 		b += width;
449 		lm += stride;
450 	}
451 	qfglTexSubImage2D (GL_TEXTURE_2D, 0, rect->l, rect->t, rect->w, rect->h,
452 					   gl_lightmap_format, GL_UNSIGNED_BYTE, block);
453 }
454 
455 static void
GL_UploadLightmap(int i)456 GL_UploadLightmap (int i)
457 {
458 	switch (gl_lightmap_subimage->int_val) {
459 	case 2:
460 		do_subimage_2 (i);
461 		break;
462 	case 1:
463 		qfglTexSubImage2D (GL_TEXTURE_2D, 0, 0, gl_lightmap_rectchange[i].t,
464 						   BLOCK_WIDTH, gl_lightmap_rectchange[i].h,
465 						   gl_lightmap_format, GL_UNSIGNED_BYTE,
466 						   lightmaps[i] + (gl_lightmap_rectchange[i].t *
467 										   BLOCK_WIDTH) * lightmap_bytes);
468 		break;
469 	default:
470 	case 0:
471 		qfglTexImage2D (GL_TEXTURE_2D, 0, gl_internalformat, BLOCK_WIDTH,
472 						BLOCK_HEIGHT, 0, gl_lightmap_format, GL_UNSIGNED_BYTE,
473 						lightmaps[i]);
474 		break;
475 	}
476 }
477 
478 void
gl_R_CalcLightmaps(void)479 gl_R_CalcLightmaps (void)
480 {
481 	int         i;
482 
483 	for (i = 0; i < MAX_LIGHTMAPS; i++) {
484 		if (!gl_lightmap_polys[i])
485 			continue;
486 		if (gl_lightmap_modified[i]) {
487 			qfglBindTexture (GL_TEXTURE_2D, gl_lightmap_textures + i);
488 			GL_UploadLightmap (i);
489 			gl_lightmap_modified[i] = false;
490 		}
491 	}
492 }
493 
494 void
gl_R_BlendLightmaps(void)495 gl_R_BlendLightmaps (void)
496 {
497 	float      *v;
498 	int         i, j;
499 	instsurf_t *sc;
500 	glpoly_t   *p;
501 
502 	qfglDepthMask (GL_FALSE);					// don't bother writing Z
503 	qfglBlendFunc (lm_src_blend, lm_dest_blend);
504 
505 	for (i = 0; i < MAX_LIGHTMAPS; i++) {
506 		for (sc = gl_lightmap_polys[i]; sc; sc = sc->lm_chain) {
507 			qfglBindTexture (GL_TEXTURE_2D, gl_lightmap_textures + i);
508 			if (sc->transform) {
509 				qfglPushMatrix ();
510 				qfglLoadMatrixf (sc->transform);
511 			}
512 			for (p = sc->surface->polys; p; p = p->next) {
513 				qfglBegin (GL_POLYGON);
514 				v = p->verts[0];
515 				for (j = 0; j < p->numverts; j++, v += VERTEXSIZE) {
516 					qfglTexCoord2fv (&v[5]);
517 					qfglVertex3fv (v);
518 				}
519 				qfglEnd ();
520 			}
521 			if (sc->transform)
522 				qfglPopMatrix ();
523 		}
524 	}
525 
526 	// Return to normal blending  --KB
527 	qfglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
528 	qfglDepthMask (GL_TRUE);					// back to normal Z buffering
529 }
530 
531 void
gl_overbright_f(cvar_t * var)532 gl_overbright_f (cvar_t *var)
533 {
534 	int			 num, i, j;
535 	model_t		*m;
536 	msurface_t  *fa;
537 	entity_t    *ent;
538 
539 	if (!var)
540 		return;
541 
542 	if (var->int_val) {
543 		if (!gl_combine_capable && gl_mtex_capable) {
544 			Sys_Printf ("Warning: gl_overbright has no effect with "
545 						"gl_multitexture enabled if you don't have "
546 						"GL_COMBINE support in your driver.\n");
547 			lm_src_blend = GL_ZERO;
548 			lm_dest_blend = GL_SRC_COLOR;
549 			lmshift = 7;
550 			gl_rgb_scale = 1.0;
551 		} else {
552 			lm_src_blend = GL_DST_COLOR;
553 			lm_dest_blend = GL_SRC_COLOR;
554 
555 			switch (var->int_val) {
556 			case 2:
557 				lmshift = 9;
558 				gl_rgb_scale = 4.0;
559 				break;
560 			case 1:
561 				lmshift = 8;
562 				gl_rgb_scale = 2.0;
563 				break;
564 			default:
565 				lmshift = 7;
566 				gl_rgb_scale = 1.0;
567 				break;
568 			}
569 		}
570 	} else {
571 		lm_src_blend = GL_ZERO;
572 		lm_dest_blend = GL_SRC_COLOR;
573 		lmshift = 7;
574 		gl_rgb_scale = 1.0;
575 	}
576 
577 	if (gl_multitexture)
578 		gl_multitexture_f (gl_multitexture);
579 
580 	if (!gl_R_BuildLightMap)
581 		return;
582 
583 	for (ent = r_ent_queue; ent; ent = ent->next) {
584 		m = ent->model;
585 
586 		if (m->type != mod_brush)
587 			continue;
588 		if (m->name[0] == '*')
589 			continue;
590 
591 		for (j = 0, fa = m->surfaces; j < m->numsurfaces; j++, fa++) {
592 			if (fa->flags & (SURF_DRAWTURB | SURF_DRAWSKY))
593 				continue;
594 
595 			num = fa->lightmaptexturenum;
596 			gl_lightmap_modified[num] = true;
597 			gl_lightmap_rectchange[num].l = 0;
598 			gl_lightmap_rectchange[num].t = 0;
599 			gl_lightmap_rectchange[num].w = BLOCK_WIDTH;
600 			gl_lightmap_rectchange[num].h = BLOCK_HEIGHT;
601 
602 			gl_R_BuildLightMap (fa);
603 		}
604 	}
605 
606 	m = r_worldentity.model;
607 
608 	for (i = 0, fa = m->surfaces; i < m->numsurfaces; i++, fa++) {
609 		if (fa->flags & (SURF_DRAWTURB | SURF_DRAWSKY))
610 			continue;
611 
612 		num = fa->lightmaptexturenum;
613 		gl_lightmap_modified[num] = true;
614 		gl_lightmap_rectchange[num].l = 0;
615 		gl_lightmap_rectchange[num].t = 0;
616 		gl_lightmap_rectchange[num].w = BLOCK_WIDTH;
617 		gl_lightmap_rectchange[num].h = BLOCK_HEIGHT;
618 
619 		gl_R_BuildLightMap (fa);
620 	}
621 }
622 
623 // LIGHTMAP ALLOCATION ========================================================
624 
625 // returns a texture number and the position inside it
626 static int
AllocBlock(int w,int h,int * x,int * y)627 AllocBlock (int w, int h, int *x, int *y)
628 {
629 	int         best, best2, texnum, i, j;
630 
631 	for (texnum = 0; texnum < MAX_LIGHTMAPS; texnum++) {
632 		best = BLOCK_HEIGHT;
633 
634 		for (i = 0; i < BLOCK_WIDTH - w; i++) {
635 			best2 = 0;
636 
637 			for (j = 0; j < w; j++) {
638 				if (allocated[texnum][i + j] >= best)
639 					break;
640 				if (allocated[texnum][i + j] > best2)
641 					best2 = allocated[texnum][i + j];
642 			}
643 			if (j == w) {
644 				// this is a valid spot
645 				*x = i;
646 				*y = best = best2;
647 			}
648 		}
649 
650 		if (best + h > BLOCK_HEIGHT)
651 			continue;
652 
653 		// LordHavoc: allocate lightmaps only as needed
654 		if (!lightmaps[texnum])
655 			lightmaps[texnum] = calloc (BLOCK_WIDTH * BLOCK_HEIGHT,
656 										lightmap_bytes);
657 		for (i = 0; i < w; i++)
658 			allocated[texnum][*x + i] = best + h;
659 
660 		return texnum;
661 	}
662 
663 	Sys_Error ("AllocBlock: full");
664 	return 0;
665 }
666 
667 static void
GL_CreateSurfaceLightmap(msurface_t * surf)668 GL_CreateSurfaceLightmap (msurface_t *surf)
669 {
670 	int         smax, tmax;
671 
672 	if (surf->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
673 		return;
674 
675 	smax = (surf->extents[0] >> 4) + 1;
676 	tmax = (surf->extents[1] >> 4) + 1;
677 
678 	surf->lightmaptexturenum =
679 		AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
680 	gl_R_BuildLightMap (surf);
681 }
682 
683 /*
684   GL_BuildLightmaps
685 
686   Builds the lightmap texture with all the surfaces from all brush models
687 */
688 void
GL_BuildLightmaps(model_t ** models,int num_models)689 GL_BuildLightmaps (model_t **models, int num_models)
690 {
691 	int         i, j;
692 	model_t    *m;
693 
694 	memset (allocated, 0, sizeof (allocated));
695 
696 	r_framecount = 1;					// no dlightcache
697 
698 	if (!gl_lightmap_textures) {
699 		gl_lightmap_textures = gl_texture_number;
700 		gl_texture_number += MAX_LIGHTMAPS;
701 	}
702 
703 	switch (r_lightmap_components->int_val) {
704 	case 1:
705 		gl_internalformat = 1;
706 		gl_lightmap_format = GL_LUMINANCE;
707 		lightmap_bytes = 1;
708 		gl_R_BuildLightMap = R_BuildLightMap_1;
709 		break;
710 	case 3:
711 		gl_internalformat = 3;
712 		if (gl_use_bgra)
713 			gl_lightmap_format = GL_BGR;
714 		else
715 			gl_lightmap_format = GL_RGB;
716 		lightmap_bytes = 3;
717 		gl_R_BuildLightMap = R_BuildLightMap_3;
718 		break;
719 	case 4:
720 	default:
721 		gl_internalformat = 3;
722 		if (gl_use_bgra)
723 			gl_lightmap_format = GL_BGRA;
724 		else
725 			gl_lightmap_format = GL_RGBA;
726 		lightmap_bytes = 4;
727 		gl_R_BuildLightMap = R_BuildLightMap_4;
728 		break;
729 	}
730 
731 	for (j = 1; j < num_models; j++) {
732 		m = models[j];
733 		if (!m)
734 			break;
735 		if (m->name[0] == '*') {
736 			// sub model surfaces are processed as part of the main model
737 			continue;
738 		}
739 		r_pcurrentvertbase = m->vertexes;
740 		gl_currentmodel = m;
741 		// non-bsp models don't have surfaces.
742 		for (i = 0; i < m->numsurfaces; i++) {
743 			if (m->surfaces[i].flags & SURF_DRAWTURB)
744 				continue;
745 			if (gl_sky_divide->int_val && (m->surfaces[i].flags &
746 										   SURF_DRAWSKY))
747 				continue;
748 			GL_CreateSurfaceLightmap (m->surfaces + i);
749 			GL_BuildSurfaceDisplayList (m->surfaces + i);
750 		}
751 	}
752 
753 	// upload all lightmaps that were filled
754 	for (i = 0; i < MAX_LIGHTMAPS; i++) {
755 		if (!allocated[i][0])
756 			break;						// no more used
757 		gl_lightmap_modified[i] = false;
758 		gl_lightmap_rectchange[i].l = BLOCK_WIDTH;
759 		gl_lightmap_rectchange[i].t = BLOCK_HEIGHT;
760 		gl_lightmap_rectchange[i].w = 0;
761 		gl_lightmap_rectchange[i].h = 0;
762 		qfglBindTexture (GL_TEXTURE_2D, gl_lightmap_textures + i);
763 		qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
764 		qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
765 		if (gl_Anisotropy)
766 			qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
767 							   gl_aniso);
768 		qfglTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes, BLOCK_WIDTH,
769 						BLOCK_HEIGHT, 0, gl_lightmap_format,
770 						GL_UNSIGNED_BYTE, lightmaps[i]);
771 	}
772 }
773