Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

lightmaps.c (9328B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 #include "qbsp.h"
     23 
     24 
     25 /*
     26 
     27   Lightmap allocation has to be done after all flood filling and
     28   visible surface determination.
     29 
     30 */
     31 
     32 int					numSortShaders;
     33 mapDrawSurface_t	*surfsOnShader[MAX_MAP_SHADERS];
     34 
     35 
     36 int		allocated[LIGHTMAP_WIDTH];
     37 
     38 int		numLightmaps = 1;
     39 int		c_exactLightmap;
     40 
     41 
     42 void PrepareNewLightmap( void ) {
     43 	memset( allocated, 0, sizeof( allocated ) );
     44 	numLightmaps++;
     45 }
     46 
     47 /*
     48 ===============
     49 AllocLMBlock
     50 
     51 returns a texture number and the position inside it
     52 ===============
     53 */
     54 qboolean AllocLMBlock (int w, int h, int *x, int *y)
     55 {
     56 	int		i, j;
     57 	int		best, best2;
     58 
     59 	best = LIGHTMAP_HEIGHT;
     60 
     61 	for ( i=0 ; i <= LIGHTMAP_WIDTH-w ; i++ ) {
     62 		best2 = 0;
     63 
     64 		for (j=0 ; j<w ; j++) {
     65 			if (allocated[i+j] >= best) {
     66 				break;
     67 			}
     68 			if (allocated[i+j] > best2) {
     69 				best2 = allocated[i+j];
     70 			}
     71 		}
     72 		if (j == w)	{	// this is a valid spot
     73 			*x = i;
     74 			*y = best = best2;
     75 		}
     76 	}
     77 
     78 	if (best + h > LIGHTMAP_HEIGHT) {
     79 		return qfalse;
     80 	}
     81 
     82 	for (i=0 ; i<w ; i++) {
     83 		allocated[*x + i] = best + h;
     84 	}
     85 
     86 	return qtrue;
     87 }
     88 
     89 
     90 /*
     91 ===================
     92 AllocateLightmapForPatch
     93 ===================
     94 */
     95 //#define LIGHTMAP_PATCHSHIFT
     96 
     97 void AllocateLightmapForPatch( mapDrawSurface_t *ds ) {
     98 	int			i, j, k;
     99 	drawVert_t	*verts;
    100 	int			w, h;
    101 	int			x, y;
    102 	float		s, t;
    103 	mesh_t		mesh, *subdividedMesh, *tempMesh, *newmesh;
    104 	int			widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_HEIGHT], ssize;
    105 
    106 	verts = ds->verts;
    107 
    108 	mesh.width = ds->patchWidth;
    109 	mesh.height = ds->patchHeight;
    110 	mesh.verts = verts;
    111 	newmesh = SubdivideMesh( mesh, 8, 999 );
    112 
    113 	PutMeshOnCurve( *newmesh );
    114 	tempMesh = RemoveLinearMeshColumnsRows( newmesh );
    115 	FreeMesh(newmesh);
    116 
    117 	ssize = samplesize;
    118 	if (ds->shaderInfo->lightmapSampleSize)
    119 		ssize = ds->shaderInfo->lightmapSampleSize;
    120 
    121 #ifdef LIGHTMAP_PATCHSHIFT
    122 	subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH-1, widthtable, heighttable);
    123 #else
    124 	subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH, widthtable, heighttable);
    125 #endif
    126 
    127 	w = subdividedMesh->width;
    128 	h = subdividedMesh->height;
    129 
    130 #ifdef LIGHTMAP_PATCHSHIFT
    131 	w++;
    132 	h++;
    133 #endif
    134 
    135 	FreeMesh(subdividedMesh);
    136 
    137 	// allocate the lightmap
    138 	c_exactLightmap += w * h;
    139 
    140 	if ( !AllocLMBlock( w, h, &x, &y ) ) {
    141 		PrepareNewLightmap();
    142 		if ( !AllocLMBlock( w, h, &x, &y ) ) {
    143 			Error("Entity %i, brush %i: Lightmap allocation failed", 
    144 				ds->mapBrush->entitynum, ds->mapBrush->brushnum );
    145 		}
    146 	}
    147 
    148 #ifdef LIGHTMAP_PATCHSHIFT
    149 	w--;
    150 	h--;
    151 #endif
    152 
    153 	// set the lightmap texture coordinates in the drawVerts
    154 	ds->lightmapNum = numLightmaps - 1;
    155 	ds->lightmapWidth = w;
    156 	ds->lightmapHeight = h;
    157 	ds->lightmapX = x;
    158 	ds->lightmapY = y;
    159 
    160 	for ( i = 0 ; i < ds->patchWidth ; i++ ) {
    161 		for ( k = 0 ; k < w ; k++ ) {
    162 			if ( originalWidths[k] >= i ) {
    163 				break;
    164 			}
    165 		}
    166 		if (k >= w)
    167 			k = w-1;
    168 		s = x + k;
    169 		for ( j = 0 ; j < ds->patchHeight ; j++ ) {
    170 			for ( k = 0 ; k < h ; k++ ) {
    171 				if ( originalHeights[k] >= j ) {
    172 					break;
    173 				}
    174 			}
    175 			if (k >= h)
    176 				k = h-1;
    177 			t = y + k;
    178 			verts[i + j * ds->patchWidth].lightmap[0] = ( s + 0.5 ) / LIGHTMAP_WIDTH;
    179 			verts[i + j * ds->patchWidth].lightmap[1] = ( t + 0.5 ) / LIGHTMAP_HEIGHT;
    180 		}
    181 	}
    182 }
    183 
    184 
    185 /*
    186 ===================
    187 AllocateLightmapForSurface
    188 ===================
    189 */
    190 //#define	LIGHTMAP_BLOCK	16
    191 void AllocateLightmapForSurface( mapDrawSurface_t *ds ) {
    192 	vec3_t		mins, maxs, size, exactSize, delta;
    193 	int			i;
    194 	drawVert_t	*verts;
    195 	int			w, h;
    196 	int			x, y, ssize;
    197 	int			axis;
    198 	vec3_t		vecs[2];
    199 	float		s, t;
    200 	vec3_t		origin;
    201 	plane_t		*plane;
    202 	float		d;
    203 	vec3_t		planeNormal;
    204 
    205 	if ( ds->patch ) {
    206 		AllocateLightmapForPatch( ds );
    207 		return;
    208 	}
    209 
    210 	ssize = samplesize;
    211 	if (ds->shaderInfo->lightmapSampleSize)
    212 		ssize = ds->shaderInfo->lightmapSampleSize;
    213 
    214 	plane = &mapplanes[ ds->side->planenum ];
    215 
    216 	// bound the surface
    217 	ClearBounds( mins, maxs );
    218 	verts = ds->verts;
    219 	for ( i = 0 ; i < ds->numVerts ; i++ ) {
    220 		AddPointToBounds( verts[i].xyz, mins, maxs );
    221 	}
    222 
    223 	// round to the lightmap resolution
    224 	for ( i = 0 ; i < 3 ; i++ ) {
    225 		exactSize[i] = maxs[i] - mins[i];
    226 		mins[i] = ssize * floor( mins[i] / ssize );
    227 		maxs[i] = ssize * ceil( maxs[i] / ssize );
    228 		size[i] = (maxs[i] - mins[i]) / ssize + 1;
    229 	}
    230 
    231 	// the two largest axis will be the lightmap size
    232 	memset( vecs, 0, sizeof( vecs ) );
    233 
    234 	planeNormal[0] = fabs( plane->normal[0] );
    235 	planeNormal[1] = fabs( plane->normal[1] );
    236 	planeNormal[2] = fabs( plane->normal[2] );
    237 
    238 	if ( planeNormal[0] >= planeNormal[1] && planeNormal[0] >= planeNormal[2] ) {
    239 		w = size[1];
    240 		h = size[2];
    241 		axis = 0;
    242 		vecs[0][1] = 1.0 / ssize;
    243 		vecs[1][2] = 1.0 / ssize;
    244 	} else if ( planeNormal[1] >= planeNormal[0] && planeNormal[1] >= planeNormal[2] ) {
    245 		w = size[0];
    246 		h = size[2];
    247 		axis = 1;
    248 		vecs[0][0] = 1.0 / ssize;
    249 		vecs[1][2] = 1.0 / ssize;
    250 	} else {
    251 		w = size[0];
    252 		h = size[1];
    253 		axis = 2;
    254 		vecs[0][0] = 1.0 / ssize;
    255 		vecs[1][1] = 1.0 / ssize;
    256 	}
    257 
    258 	if ( !plane->normal[axis] ) {
    259 		Error( "Chose a 0 valued axis" );
    260 	}
    261 
    262 	if ( w > LIGHTMAP_WIDTH ) {
    263 		VectorScale ( vecs[0], (float)LIGHTMAP_WIDTH/w, vecs[0] );
    264 		w = LIGHTMAP_WIDTH;
    265 	}
    266 	
    267 	if ( h > LIGHTMAP_HEIGHT ) {
    268 		VectorScale ( vecs[1], (float)LIGHTMAP_HEIGHT/h, vecs[1] );
    269 		h = LIGHTMAP_HEIGHT;
    270 	}
    271 	
    272 	c_exactLightmap += w * h;
    273 
    274 	if ( !AllocLMBlock( w, h, &x, &y ) ) {
    275 		PrepareNewLightmap();
    276 		if ( !AllocLMBlock( w, h, &x, &y ) ) {
    277 			Error("Entity %i, brush %i: Lightmap allocation failed", 
    278 				ds->mapBrush->entitynum, ds->mapBrush->brushnum );
    279 		}
    280 	}
    281 
    282 	// set the lightmap texture coordinates in the drawVerts
    283 	ds->lightmapNum = numLightmaps - 1;
    284 	ds->lightmapWidth = w;
    285 	ds->lightmapHeight = h;
    286 	ds->lightmapX = x;
    287 	ds->lightmapY = y;
    288 
    289 	for ( i = 0 ; i < ds->numVerts ; i++ ) {
    290 		VectorSubtract( verts[i].xyz, mins, delta );
    291 		s = DotProduct( delta, vecs[0] ) + x + 0.5;
    292 		t = DotProduct( delta, vecs[1] ) + y + 0.5;
    293 		verts[i].lightmap[0] = s / LIGHTMAP_WIDTH;
    294 		verts[i].lightmap[1] = t / LIGHTMAP_HEIGHT;
    295 	}
    296 
    297 	// calculate the world coordinates of the lightmap samples
    298 
    299 	// project mins onto plane to get origin
    300 	d = DotProduct( mins, plane->normal ) - plane->dist;
    301 	d /= plane->normal[ axis ];
    302 	VectorCopy( mins, origin );
    303 	origin[axis] -= d;
    304 
    305 	// project stepped lightmap blocks and subtract to get planevecs
    306 	for ( i = 0 ; i < 2 ; i++ ) {
    307 		vec3_t	normalized;
    308 		float	len;
    309 
    310 		len = VectorNormalize( vecs[i], normalized );
    311 		VectorScale( normalized, (1.0/len), vecs[i] );
    312 		d = DotProduct( vecs[i], plane->normal );
    313 		d /= plane->normal[ axis ];
    314 		vecs[i][axis] -= d;
    315 	}
    316 
    317 	VectorCopy( origin, ds->lightmapOrigin );
    318 	VectorCopy( vecs[0], ds->lightmapVecs[0] );
    319 	VectorCopy( vecs[1], ds->lightmapVecs[1] );
    320 	VectorCopy( plane->normal, ds->lightmapVecs[2] );
    321 }
    322 
    323 /*
    324 ===================
    325 AllocateLightmaps
    326 ===================
    327 */
    328 void AllocateLightmaps( entity_t *e ) {
    329 	int				i, j;
    330 	mapDrawSurface_t	*ds;
    331 	shaderInfo_t	*si;
    332 
    333 	qprintf ("--- AllocateLightmaps ---\n");
    334 
    335 
    336 	// sort all surfaces by shader so common shaders will usually
    337 	// be in the same lightmap
    338 	numSortShaders = 0;
    339 
    340 	for ( i = e->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
    341 		ds = &mapDrawSurfs[i];
    342 		if ( !ds->numVerts ) {
    343 			continue;		// leftover from a surface subdivision
    344 		}
    345 		if ( ds->miscModel ) {
    346 			continue;
    347 		}
    348 		if ( !ds->patch ) {
    349 			VectorCopy( mapplanes[ds->side->planenum].normal, ds->lightmapVecs[2] );
    350 		}
    351 
    352 		// search for this shader
    353 		for ( j = 0 ; j < numSortShaders ; j++ ) {
    354 			if ( ds->shaderInfo == surfsOnShader[j]->shaderInfo ) {
    355 				ds->nextOnShader = surfsOnShader[j];
    356 				surfsOnShader[j] = ds;
    357 				break;
    358 			}
    359 		}
    360 		if ( j == numSortShaders ) {
    361 			if ( numSortShaders >= MAX_MAP_SHADERS ) {
    362 				Error( "MAX_MAP_SHADERS" );
    363 			}
    364 			surfsOnShader[j] = ds;
    365 			numSortShaders++;
    366 		}
    367 	}
    368 	qprintf( "%5i unique shaders\n", numSortShaders );
    369 
    370 	// for each shader, allocate lightmaps for each surface
    371 
    372 //	numLightmaps = 0;
    373 //	PrepareNewLightmap();
    374 
    375 	for ( i = 0 ; i < numSortShaders ; i++ ) {
    376 		si = surfsOnShader[i]->shaderInfo;
    377 
    378 		for ( ds = surfsOnShader[i] ; ds ; ds = ds->nextOnShader ) {
    379 			// some surfaces don't need lightmaps allocated for them
    380 			if ( si->surfaceFlags & SURF_NOLIGHTMAP ) {
    381 				ds->lightmapNum = -1;
    382 			} else if ( si->surfaceFlags & SURF_POINTLIGHT ) {
    383 				ds->lightmapNum = -3;
    384 			} else {
    385 				AllocateLightmapForSurface( ds );
    386 			}
    387 		}
    388 	}
    389 
    390 	qprintf( "%7i exact lightmap texels\n", c_exactLightmap );
    391 	qprintf( "%7i block lightmap texels\n", numLightmaps * LIGHTMAP_WIDTH*LIGHTMAP_HEIGHT );
    392 }
    393 
    394 
    395