00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "qbsp.h"
00023 #include <assert.h>
00024
00025 #define SURF_WIDTH 2048
00026 #define SURF_HEIGHT 2048
00027
00028 #define GROW_VERTS 512
00029 #define GROW_INDICES 512
00030 #define GROW_SURFACES 128
00031
00032 #define VectorSet(v, x, y, z) v[0] = x;v[1] = y;v[2] = z;
00033
00034 void QuakeTextureVecs( plane_t *plane, vec_t shift[2], vec_t rotate, vec_t scale[2], vec_t mappingVecs[2][4] );
00035
00036 typedef struct {
00037 shaderInfo_t *shader;
00038 int x, y;
00039
00040 int maxVerts;
00041 int numVerts;
00042 drawVert_t *verts;
00043
00044 int maxIndexes;
00045 int numIndexes;
00046 int *indexes;
00047 } terrainSurf_t;
00048
00049 static terrainSurf_t *surfaces = NULL;
00050 static terrainSurf_t *lastSurface = NULL;
00051 static int numsurfaces = 0;
00052 static int maxsurfaces = 0;
00053
00054
00055
00056
00057
00058
00059 shaderInfo_t *ShaderForLayer( int minlayer, int maxlayer, const char *shadername ) {
00060 char shader[ MAX_QPATH ];
00061
00062 if ( minlayer == maxlayer ) {
00063 sprintf( shader, "textures/%s_%d", shadername, maxlayer );
00064 } else {
00065 sprintf( shader, "textures/%s_%dto%d", shadername, minlayer, maxlayer );
00066 }
00067
00068 return ShaderInfoForShader( shader );
00069 }
00070
00071
00072
00073
00074
00075
00076 qboolean CompareVert( drawVert_t *v1, drawVert_t *v2, qboolean checkst ) {
00077 int i;
00078
00079 for( i = 0; i < 3; i++ ) {
00080 if ( floor( v1->xyz[ i ] + 0.1 ) != floor( v2->xyz[ i ] + 0.1 ) ) {
00081 return qfalse;
00082 }
00083 if ( checkst && ( ( v1->st[ 0 ] != v2->st[ 0 ] ) || ( v1->st[ 1 ] != v2->st[ 1 ] ) ) ) {
00084 return qfalse;
00085 }
00086 }
00087
00088 return qtrue;
00089 }
00090
00091
00092
00093
00094
00095
00096 byte *LoadAlphaMap( int *num_layers, int *alphawidth, int *alphaheight ) {
00097 int *alphamap32;
00098 byte *alphamap;
00099 const char *alphamapname;
00100 char ext[ 128 ];
00101 int width;
00102 int height;
00103 int layers;
00104 int size;
00105 int i;
00106
00107 assert( alphawidth );
00108 assert( alphaheight );
00109 assert( num_layers );
00110
00111 layers = atoi( ValueForKey( mapent, "layers" ) );
00112 if ( layers < 1 ) {
00113 Error ("SetTerrainTextures: invalid value for 'layers' (%d)", layers );
00114 }
00115
00116 alphamapname = ValueForKey( mapent, "alphamap" );
00117 if ( !alphamapname[ 0 ] ) {
00118 Error ("LoadAlphaMap: No alphamap specified on terrain" );
00119 }
00120
00121 ExtractFileExtension( alphamapname, ext);
00122 if ( !Q_stricmp( ext, "tga" ) ) {
00123 Load32BitImage( ExpandGamePath( alphamapname ), &alphamap32, &width, &height );
00124
00125 size = width * height;
00126 alphamap = malloc( size );
00127 for( i = 0; i < size; i++ ) {
00128 alphamap[ i ] = ( ( alphamap32[ i ] & 0xff ) * layers ) / 256;
00129 if ( alphamap[ i ] >= layers ) {
00130 alphamap[ i ] = layers - 1;
00131 }
00132 }
00133 } else {
00134 Load256Image( ExpandGamePath( alphamapname ), &alphamap, NULL, &width, &height );
00135 size = width * height;
00136 for( i = 0; i < size; i++ ) {
00137 if ( alphamap[ i ] >= layers ) {
00138 alphamap[ i ] = layers - 1;
00139 }
00140 }
00141 }
00142
00143 if ( ( width < 2 ) || ( height < 2 ) ) {
00144 Error ("LoadAlphaMap: alphamap width/height must be at least 2x2." );
00145 }
00146
00147 *num_layers = layers;
00148 *alphawidth = width;
00149 *alphaheight = height;
00150
00151 return alphamap;
00152 }
00153
00154
00155
00156
00157
00158
00159 void CalcTerrainSize( vec3_t mins, vec3_t maxs, vec3_t size ) {
00160 bspbrush_t *brush;
00161 int i;
00162 const char *key;
00163
00164
00165 ClearBounds( mins, maxs );
00166 for( brush = mapent->brushes; brush != NULL; brush = brush->next ) {
00167 AddPointToBounds( brush->mins, mins, maxs );
00168 AddPointToBounds( brush->maxs, mins, maxs );
00169 }
00170
00171 key = ValueForKey( mapent, "min" );
00172 if ( key[ 0 ] ) {
00173 GetVectorForKey( mapent, "min", mins );
00174 }
00175
00176 key = ValueForKey( mapent, "max" );
00177 if ( key[ 0 ] ) {
00178 GetVectorForKey( mapent, "max", maxs );
00179 }
00180
00181 for( i = 0; i < 3; i++ ) {
00182 mins[ i ] = floor( mins[ i ] + 0.1 );
00183 maxs[ i ] = floor( maxs[ i ] + 0.1 );
00184 }
00185
00186 VectorSubtract( maxs, mins, size );
00187
00188 if ( ( size[ 0 ] <= 0 ) || ( size[ 1 ] <= 0 ) ) {
00189 Error ("CalcTerrainSize: Invalid terrain size: %fx%f", size[ 0 ], size[ 1 ] );
00190 }
00191 }
00192
00193
00194
00195
00196
00197
00198
00199
00200 #define COLINEAR_AREA 10
00201 static qboolean IsTriangleDegenerate( drawVert_t *points, int a, int b, int c ) {
00202 vec3_t v1, v2, v3;
00203 float d;
00204
00205 VectorSubtract( points[b].xyz, points[a].xyz, v1 );
00206 VectorSubtract( points[c].xyz, points[a].xyz, v2 );
00207 CrossProduct( v1, v2, v3 );
00208 d = VectorLength( v3 );
00209
00210
00211 if ( d < COLINEAR_AREA ) {
00212 return qtrue;
00213 }
00214
00215 return qfalse;
00216 }
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227 static void SideAsTriFan( terrainSurf_t *surf, int *index, int num ) {
00228 int i;
00229 int colorSum[4];
00230 drawVert_t *mid, *v;
00231
00232
00233 if ( surf->numVerts >= surf->maxVerts ) {
00234 surf->maxVerts += GROW_VERTS;
00235 surf->verts = realloc( surf->verts, surf->maxVerts * sizeof( *surf->verts ) );
00236 }
00237
00238
00239 mid = &surf->verts[ surf->numVerts ];
00240 surf->numVerts++;
00241
00242 colorSum[0] = colorSum[1] = colorSum[2] = colorSum[3] = 0;
00243
00244 for (i = 0 ; i < num; i++ ) {
00245 v = &surf->verts[ index[ i ] ];
00246 VectorAdd( mid->xyz, v->xyz, mid->xyz );
00247 mid->st[0] += v->st[0];
00248 mid->st[1] += v->st[1];
00249 mid->lightmap[0] += v->lightmap[0];
00250 mid->lightmap[1] += v->lightmap[1];
00251
00252 colorSum[0] += v->color[0];
00253 colorSum[1] += v->color[1];
00254 colorSum[2] += v->color[2];
00255 colorSum[3] += v->color[3];
00256 }
00257
00258 mid->xyz[0] /= num;
00259 mid->xyz[1] /= num;
00260 mid->xyz[2] /= num;
00261
00262 mid->st[0] /= num;
00263 mid->st[1] /= num;
00264
00265 mid->lightmap[0] /= num;
00266 mid->lightmap[1] /= num;
00267
00268 mid->color[0] = colorSum[0] / num;
00269 mid->color[1] = colorSum[1] / num;
00270 mid->color[2] = colorSum[2] / num;
00271 mid->color[3] = colorSum[3] / num;
00272
00273
00274 if ( surf->numIndexes + num * 3 > surf->maxIndexes ) {
00275 surf->maxIndexes = surf->numIndexes + num * 3;
00276 surf->indexes = realloc( surf->indexes, surf->maxIndexes * sizeof( *surf->indexes ) );
00277 }
00278
00279
00280 for ( i = 0 ; i < num; i++ ) {
00281 surf->indexes[ surf->numIndexes++ ] = surf->numVerts - 1;
00282 surf->indexes[ surf->numIndexes++ ] = index[ i ];
00283 surf->indexes[ surf->numIndexes++ ] = index[ (i+1) % ( surf->numVerts - 1 ) ];
00284 }
00285 }
00286
00287
00288
00289
00290
00291
00292
00293 #define MAX_INDICES 1024
00294 static void SideAsTristrip( terrainSurf_t *surf, int *index, int num ) {
00295 int i;
00296 int rotate;
00297 int numIndices;
00298 int ni;
00299 int a, b, c;
00300 int indices[ MAX_INDICES ];
00301
00302
00303 numIndices = ( num - 2 ) * 3;
00304 if ( numIndices > MAX_INDICES ) {
00305 Error( "MAX_INDICES exceeded for surface" );
00306 }
00307
00308
00309
00310 for ( rotate = 0 ; rotate < num; rotate++ ) {
00311 for ( ni = 0, i = 0 ; i < num - 2 - i ; i++ ) {
00312 a = index[ ( num - 1 - i + rotate ) % num ];
00313 b = index[ ( i + rotate ) % num ];
00314 c = index[ ( num - 2 - i + rotate ) % num ];
00315
00316 if ( IsTriangleDegenerate( surf->verts, a, b, c ) ) {
00317 break;
00318 }
00319 indices[ni++] = a;
00320 indices[ni++] = b;
00321 indices[ni++] = c;
00322
00323 if ( i + 1 != num - 1 - i ) {
00324 a = index[ ( num - 2 - i + rotate ) % num ];
00325 b = index[ ( i + rotate ) % num ];
00326 c = index[ ( i + 1 + rotate ) % num ];
00327
00328 if ( IsTriangleDegenerate( surf->verts, a, b, c ) ) {
00329 break;
00330 }
00331 indices[ni++] = a;
00332 indices[ni++] = b;
00333 indices[ni++] = c;
00334 }
00335 }
00336 if ( ni == numIndices ) {
00337 break;
00338 }
00339 }
00340
00341
00342
00343 if ( ni < numIndices ) {
00344 SideAsTriFan( surf, index, num );
00345 return;
00346 }
00347
00348
00349 if ( surf->numIndexes + ni > surf->maxIndexes ) {
00350 surf->maxIndexes = surf->numIndexes + ni;
00351 surf->indexes = realloc( surf->indexes, surf->maxIndexes * sizeof( *surf->indexes ) );
00352 }
00353
00354 memcpy( surf->indexes + surf->numIndexes, indices, ni * sizeof( *surf->indexes ) );
00355 surf->numIndexes += ni;
00356 }
00357
00358
00359
00360
00361
00362
00363 void CreateTerrainSurface( terrainSurf_t *surf, shaderInfo_t *shader ) {
00364 int i, j, k;
00365 drawVert_t *out;
00366 drawVert_t *in;
00367 mapDrawSurface_t *newsurf;
00368
00369 newsurf = AllocDrawSurf();
00370
00371 newsurf->miscModel = qtrue;
00372 newsurf->shaderInfo = shader;
00373 newsurf->lightmapNum = -1;
00374 newsurf->fogNum = -1;
00375 newsurf->numIndexes = surf->numIndexes;
00376 newsurf->numVerts = surf->numVerts;
00377
00378
00379 newsurf->indexes = malloc( surf->numIndexes * sizeof( *newsurf->indexes ) );
00380 memcpy( newsurf->indexes, surf->indexes, surf->numIndexes * sizeof( *newsurf->indexes ) );
00381
00382
00383 newsurf->verts = malloc( surf->numVerts * sizeof( *newsurf->verts ) );
00384 memset( newsurf->verts, 0, surf->numVerts * sizeof( *newsurf->verts ) );
00385
00386
00387 out = newsurf->verts;
00388 for( i = 0; i < newsurf->numVerts; i++, out++ ) {
00389 VectorCopy( surf->verts[ i ].xyz, out->xyz );
00390
00391
00392 out->st[ 0 ] = surf->verts[ i ].st[ 0 ];
00393 out->st[ 1 ] = surf->verts[ i ].st[ 1 ];
00394
00395
00396 out->color[0] = 255;
00397 out->color[1] = 255;
00398 out->color[2] = 255;
00399 out->color[3] = surf->verts[ i ].color[ 3 ];
00400
00401
00402 VectorClear( out->normal );
00403 for( j = 0; j < numsurfaces; j++ ) {
00404 in = surfaces[ j ].verts;
00405 for( k = 0; k < surfaces[ j ].numVerts; k++, in++ ) {
00406 if ( CompareVert( out, in, qfalse ) ) {
00407 VectorAdd( out->normal, in->normal, out->normal );
00408 }
00409 }
00410 }
00411
00412 VectorNormalize( out->normal, out->normal );
00413 }
00414 }
00415
00416
00417
00418
00419
00420
00421 void EmitTerrainVerts( side_t *side, terrainSurf_t *surf, int maxlayer, int alpha[ MAX_POINTS_ON_WINDING ], qboolean projecttexture ) {
00422 int i;
00423 int j;
00424 drawVert_t *vert;
00425 int *indices;
00426 int numindices;
00427 int maxindices;
00428 int xyplane;
00429 vec3_t xynorm = { 0, 0, 1 };
00430 vec_t shift[ 2 ] = { 0, 0 };
00431 vec_t scale[ 2 ] = { 0.5, 0.5 };
00432 float vecs[ 2 ][ 4 ];
00433 static int numtimes = 0;
00434
00435 numtimes++;
00436
00437 if ( !surf->verts ) {
00438 surf->numVerts = 0;
00439 surf->maxVerts = GROW_VERTS;
00440 surf->verts = malloc( surf->maxVerts * sizeof( *surf->verts ) );
00441
00442 surf->numIndexes = 0;
00443 surf->maxIndexes = GROW_INDICES;
00444 surf->indexes = malloc( surf->maxIndexes * sizeof( *surf->indexes ) );
00445 }
00446
00447
00448 xyplane = FindFloatPlane( xynorm, 0 );
00449 QuakeTextureVecs( &mapplanes[ xyplane ], shift, 0, scale, vecs );
00450
00451
00452 numindices = 0;
00453 maxindices = surf->maxIndexes;
00454 indices = malloc ( maxindices * sizeof( *indices ) );
00455
00456 for ( i = 0; i < side->winding->numpoints; i++ ) {
00457 vert = &surf->verts[ surf->numVerts ];
00458
00459
00460 if ( alpha[ i ] < maxlayer ) {
00461 vert->color[3] = 0;
00462 } else {
00463 vert->color[3] = 255;
00464 }
00465
00466 vert->xyz[ 0 ] = floor( side->winding->p[ i ][ 0 ] + 0.1f );
00467 vert->xyz[ 1 ] = floor( side->winding->p[ i ][ 1 ] + 0.1f );
00468 vert->xyz[ 2 ] = floor( side->winding->p[ i ][ 2 ] + 0.1f );
00469
00470
00471 if ( projecttexture ) {
00472 vert->st[0] = ( vecs[0][3] + DotProduct( vecs[ 0 ], vert->xyz ) ) / surf->shader->width;
00473 vert->st[1] = ( vecs[1][3] + DotProduct( vecs[ 1 ], vert->xyz ) ) / surf->shader->height;
00474 } else {
00475 vert->st[0] = ( side->vecs[0][3] + DotProduct( side->vecs[ 0 ], vert->xyz ) ) / surf->shader->width;
00476 vert->st[1] = ( side->vecs[1][3] + DotProduct( side->vecs[ 1 ], vert->xyz ) ) / surf->shader->height;
00477 }
00478
00479 VectorCopy( mapplanes[ side->planenum ].normal, vert->normal );
00480
00481 for( j = 0; j < surf->numVerts; j++ ) {
00482 if ( CompareVert( vert, &surf->verts[ j ], qtrue ) ) {
00483 break;
00484 }
00485 }
00486
00487 if ( numindices >= maxindices ) {
00488 maxindices += GROW_INDICES;
00489 indices = realloc( indices, maxindices * sizeof( *indices ) );
00490 }
00491
00492 if ( j != surf->numVerts ) {
00493 indices[ numindices++ ] = j;
00494 } else {
00495 indices[ numindices++ ] = surf->numVerts;
00496 surf->numVerts++;
00497 if ( surf->numVerts >= surf->maxVerts ) {
00498 surf->maxVerts += GROW_VERTS;
00499 surf->verts = realloc( surf->verts, surf->maxVerts * sizeof( *surf->verts ) );
00500 }
00501 }
00502 }
00503
00504 SideAsTristrip( surf, indices, numindices );
00505
00506 free( indices );
00507 }
00508
00509
00510
00511
00512
00513
00514 terrainSurf_t *SurfaceForShader( shaderInfo_t *shader, int x, int y ) {
00515 int i;
00516
00517 if ( lastSurface && ( lastSurface->shader == shader ) && ( lastSurface->x == x ) && ( lastSurface->y == y ) ) {
00518 return lastSurface;
00519 }
00520
00521 lastSurface = surfaces;
00522 for( i = 0; i < numsurfaces; i++, lastSurface++ ) {
00523 if ( ( lastSurface->shader == shader ) && ( lastSurface->x == x ) && ( lastSurface->y == y ) ) {
00524 return lastSurface;
00525 }
00526 }
00527
00528 if ( numsurfaces >= maxsurfaces ) {
00529 maxsurfaces += GROW_SURFACES;
00530 surfaces = realloc( surfaces, maxsurfaces * sizeof( *surfaces ) );
00531 memset( surfaces + numsurfaces + 1, 0, ( maxsurfaces - numsurfaces - 1 ) * sizeof( *surfaces ) );
00532 }
00533
00534 lastSurface= &surfaces[ numsurfaces++ ];
00535 lastSurface->shader = shader;
00536 lastSurface->x = x;
00537 lastSurface->y = y;
00538
00539 return lastSurface;
00540 }
00541
00542
00543
00544
00545
00546
00547 void SetTerrainTextures( void ) {
00548 int i;
00549 int x, y;
00550 int layer;
00551 int minlayer, maxlayer;
00552 float s, t;
00553 float min_s, min_t;
00554 int alpha[ MAX_POINTS_ON_WINDING ];
00555 shaderInfo_t *si, *terrainShader;
00556 bspbrush_t *brush;
00557 side_t *side;
00558 const char *shadername;
00559 vec3_t mins, maxs;
00560 vec3_t size;
00561 int surfwidth, surfheight, surfsize;
00562 terrainSurf_t *surf;
00563 byte *alphamap;
00564 int alphawidth, alphaheight;
00565 int num_layers;
00566 extern qboolean onlyents;
00567
00568 if ( onlyents ) {
00569 return;
00570 }
00571
00572 shadername = ValueForKey( mapent, "shader" );
00573 if ( !shadername[ 0 ] ) {
00574 Error ("SetTerrainTextures: shader not specified" );
00575 }
00576
00577 alphamap = LoadAlphaMap( &num_layers, &alphawidth, &alphaheight );
00578
00579 mapent->firstDrawSurf = numMapDrawSurfs;
00580
00581
00582 CalcTerrainSize( mins, maxs, size );
00583
00584 surfwidth = ( size[ 0 ] + SURF_WIDTH - 1 ) / SURF_WIDTH;
00585 surfheight = ( size[ 1 ] + SURF_HEIGHT - 1 ) / SURF_HEIGHT;
00586 surfsize = surfwidth * surfheight;
00587
00588 lastSurface = NULL;
00589 numsurfaces = 0;
00590 maxsurfaces = 0;
00591 for( i = num_layers; i > 0; i-- ) {
00592 maxsurfaces += i * surfsize;
00593 }
00594 surfaces = malloc( maxsurfaces * sizeof( *surfaces ) );
00595 memset( surfaces, 0, maxsurfaces * sizeof( *surfaces ) );
00596
00597 terrainShader = ShaderInfoForShader( "textures/common/terrain" );
00598
00599 for( brush = mapent->brushes; brush != NULL; brush = brush->next ) {
00600
00601 for( side = brush->sides; side < &brush->sides[ brush->numsides ]; side++ ) {
00602 if ( !side->shaderInfo ) {
00603 continue;
00604 }
00605
00606 if ( ( ( side->surfaceFlags | side->shaderInfo->surfaceFlags ) & SURF_NODRAW ) && !strstr( side->shaderInfo->shader, "terrain" ) ) {
00607 continue;
00608 }
00609
00610 minlayer = num_layers;
00611 maxlayer = 0;
00612
00613
00614
00615 min_s = 1.0;
00616 min_t = 1.0;
00617 for( i = 0; i < side->winding->numpoints; i++ ) {
00618 s = floor( side->winding->p[ i ][ 0 ] + 0.1f - mins[ 0 ] ) / size[ 0 ];
00619 t = floor( side->winding->p[ i ][ 1 ] + 0.1f - mins[ 0 ] ) / size[ 1 ];
00620
00621 if ( s < 0 ) {
00622 s = 0;
00623 }
00624
00625 if ( t < 0 ) {
00626 t = 0;
00627 }
00628
00629 if ( s >= 1.0 ) {
00630 s = 1.0;
00631 }
00632
00633 if ( t >= 1.0 ) {
00634 t = 1.0;
00635 }
00636
00637 if ( s < min_s ) {
00638 min_s = s;
00639 }
00640
00641 if ( t < min_t ) {
00642 min_t = t;
00643 }
00644
00645 x = ( alphawidth - 1 ) * s;
00646 y = ( alphaheight - 1 ) * t;
00647
00648 layer = alphamap[ x + y * alphawidth ];
00649 if ( layer < minlayer ) {
00650 minlayer = layer;
00651 }
00652
00653 if ( layer > maxlayer ) {
00654 maxlayer = layer;
00655 }
00656
00657 alpha[ i ] = layer;
00658 }
00659
00660 x = min_s * surfwidth;
00661 if ( x >= surfwidth ) {
00662 x = surfwidth - 1;
00663 }
00664
00665 y = min_t * surfheight;
00666 if ( y >= surfheight ) {
00667 y = surfheight - 1;
00668 }
00669
00670 if ( strstr( side->shaderInfo->shader, "terrain" ) ) {
00671 si = ShaderForLayer( minlayer, maxlayer, shadername );
00672 if ( showseams ) {
00673 for( i = 0; i < side->winding->numpoints; i++ ) {
00674 if ( ( alpha[ i ] != minlayer ) && ( alpha[ i ] != maxlayer ) ) {
00675 si = ShaderInfoForShader( "textures/common/white" );
00676 break;
00677 }
00678 }
00679 }
00680 surf = SurfaceForShader( si, x, y );
00681 EmitTerrainVerts( side, surf, maxlayer, alpha, qtrue );
00682 } else {
00683 si = side->shaderInfo;
00684 side->shaderInfo = terrainShader;
00685 surf = SurfaceForShader( si, x, y );
00686 EmitTerrainVerts( side, surf, maxlayer, alpha, qfalse );
00687 }
00688 }
00689 }
00690
00691
00692 for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
00693 if ( surf->numVerts ) {
00694 CreateTerrainSurface( surf, surf->shader );
00695 }
00696 }
00697
00698
00699
00700
00701 for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
00702 if ( surf->verts ) {
00703 free( surf->verts );
00704 free( surf->indexes );
00705 }
00706 }
00707 free( alphamap );
00708 free( surfaces );
00709
00710 surfaces = NULL;
00711 lastSurface = NULL;
00712 numsurfaces = 0;
00713 maxsurfaces = 0;
00714 }
00715
00716
00717
00718
00719
00720
00721
00722 typedef struct terrainFace_s {
00723 shaderInfo_t *shaderInfo;
00724
00725
00726 float vecs[ 2 ][ 4 ];
00727 } terrainFace_t;
00728
00729 typedef struct terrainVert_s {
00730 vec3_t xyz;
00731 terrainFace_t tri;
00732 } terrainVert_t;
00733
00734 typedef struct terrainMesh_s {
00735 float scale_x;
00736 float scale_y;
00737 vec3_t origin;
00738
00739 int width, height;
00740 terrainVert_t *map;
00741 } terrainMesh_t;
00742
00743 terrainVert_t *Terrain_GetVert( terrainMesh_t *pm, int x, int y ) {
00744 return &pm->map[ x + y * pm->width ];
00745 }
00746
00747 void Terrain_GetTriangles( terrainMesh_t *pm, int x, int y, terrainVert_t **verts ) {
00748 if ( ( x + y ) & 1 ) {
00749
00750 verts[ 0 ] = Terrain_GetVert( pm, x, y );
00751 verts[ 1 ] = Terrain_GetVert( pm, x, y + 1 );
00752 verts[ 2 ] = Terrain_GetVert( pm, x + 1, y + 1 );
00753
00754
00755 verts[ 3 ] = verts[ 2 ];
00756 verts[ 4 ] = Terrain_GetVert( pm, x + 1, y );
00757 verts[ 5 ] = verts[ 0 ];
00758 } else {
00759
00760 verts[ 0 ] = Terrain_GetVert( pm, x, y );
00761 verts[ 1 ] = Terrain_GetVert( pm, x, y + 1 );
00762 verts[ 2 ] = Terrain_GetVert( pm, x + 1, y );
00763
00764
00765 verts[ 3 ] = verts[ 2 ];
00766 verts[ 4 ] = verts[ 1 ];
00767 verts[ 5 ] = Terrain_GetVert( pm, x + 1, y + 1 );
00768 }
00769 }
00770
00771
00772
00773
00774
00775
00776 void EmitTerrainVerts2( terrainSurf_t *surf, terrainVert_t **verts, int alpha[ 3 ] ) {
00777 int i;
00778 int j;
00779 drawVert_t *vert;
00780 int *indices;
00781 int numindices;
00782 int maxindices;
00783 int xyplane;
00784 vec3_t xynorm = { 0, 0, 1 };
00785 vec_t shift[ 2 ] = { 0, 0 };
00786 vec_t scale[ 2 ] = { 0.5, 0.5 };
00787 float vecs[ 2 ][ 4 ];
00788 vec4_t plane;
00789
00790 if ( !surf->verts ) {
00791 surf->numVerts = 0;
00792 surf->maxVerts = GROW_VERTS;
00793 surf->verts = malloc( surf->maxVerts * sizeof( *surf->verts ) );
00794
00795 surf->numIndexes = 0;
00796 surf->maxIndexes = GROW_INDICES;
00797 surf->indexes = malloc( surf->maxIndexes * sizeof( *surf->indexes ) );
00798 }
00799
00800
00801 xyplane = FindFloatPlane( xynorm, 0 );
00802 QuakeTextureVecs( &mapplanes[ xyplane ], shift, 0, scale, vecs );
00803
00804
00805 numindices = 0;
00806 maxindices = surf->maxIndexes;
00807 assert( maxindices >= 0 );
00808 indices = malloc ( maxindices * sizeof( *indices ) );
00809
00810 PlaneFromPoints( plane, verts[ 0 ]->xyz, verts[ 1 ]->xyz, verts[ 2 ]->xyz );
00811
00812 for ( i = 0; i < 3; i++ ) {
00813 vert = &surf->verts[ surf->numVerts ];
00814
00815 if ( alpha[ i ] ) {
00816 vert->color[3] = 255;
00817 } else {
00818 vert->color[3] = 0;
00819 }
00820
00821 vert->xyz[ 0 ] = floor( verts[ i ]->xyz[ 0 ] + 0.1f );
00822 vert->xyz[ 1 ] = floor( verts[ i ]->xyz[ 1 ] + 0.1f );
00823 vert->xyz[ 2 ] = floor( verts[ i ]->xyz[ 2 ] + 0.1f );
00824
00825
00826 vert->st[0] = ( vecs[0][3] + DotProduct( vecs[ 0 ], vert->xyz ) ) / surf->shader->width;
00827 vert->st[1] = ( vecs[1][3] + DotProduct( vecs[ 1 ], vert->xyz ) ) / surf->shader->height;
00828
00829 VectorCopy( plane, vert->normal );
00830
00831 for( j = 0; j < surf->numVerts; j++ ) {
00832 if ( CompareVert( vert, &surf->verts[ j ], qtrue ) ) {
00833 break;
00834 }
00835 }
00836
00837 if ( numindices >= maxindices ) {
00838 maxindices += GROW_INDICES;
00839 indices = realloc( indices, maxindices * sizeof( *indices ) );
00840 }
00841
00842 if ( j != surf->numVerts ) {
00843 indices[ numindices++ ] = j;
00844 } else {
00845 indices[ numindices++ ] = surf->numVerts;
00846 surf->numVerts++;
00847 if ( surf->numVerts >= surf->maxVerts ) {
00848 surf->maxVerts += GROW_VERTS;
00849 surf->verts = realloc( surf->verts, surf->maxVerts * sizeof( *surf->verts ) );
00850 }
00851 }
00852 }
00853
00854 SideAsTristrip( surf, indices, numindices );
00855
00856 free( indices );
00857 }
00858
00859 int MapPlaneFromPoints( vec3_t p0, vec3_t p1, vec3_t p2 );
00860 void QuakeTextureVecs( plane_t *plane, vec_t shift[2], vec_t rotate, vec_t scale[2], vec_t mappingVecs[2][4] );
00861 qboolean RemoveDuplicateBrushPlanes( bspbrush_t *b );
00862 void SetBrushContents( bspbrush_t *b );
00863
00864 void AddBrushSide( vec3_t v1, vec3_t v2, vec3_t v3, shaderInfo_t *terrainShader ) {
00865 side_t *side;
00866 int planenum;
00867
00868 side = &buildBrush->sides[ buildBrush->numsides ];
00869 memset( side, 0, sizeof( *side ) );
00870 buildBrush->numsides++;
00871
00872 side->shaderInfo = terrainShader;
00873
00874
00875 planenum = MapPlaneFromPoints( v1, v2, v3 );
00876 side->planenum = planenum;
00877 }
00878
00879 void MakeBrushFromTriangle( vec3_t v1, vec3_t v2, vec3_t v3, shaderInfo_t *terrainShader ) {
00880 bspbrush_t *b;
00881 vec3_t d1;
00882 vec3_t d2;
00883 vec3_t d3;
00884
00885 VectorSet( d1, v1[ 0 ], v1[ 1 ], MIN_WORLD_COORD + 10 );
00886 VectorSet( d2, v2[ 0 ], v2[ 1 ], MIN_WORLD_COORD + 10 );
00887 VectorSet( d3, v3[ 0 ], v3[ 1 ], MIN_WORLD_COORD + 10 );
00888
00889 buildBrush->numsides = 0;
00890 buildBrush->detail = qfalse;
00891
00892 AddBrushSide( v1, v2, v3, terrainShader );
00893 AddBrushSide( v1, d1, v2, terrainShader );
00894 AddBrushSide( v2, d2, v3, terrainShader );
00895 AddBrushSide( v3, d3, v1, terrainShader );
00896 AddBrushSide( d3, d2, d1, terrainShader );
00897
00898 buildBrush->portalareas[0] = -1;
00899 buildBrush->portalareas[1] = -1;
00900 buildBrush->entitynum = num_entities-1;
00901 buildBrush->brushnum = entitySourceBrushes;
00902
00903
00904 if ( !RemoveDuplicateBrushPlanes( buildBrush ) ) {
00905 return;
00906 }
00907
00908
00909 SetBrushContents( buildBrush );
00910 buildBrush->contents |= CONTENTS_DETAIL;
00911
00912 b = FinishBrush();
00913 if ( !b ) {
00914 return;
00915 }
00916 }
00917
00918 void MakeTerrainIntoBrushes( terrainMesh_t *tm ) {
00919 int index[ 6 ];
00920 int y;
00921 int x;
00922 terrainVert_t *verts;
00923 shaderInfo_t *terrainShader;
00924
00925 terrainShader = ShaderInfoForShader( "textures/common/terrain" );
00926
00927 verts = tm->map;
00928 for( y = 0; y < tm->height - 1; y++ ) {
00929 for( x = 0; x < tm->width - 1; x++ ) {
00930 if ( ( x + y ) & 1 ) {
00931
00932 index[ 0 ] = x + y * tm->width;
00933 index[ 1 ] = x + ( y + 1 ) * tm->width;
00934 index[ 2 ] = ( x + 1 ) + ( y + 1 ) * tm->width;
00935 index[ 3 ] = ( x + 1 ) + ( y + 1 ) * tm->width;
00936 index[ 4 ] = ( x + 1 ) + y * tm->width;
00937 index[ 5 ] = x + y * tm->width;
00938 } else {
00939
00940 index[ 0 ] = x + y * tm->width;
00941 index[ 1 ] = x + ( y + 1 ) * tm->width;
00942 index[ 2 ] = ( x + 1 ) + y * tm->width;
00943 index[ 3 ] = ( x + 1 ) + y * tm->width;
00944 index[ 4 ] = x + ( y + 1 ) * tm->width;
00945 index[ 5 ] = ( x + 1 ) + ( y + 1 ) * tm->width;
00946 }
00947
00948 MakeBrushFromTriangle( verts[ index[ 0 ] ].xyz, verts[ index[ 1 ] ].xyz, verts[ index[ 2 ] ].xyz, terrainShader );
00949 MakeBrushFromTriangle( verts[ index[ 3 ] ].xyz, verts[ index[ 4 ] ].xyz, verts[ index[ 5 ] ].xyz, terrainShader );
00950 }
00951 }
00952 }
00953
00954 void Terrain_ParseFace( terrainFace_t *face ) {
00955 shaderInfo_t *si;
00956 vec_t shift[ 2 ];
00957 vec_t rotate;
00958 vec_t scale[ 2 ];
00959 char name[ MAX_QPATH ];
00960 char shader[ MAX_QPATH ];
00961 plane_t p;
00962
00963
00964 GetToken( qfalse );
00965 strcpy( name, token );
00966
00967 GetToken( qfalse );
00968 shift[ 0 ] = atof(token);
00969 GetToken( qfalse );
00970 shift[ 1 ] = atof( token );
00971 GetToken( qfalse );
00972 rotate = atof( token );
00973 GetToken( qfalse );
00974 scale[ 0 ] = atof( token );
00975 GetToken( qfalse );
00976 scale[ 1 ] = atof( token );
00977
00978
00979 sprintf( shader, "textures/%s", name );
00980 si = ShaderInfoForShader( shader );
00981 face->shaderInfo = si;
00982
00983
00984
00985 GetToken( qfalse );
00986
00987
00988 GetToken( qfalse );
00989
00990
00991 GetToken( qfalse );
00992
00993
00994
00995
00996
00997 VectorSet( p.normal, 0, 0, 1 );
00998 p.dist = 0;
00999 p.type = PlaneTypeForNormal( p.normal );
01000
01001 QuakeTextureVecs( &p, shift, rotate, scale, face->vecs );
01002 }
01003
01004 #define MAX_TERRAIN_TEXTURES 128
01005 static int numtextures = 0;;
01006 static shaderInfo_t *textures[ MAX_TERRAIN_TEXTURES ];
01007
01008 void Terrain_AddTexture( shaderInfo_t *texture ) {
01009 int i;
01010
01011 if ( !texture ) {
01012 return;
01013 }
01014
01015 for( i = 0; i < numtextures; i++ ) {
01016 if ( textures[ i ] == texture ) {
01017 return;
01018 }
01019 }
01020
01021 if ( numtextures >= MAX_TERRAIN_TEXTURES ) {
01022 Error( "Too many textures on terrain" );
01023 return;
01024 }
01025
01026 textures[ numtextures++ ] = texture;
01027 }
01028
01029 int LayerForShader( shaderInfo_t *shader ) {
01030 int i;
01031 int l;
01032
01033 l = strlen( shader->shader );
01034 for( i = l - 1; i >= 0; i-- ) {
01035 if ( shader->shader[ i ] == '_' ) {
01036 return atoi( &shader->shader[ i + 1 ] );
01037 break;
01038 }
01039 }
01040
01041 return 0;
01042 }
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052 void ParseTerrain( void ) {
01053 int i, j;
01054 int x, y;
01055 int x1, y1;
01056 terrainMesh_t t;
01057 int index;
01058 terrainVert_t *verts[ 6 ];
01059 int num_layers;
01060 int layer, minlayer, maxlayer;
01061 int alpha[ 6 ];
01062 shaderInfo_t *si, *terrainShader;
01063 int surfwidth, surfheight, surfsize;
01064 terrainSurf_t *surf;
01065 char shadername[ MAX_QPATH ];
01066
01067 mapent->firstDrawSurf = numMapDrawSurfs;
01068
01069 memset( &t, 0, sizeof( t ) );
01070
01071 MatchToken( "{" );
01072
01073
01074 GetToken( qtrue );
01075 t.width = atoi( token );
01076
01077
01078 GetToken( qfalse );
01079 t.height = atoi( token );
01080
01081
01082 GetToken( qfalse );
01083 t.scale_x = atof( token );
01084
01085
01086 GetToken( qfalse );
01087 t.scale_y = atof( token );
01088
01089
01090 GetToken( qtrue );
01091 t.origin[ 0 ] = atof( token );
01092 GetToken( qfalse );
01093 t.origin[ 1 ] = atof( token );
01094 GetToken( qfalse );
01095 t.origin[ 2 ] = atof( token );
01096
01097 t.map = malloc( t.width * t.height * sizeof( t.map[ 0 ] ) );
01098
01099 if ( t.width <= 0 || t.height <= 0 ) {
01100 Error( "ParseTerrain: bad size" );
01101 }
01102
01103 numtextures = 0;
01104 index = 0;
01105 for ( i = 0; i < t.height; i++ ) {
01106 for( j = 0; j < t.width; j++, index++ ) {
01107
01108 GetToken( qtrue );
01109 t.map[ index ].xyz[ 0 ] = t.origin[ 0 ] + t.scale_x * ( float )j;
01110 t.map[ index ].xyz[ 1 ] = t.origin[ 1 ] + t.scale_y * ( float )i;
01111 t.map[ index ].xyz[ 2 ] = t.origin[ 2 ] + atof( token );
01112
01113 Terrain_ParseFace( &t.map[ index ].tri );
01114 Terrain_AddTexture( t.map[ index ].tri.shaderInfo );
01115 }
01116 }
01117
01118 MatchToken( "}" );
01119 MatchToken( "}" );
01120
01121 MakeTerrainIntoBrushes( &t );
01122
01123 surfwidth = ( ( t.scale_x * t.width ) + SURF_WIDTH - 1 ) / SURF_WIDTH;
01124 surfheight = ( ( t.scale_y * t.height ) + SURF_HEIGHT - 1 ) / SURF_HEIGHT;
01125 surfsize = surfwidth * surfheight;
01126
01127
01128 num_layers = 0;
01129 for( i = 0; i < numtextures; i++ ) {
01130 layer = LayerForShader( textures[ i ] ) + 1;
01131 if ( layer > num_layers ) {
01132 num_layers = layer;
01133 }
01134 }
01135 num_layers = 4;
01136
01137 memset( alpha, 0, sizeof( alpha ) );
01138
01139 lastSurface = NULL;
01140 numsurfaces = 0;
01141 maxsurfaces = 0;
01142 for( i = num_layers; i > 0; i-- ) {
01143 maxsurfaces += i * surfsize;
01144 }
01145
01146 surfaces = malloc( maxsurfaces * sizeof( *surfaces ) );
01147 memset( surfaces, 0, maxsurfaces * sizeof( *surfaces ) );
01148
01149 terrainShader = ShaderInfoForShader( "textures/common/terrain" );
01150
01151
01152 if ( Q_strncasecmp( textures[ 0 ]->shader, "textures/", 9 ) == 0 ) {
01153 strcpy( shadername, &textures[ 0 ]->shader[ 9 ] );
01154 } else {
01155 strcpy( shadername, textures[ 0 ]->shader );
01156 }
01157 j = strlen( shadername );
01158 for( i = j - 1; i >= 0; i-- ) {
01159 if ( shadername[ i ] == '_' ) {
01160 shadername[ i ] = 0;
01161 break;
01162 }
01163 }
01164
01165 for( y = 0; y < t.height - 1; y++ ) {
01166 for( x = 0; x < t.width - 1; x++ ) {
01167 Terrain_GetTriangles( &t, x, y, verts );
01168
01169 x1 = ( ( float )x / ( float )( t.width - 1 ) ) * surfwidth;
01170 if ( x1 >= surfwidth ) {
01171 x1 = surfwidth - 1;
01172 }
01173
01174 y1 = ( ( float )y / ( float )( t.height - 1 ) ) * surfheight;
01175 if ( y1 >= surfheight ) {
01176 y1 = surfheight - 1;
01177 }
01178
01179 maxlayer = minlayer = LayerForShader( verts[ 0 ]->tri.shaderInfo );
01180 for( i = 0; i < 3; i++ ) {
01181 layer = LayerForShader( verts[ i ]->tri.shaderInfo );
01182 if ( layer < minlayer ) {
01183 minlayer = layer;
01184 }
01185 if ( layer > maxlayer ) {
01186 maxlayer = layer;
01187 }
01188 }
01189
01190 for( i = 0; i < 3; i++ ) {
01191 layer = LayerForShader( verts[ i ]->tri.shaderInfo );
01192 if ( layer > minlayer ) {
01193 alpha[ i ] = 1.0f;
01194 } else {
01195 alpha[ i ] = 0.0f;
01196 }
01197 }
01198
01199 si = ShaderForLayer( minlayer, maxlayer, shadername );
01200 surf = SurfaceForShader( si, x1, y1 );
01201 EmitTerrainVerts2( surf, &verts[ 0 ], &alpha[ 0 ] );
01202
01203
01204 maxlayer = minlayer = LayerForShader( verts[ 3 ]->tri.shaderInfo );
01205 for( i = 3; i < 6; i++ ) {
01206 layer = LayerForShader( verts[ i ]->tri.shaderInfo );
01207 if ( layer < minlayer ) {
01208 minlayer = layer;
01209 }
01210 if ( layer > maxlayer ) {
01211 maxlayer = layer;
01212 }
01213 }
01214
01215 for( i = 3; i < 6; i++ ) {
01216 layer = LayerForShader( verts[ i ]->tri.shaderInfo );
01217 if ( layer > minlayer ) {
01218 alpha[ i ] = 1.0f;
01219 } else {
01220 alpha[ i ] = 0.0f;
01221 }
01222 }
01223
01224 si = ShaderForLayer( minlayer, maxlayer, shadername );
01225 surf = SurfaceFo