1 /*
2 Copyright (C) 2003-2006 Andrey Nazarov
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 
21 /*
22  * gl_surf.c -- surface post-processing code
23  *
24  */
25 #include "gl_local.h"
26 
27 lightmapBuilder_t lm;
28 
29 static cvar_t *gl_coloredlightmaps;
30 static cvar_t *gl_brightness;
31 
32 cvar_t *gl_modulate_hack;
33 
34 /*
35 =============================================================================
36 
37 LIGHTMAP TEXTURES BUILDING
38 
39 =============================================================================
40 */
41 
42 static float colorScale, brightness;
43 
LM_AllocBlock(int w,int h,int * s,int * t)44 static qboolean LM_AllocBlock( int w, int h, int *s, int *t ) {
45     int i, j;
46     int x, y, maxInuse, minInuse;
47 
48 	x = 0; y = LM_BLOCK_HEIGHT;
49     minInuse = LM_BLOCK_HEIGHT;
50     for( i = 0; i < LM_BLOCK_WIDTH - w; i++ ) {
51         maxInuse = 0;
52         for( j = 0; j < w; j++ ) {
53             if( lm.inuse[ i + j ] >= minInuse ) {
54                 break;
55             }
56             if( maxInuse < lm.inuse[ i + j ] ) {
57                 maxInuse = lm.inuse[ i + j ];
58             }
59         }
60         if( j == w ) {
61             x = i;
62             y = minInuse = maxInuse;
63         }
64     }
65 
66     if( y + h > LM_BLOCK_HEIGHT ) {
67         return qfalse;
68     }
69 
70     for( i = 0; i < w; i++ ) {
71         lm.inuse[ x + i ] = y + h;
72     }
73 
74     *s = x;
75     *t = y;
76     return qtrue;
77 }
78 
LM_InitBlock(void)79 static void LM_InitBlock( void ) {
80     int i;
81 
82     for( i = 0; i < LM_BLOCK_WIDTH; i++ ) {
83         lm.inuse[i] = 0;
84     }
85 }
86 
LM_UploadBlock(void)87 static void LM_UploadBlock( void ) {
88     /* lightmap images would be automatically freed
89 	 * by R_FreeUnusedImages on next level load */
90     GL_SelectTMU( 1 );
91     lm.lightmaps[lm.numMaps] = R_CreateImage( va( "*lightmap%d", lm.numMaps ),
92             lm.buffer, LM_BLOCK_WIDTH, LM_BLOCK_HEIGHT,
93                 it_lightmap, if_auto );
94     qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
95     qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
96     lm.numMaps++;
97     GL_SelectTMU( 0 );
98 }
99 
LM_BuildSurfaceLightmap(bspSurface_t * surf)100 static int LM_BuildSurfaceLightmap( bspSurface_t *surf ) {
101     byte *ptr, *dst, *src;
102     int i, j;
103     bspPoly_t *poly;
104     vec_t *vert;
105     int smax, tmax, s, t;
106 
107     smax = ( surf->extents[0] >> 4 ) + 1;
108     tmax = ( surf->extents[1] >> 4 ) + 1;
109 
110     if( !LM_AllocBlock( smax, tmax, &s, &t ) ) {
111         LM_UploadBlock();
112         if( lm.numMaps == LM_MAX_LIGHTMAPS ) {
113             Com_EPrintf( "LM_MAX_LIGHTMAPS exceeded\n" );
114             return -1;
115         }
116         LM_InitBlock();
117         if( !LM_AllocBlock( smax, tmax, &s, &t ) ) {
118             Com_EPrintf( "LM_AllocBlock( %d, %d ) failed\n",
119                     smax, tmax );
120             return -1;
121         }
122     }
123 
124     src = surf->lightmap;
125     dst = &lm.buffer[ ( t * LM_BLOCK_WIDTH + s ) << 2 ];
126 
127     for( i = 0; i < tmax; i++ ) {
128         ptr = dst;
129         for( j = 0; j < smax; j++ ) {
130 			float r, g, b, min, max, mid;
131 
132 			r = src[0];
133 			g = src[1];
134 			b = src[2];
135 
136 			if( colorScale != 1.0f ) {
137 			min = max = r;
138 				if ( g < min ) min = g;
139 				if ( b < min ) min = b;
140 				if ( g > max ) max = g;
141 				if ( b > max ) max = b;
142 				mid = 0.5 * ( min + max );
143 				r = mid + ( r - mid ) * colorScale;
144 				g = mid + ( g - mid ) * colorScale;
145 				b = mid + ( b - mid ) * colorScale;
146 			}
147 
148 			if( !gl_modulate_hack->integer ) {
149 				r *= gl_modulate->value;
150 				g *= gl_modulate->value;
151 				b *= gl_modulate->value;
152 			}
153 
154 			max = g;
155 			if( r > max ) {
156 				max = r;
157 			}
158 			if( b > max ) {
159 				max = b;
160 			}
161 
162 			if( max > 255 ) {
163 				r *= 255.0f / max;
164 				g *= 255.0f / max;
165 				b *= 255.0f / max;
166 			}
167 
168 			//atu brightness adjustments
169 			brightness = 255.0f * gl_brightness->value;
170 			r += brightness;
171 			g += brightness;
172 			b += brightness;
173 			if ( r > 255.0f ) r = 255.0f;
174 			else if ( r < 0.0f ) r = 0.0f;
175 			if ( g > 255.0f ) g = 255.0f;
176 			else if ( g < 0.0f ) g = 0.0f;
177 			if ( b > 255.0f ) b = 255.0f;
178 			else if ( b < 0.0f ) b = 0.0f;
179 
180 			src[0] = r;
181 			src[1] = g;
182 			src[2] = b;
183 
184 			ptr[0] = src[0];
185             ptr[1] = src[1];
186             ptr[2] = src[2];
187             ptr[3] = 255;
188 
189             src += 3; ptr += 4;
190         }
191         dst += LM_BLOCK_WIDTH * 4;
192     }
193 
194     surf->lightmapnum = lm.numMaps + 1;
195 
196     s = ( s << 4 ) + 8;
197     t = ( t << 4 ) + 8;
198 
199     poly = surf->polys;
200     vert = poly->vertices;
201     for( i = 0; i < poly->numVerts; i++ ) {
202         vert[5] = vert[3] - surf->texturemins[0] + s;
203         vert[6] = vert[4] - surf->texturemins[1] + t;
204         vert[5] /= LM_BLOCK_WIDTH * 16;
205         vert[6] /= LM_BLOCK_HEIGHT * 16;
206         vert += VERTEX_SIZE;
207     }
208 
209     return 0;
210 }
211 
212 /*
213 =============================================================================
214 
215 POLYGONS BUILDING
216 
217 =============================================================================
218 */
219 
GL_CalcSurfaceExtents(bspSurface_t * surf)220 static void GL_CalcSurfaceExtents( bspSurface_t *surf ) {
221 	vec2_t mins, maxs;
222     int bmins[2], bmaxs[2];
223 	int i;
224     bspPoly_t *poly = surf->polys;
225     vec_t *vert;
226 
227 	mins[0] = mins[1] = 99999;
228 	maxs[0] = maxs[1] = -99999;
229 
230     vert = poly->vertices;
231 	for( i = 0; i < poly->numVerts; i++ ) {
232 		if( mins[0] > vert[3] ) mins[0] = vert[3];
233 		if( maxs[0] < vert[3] ) maxs[0] = vert[3];
234 
235 		if( mins[1] > vert[4] ) mins[1] = vert[4];
236 		if( maxs[1] < vert[4] ) maxs[1] = vert[4];
237 
238 		vert += VERTEX_SIZE;
239 	}
240 
241     bmins[0] = floor( mins[0] / 16 );
242     bmins[1] = floor( mins[1] / 16 );
243     bmaxs[0] = ceil( maxs[0] / 16 );
244     bmaxs[1] = ceil( maxs[1] / 16 );
245 
246 	surf->texturemins[0] = bmins[0] << 4;
247 	surf->texturemins[1] = bmins[1] << 4;
248 
249 	surf->extents[0] = ( bmaxs[0] - bmins[0] ) << 4;
250 	surf->extents[1] = ( bmaxs[1] - bmins[1] ) << 4;
251 
252 }
253 
254 #define NOLIGHT_MASK \
255     (SURF_SKY|SURF_WARP|SURF_TRANS33|SURF_TRANS66)
256 
GL_BuildSurfacePoly(bspSurface_t * surf)257 static int GL_BuildSurfacePoly( bspSurface_t *surf ) {
258 	int *src_surfedge;
259 	dvertex_t *src_vert;
260 	dedge_t *src_edge;
261 	vec_t *dst_vert;
262 	bspTexinfo_t *texinfo;
263 	bspPoly_t *poly;
264 	int i;
265 	int index, vertIndex;
266     int numEdges = surf->numSurfEdges;
267 
268 	poly = sys.HunkAlloc( &r_world.pool, sizeof( *poly ) +
269             sizeof( vec_t ) * VERTEX_SIZE * ( numEdges - 1 ) );
270 	poly->next = NULL;
271 	poly->numVerts = numEdges;
272 	poly->numIndices = ( numEdges - 2 ) * 3;
273     surf->polys = poly;
274 
275 	texinfo = surf->texinfo;
276 	if( !surf->lightmap || ( texinfo->flags & NOLIGHT_MASK ) ||
277             gl_fullbright->integer )
278     {
279 		surf->type = DSURF_NOLM;
280 	} else {
281 		surf->type = DSURF_POLY;
282 	}
283 
284 	src_surfedge = surf->firstSurfEdge;
285 	dst_vert = poly->vertices;
286 	for( i = 0; i < numEdges; i++ ) {
287 		index = *src_surfedge++;
288 
289 		vertIndex = 0;
290 		if( index < 0 ) {
291 			index = -index;
292 			vertIndex = 1;
293 		}
294 
295 		if( index >= r_world.numEdges ) {
296 			printf( "LoadFace: bad edge index" );
297 			return -1;
298 		}
299 
300 		src_edge = r_world.edges + index;
301 		src_vert = r_world.vertices + src_edge->v[vertIndex];
302 
303 		VectorCopy( src_vert->point, dst_vert );
304 
305 		/* texture coordinates */
306 		dst_vert[3] = DotProduct( dst_vert, texinfo->axis[0] ) +
307             texinfo->offset[0];
308 		dst_vert[4] = DotProduct( dst_vert, texinfo->axis[1] ) +
309             texinfo->offset[1];
310 
311         /* lightmap coordinates */
312         dst_vert[5] = 0;
313         dst_vert[6] = 0;
314 
315 		dst_vert += VERTEX_SIZE;
316 	}
317 
318     return 0;
319 
320 }
321 
322 #define SUBDIVIDE_SIZE  64
323 #define SUBDIVIDE_VERTS 64
324 
325 static bspSurface_t *warpsurf;
326 
BoundPolygon(int numVerts,const vec_t * verts,vec3_t mins,vec3_t maxs)327 static void BoundPolygon( int numVerts, const vec_t *verts,
328         vec3_t mins, vec3_t maxs )
329 {
330     ClearBounds( mins, maxs );
331 
332     while( numVerts-- ) {
333         AddPointToBounds( verts, mins, maxs );
334         verts += 3;
335     }
336 }
337 
338 
SubdividePolygon_r(int numVerts,vec_t * verts)339 static void SubdividePolygon_r( int numVerts, vec_t *verts ) {
340     int i, j;
341     vec3_t front[SUBDIVIDE_VERTS];
342     vec3_t back[SUBDIVIDE_VERTS];
343     vec_t dist[SUBDIVIDE_VERTS];
344     vec3_t mins, maxs;
345     int f, b;
346     vec_t mid, frac, scale, *v;
347     bspPoly_t *poly;
348     vec3_t total;
349     vec_t total_s, total_t;
350     bspTexinfo_t *texinfo;
351 
352     if( numVerts > SUBDIVIDE_VERTS - 4 ) {
353         Com_Error( ERR_DROP, "SubdividePolygon_r: numVerts = %d", numVerts );
354     }
355 
356     BoundPolygon( numVerts, verts, mins, maxs );
357 
358     for( i = 0; i < 3; i++ ) {
359         mid = ( mins[i] + maxs[i] ) * 0.5f;
360         mid = SUBDIVIDE_SIZE * floor( mid / SUBDIVIDE_SIZE + 0.5f );
361         if( mid - mins[i] < 8 ) {
362             continue;
363         }
364         if( maxs[i] - mid < 8 ) {
365             continue;
366         }
367 
368         v = verts + i;
369         for( j = 0; j < numVerts; j++, v += 3 ) {
370             dist[j] = *v - mid;
371         }
372 
373         dist[j] = dist[0];
374         VectorCopy( verts, v - i );
375 
376         f = b = 0;
377         v = verts;
378         for( j = 0; j < numVerts; j++, v += 3 ) {
379             if( dist[j] >= 0 ) {
380                 VectorCopy( v, front[f] ); f++;
381             }
382             if( dist[j] <= 0 ) {
383                 VectorCopy( v, back[b] ); b++;
384             }
385             if( dist[j] == 0 || dist[j+1] == 0 ) {
386                 continue;
387             }
388             if( ( dist[j] > 0 ) != ( dist[j+1] > 0 ) ) {
389                 frac = dist[j] / ( dist[j] - dist[j+1] );
390                 front[f][0] = back[b][0] = v[0] + frac * ( v[3+0] - v[0] );
391                 front[f][1] = back[b][1] = v[1] + frac * ( v[3+1] - v[1] );
392                 front[f][2] = back[b][2] = v[2] + frac * ( v[3+2] - v[2] );
393                 f++; b++;
394             }
395         }
396 
397         SubdividePolygon_r( f, front[0] );
398         SubdividePolygon_r( b, back[0] );
399         return;
400     }
401 
402     poly = sys.HunkAlloc( &r_world.pool, sizeof( *poly ) +
403             sizeof( vec_t ) * VERTEX_SIZE * numVerts );
404     poly->next = warpsurf->polys;
405     poly->numVerts = numVerts + 1;
406     poly->numIndices = numVerts * 3;
407     warpsurf->polys = poly;
408 
409     texinfo = warpsurf->texinfo;
410     VectorClear( total );
411     total_s = total_t = 0;
412     v = poly->vertices + VERTEX_SIZE;
413     for( i = 0; i < numVerts; i++ ) {
414         VectorCopy( verts, v );
415         v[3] = DotProduct( verts, texinfo->axis[0] );
416         v[4] = DotProduct( verts, texinfo->axis[1] );
417         total_s += v[3];
418         total_t += v[4];
419         VectorAdd( total, verts, total );
420         verts += 3; v += VERTEX_SIZE;
421     }
422 
423     /* middle point */
424     v = poly->vertices;
425     scale = 1.0f / numVerts;
426     VectorScale( total, scale, v );
427     v[3] = total_s * scale;
428     v[4] = total_t * scale;
429 
430 }
431 
GL_BuildSurfaceWarpPolys(bspSurface_t * surf)432 static int GL_BuildSurfaceWarpPolys( bspSurface_t *surf ) {
433 	int *src_surfedge;
434 	dvertex_t *src_vert;
435 	dedge_t *src_edge;
436 	vec_t *dst_vert;
437 	int i;
438 	int index, vertIndex;
439     int numEdges = surf->numSurfEdges;
440     vec3_t verts[SUBDIVIDE_VERTS];
441 
442     surf->polys = NULL;
443     surf->type = DSURF_WARP;
444     warpsurf = surf;
445 
446 	src_surfedge = surf->firstSurfEdge;
447     dst_vert = verts[0];
448 	for( i = 0; i < numEdges; i++ ) {
449 		index = *src_surfedge++;
450 
451 		vertIndex = 0;
452 		if( index < 0 ) {
453 			index = -index;
454 			vertIndex = 1;
455 		}
456 
457 		if( index >= r_world.numEdges ) {
458 			printf( "LoadFace: bad edge index" );
459 			return -1;
460 		}
461 
462 		src_edge = r_world.edges + index;
463 		src_vert = r_world.vertices + src_edge->v[vertIndex];
464 
465 		VectorCopy( src_vert->point, dst_vert );
466 
467 		dst_vert += 3;
468 	}
469 
470     SubdividePolygon_r( numEdges, verts[0] );
471 
472     return 0;
473 
474 }
475 
GL_NormalizeSurfaceTexcoords(bspSurface_t * surf)476 static void GL_NormalizeSurfaceTexcoords( bspSurface_t *surf ) {
477     bspTexinfo_t *texinfo = surf->texinfo;
478     bspPoly_t *poly = surf->polys;
479     vec_t *vert;
480     tcoord_t *tc;
481     int i;
482     vec2_t scale;
483 
484     surf->normalizedTC = sys.HunkAlloc( &r_world.pool, sizeof( tcoord_t ) * poly->numVerts );
485 
486     scale[0] = 1.0f / texinfo->image->width;
487     scale[1] = 1.0f / texinfo->image->height;
488 
489     tc = surf->normalizedTC;
490     vert = poly->vertices;
491     for( i = 0; i < poly->numVerts; i++ ) {
492         vert[3] *= scale[0];
493         vert[4] *= scale[1];
494         tc->st[0] = DotProduct( vert, texinfo->normalizedAxis[0] );
495         tc->st[1] = DotProduct( vert, texinfo->normalizedAxis[1] );
496 
497         vert += VERTEX_SIZE; tc++;
498     }
499 }
500 
GL_PostProcessSurface(bspSurface_t * surf)501 int GL_PostProcessSurface( bspSurface_t *surf ) {
502 	bspTexinfo_t *texinfo = surf->texinfo;
503 
504     if( texinfo->flags & SURF_SKY ) {
505     }
506     if( ( texinfo->flags & SURF_WARP ) && gl_subdivide->integer ) {
507         if( GL_BuildSurfaceWarpPolys( surf ) ) {
508             return -1;
509         }
510     } else {
511         if( GL_BuildSurfacePoly( surf ) ) {
512             return -1;
513         }
514         GL_CalcSurfaceExtents( surf );
515     }
516 
517     if( surf->type == DSURF_POLY ) {
518         if( LM_BuildSurfaceLightmap( surf ) ) {
519             return -1;
520         }
521     }
522 
523     if( !( texinfo->flags & (SURF_SKY|SURF_WARP) ) ) {
524         GL_NormalizeSurfaceTexcoords( surf );
525     }
526 
527     if( ( texinfo->flags & SURF_WARP ) && !gl_subdivide->integer ) {
528         GL_NormalizeSurfaceTexcoords( surf );
529     }
530 
531     return 0;
532 }
533 
GL_BeginPostProcessing(void)534 void GL_BeginPostProcessing( void ) {
535     lm.numMaps = 0;
536     LM_InitBlock();
537 
538 	gl_coloredlightmaps = cvar.Get( "gl_coloredlightmaps", "1",
539         CVAR_ARCHIVE|CVAR_LATCHED );
540 	gl_brightness = cvar.Get( "gl_brightness", "0",
541         CVAR_ARCHIVE|CVAR_LATCHED );
542 	gl_modulate_hack = cvar.Get( "gl_modulate_hack", "0", CVAR_LATCHED );
543 
544 	if( gl_coloredlightmaps->value < 0 ) {
545 		cvar.Set( "gl_coloredlightmaps", "0" );
546 	} else if( gl_coloredlightmaps->value > 1 ) {
547 		cvar.Set( "gl_coloredlightmaps", "1" );
548 	}
549 
550 	if( gl_brightness->value < -1 ) {
551 		cvar.Set( "gl_brightness", "-1" );
552 	} else if( gl_brightness->value > 1 ) {
553 		cvar.Set( "gl_brightness", "1" );
554 	}
555 
556 	brightness = gl_brightness->value;
557 	colorScale = gl_coloredlightmaps->value;
558 }
559 
GL_EndPostProcessing(void)560 void GL_EndPostProcessing( void ) {
561     int i;
562 
563     for( i = 0; i < LM_BLOCK_WIDTH; i++ ) {
564         if( lm.inuse[i] ) {
565             LM_UploadBlock();
566             break;
567         }
568     }
569 
570     Com_DPrintf( "GL_EndPostProcessing: %d lightmaps built\n", lm.numMaps );
571 }
572 
573 
574