Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

terrain.c (31376B)


      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 #include <assert.h>
     24 
     25 #define SURF_WIDTH	2048
     26 #define SURF_HEIGHT 2048
     27 
     28 #define GROW_VERTS		512
     29 #define GROW_INDICES	512
     30 #define GROW_SURFACES	128
     31 
     32 #define VectorSet(v, x, y, z)		v[0] = x;v[1] = y;v[2] = z;
     33 
     34 void QuakeTextureVecs( 	plane_t *plane, vec_t shift[2], vec_t rotate, vec_t scale[2], vec_t mappingVecs[2][4] );
     35 
     36 typedef struct {
     37 	shaderInfo_t	*shader;
     38 	int				x, y;
     39 
     40 	int				maxVerts;
     41 	int				numVerts;
     42 	drawVert_t		*verts;
     43 
     44 	int				maxIndexes;
     45 	int				numIndexes;
     46 	int				*indexes;
     47 } terrainSurf_t;
     48 
     49 static terrainSurf_t	*surfaces = NULL;
     50 static terrainSurf_t	*lastSurface = NULL;
     51 static int				numsurfaces = 0;
     52 static int				maxsurfaces = 0;
     53 
     54 /*
     55 ================
     56 ShaderForLayer
     57 ================
     58 */
     59 shaderInfo_t *ShaderForLayer( int minlayer, int maxlayer, const char *shadername ) {
     60 	char	shader[ MAX_QPATH ];
     61 
     62 	if ( minlayer == maxlayer ) {
     63 		sprintf( shader, "textures/%s_%d", shadername, maxlayer );
     64 	} else {
     65 		sprintf( shader, "textures/%s_%dto%d", shadername, minlayer, maxlayer );
     66 	}
     67 
     68 	return ShaderInfoForShader( shader );
     69 }
     70 
     71 /*
     72 ================
     73 CompareVert
     74 ================
     75 */
     76 qboolean CompareVert( drawVert_t *v1, drawVert_t *v2, qboolean checkst ) {
     77 	int i;
     78 
     79 	for( i = 0; i < 3; i++ ) {
     80 		if ( floor( v1->xyz[ i ] + 0.1 ) != floor( v2->xyz[ i ] + 0.1 ) ) {
     81 			return qfalse;
     82 		}
     83 		if ( checkst && ( ( v1->st[ 0 ] != v2->st[ 0 ] ) || ( v1->st[ 1 ] != v2->st[ 1 ] ) ) ) {
     84 			return qfalse;
     85 		}
     86 	}
     87 
     88 	return qtrue;
     89 }
     90 
     91 /*
     92 ================
     93 LoadAlphaMap
     94 ================
     95 */
     96 byte *LoadAlphaMap( int *num_layers, int *alphawidth, int *alphaheight ) {
     97 	int			*alphamap32;
     98 	byte		*alphamap;
     99 	const char	*alphamapname;
    100 	char		ext[ 128 ];
    101 	int			width;
    102 	int			height;
    103 	int			layers;
    104 	int			size;
    105 	int			i;
    106 
    107 	assert( alphawidth );
    108 	assert( alphaheight );
    109 	assert( num_layers );
    110 
    111 	layers = atoi( ValueForKey( mapent, "layers" ) );
    112 	if ( layers < 1 ) {
    113 		Error ("SetTerrainTextures: invalid value for 'layers' (%d)", layers );
    114 	}
    115 
    116 	alphamapname = ValueForKey( mapent, "alphamap" );
    117 	if ( !alphamapname[ 0 ] ) {
    118 		Error ("LoadAlphaMap: No alphamap specified on terrain" );
    119 	}
    120 
    121 	ExtractFileExtension( alphamapname, ext);
    122 	if ( !Q_stricmp( ext, "tga" ) ) {
    123 		Load32BitImage( ExpandGamePath( alphamapname ), &alphamap32, &width, &height );
    124 
    125 		size = width * height;
    126 		alphamap = malloc( size );
    127 		for( i = 0; i < size; i++ ) {
    128 			alphamap[ i ] = ( ( alphamap32[ i ] & 0xff ) * layers ) / 256;
    129 			if ( alphamap[ i ] >= layers ) {
    130 				alphamap[ i ] = layers - 1;
    131 			}
    132 		}
    133 	} else {
    134 		Load256Image( ExpandGamePath( alphamapname ), &alphamap, NULL, &width, &height );
    135 		size = width * height;
    136 		for( i = 0; i < size; i++ ) {
    137 			if ( alphamap[ i ] >= layers ) {
    138 				alphamap[ i ] = layers - 1;
    139 			}
    140 		}
    141 	}
    142 
    143 	if ( ( width < 2 ) || ( height < 2 ) ) {
    144 		Error ("LoadAlphaMap: alphamap width/height must be at least 2x2." );
    145 	}
    146 
    147 	*num_layers		= layers;
    148 	*alphawidth		= width;
    149 	*alphaheight	= height;
    150 
    151 	return alphamap;
    152 }
    153 
    154 /*
    155 ================
    156 CalcTerrainSize
    157 ================
    158 */
    159 void CalcTerrainSize( vec3_t mins, vec3_t maxs, vec3_t size ) {
    160 	bspbrush_t	*brush;
    161 	int			i;
    162 	const char  *key;
    163 
    164 	// calculate the size of the terrain
    165 	ClearBounds( mins, maxs );
    166 	for( brush = mapent->brushes; brush != NULL; brush = brush->next ) {
    167 		AddPointToBounds( brush->mins, mins, maxs );
    168 		AddPointToBounds( brush->maxs, mins, maxs );
    169 	}
    170 
    171 	key = ValueForKey( mapent, "min" ); 
    172 	if ( key[ 0 ] ) {
    173 		GetVectorForKey( mapent, "min", mins );
    174 	}
    175 
    176 	key = ValueForKey( mapent, "max" ); 
    177 	if ( key[ 0 ] ) {
    178 		GetVectorForKey( mapent, "max", maxs );
    179 	}
    180 
    181 	for( i = 0; i < 3; i++ ) {
    182 		mins[ i ] =  floor( mins[ i ] + 0.1 );
    183 		maxs[ i ] =  floor( maxs[ i ] + 0.1 );
    184 	}
    185 
    186 	VectorSubtract( maxs, mins, size );
    187 
    188 	if ( ( size[ 0 ] <= 0 ) || ( size[ 1 ] <= 0 ) ) {
    189 		Error ("CalcTerrainSize: Invalid terrain size: %fx%f", size[ 0 ], size[ 1 ] );
    190 	}
    191 }
    192 
    193 /*
    194 ==================
    195 IsTriangleDegenerate
    196 
    197 Returns qtrue if all three points are collinear or backwards
    198 ===================
    199 */
    200 #define	COLINEAR_AREA	10
    201 static qboolean	IsTriangleDegenerate( drawVert_t *points, int a, int b, int c ) {
    202 	vec3_t		v1, v2, v3;
    203 	float		d;
    204 
    205 	VectorSubtract( points[b].xyz, points[a].xyz, v1 );
    206 	VectorSubtract( points[c].xyz, points[a].xyz, v2 );
    207 	CrossProduct( v1, v2, v3 );
    208 	d = VectorLength( v3 );
    209 
    210 	// assume all very small or backwards triangles will cause problems
    211 	if ( d < COLINEAR_AREA ) {
    212 		return qtrue;
    213 	}
    214 
    215 	return qfalse;
    216 }
    217 
    218 /*
    219 ===============
    220 SideAsTriFan
    221 
    222 The surface can't be represented as a single tristrip without
    223 leaving a degenerate triangle (and therefore a crack), so add
    224 a point in the middle and create (points-1) triangles in fan order
    225 ===============
    226 */
    227 static void SideAsTriFan( terrainSurf_t *surf, int *index, int num ) {
    228 	int					i;
    229 	int					colorSum[4];
    230 	drawVert_t			*mid, *v;
    231 
    232 	// make sure we have enough space for a new vert
    233 	if ( surf->numVerts >= surf->maxVerts ) {
    234 		surf->maxVerts += GROW_VERTS;
    235 		surf->verts = realloc( surf->verts, surf->maxVerts * sizeof( *surf->verts ) );
    236 	}
    237 
    238 	// create a new point in the center of the face
    239 	mid = &surf->verts[ surf->numVerts ];
    240 	surf->numVerts++;
    241 
    242 	colorSum[0] = colorSum[1] = colorSum[2] = colorSum[3] = 0;
    243 
    244 	for (i = 0 ; i < num; i++ ) {
    245 		v = &surf->verts[ index[ i ] ];
    246 		VectorAdd( mid->xyz, v->xyz, mid->xyz );
    247 		mid->st[0] += v->st[0];
    248 		mid->st[1] += v->st[1];
    249 		mid->lightmap[0] += v->lightmap[0];
    250 		mid->lightmap[1] += v->lightmap[1];
    251 
    252 		colorSum[0] += v->color[0];
    253 		colorSum[1] += v->color[1];
    254 		colorSum[2] += v->color[2];
    255 		colorSum[3] += v->color[3];
    256 	}
    257 
    258 	mid->xyz[0] /= num;
    259 	mid->xyz[1] /= num;
    260 	mid->xyz[2] /= num;
    261 
    262 	mid->st[0] /= num;
    263 	mid->st[1] /= num;
    264 
    265 	mid->lightmap[0] /= num;
    266 	mid->lightmap[1] /= num;
    267 
    268 	mid->color[0] = colorSum[0] / num;
    269 	mid->color[1] = colorSum[1] / num;
    270 	mid->color[2] = colorSum[2] / num;
    271 	mid->color[3] = colorSum[3] / num;
    272 
    273 	// fill in indices in trifan order
    274 	if ( surf->numIndexes + num * 3 > surf->maxIndexes ) {
    275 		surf->maxIndexes = surf->numIndexes + num * 3;
    276 		surf->indexes = realloc( surf->indexes, surf->maxIndexes * sizeof( *surf->indexes ) );
    277 	}
    278 
    279 
    280 	for ( i = 0 ; i < num; i++ ) {
    281 		surf->indexes[ surf->numIndexes++ ] = surf->numVerts - 1;
    282 		surf->indexes[ surf->numIndexes++ ] = index[ i ];
    283 		surf->indexes[ surf->numIndexes++ ] = index[ (i+1) % ( surf->numVerts - 1 ) ];
    284 	}
    285 }
    286 /*
    287 ================
    288 SideAsTristrip
    289 
    290 Try to create indices that make (points-2) triangles in tristrip order
    291 ================
    292 */
    293 #define	MAX_INDICES	1024
    294 static void SideAsTristrip( terrainSurf_t *surf, int *index, int num ) {
    295 	int					i;
    296 	int					rotate;
    297 	int					numIndices;
    298 	int					ni;
    299 	int					a, b, c;
    300 	int					indices[ MAX_INDICES ];
    301 
    302 	// determine the triangle strip order
    303 	numIndices = ( num - 2 ) * 3;
    304 	if ( numIndices > MAX_INDICES ) {
    305 		Error( "MAX_INDICES exceeded for surface" );
    306 	}
    307 
    308 	// try all possible orderings of the points looking
    309 	// for a strip order that isn't degenerate
    310 	for ( rotate = 0 ; rotate < num; rotate++ ) {
    311 		for ( ni = 0, i = 0 ; i < num - 2 - i ; i++ ) {
    312 			a = index[ ( num - 1 - i + rotate ) % num ];
    313 			b = index[ ( i + rotate ) % num ];
    314 			c = index[ ( num - 2 - i + rotate ) % num ];
    315 
    316 			if ( IsTriangleDegenerate( surf->verts, a, b, c ) ) {
    317 				break;
    318 			}
    319 			indices[ni++] = a;
    320 			indices[ni++] = b;
    321 			indices[ni++] = c;
    322 
    323 			if ( i + 1 != num - 1 - i ) {
    324 				a = index[ ( num - 2 - i + rotate ) % num ];
    325 				b = index[ ( i + rotate ) % num ];
    326 				c = index[ ( i + 1 + rotate ) % num ];
    327 
    328 				if ( IsTriangleDegenerate( surf->verts, a, b, c ) ) {
    329 					break;
    330 				}
    331 				indices[ni++] = a;
    332 				indices[ni++] = b;
    333 				indices[ni++] = c;
    334 			}
    335 		}
    336 		if ( ni == numIndices ) {
    337 			break;		// got it done without degenerate triangles
    338 		}
    339 	}
    340 
    341 	// if any triangle in the strip is degenerate,
    342 	// render from a centered fan point instead
    343 	if ( ni < numIndices ) {
    344 		SideAsTriFan( surf, index, num );
    345 		return;
    346 	}
    347 
    348 	// a normal tristrip
    349 	if ( surf->numIndexes + ni > surf->maxIndexes ) {
    350 		surf->maxIndexes = surf->numIndexes + ni;
    351 		surf->indexes = realloc( surf->indexes, surf->maxIndexes * sizeof( *surf->indexes ) );
    352 	}
    353 
    354 	memcpy( surf->indexes + surf->numIndexes, indices, ni * sizeof( *surf->indexes ) );
    355 	surf->numIndexes += ni;
    356 }
    357 
    358 /*
    359 ================
    360 CreateTerrainSurface
    361 ================
    362 */
    363 void CreateTerrainSurface( terrainSurf_t *surf, shaderInfo_t *shader ) {
    364 	int					i, j, k;
    365 	drawVert_t			*out;
    366 	drawVert_t			*in;
    367 	mapDrawSurface_t	*newsurf;
    368 
    369 	newsurf = AllocDrawSurf();
    370 
    371 	newsurf->miscModel		= qtrue;
    372 	newsurf->shaderInfo		= shader;
    373 	newsurf->lightmapNum	= -1;
    374 	newsurf->fogNum			= -1;
    375 	newsurf->numIndexes		= surf->numIndexes;
    376 	newsurf->numVerts		= surf->numVerts;
    377 
    378 	// copy the indices
    379 	newsurf->indexes = malloc( surf->numIndexes * sizeof( *newsurf->indexes ) );
    380 	memcpy( newsurf->indexes, surf->indexes, surf->numIndexes * sizeof( *newsurf->indexes ) );
    381 
    382 	// allocate the vertices
    383 	newsurf->verts = malloc( surf->numVerts * sizeof( *newsurf->verts ) );
    384 	memset( newsurf->verts, 0, surf->numVerts * sizeof( *newsurf->verts ) );
    385 
    386 	// calculate the surface verts
    387 	out = newsurf->verts;
    388 	for( i = 0; i < newsurf->numVerts; i++, out++ ) {
    389 		VectorCopy( surf->verts[ i ].xyz, out->xyz );
    390 
    391 		// set the texture coordinates
    392 		out->st[ 0 ] = surf->verts[ i ].st[ 0 ];
    393 		out->st[ 1 ] = surf->verts[ i ].st[ 1 ];
    394 
    395 		// the colors will be set by the lighting pass
    396 		out->color[0] = 255;
    397 		out->color[1] = 255;
    398 		out->color[2] = 255;
    399 		out->color[3] = surf->verts[ i ].color[ 3 ];
    400 
    401 		// calculate the vertex normal
    402 		VectorClear( out->normal );
    403 		for( j = 0; j < numsurfaces; j++ ) {
    404 			in = surfaces[ j ].verts;
    405 			for( k = 0; k < surfaces[ j ].numVerts; k++, in++ ) {
    406 				if ( CompareVert( out, in, qfalse ) ) {
    407 					VectorAdd( out->normal, in->normal, out->normal );
    408 				}
    409 			}
    410 		}
    411 
    412 		VectorNormalize( out->normal, out->normal );
    413 	}
    414 }
    415 
    416 /*
    417 ================
    418 EmitTerrainVerts
    419 ================
    420 */
    421 void EmitTerrainVerts( side_t *side, terrainSurf_t *surf, int maxlayer, int alpha[ MAX_POINTS_ON_WINDING ], qboolean projecttexture ) {
    422 	int			i;
    423 	int			j;
    424 	drawVert_t	*vert;
    425 	int			*indices;
    426 	int			numindices;
    427 	int			maxindices;
    428 	int			xyplane;
    429 	vec3_t		xynorm = { 0, 0, 1 };
    430 	vec_t		shift[ 2 ] = { 0, 0 };
    431 	vec_t		scale[ 2 ] = { 0.5, 0.5 };
    432 	float		vecs[ 2 ][ 4 ];
    433 	static int numtimes = 0;
    434 
    435 	numtimes++;
    436 
    437 	if ( !surf->verts ) {
    438 		surf->numVerts		= 0;
    439 		surf->maxVerts		= GROW_VERTS;
    440 		surf->verts			= malloc( surf->maxVerts * sizeof( *surf->verts ) );
    441 
    442 		surf->numIndexes	= 0;
    443 		surf->maxIndexes	= GROW_INDICES;
    444 		surf->indexes		= malloc( surf->maxIndexes * sizeof( *surf->indexes ) );
    445 	}
    446 
    447 	// calculate the texture coordinate vectors
    448 	xyplane = FindFloatPlane( xynorm, 0 );
    449 	QuakeTextureVecs( &mapplanes[ xyplane ], shift, 0, scale, vecs );
    450 
    451 	// emit the vertexes
    452 	numindices = 0;
    453 	maxindices = surf->maxIndexes;
    454 	indices = malloc ( maxindices * sizeof( *indices ) );
    455 
    456 	for ( i = 0; i < side->winding->numpoints; i++ ) {
    457 		vert = &surf->verts[ surf->numVerts ];
    458 
    459 		// set the final alpha value--0 for texture 1, 255 for texture 2
    460 		if ( alpha[ i ] < maxlayer ) {
    461 			vert->color[3] = 0;
    462 		} else {
    463 			vert->color[3] = 255;
    464 		}
    465 
    466 		vert->xyz[ 0 ] = floor( side->winding->p[ i ][ 0 ] + 0.1f );
    467 		vert->xyz[ 1 ] = floor( side->winding->p[ i ][ 1 ] + 0.1f );
    468 		vert->xyz[ 2 ] = floor( side->winding->p[ i ][ 2 ] + 0.1f );
    469 
    470 		// set the texture coordinates
    471 		if ( projecttexture ) {
    472 			vert->st[0] = ( vecs[0][3] + DotProduct( vecs[ 0 ], vert->xyz ) ) / surf->shader->width;
    473 			vert->st[1] = ( vecs[1][3] + DotProduct( vecs[ 1 ], vert->xyz ) ) / surf->shader->height;
    474 		} else {
    475 			vert->st[0] = ( side->vecs[0][3] + DotProduct( side->vecs[ 0 ], vert->xyz ) ) / surf->shader->width;
    476 			vert->st[1] = ( side->vecs[1][3] + DotProduct( side->vecs[ 1 ], vert->xyz ) ) / surf->shader->height;
    477 		}
    478 
    479 		VectorCopy( mapplanes[ side->planenum ].normal, vert->normal );
    480 
    481 		for( j = 0; j < surf->numVerts; j++ ) {
    482 			if ( CompareVert( vert, &surf->verts[ j ], qtrue ) ) {
    483 				break;
    484 			}
    485 		}
    486 		
    487 		if ( numindices >= maxindices ) {
    488 			maxindices += GROW_INDICES;
    489 			indices = realloc( indices, maxindices * sizeof( *indices ) );
    490 		}
    491 
    492 		if ( j != surf->numVerts ) {
    493 			indices[ numindices++ ] = j;
    494 		} else {
    495 			indices[ numindices++ ] = surf->numVerts;
    496 			surf->numVerts++;
    497 			if ( surf->numVerts >= surf->maxVerts ) {
    498 				surf->maxVerts += GROW_VERTS;
    499 				surf->verts = realloc( surf->verts, surf->maxVerts * sizeof( *surf->verts ) );
    500 			}
    501 		}
    502 	}
    503 
    504 	SideAsTristrip( surf, indices, numindices );
    505 
    506 	free( indices );
    507 }
    508 
    509 /*
    510 ================
    511 SurfaceForShader
    512 ================
    513 */
    514 terrainSurf_t *SurfaceForShader( shaderInfo_t *shader, int x, int y ) {
    515 	int i;
    516 
    517 	if ( lastSurface && ( lastSurface->shader == shader ) && ( lastSurface->x == x ) && ( lastSurface->y == y ) ) {
    518 		return lastSurface;
    519 	}
    520 
    521 	lastSurface = surfaces;
    522 	for( i = 0; i < numsurfaces; i++, lastSurface++ ) {
    523 		if ( ( lastSurface->shader == shader ) && ( lastSurface->x == x ) && ( lastSurface->y == y ) ) {
    524 			return lastSurface;
    525 		}
    526 	}
    527 
    528 	if ( numsurfaces >= maxsurfaces ) {
    529 		maxsurfaces += GROW_SURFACES;
    530 		surfaces = realloc( surfaces, maxsurfaces * sizeof( *surfaces ) );
    531 		memset( surfaces + numsurfaces + 1, 0, ( maxsurfaces - numsurfaces - 1 ) * sizeof( *surfaces ) );
    532 	}
    533 
    534 	lastSurface= &surfaces[ numsurfaces++ ];
    535 	lastSurface->shader = shader;
    536 	lastSurface->x = x;
    537 	lastSurface->y = y;
    538 
    539 	return lastSurface;
    540 }
    541 
    542 /*
    543 ================
    544 SetTerrainTextures
    545 ================
    546 */
    547 void SetTerrainTextures( void ) {
    548 	int				i;
    549 	int				x, y;
    550 	int				layer;
    551 	int				minlayer, maxlayer;
    552 	float			s, t;
    553 	float			min_s, min_t;
    554 	int				alpha[ MAX_POINTS_ON_WINDING ];
    555 	shaderInfo_t	*si, *terrainShader;
    556 	bspbrush_t		*brush;
    557 	side_t			*side;
    558 	const char		*shadername;
    559 	vec3_t			mins, maxs;
    560 	vec3_t			size;
    561 	int				surfwidth, surfheight, surfsize;
    562 	terrainSurf_t	*surf;
    563 	byte			*alphamap;
    564 	int				alphawidth, alphaheight;
    565 	int				num_layers;
    566 	extern qboolean	onlyents;
    567 
    568 	if ( onlyents ) {
    569 		return;
    570 	}
    571 
    572 	shadername = ValueForKey( mapent, "shader" );
    573 	if ( !shadername[ 0 ] ) {
    574 		Error ("SetTerrainTextures: shader not specified" );
    575 	}
    576 
    577 	alphamap = LoadAlphaMap( &num_layers, &alphawidth, &alphaheight );
    578 
    579 	mapent->firstDrawSurf = numMapDrawSurfs;
    580 
    581 	// calculate the size of the terrain
    582 	CalcTerrainSize( mins, maxs, size );
    583 
    584 	surfwidth	= ( size[ 0 ] + SURF_WIDTH - 1 ) / SURF_WIDTH;
    585 	surfheight	= ( size[ 1 ] + SURF_HEIGHT - 1 ) / SURF_HEIGHT;
    586 	surfsize = surfwidth * surfheight;
    587 
    588 	lastSurface = NULL;
    589 	numsurfaces = 0;
    590 	maxsurfaces = 0;
    591 	for( i = num_layers; i > 0; i-- ) {
    592 		maxsurfaces += i * surfsize;
    593 	}
    594 	surfaces = malloc( maxsurfaces * sizeof( *surfaces ) );
    595 	memset( surfaces, 0, maxsurfaces * sizeof( *surfaces ) );
    596 
    597 	terrainShader = ShaderInfoForShader( "textures/common/terrain" );
    598 
    599 	for( brush = mapent->brushes; brush != NULL; brush = brush->next ) {
    600 		// only create surfaces for sides marked as terrain
    601 		for( side = brush->sides; side < &brush->sides[ brush->numsides ]; side++ ) {
    602 			if ( !side->shaderInfo ) {
    603 				continue;
    604 			}
    605 
    606 			if ( ( ( side->surfaceFlags | side->shaderInfo->surfaceFlags ) & SURF_NODRAW ) && !strstr( side->shaderInfo->shader, "terrain" ) ) {
    607 				continue;
    608 			}
    609 
    610 			minlayer = num_layers;
    611 			maxlayer = 0;
    612 
    613 			// project each point of the winding onto the alphamap to determine which
    614 			// textures to blend
    615 			min_s = 1.0;
    616 			min_t = 1.0;
    617 			for( i = 0; i < side->winding->numpoints; i++ ) {
    618 				s = floor( side->winding->p[ i ][ 0 ] + 0.1f - mins[ 0 ] ) / size[ 0 ];
    619 				t = floor( side->winding->p[ i ][ 1 ] + 0.1f - mins[ 0 ] ) / size[ 1 ];
    620 
    621 				if ( s < 0 ) {
    622 					s = 0;
    623 				}
    624 				
    625 				if ( t < 0 ) {
    626 					t = 0;
    627 				}
    628 
    629 				if ( s >= 1.0 ) {
    630 					s = 1.0;
    631 				}
    632 
    633 				if ( t >= 1.0 ) {
    634 					t = 1.0;
    635 				}
    636 
    637 				if ( s < min_s ) {
    638 					min_s = s;
    639 				}
    640 
    641 				if ( t < min_t ) {
    642 					min_t = t;
    643 				}
    644 
    645 				x = ( alphawidth - 1 ) * s;
    646 				y = ( alphaheight - 1 ) * t;
    647 
    648 				layer = alphamap[ x + y * alphawidth ];
    649 				if ( layer < minlayer ) {
    650 					minlayer = layer;
    651 				}
    652 
    653 				if ( layer > maxlayer ) {
    654 					maxlayer = layer;
    655 				}
    656 
    657 				alpha[ i ] = layer;
    658 			}
    659 
    660 			x = min_s * surfwidth;
    661 			if ( x >= surfwidth ) {
    662 				x = surfwidth - 1;
    663 			}
    664 
    665 			y = min_t * surfheight;
    666 			if ( y >= surfheight ) {
    667 				y = surfheight - 1;
    668 			}
    669 
    670 			if ( strstr( side->shaderInfo->shader, "terrain" ) ) {
    671 				si = ShaderForLayer( minlayer, maxlayer, shadername );
    672 				if ( showseams ) {
    673 					for( i = 0; i < side->winding->numpoints; i++ ) {
    674 						if ( ( alpha[ i ] != minlayer ) && ( alpha[ i ] != maxlayer ) ) {
    675 							si = ShaderInfoForShader( "textures/common/white" );
    676 							break;
    677 						}
    678 					}
    679 				}
    680 				surf = SurfaceForShader( si, x, y );
    681 				EmitTerrainVerts( side, surf, maxlayer, alpha, qtrue );
    682 			} else {
    683 				si = side->shaderInfo;
    684 				side->shaderInfo = terrainShader;
    685 				surf = SurfaceForShader( si, x, y );
    686 				EmitTerrainVerts( side, surf, maxlayer, alpha, qfalse );
    687 			}
    688 		}
    689 	}
    690 
    691 	// create the final surfaces
    692 	for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
    693 		if ( surf->numVerts ) {
    694 			CreateTerrainSurface( surf, surf->shader );
    695 		}
    696 	}
    697 
    698 	//
    699 	// clean up any allocated memory
    700 	//
    701 	for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
    702 		if ( surf->verts ) {
    703 			free( surf->verts );
    704 			free( surf->indexes );
    705 		}
    706 	}
    707 	free( alphamap );
    708 	free( surfaces );
    709 
    710 	surfaces = NULL;
    711 	lastSurface = NULL;
    712 	numsurfaces = 0;
    713 	maxsurfaces = 0;
    714 }
    715 
    716 /*****************************************************************************
    717 
    718 	New terrain code
    719 
    720 ******************************************************************************/
    721 
    722 typedef struct terrainFace_s {
    723 	shaderInfo_t			*shaderInfo;
    724 	//texdef_t				texdef;
    725 
    726 	float					vecs[ 2 ][ 4 ]; // texture coordinate mapping
    727 } terrainFace_t;
    728 
    729 typedef struct terrainVert_s {
    730 	vec3_t					xyz;
    731 	terrainFace_t			tri;
    732 } terrainVert_t;
    733 
    734 typedef struct terrainMesh_s {
    735 	float					scale_x;
    736 	float					scale_y;
    737 	vec3_t					origin;
    738 
    739 	int						width, height;
    740 	terrainVert_t			*map;
    741 } terrainMesh_t;
    742 
    743 terrainVert_t *Terrain_GetVert( terrainMesh_t *pm, int x, int y ) {
    744 	return &pm->map[ x + y * pm->width ];
    745 }
    746 
    747 void Terrain_GetTriangles( terrainMesh_t *pm, int x, int y, terrainVert_t **verts ) {
    748 	if ( ( x + y ) & 1 ) {
    749 		// first tri
    750 		verts[ 0 ] = Terrain_GetVert( pm, x, y );
    751 		verts[ 1 ] = Terrain_GetVert( pm, x, y + 1 );
    752 		verts[ 2 ] = Terrain_GetVert( pm, x + 1, y + 1 );
    753 
    754 		// second tri
    755 		verts[ 3 ] = verts[ 2 ];
    756 		verts[ 4 ] = Terrain_GetVert( pm, x + 1, y );
    757 		verts[ 5 ] = verts[ 0 ];
    758 	} else {
    759 		// first tri
    760 		verts[ 0 ] = Terrain_GetVert( pm, x, y );
    761 		verts[ 1 ] = Terrain_GetVert( pm, x, y + 1 );
    762 		verts[ 2 ] = Terrain_GetVert( pm, x + 1, y );
    763 
    764 		// second tri
    765 		verts[ 3 ] = verts[ 2 ];
    766 		verts[ 4 ] = verts[ 1 ];
    767 		verts[ 5 ] = Terrain_GetVert( pm, x + 1, y + 1 );
    768 	}
    769 }
    770 
    771 /*
    772 ================
    773 EmitTerrainVerts2
    774 ================
    775 */
    776 void EmitTerrainVerts2( terrainSurf_t *surf, terrainVert_t **verts, int alpha[ 3 ] ) {
    777 	int			i;
    778 	int			j;
    779 	drawVert_t	*vert;
    780 	int			*indices;
    781 	int			numindices;
    782 	int			maxindices;
    783 	int			xyplane;
    784 	vec3_t		xynorm = { 0, 0, 1 };
    785 	vec_t		shift[ 2 ] = { 0, 0 };
    786 	vec_t		scale[ 2 ] = { 0.5, 0.5 };
    787 	float		vecs[ 2 ][ 4 ];
    788 	vec4_t		plane;
    789 
    790 	if ( !surf->verts ) {
    791 		surf->numVerts		= 0;
    792 		surf->maxVerts		= GROW_VERTS;
    793 		surf->verts			= malloc( surf->maxVerts * sizeof( *surf->verts ) );
    794 
    795 		surf->numIndexes	= 0;
    796 		surf->maxIndexes	= GROW_INDICES;
    797 		surf->indexes		= malloc( surf->maxIndexes * sizeof( *surf->indexes ) );
    798 	}
    799 
    800 	// calculate the texture coordinate vectors
    801 	xyplane = FindFloatPlane( xynorm, 0 );
    802 	QuakeTextureVecs( &mapplanes[ xyplane ], shift, 0, scale, vecs );
    803 
    804 	// emit the vertexes
    805 	numindices = 0;
    806 	maxindices = surf->maxIndexes;
    807 	assert( maxindices >= 0 );
    808 	indices = malloc ( maxindices * sizeof( *indices ) );
    809 
    810 	PlaneFromPoints( plane, verts[ 0 ]->xyz, verts[ 1 ]->xyz, verts[ 2 ]->xyz );
    811 
    812 	for ( i = 0; i < 3; i++ ) {
    813 		vert = &surf->verts[ surf->numVerts ];
    814 
    815 		if ( alpha[ i ] ) {
    816 			vert->color[3] = 255;
    817 		} else {
    818 			vert->color[3] = 0;
    819 		}
    820 
    821 		vert->xyz[ 0 ] = floor( verts[ i ]->xyz[ 0 ] + 0.1f );
    822 		vert->xyz[ 1 ] = floor( verts[ i ]->xyz[ 1 ] + 0.1f );
    823 		vert->xyz[ 2 ] = floor( verts[ i ]->xyz[ 2 ] + 0.1f );
    824 
    825 		// set the texture coordinates
    826 		vert->st[0] = ( vecs[0][3] + DotProduct( vecs[ 0 ], vert->xyz ) ) / surf->shader->width;
    827 		vert->st[1] = ( vecs[1][3] + DotProduct( vecs[ 1 ], vert->xyz ) ) / surf->shader->height;
    828 
    829 		VectorCopy( plane, vert->normal );
    830 
    831 		for( j = 0; j < surf->numVerts; j++ ) {
    832 			if ( CompareVert( vert, &surf->verts[ j ], qtrue ) ) {
    833 				break;
    834 			}
    835 		}
    836 		
    837 		if ( numindices >= maxindices ) {
    838 			maxindices += GROW_INDICES;
    839 			indices = realloc( indices, maxindices * sizeof( *indices ) );
    840 		}
    841 
    842 		if ( j != surf->numVerts ) {
    843 			indices[ numindices++ ] = j;
    844 		} else {
    845 			indices[ numindices++ ] = surf->numVerts;
    846 			surf->numVerts++;
    847 			if ( surf->numVerts >= surf->maxVerts ) {
    848 				surf->maxVerts += GROW_VERTS;
    849 				surf->verts = realloc( surf->verts, surf->maxVerts * sizeof( *surf->verts ) );
    850 			}
    851 		}
    852 	}
    853 
    854 	SideAsTristrip( surf, indices, numindices );
    855 
    856 	free( indices );
    857 }
    858 
    859 int      MapPlaneFromPoints( vec3_t p0, vec3_t p1, vec3_t p2 );
    860 void     QuakeTextureVecs( plane_t *plane, vec_t shift[2], vec_t rotate, vec_t scale[2], vec_t mappingVecs[2][4] );
    861 qboolean RemoveDuplicateBrushPlanes( bspbrush_t *b );
    862 void     SetBrushContents( bspbrush_t *b );
    863 
    864 void AddBrushSide( vec3_t v1, vec3_t v2, vec3_t v3, shaderInfo_t *terrainShader ) {
    865 	side_t	*side;
    866 	int		planenum;
    867 
    868 	side = &buildBrush->sides[ buildBrush->numsides ];
    869 	memset( side, 0, sizeof( *side ) );
    870 	buildBrush->numsides++;
    871 
    872 	side->shaderInfo = terrainShader;
    873 
    874 	// find the plane number
    875 	planenum = MapPlaneFromPoints( v1, v2, v3 );
    876 	side->planenum = planenum;
    877 }
    878 
    879 void MakeBrushFromTriangle( vec3_t v1, vec3_t v2, vec3_t v3, shaderInfo_t *terrainShader ) {
    880 	bspbrush_t	*b;
    881 	vec3_t		d1;
    882 	vec3_t		d2;
    883 	vec3_t		d3;
    884 
    885 	VectorSet( d1, v1[ 0 ], v1[ 1 ], MIN_WORLD_COORD + 10 );	//FIXME
    886 	VectorSet( d2, v2[ 0 ], v2[ 1 ], MIN_WORLD_COORD + 10 );
    887 	VectorSet( d3, v3[ 0 ], v3[ 1 ], MIN_WORLD_COORD + 10 );
    888 
    889 	buildBrush->numsides = 0;
    890 	buildBrush->detail = qfalse;
    891 
    892 	AddBrushSide( v1, v2, v3, terrainShader );
    893 	AddBrushSide( v1, d1, v2, terrainShader );
    894 	AddBrushSide( v2, d2, v3, terrainShader );
    895 	AddBrushSide( v3, d3, v1, terrainShader );
    896 	AddBrushSide( d3, d2, d1, terrainShader );
    897 
    898 	buildBrush->portalareas[0] = -1;
    899 	buildBrush->portalareas[1] = -1;
    900 	buildBrush->entitynum = num_entities-1;
    901 	buildBrush->brushnum = entitySourceBrushes;
    902 
    903 	// if there are mirrored planes, the entire brush is invalid
    904 	if ( !RemoveDuplicateBrushPlanes( buildBrush ) ) {
    905 		return;
    906 	}
    907 
    908 	// get the content for the entire brush
    909 	SetBrushContents( buildBrush );
    910 	buildBrush->contents |= CONTENTS_DETAIL;
    911 
    912 	b = FinishBrush();
    913 	if ( !b ) {
    914 		return;
    915 	}
    916 }
    917 
    918 void MakeTerrainIntoBrushes( terrainMesh_t *tm ) {
    919 	int				index[ 6 ];
    920 	int				y;
    921 	int				x;
    922 	terrainVert_t	*verts;
    923 	shaderInfo_t	*terrainShader;
    924 
    925 	terrainShader = ShaderInfoForShader( "textures/common/terrain" );
    926 
    927 	verts = tm->map;
    928 	for( y = 0; y < tm->height - 1; y++ ) {
    929 		for( x = 0; x < tm->width - 1; x++ ) {
    930 			if ( ( x + y ) & 1 ) {
    931 				// first tri
    932 				index[ 0 ] = x + y * tm->width;
    933 				index[ 1 ] = x + ( y + 1 ) * tm->width;
    934 				index[ 2 ] = ( x + 1 ) + ( y + 1 ) * tm->width;
    935 				index[ 3 ] = ( x + 1 ) + ( y + 1 ) * tm->width;
    936 				index[ 4 ] = ( x + 1 ) + y * tm->width;
    937 				index[ 5 ] = x + y * tm->width;
    938 			} else {
    939 				// first tri
    940 				index[ 0 ] = x + y * tm->width;
    941 				index[ 1 ] = x + ( y + 1 ) * tm->width;
    942 				index[ 2 ] = ( x + 1 ) + y * tm->width;
    943 				index[ 3 ] = ( x + 1 ) + y * tm->width;
    944 				index[ 4 ] = x + ( y + 1 ) * tm->width;
    945 				index[ 5 ] = ( x + 1 ) + ( y + 1 ) * tm->width;
    946 			}
    947 
    948 			MakeBrushFromTriangle( verts[ index[ 0 ] ].xyz, verts[ index[ 1 ] ].xyz, verts[ index[ 2 ] ].xyz, terrainShader );
    949 			MakeBrushFromTriangle( verts[ index[ 3 ] ].xyz, verts[ index[ 4 ] ].xyz, verts[ index[ 5 ] ].xyz, terrainShader );
    950 		}
    951 	}
    952 }
    953 
    954 void Terrain_ParseFace( terrainFace_t *face ) {
    955 	shaderInfo_t	*si;
    956 	vec_t			shift[ 2 ];
    957 	vec_t			rotate;
    958 	vec_t			scale[ 2 ];
    959 	char			name[ MAX_QPATH ];
    960 	char			shader[ MAX_QPATH ];
    961 	plane_t			p;
    962 
    963 	// read the texturedef
    964 	GetToken( qfalse );
    965 	strcpy( name, token );
    966 
    967 	GetToken( qfalse );
    968 	shift[ 0 ] = atof(token);
    969 	GetToken( qfalse );
    970 	shift[ 1 ] = atof( token ); 
    971 	GetToken( qfalse );
    972 	rotate = atof( token );
    973 	GetToken( qfalse );
    974 	scale[ 0 ] = atof( token );
    975 	GetToken( qfalse );
    976 	scale[ 1 ] = atof( token );
    977 
    978 	// find default flags and values
    979 	sprintf( shader, "textures/%s", name );
    980 	si = ShaderInfoForShader( shader );
    981 	face->shaderInfo = si;
    982 	//face->texdef = si->texdef;
    983 
    984 	// skip over old contents
    985 	GetToken( qfalse );
    986 
    987 	// skip over old flags
    988 	GetToken( qfalse );
    989 
    990 	// skip over old value
    991 	GetToken( qfalse );
    992 
    993 	//Surface_Parse( &face->texdef );
    994 	//Surface_BuildTexdef( &face->texdef );
    995 
    996 	// make a fake horizontal plane
    997 	VectorSet( p.normal, 0, 0, 1 );
    998 	p.dist = 0;
    999 	p.type = PlaneTypeForNormal( p.normal );
   1000 
   1001 	QuakeTextureVecs( &p, shift, rotate, scale, face->vecs );
   1002 }
   1003 
   1004 #define MAX_TERRAIN_TEXTURES 128
   1005 static int			numtextures = 0;;
   1006 static shaderInfo_t	*textures[ MAX_TERRAIN_TEXTURES ];
   1007 
   1008 void Terrain_AddTexture( shaderInfo_t *texture ) {
   1009 	int i;
   1010 
   1011 	if ( !texture ) {
   1012 		return;
   1013 	}
   1014 
   1015 	for( i = 0; i < numtextures; i++ ) {
   1016 		if ( textures[ i ] == texture ) {
   1017 			return;
   1018 		}
   1019 	}
   1020 
   1021 	if ( numtextures >= MAX_TERRAIN_TEXTURES ) {
   1022 		Error( "Too many textures on terrain" );
   1023 		return;
   1024 	}
   1025 
   1026 	textures[ numtextures++ ] = texture;
   1027 }
   1028 
   1029 int LayerForShader( shaderInfo_t *shader ) {
   1030 	int i;
   1031 	int l;
   1032 
   1033 	l = strlen( shader->shader );
   1034 	for( i = l - 1; i >= 0; i-- ) {
   1035 		if ( shader->shader[ i ] == '_' ) {
   1036 			return atoi( &shader->shader[ i + 1 ] );
   1037 			break;
   1038 		}
   1039 	}
   1040 
   1041 	return 0;
   1042 }
   1043 
   1044 /*
   1045 =================
   1046 ParseTerrain
   1047 
   1048 Creates a mapDrawSurface_t from the terrain text
   1049 =================
   1050 */
   1051 
   1052 void ParseTerrain( void ) {
   1053 	int				i, j;
   1054 	int				x, y;
   1055 	int				x1, y1;
   1056 	terrainMesh_t	t;
   1057 	int				index;
   1058 	terrainVert_t	*verts[ 6 ];
   1059 	int				num_layers;
   1060 	int				layer, minlayer, maxlayer;
   1061 	int				alpha[ 6 ];
   1062 	shaderInfo_t	*si, *terrainShader;
   1063 	int				surfwidth, surfheight, surfsize;
   1064 	terrainSurf_t	*surf;
   1065 	char			shadername[ MAX_QPATH ];
   1066 
   1067 	mapent->firstDrawSurf = numMapDrawSurfs;
   1068 
   1069 	memset( &t, 0, sizeof( t ) );
   1070 
   1071 	MatchToken( "{" );
   1072 
   1073 	// get width
   1074 	GetToken( qtrue );
   1075 	t.width = atoi( token );
   1076 
   1077 	// get height
   1078 	GetToken( qfalse );
   1079 	t.height = atoi( token );
   1080 
   1081 	// get scale_x
   1082 	GetToken( qfalse );
   1083 	t.scale_x = atof( token );
   1084 
   1085 	// get scale_y
   1086 	GetToken( qfalse );
   1087 	t.scale_y = atof( token );
   1088 
   1089 	// get origin
   1090 	GetToken( qtrue );
   1091 	t.origin[ 0 ] = atof( token );
   1092 	GetToken( qfalse );
   1093 	t.origin[ 1 ] = atof( token );
   1094 	GetToken( qfalse );
   1095 	t.origin[ 2 ] = atof( token );
   1096 
   1097 	t.map = malloc( t.width * t.height * sizeof( t.map[ 0 ] ) );
   1098 
   1099 	if ( t.width <= 0 || t.height <= 0 ) {
   1100 		Error( "ParseTerrain: bad size" );
   1101 	}
   1102 
   1103 	numtextures = 0;
   1104 	index = 0;
   1105 	for ( i = 0; i < t.height; i++ ) {
   1106 		for( j = 0; j < t.width; j++, index++ ) {
   1107 			// get height
   1108 			GetToken( qtrue );
   1109 			t.map[ index ].xyz[ 0 ] = t.origin[ 0 ] + t.scale_x * ( float )j;
   1110 			t.map[ index ].xyz[ 1 ] = t.origin[ 1 ] + t.scale_y * ( float )i;
   1111 			t.map[ index ].xyz[ 2 ] = t.origin[ 2 ] + atof( token );
   1112 
   1113 			Terrain_ParseFace( &t.map[ index ].tri );
   1114 			Terrain_AddTexture( t.map[ index ].tri.shaderInfo );
   1115 		}
   1116 	}
   1117 
   1118 	MatchToken( "}" );
   1119 	MatchToken( "}" );
   1120 
   1121 	MakeTerrainIntoBrushes( &t );
   1122 
   1123 	surfwidth	= ( ( t.scale_x * t.width ) + SURF_WIDTH - 1 ) / SURF_WIDTH;
   1124 	surfheight	= ( ( t.scale_y * t.height ) + SURF_HEIGHT - 1 ) / SURF_HEIGHT;
   1125 	surfsize = surfwidth * surfheight;
   1126 
   1127 	//FIXME
   1128 	num_layers = 0;
   1129 	for( i = 0; i < numtextures; i++ ) {
   1130 		layer = LayerForShader( textures[ i ] ) + 1;
   1131 		if ( layer > num_layers ) {
   1132 			num_layers = layer;
   1133 		}
   1134 	}
   1135 	num_layers = 4;
   1136 
   1137 	memset( alpha, 0, sizeof( alpha ) );
   1138 
   1139 	lastSurface = NULL;
   1140 	numsurfaces = 0;
   1141 	maxsurfaces = 0;
   1142 	for( i = num_layers; i > 0; i-- ) {
   1143 		maxsurfaces += i * surfsize;
   1144 	}
   1145 
   1146 	surfaces = malloc( maxsurfaces * sizeof( *surfaces ) );
   1147 	memset( surfaces, 0, maxsurfaces * sizeof( *surfaces ) );
   1148 
   1149 	terrainShader = ShaderInfoForShader( "textures/common/terrain" );
   1150 
   1151 	// get the shadername
   1152 	if ( Q_strncasecmp( textures[ 0 ]->shader, "textures/", 9 ) == 0 ) {
   1153 		strcpy( shadername, &textures[ 0 ]->shader[ 9 ] );
   1154 	} else {
   1155 		strcpy( shadername, textures[ 0 ]->shader );
   1156 	}
   1157 	j = strlen( shadername );
   1158 	for( i = j - 1; i >= 0; i-- ) {
   1159 		if ( shadername[ i ] == '_' ) {
   1160 			shadername[ i ] = 0;
   1161 			break;
   1162 		}
   1163 	}
   1164 	
   1165 	for( y = 0; y < t.height - 1; y++ ) {
   1166 		for( x = 0; x < t.width - 1; x++ ) {
   1167 			Terrain_GetTriangles( &t, x, y, verts );
   1168 
   1169 			x1 = ( ( float )x / ( float )( t.width - 1 ) ) * surfwidth;
   1170 			if ( x1 >= surfwidth ) {
   1171 				x1 = surfwidth - 1;
   1172 			}
   1173 
   1174 			y1 = ( ( float )y / ( float )( t.height - 1 ) ) * surfheight;
   1175 			if ( y1 >= surfheight ) {
   1176 				y1 = surfheight - 1;
   1177 			}
   1178 
   1179 			maxlayer = minlayer = LayerForShader( verts[ 0 ]->tri.shaderInfo );
   1180 			for( i = 0; i < 3; i++ ) {
   1181 				layer = LayerForShader( verts[ i ]->tri.shaderInfo );
   1182 				if ( layer < minlayer ) {
   1183 					minlayer = layer;
   1184 				}
   1185 				if ( layer > maxlayer ) {
   1186 					maxlayer = layer;
   1187 				}
   1188 			}
   1189 
   1190 			for( i = 0; i < 3; i++ ) {
   1191 				layer = LayerForShader( verts[ i ]->tri.shaderInfo );
   1192 				if ( layer > minlayer ) {
   1193 					alpha[ i ] = 1.0f;
   1194 				} else {
   1195 					alpha[ i ] = 0.0f;
   1196 				}
   1197 			}
   1198 
   1199 			si = ShaderForLayer( minlayer, maxlayer, shadername );
   1200 			surf = SurfaceForShader( si, x1, y1 );
   1201 			EmitTerrainVerts2( surf, &verts[ 0 ], &alpha[ 0 ] );
   1202 
   1203 			// second triangle
   1204 			maxlayer = minlayer = LayerForShader( verts[ 3 ]->tri.shaderInfo );
   1205 			for( i = 3; i < 6; i++ ) {
   1206 				layer = LayerForShader( verts[ i ]->tri.shaderInfo );
   1207 				if ( layer < minlayer ) {
   1208 					minlayer = layer;
   1209 				}
   1210 				if ( layer > maxlayer ) {
   1211 					maxlayer = layer;
   1212 				}
   1213 			}
   1214 
   1215 			for( i = 3; i < 6; i++ ) {
   1216 				layer = LayerForShader( verts[ i ]->tri.shaderInfo );
   1217 				if ( layer > minlayer ) {
   1218 					alpha[ i ] = 1.0f;
   1219 				} else {
   1220 					alpha[ i ] = 0.0f;
   1221 				}
   1222 			}
   1223 
   1224 			si = ShaderForLayer( minlayer, maxlayer, shadername );
   1225 			surf = SurfaceForShader( si, x1, y1 );
   1226 			EmitTerrainVerts2( surf, &verts[ 3 ], &alpha[ 3 ] );
   1227 		}
   1228 	}
   1229 
   1230 	// create the final surfaces
   1231 	for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
   1232 		if ( surf->numVerts ) {
   1233 			CreateTerrainSurface( surf, surf->shader );
   1234 		}
   1235 	}
   1236 
   1237 	//
   1238 	// clean up any allocated memory
   1239 	//
   1240 	for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
   1241 		if ( surf->verts ) {
   1242 			free( surf->verts );
   1243 			free( surf->indexes );
   1244 		}
   1245 	}
   1246 	free( surfaces );
   1247 
   1248 	surfaces = NULL;
   1249 	lastSurface = NULL;
   1250 	numsurfaces = 0;
   1251 	maxsurfaces = 0;
   1252 
   1253     free( t.map );
   1254 }
   1255