00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 #include "stdafx.h"
00047 #include "qe3.h"
00048 #include "DialogInfo.h"
00049 #include "assert.h"
00050
00051
00052 #define random() ((rand () & 0x7fff) / ((float)0x7fff))
00053
00054
00055 #define crandom() (2.0 * (random() - 0.5))
00056
00057 typedef struct {
00058 int index;
00059 vec3_t xyz;
00060 vec4_t rgba;
00061 vec2_t tc;
00062 } terravert_t;
00063
00064
00065
00066
00067
00068
00069
00070 void Terrain_SetEpair( terrainMesh_t *p, const char *pKey, const char *pValue ) {
00071 if ( g_qeglobals.m_bBrushPrimitMode ) {
00072 SetKeyValue( p->epairs, pKey, pValue );
00073 }
00074 }
00075
00076
00077
00078
00079
00080
00081 const char *Terrain_GetKeyValue( terrainMesh_t *p, const char *pKey ) {
00082 if ( g_qeglobals.m_bBrushPrimitMode ) {
00083 return ValueForKey( p->epairs, pKey );
00084 }
00085 return "";
00086 }
00087
00088
00089
00090
00091
00092
00093 int Terrain_MemorySize( terrainMesh_t *p ) {
00094 return _msize( p );
00095 }
00096
00097 void Terrain_GetVert( terrainMesh_t *pm, int x, int y, float s, float t, terravert_t *v, qtexture_t *texture = NULL ) {
00098 terrainVert_t *cell;
00099
00100 v->index = x + y * pm->width;
00101
00102 cell = &pm->heightmap[ v->index ];
00103
00104 v->xyz[ 0 ] = pm->origin[ 0 ] + x * pm->scale_x;
00105 v->xyz[ 1 ] = pm->origin[ 1 ] + y * pm->scale_y;
00106 v->xyz[ 2 ] = pm->origin[ 2 ] + cell->height;
00107
00108 VectorCopy( cell->rgba, v->rgba );
00109
00110 if ( !texture || ( texture == cell->tri.texture ) ) {
00111 v->rgba[ 3 ] = 1.0f;
00112 } else {
00113 v->rgba[ 3 ] = 0.0f;
00114 }
00115
00116 v->tc[ 0 ] = s;
00117 v->tc[ 1 ] = t;
00118 }
00119
00120 void Terrain_GetTriangles( terrainMesh_t *pm, int x, int y, terravert_t *a0, terravert_t *a1, terravert_t *a2, terravert_t *b0, terravert_t *b1, terravert_t *b2, qtexture_t *texture ) {
00121 if ( ( x + y ) & 1 ) {
00122
00123 Terrain_GetVert( pm, x, y, 1.0f, 1.0f, a0, texture );
00124 Terrain_GetVert( pm, x, y + 1, 1.0f, 0.0f, a1, texture );
00125 Terrain_GetVert( pm, x + 1, y + 1, 0.0f, 0.0f, a2, texture );
00126
00127
00128 *b0 = *a2;
00129 Terrain_GetVert( pm, x + 1, y, 0.0f, 1.0f, b1, texture );
00130 *b2 = *a0;
00131 } else {
00132
00133 Terrain_GetVert( pm, x, y, 1.0f, 1.0f, a0, texture );
00134 Terrain_GetVert( pm, x, y + 1, 1.0f, 0.0f, a1, texture );
00135 Terrain_GetVert( pm, x + 1, y, 0.0f, 1.0f, a2, texture );
00136
00137
00138 *b0 = *a2;
00139 *b1 = *a1;
00140 Terrain_GetVert( pm, x + 1, y + 1, 0.0f, 0.0f, b2, texture );
00141 }
00142 }
00143
00144 void Terrain_GetTriangle( terrainMesh_t *pm, int index, terravert_t *a0, terravert_t *a1, terravert_t *a2 ) {
00145 int x;
00146 int y;
00147 int which;
00148
00149 which = index & 1;
00150 index >>= 1;
00151 y = index / pm->width;
00152 x = index % pm->width;
00153
00154 if ( ( x + y ) & 1 ) {
00155 if ( !which ) {
00156
00157 Terrain_GetVert( pm, x, y, 1.0f, 1.0f, a0 );
00158 Terrain_GetVert( pm, x, y + 1, 1.0f, 0.0f, a1 );
00159 Terrain_GetVert( pm, x + 1, y + 1, 0.0f, 0.0f, a2 );
00160 } else {
00161 Terrain_GetVert( pm, x + 1, y + 1, 0.0f, 0.0f, a0 );
00162 Terrain_GetVert( pm, x + 1, y, 0.0f, 1.0f, a1 );
00163 Terrain_GetVert( pm, x, y, 1.0f, 1.0f, a2 );
00164 }
00165 } else {
00166 if ( !which ) {
00167
00168 Terrain_GetVert( pm, x, y, 1.0f, 1.0f, a0 );
00169 Terrain_GetVert( pm, x, y + 1, 1.0f, 0.0f, a1 );
00170 Terrain_GetVert( pm, x + 1, y, 0.0f, 1.0f, a2 );
00171 } else {
00172 Terrain_GetVert( pm, x + 1, y, 0.0f, 1.0f, a0 );
00173 Terrain_GetVert( pm, x, y + 1, 1.0f, 0.0f, a1 );
00174 Terrain_GetVert( pm, x + 1, y + 1, 0.0f, 0.0f, a2 );
00175 }
00176 }
00177 }
00178
00179 void Terrain_Delete( terrainMesh_t *p ) {
00180 if ( p->pSymbiot ) {
00181 p->pSymbiot->pTerrain = NULL;
00182 p->pSymbiot->terrainBrush = false;
00183 }
00184
00185 free( p );
00186
00187 p = NULL;
00188
00189 UpdateTerrainInspector();
00190 }
00191
00192 void Terrain_AddTexture( terrainMesh_t *pm, qtexture_t *texture ) {
00193 int i;
00194
00195 if ( !texture ) {
00196 return;
00197 }
00198
00199 for( i = 0; i < pm->numtextures; i++ ) {
00200 if ( pm->textures[ i ] == texture ) {
00201 return;
00202 }
00203 }
00204
00205 if ( pm->numtextures >= MAX_TERRAIN_TEXTURES ) {
00206 Warning( "Too many textures on terrain" );
00207 return;
00208 }
00209
00210 pm->textures[ pm->numtextures++ ] = texture;
00211 }
00212
00213 void Terrain_RemoveTexture( terrainMesh_t *p, qtexture_t *texture ) {
00214 int i;
00215
00216 for( i = 0; i < p->numtextures; i++ ) {
00217 if ( p->textures[ i ] == texture ) {
00218 break;
00219 }
00220 }
00221
00222 if ( i < p->numtextures ) {
00223
00224 p->numtextures--;
00225 for( ; i < p->numtextures; i++ ) {
00226 p->textures[ i ] = p->textures[ i + 1 ];
00227 }
00228 }
00229 }
00230
00231 terrainMesh_t *MakeNewTerrain( int width, int height, qtexture_t *texture ) {
00232 int h;
00233 int w;
00234 terrainMesh_t *pm;
00235 size_t size;
00236 size_t heightmapsize;
00237 terrainVert_t *vert;
00238 int index;
00239
00240 heightmapsize = sizeof( terrainVert_t ) * width * height;
00241 size = sizeof( terrainMesh_t ) + heightmapsize;
00242
00243 pm = reinterpret_cast< terrainMesh_t * >( qmalloc( size ) );
00244
00245 memset( pm, 0x00, size );
00246
00247 pm->numtextures = 0;
00248 pm->width = width;
00249 pm->height = height;
00250 pm->heightmap = reinterpret_cast< terrainVert_t * >( pm + 1 );
00251
00252 if ( texture ) {
00253 Terrain_AddTexture( pm, texture );
00254 }
00255
00256 index = 0;
00257 vert = pm->heightmap;
00258 for( h = 0; h < pm->height; h++ ) {
00259 for( w = 0; w < pm->width; w++, vert++ ) {
00260 vert->tri.index = index++;
00261 vert->tri.texture = texture;
00262 if ( texture ) {
00263 vert->tri.texdef.SetName( texture->name );
00264 }
00265
00266 vert->height = 0;
00267
00268 VectorClear( vert->normal );
00269 VectorSet( vert->rgba, 1.0f, 1.0f, 1.0f );
00270 vert->rgba[ 3 ] = 1.0f;
00271 }
00272 }
00273
00274 return pm;
00275 }
00276
00277 brush_t *AddBrushForTerrain( terrainMesh_t *pm, bool bLinkToWorld ) {
00278 int j;
00279 vec3_t vMin;
00280 vec3_t vMax;
00281 brush_t *b;
00282 face_t *f;
00283
00284
00285 Terrain_CalcNormals( pm );
00286
00287
00288 Terrain_CalcBounds( pm, vMin, vMax );
00289
00290 for( j = 0; j < 3; j++ ) {
00291 if ( vMin[ j ] == vMax[ j ] ) {
00292 vMin[ j ] -= 4;
00293 vMax[ j ] += 4;
00294 }
00295 }
00296
00297 b = Brush_Create( vMin, vMax, &pm->heightmap->tri.texdef );
00298
00299 for( f = b->brush_faces; f != NULL; f = f->next ) {
00300
00301 f->texdef = pm->heightmap->tri.texdef;
00302 }
00303
00304
00305 b->pTerrain = pm;
00306 b->terrainBrush = true;
00307 pm->pSymbiot = b;
00308 pm->bSelected = false;
00309 pm->bDirty = true;
00310 pm->nListID = -1;
00311
00312 if ( bLinkToWorld ) {
00313 Brush_AddToList( b, &active_brushes );
00314 Entity_LinkBrush( world_entity, b );
00315 Brush_Build( b, true );
00316 }
00317
00318 return b;
00319 }
00320
00321 terrainMesh_t *Terrain_Duplicate( terrainMesh_t *pFrom ) {
00322 terrainMesh_t *p;
00323 int w;
00324 int h;
00325 int index;
00326
00327 p = MakeNewTerrain( pFrom->width, pFrom->height );
00328
00329 VectorCopy( pFrom->origin, p->origin );
00330 VectorCopy( pFrom->mins, p->mins );
00331 VectorCopy( pFrom->maxs, p->maxs );
00332
00333 p->scale_x = pFrom->scale_x;
00334 p->scale_y = pFrom->scale_y;
00335 p->pSymbiot = pFrom->pSymbiot;
00336
00337 for( index = 0; index < pFrom->numtextures; index++ ) {
00338 Terrain_AddTexture( p, pFrom->textures[ index ] );
00339 }
00340
00341 index = 0;
00342 for( h = 0; h < p->height; h++ ) {
00343 for( w = 0; w < p->width; w++, index++ ) {
00344 p->heightmap[ index ] = pFrom->heightmap[ index ];
00345 }
00346 }
00347
00348 p->bSelected = false;
00349 p->bDirty = true;
00350 p->nListID = -1;
00351
00352 AddBrushForTerrain( p );
00353
00354 return p;
00355 }
00356
00357 void Terrain_BrushToMesh( void ) {
00358 brush_t *b;
00359 terrainMesh_t *p;
00360
00361 if ( !QE_SingleBrush() ) {
00362 return;
00363 }
00364
00365 b = selected_brushes.next;
00366
00367 if ( g_qeglobals.d_terrainWidth < 1 ) {
00368 g_qeglobals.d_terrainWidth = 1;
00369 }
00370
00371 if ( g_qeglobals.d_terrainHeight < 1 ) {
00372 g_qeglobals.d_terrainHeight = 1;
00373 }
00374
00375 p = MakeNewTerrain( g_qeglobals.d_terrainWidth + 1, g_qeglobals.d_terrainHeight + 1, b->brush_faces->d_texture );
00376 p->scale_x = ( b->maxs[ 0 ] - b->mins[ 0 ] ) / float( p->width - 1 );
00377 p->scale_y = ( b->maxs[ 1 ] - b->mins[ 1 ] ) / float( p->height - 1 );
00378
00379 VectorCopy( b->mins, p->origin );
00380
00381 b = AddBrushForTerrain( p );
00382 Select_Delete();
00383 Select_Brush( b );
00384 }
00385
00386 terrainFace_t *Terrain_ParseFace( terrainFace_t *f ) {
00387
00388 GetToken( false );
00389 f->texdef.SetName( token );
00390
00391
00392 f->texture = Texture_ForName( f->texdef.Name() );
00393
00394
00395 GetToken( false );
00396 f->texdef.shift[ 0 ] = ( float )atoi( token );
00397 GetToken( false );
00398 f->texdef.shift[ 1 ] = ( float )atoi( token );
00399 GetToken( false );
00400 f->texdef.rotate = atof( token );
00401 GetToken( false );
00402 f->texdef.scale[ 0 ] = atof( token );
00403 GetToken( false );
00404 f->texdef.scale[ 1 ] = atof( token );
00405
00406
00407
00408 f->texdef.flags = f->texture->flags;
00409 f->texdef.value = f->texture->value;
00410 f->texdef.contents = f->texture->contents;
00411
00412 if ( TokenAvailable () ) {
00413 GetToken (false);
00414 f->texdef.contents = atoi(token);
00415 GetToken (false);
00416 f->texdef.flags = atoi(token);
00417 GetToken (false);
00418 f->texdef.value = atoi(token);
00419 }
00420
00421 return f;
00422 }
00423
00424 brush_t *Terrain_Parse( void ) {
00425 terrainMesh_t *pm;
00426 terrainVert_t *vert;
00427 int w;
00428 int h;
00429
00430 GetToken( true );
00431 if ( strcmp( token, "{" ) ) {
00432 return NULL;
00433 }
00434
00435
00436 GetToken( false );
00437 w = atoi( token );
00438
00439
00440 GetToken( false );
00441 h = atoi( token );
00442
00443 pm = MakeNewTerrain( w, h );
00444
00445
00446 GetToken( false );
00447 pm->scale_x = atoi( token );
00448
00449
00450 GetToken( false );
00451 pm->scale_y = atoi( token );
00452
00453
00454 GetToken( true );
00455 pm->origin[ 0 ] = atoi( token );
00456 GetToken( false );
00457 pm->origin[ 1 ] = atoi( token );
00458 GetToken( false );
00459 pm->origin[ 2 ] = atoi( token );
00460
00461
00462 vert = pm->heightmap;
00463 for( h = 0; h < pm->height; h++ ) {
00464 for( w = 0; w < pm->width; w++, vert++ ) {
00465 GetToken( true );
00466 vert->height = atoi( token );
00467
00468 if ( !Terrain_ParseFace( &vert->tri ) ) {
00469 Terrain_Delete( pm );
00470 return NULL;
00471 }
00472
00473 Terrain_AddTexture( pm, vert->tri.texture );
00474 }
00475 }
00476
00477 GetToken( true );
00478 if ( strcmp( token, "}" ) ) {
00479 Terrain_Delete( pm );
00480 return NULL;
00481 }
00482
00483 return AddBrushForTerrain( pm, false );
00484 }
00485
00486 CString Terrain_SurfaceString( terrainFace_t *face ) {
00487 char temp[ 1024 ];
00488 CString text;
00489 const char *pname;
00490
00491 pname = face->texdef.Name();
00492 if ( pname[ 0 ] == 0 ) {
00493 pname = "unnamed";
00494 }
00495
00496 sprintf( temp, "%s %i %i %.2f ", pname, ( int )face->texdef.shift[ 0 ], ( int )face->texdef.shift[ 1 ], face->texdef.rotate );
00497 text += temp;
00498
00499 if ( face->texdef.scale[ 0 ] == ( int )face->texdef.scale[ 0 ] ) {
00500 sprintf( temp, "%i ", ( int )face->texdef.scale[ 0 ] );
00501 } else {
00502 sprintf( temp, "%f ", ( float )face->texdef.scale[ 0 ] );
00503 }
00504 text += temp;
00505
00506 if ( face->texdef.scale[ 1 ] == (int)face->texdef.scale[ 1 ] ) {
00507 sprintf( temp, "%i", ( int )face->texdef.scale[ 1 ] );
00508 } else {
00509 sprintf( temp, "%f", ( float )face->texdef.scale[ 1 ] );
00510 }
00511 text += temp;
00512
00513
00514 sprintf( temp, " %i %i %i ", face->texdef.contents, face->texdef.flags, face->texdef.value );
00515 text += temp;
00516
00517 return text;
00518 }
00519
00520 void Terrain_Write( terrainMesh_t *p, CMemFile *file ) {
00521 int w;
00522 int h;
00523 terrainVert_t *vert;
00524
00525 MemFile_fprintf( file, " {\n terrainDef\n {\n" );
00526 MemFile_fprintf( file, " %d %d %f %f\n", p->width, p->height, p->scale_x, p->scale_y );
00527 MemFile_fprintf( file, " %f %f %f\n", p->origin[ 0 ], p->origin[ 1 ], p->origin[ 2 ] );
00528
00529 vert = p->heightmap;
00530 for( h = 0; h < p->height; h++ ) {
00531 for( w = 0; w < p->width; w++, vert++ ) {
00532 MemFile_fprintf( file, " %f %s\n", vert->height, ( const char * )Terrain_SurfaceString( &vert->tri ) );
00533 }
00534 }
00535
00536 MemFile_fprintf( file, " }\n }\n" );
00537 }
00538
00539 void Terrain_Write( terrainMesh_t *p, FILE *file ) {
00540 int w;
00541 int h;
00542 terrainVert_t *vert;
00543
00544 fprintf( file, " {\n terrainDef\n {\n" );
00545 fprintf( file, " %d %d %f %f\n", p->width, p->height, p->scale_x, p->scale_y );
00546 fprintf( file, " %f %f %f\n", p->origin[ 0 ], p->origin[ 1 ], p->origin[ 2 ] );
00547
00548 vert = p->heightmap;
00549 for( h = 0; h < p->height; h++ ) {
00550 for( w = 0; w < p->width; w++, vert++ ) {
00551 fprintf( file, " %f %s\n", vert->height, ( const char * )Terrain_SurfaceString( &vert->tri ) );
00552 }
00553 }
00554
00555 fprintf( file, " }\n }\n" );
00556 }
00557
00558 void Terrain_Select( terrainMesh_t *p ) {
00559 p->bSelected = true;
00560 }
00561
00562 void Terrain_Deselect( terrainMesh_t *p ) {
00563 p->bSelected = false;
00564 }
00565
00566 void Terrain_Move( terrainMesh_t *pm, const vec3_t vMove, bool bRebuild ) {
00567 pm->bDirty = true;
00568
00569 VectorAdd( pm->origin, vMove, pm->origin );
00570
00571 if ( bRebuild ) {
00572 vec3_t vMin;
00573 vec3_t vMax;
00574
00575 Terrain_CalcBounds( pm, vMin, vMax );
00576 }
00577
00578 UpdateTerrainInspector();
00579 }
00580
00581 void UpdateTerrainInspector( void ) {
00582
00583 }
00584
00585 void Terrain_CalcBounds( terrainMesh_t *p, vec3_t &vMin, vec3_t &vMax ) {
00586 int w;
00587 int h;
00588 float f;
00589 terrainVert_t *vert;
00590
00591 vMin[ 0 ] = p->origin[ 0 ];
00592 vMin[ 1 ] = p->origin[ 1 ];
00593 vMin[ 2 ] = MAX_WORLD_COORD;
00594
00595 vMax[ 0 ] = p->origin[ 0 ] + ( p->width - 1 ) * p->scale_x;
00596 vMax[ 1 ] = p->origin[ 1 ] + ( p->height - 1 ) * p->scale_y;
00597 vMax[ 2 ] = MIN_WORLD_COORD;
00598
00599 p->bDirty = true;
00600 vert = p->heightmap;
00601 for( h = 0; h < p->height; h++ ) {
00602 for( w = 0; w < p->width; w++, vert++ ) {
00603 f = p->origin[ 2 ] + vert->height;
00604 if ( f < vMin[ 2 ] ) {
00605 vMin[ 2 ] = f;
00606 }
00607
00608 if ( f > vMax[ 2 ] ) {
00609 vMax[ 2 ] = f;
00610 }
00611 }
00612 }
00613 }
00614
00615 void CalcTriNormal( const vec3_t a, const vec3_t b, const vec3_t c, vec3_t o ) {
00616 vec3_t a1;
00617 vec3_t b1;
00618
00619 VectorSubtract( b, a, a1 );
00620 VectorNormalize( a1 );
00621
00622 VectorSubtract( c, a, b1 );
00623 VectorNormalize( b1 );
00624
00625 CrossProduct( a1, b1, o );
00626 VectorNormalize( o );
00627 }
00628
00629 inline void Terrain_CalcVertPos( terrainMesh_t *p, int x, int y, vec3_t vert ) {
00630 int index;
00631
00632 index = x + y * p->width;
00633 vert[ 0 ] = p->origin[ 0 ] + x * p->scale_x;
00634 vert[ 1 ] = p->origin[ 1 ] + y * p->scale_y;
00635 vert[ 2 ] = p->origin[ 2 ] + p->heightmap[ index ].height;
00636
00637 VectorCopy( vert, p->heightmap[ index ].xyz );
00638 }
00639
00640 void Terrain_CalcNormals( terrainMesh_t *p ) {
00641 int x;
00642 int y;
00643 int width;
00644 int num;
00645 terrainVert_t *vert;
00646 vec3_t norm;
00647 terravert_t a0;
00648 terravert_t a1;
00649 terravert_t a2;
00650 terravert_t b0;
00651 terravert_t b1;
00652 terravert_t b2;
00653
00654 p->bDirty = true;
00655
00656 num = p->height * p->width;
00657 vert = p->heightmap;
00658
00659 for( y = 0; y < p->height - 1; y++ ) {
00660 for( x = 0; x < p->width - 1; x++, vert++ ) {
00661 VectorClear( vert->normal );
00662 Terrain_CalcVertPos( p, x, y, norm );
00663 }
00664 }
00665
00666 width = p->width;
00667 vert = p->heightmap;
00668
00669 for( y = 0; y < p->height - 1; y++ ) {
00670 for( x = 0; x < width - 1; x++ ) {
00671 Terrain_GetTriangles( p, x, y, &a0, &a1, &a2, &b0, &b1, &b2, NULL );
00672
00673 CalcTriNormal( a0.xyz, a2.xyz, a1.xyz, norm );
00674
00675 VectorAdd( vert[ a0.index ].normal, norm, vert[ a0.index ].normal );
00676 VectorAdd( vert[ a1.index ].normal, norm, vert[ a1.index ].normal );
00677 VectorAdd( vert[ a2.index ].normal, norm, vert[ a2.index ].normal );
00678
00679 CalcTriNormal( b0.xyz, b2.xyz, b1.xyz, norm );
00680
00681 VectorAdd( vert[ b0.index ].normal, norm, vert[ b0.index ].normal );
00682 VectorAdd( vert[ b1.index ].normal, norm, vert[ b1.index ].normal );
00683 VectorAdd( vert[ b2.index ].normal, norm, vert[ b2.index ].normal );
00684 }
00685 }
00686
00687 for( x = 0; x < num; x++, vert++ ) {
00688 VectorNormalize( vert->normal );
00689
00690 vert->normal[ 2 ] += 0.5;
00691 VectorNormalize( vert->normal );
00692 assert( vert->normal[ 2 ] > 0 );
00693 VectorSet( vert->rgba, vert->normal[ 2 ], vert->normal[ 2 ], vert->normal[ 2 ] );
00694 vert->rgba[ 3 ] = 1.0f;
00695 }
00696 }
00697
00698 void Terrain_FindReplaceTexture( terrainMesh_t *p, const char *pFind, const char *pReplace, bool bForce ) {
00699 int w;
00700 int h;
00701 terrainVert_t *vert;
00702 qtexture_t *texture;
00703
00704 texture = Texture_ForName( pReplace );
00705
00706 vert = p->heightmap;
00707 for( h = 0; h < p->height; h++ ) {
00708 for( w = 0; w < p->width; w++, vert++ ) {
00709 if ( bForce || strcmpi( vert->tri.texture->name, pFind ) == 0 ) {
00710 vert->tri.texture = texture;
00711 vert->tri.texdef.SetName( texture->name );
00712 }
00713 }
00714 }
00715
00716 if ( bForce ) {
00717 p->numtextures = 0;
00718 Terrain_AddTexture( p, Texture_ForName( pReplace ) );
00719 } else {
00720 Terrain_RemoveTexture( p, Texture_ForName( pFind ) );
00721 Terrain_AddTexture( p, texture );
00722 }
00723 }
00724
00725 bool Terrain_HasTexture( terrainMesh_t *p, const char *name ) {
00726 int w;
00727 int h;
00728 terrainVert_t *vert;
00729
00730 vert = p->heightmap;
00731 for( h = 0; h < p->height; h++ ) {
00732 for( w = 0; w < p->width; w++, vert++ ) {
00733 if ( strcmpi( vert->tri.texture->name, name ) == 0 ) {
00734 return true;
00735 }
00736 }
00737 }
00738
00739 return false;
00740 }
00741
00742 void Terrain_ReplaceQTexture( terrainMesh_t *p, qtexture_t *pOld, qtexture_t *pNew ) {
00743 int w;
00744 int h;
00745 terrainVert_t *vert;
00746
00747 vert = p->heightmap;
00748 for( h = 0; h < p->height; h++ ) {
00749 for( w = 0; w < p->width; w++, vert++ ) {
00750 if ( vert->tri.texture == pOld ) {
00751 vert->tri.texture = pNew;
00752 vert->tri.texdef.SetName( pNew->name );
00753 }
00754 }
00755 }
00756
00757 Terrain_RemoveTexture( p, pOld );
00758 Terrain_AddTexture( p, pNew );
00759 }
00760
00761 void Terrain_SetTexture( terrainMesh_t *p, texdef_t *tex_def ) {
00762 int w;
00763 int h;
00764 qtexture_t *newtex;
00765 terrainVert_t *vert;
00766
00767 p->bDirty = 1;
00768
00769 newtex = Texture_ForName( tex_def->name );
00770
00771 p->numtextures = 0;
00772 Terrain_AddTexture( p, newtex );
00773
00774 vert = p->heightmap;
00775 for( h = 0; h < p->height; h++ ) {
00776 for( w = 0; w < p->width; w++, vert++ ) {
00777 vert->tri.texture = newtex;
00778 vert->tri.texdef.SetName( newtex->name );
00779 }
00780 }
00781
00782 UpdateTerrainInspector();
00783 }
00784
00785 void Terrain_Scale( terrainMesh_t *p, const vec3_t vOrigin, const vec3_t vAmt, bool bRebuild ) {
00786 int w;
00787 int h;
00788 vec3_t pos;
00789 terrainVert_t *vert;
00790 vec3_t vMin;
00791 vec3_t vMax;
00792
00793 vert = p->heightmap;
00794 for( h = 0; h < p->height; h++ ) {
00795 pos[ 1 ] = p->origin[ 1 ] + h * p->scale_y;
00796 for( w = 0; w < p->width; w++, vert++ ) {
00797 pos[ 0 ] = p->origin[ 0 ] + w * p->scale_x;
00798 pos[ 2 ] = vert->height;
00799
00800 if ( ( g_qeglobals.d_select_mode == sel_terrainpoint ) && ( Terrain_PointInMoveList( vert ) == -1 ) ) {
00801 continue;
00802 }
00803
00804 vert->height -= vOrigin[ 2 ] - p->origin[ 2 ];
00805 vert->height *= vAmt[ 2 ];
00806 vert->height += vOrigin[ 2 ] - p->origin[ 2 ];
00807 }
00808 }
00809
00810 if ( g_qeglobals.d_select_mode != sel_terrainpoint ) {
00811 p->scale_x *= vAmt[ 0 ];
00812 p->scale_y *= vAmt[ 1 ];
00813
00814 p->origin[ 0 ] -= vOrigin[ 0 ];
00815 p->origin[ 0 ] *= vAmt[ 0 ];
00816 p->origin[ 0 ] += vOrigin[ 0 ];
00817
00818 p->origin[ 1 ] -= vOrigin[ 1 ];
00819 p->origin[ 1 ] *= vAmt[ 1 ];
00820 p->origin[ 1 ] += vOrigin[ 1 ];
00821 }
00822
00823 if ( bRebuild ) {
00824 Terrain_CalcBounds( p, vMin, vMax );
00825 Terrain_CalcNormals( p );
00826 Brush_RebuildBrush( p->pSymbiot, vMin, vMax );
00827 }
00828
00829 UpdateTerrainInspector();
00830 }
00831
00832 bool Terrain_DragScale( terrainMesh_t *p, vec3_t vAmt, vec3_t vMove ) {
00833 vec3_t vMin;
00834 vec3_t vMax;
00835 vec3_t vScale;
00836 vec3_t vTemp;
00837 vec3_t vMid;
00838 int i;
00839
00840 Terrain_CalcBounds( p, vMin, vMax );
00841
00842 VectorSubtract( vMax, vMin, vTemp );
00843
00844
00845 for( i = 0; i < 3; i++ ) {
00846 if ( ( vTemp[ i ] == 0 ) && ( vMove[ i ] != 0 ) ) {
00847 return false;
00848 }
00849 }
00850
00851 for( i = 0; i < 3; i++ ) {
00852 vMid[ i ] = ( vMin[ i ] + vMax[ i ] ) / 2;
00853 }
00854
00855 for( i = 0; i < 3; i++ ) {
00856 if ( vAmt[ i ] != 0 ) {
00857 vScale[i] = 1.0 + vAmt[i] / vTemp[i];
00858 } else {
00859 vScale[i] = 1.0;
00860 }
00861 }
00862
00863 Terrain_Scale( p, vMid, vScale, false );
00864 VectorSubtract( vMax, vMin, vTemp );
00865 Terrain_CalcBounds( p, vMin, vMax );
00866 VectorSubtract( vMax, vMin, vMid );
00867 VectorSubtract( vMid, vTemp, vTemp );
00868 VectorScale( vTemp, 0.5f, vTemp );
00869
00870
00871 if ( !VectorCompare( vMove, vAmt ) ) {
00872 for( i = 0; i < 3; i++ ) {
00873 if ( vMove[ i ] != vAmt[ i ] ) {
00874 vTemp[ i ] = -vTemp[ i ];
00875 }
00876 }
00877 }
00878
00879 Terrain_CalcNormals( p );
00880 Terrain_Move( p, vTemp );
00881
00882 return true;
00883 }
00884
00885 void Terrain_ApplyMatrix( terrainMesh_t *p, const vec3_t vOrigin, const vec3_t vMatrix[ 3 ], bool bSnap ) {
00886 }
00887
00888 void Terrain_DrawFace( brush_t *brush, terrainFace_t *terraface ) {
00889 terrainMesh_t *pm;
00890 terravert_t a0;
00891 terravert_t a1;
00892 terravert_t a2;
00893
00894 pm = brush->pTerrain;
00895
00896 Terrain_GetTriangle( pm, terraface->index, &a0, &a1, &a2 );
00897
00898 qglBindTexture( GL_TEXTURE_2D, terraface->texture->texture_number );
00899 qglBegin( GL_TRIANGLES );
00900
00901
00902 qglColor4fv( a0.rgba );
00903 qglTexCoord2fv( a0.tc );
00904 qglVertex3fv( a0.xyz );
00905
00906 qglColor4fv( a1.rgba );
00907 qglTexCoord2fv( a1.tc );
00908 qglVertex3fv( a1.xyz );
00909
00910 qglColor4fv( a2.rgba );
00911 qglTexCoord2fv( a2.tc );
00912 qglVertex3fv( a2.xyz );
00913
00914 qglEnd ();
00915 }
00916
00917 void DrawTerrain( terrainMesh_t *pm, bool bPoints, bool bShade ) {
00918 int i;
00919 int w;
00920 int h;
00921 int x;
00922 int y;
00923
00924
00925
00926 float scale_x;
00927 float scale_y;
00928
00929
00930 terravert_t a0;
00931 terravert_t a1;
00932 terravert_t a2;
00933 terravert_t b0;
00934 terravert_t b1;
00935 terravert_t b2;
00936 terrainVert_t *vert;
00937 qtexture_t *texture;
00938
00939 h = pm->height - 1;
00940 w = pm->width - 1;
00941
00942 scale_x = pm->scale_x;
00943 scale_y = pm->scale_y;
00944
00945 qglShadeModel (GL_SMOOTH);
00946
00947 if ( bShade ) {
00948 for( i = 0; i < pm->numtextures; i++ ) {
00949 texture = pm->textures[ i ];
00950
00951 qglBindTexture( GL_TEXTURE_2D, texture->texture_number );
00952
00953 vert = pm->heightmap;
00954 for( y = 0; y < h; y++ ) {
00955 qglBegin( GL_TRIANGLES );
00956
00957 for( x = 0; x < w; x++, vert++ ) {
00958 Terrain_GetTriangles( pm, x, y, &a0, &a1, &a2, &b0, &b1, &b2, texture );
00959
00960
00961 if ( a0.rgba[ 3 ] || a1.rgba[ 3 ] || a2.rgba[ 3 ] ) {
00962 qglColor4fv( a0.rgba );
00963 qglTexCoord2fv( a0.tc );
00964 qglVertex3fv( a0.xyz );
00965
00966 qglColor4fv( a1.rgba );
00967 qglTexCoord2fv( a1.tc );
00968 qglVertex3fv( a1.xyz );
00969
00970 qglColor4fv( a2.rgba );
00971 qglTexCoord2fv( a2.tc );
00972 qglVertex3fv( a2.xyz );
00973 }
00974
00975
00976 if ( b0.rgba[ 3 ] || b1.rgba[ 3 ] || b2.rgba[ 3 ] ) {
00977 qglColor4fv( b0.rgba );
00978 qglTexCoord2fv( b0.tc );
00979 qglVertex3fv( b0.xyz );
00980
00981 qglColor4fv( b1.rgba );
00982 qglTexCoord2fv( b1.tc );
00983 qglVertex3fv( b1.xyz );
00984
00985 qglColor4fv( b2.rgba );
00986 qglTexCoord2fv( b2.tc );
00987 qglVertex3fv( b2.xyz );
00988 }
00989 }
00990
00991 qglEnd ();
00992 }
00993 }
00994 } else {
00995 for( i = 0; i < pm->numtextures; i++ ) {
00996 texture = pm->textures[ i ];
00997
00998 qglBindTexture( GL_TEXTURE_2D, texture->texture_number );
00999
01000 vert = pm->heightmap;
01001 for( y = 0; y < h; y++ ) {
01002 qglBegin( GL_TRIANGLES );
01003
01004 for( x = 0; x < w; x++, vert++ ) {
01005 Terrain_GetTriangles( pm, x, y, &a0, &a1, &a2, &b0, &b1, &b2, texture );
01006
01007
01008 if ( a0.rgba[ 3 ] || a1.rgba[ 3 ] || a2.rgba[ 3 ] ) {
01009 qglColor4fv( a0.rgba );
01010 qglTexCoord2fv( a0.tc );
01011 qglVertex3fv( a0.xyz );
01012
01013 qglColor4fv( a1.rgba );
01014 qglTexCoord2fv( a1.tc );
01015 qglVertex3fv( a1.xyz );
01016
01017 qglColor4fv( a2.rgba );
01018 qglTexCoord2fv( a2.tc );
01019 qglVertex3fv( a2.xyz );
01020 }
01021
01022
01023 if ( b0.rgba[ 3 ] || b1.rgba[ 3 ] || b2.rgba[ 3 ] ) {
01024 qglColor4fv( b0.rgba );
01025 qglTexCoord2fv( b0.tc );
01026 qglVertex3fv( b0.xyz );
01027
01028 qglColor4fv( b1.rgba );
01029 qglTexCoord2fv( b1.tc );
01030 qglVertex3fv( b1.xyz );
01031
01032 qglColor4fv( b2.rgba );
01033 qglTexCoord2fv( b2.tc );
01034 qglVertex3fv( b2.xyz );
01035 }
01036 }
01037 qglEnd ();
01038 }
01039 }
01040 }
01041
01042 qglPushAttrib( GL_CURRENT_BIT );
01043
01044 bool bDisabledLighting = qglIsEnabled( GL_LIGHTING );
01045 if ( bDisabledLighting ) {
01046 qglDisable( GL_LIGHTING );
01047 }
01048
01049 #if 0
01050 terrainVert_t *currentrow;
01051 terrainVert_t *nextrow;
01052 float x2;
01053 float y2;
01054
01055
01056 qglDisable( GL_TEXTURE_2D );
01057 qglDisable( GL_BLEND );
01058 qglColor3f( 1, 1, 1 );
01059 qglBegin( GL_LINES );
01060
01061 y2 = pm->origin[ 1 ];
01062 nextrow = pm->heightmap;
01063 for( y = 0; y < h; y++ ) {
01064 y1 = y2;
01065 y2 += scale_y;
01066
01067 x2 = pm->origin[ 0 ];
01068 currentrow = nextrow;
01069 nextrow = currentrow + pm->width;
01070 for( x = 0; x < w; x++ ) {
01071 x1 = x2;
01072 x2 += scale_x;
01073
01074
01075 qglVertex3f( x1, y1, pm->origin[ 2 ] + currentrow[ x ].height );
01076 qglVertex3f( x1 + currentrow[ x ].normal[ 0 ] * 16.0f, y1 + currentrow[ x ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + currentrow[ x ].height + currentrow[ x ].normal[ 2 ] * 16.0f );
01077
01078 qglVertex3f( x2, y1, pm->origin[ 2 ] + currentrow[ x + 1 ].height );
01079 qglVertex3f( x2 + currentrow[ x + 1 ].normal[ 0 ] * 16.0f, y1 + currentrow[ x + 1 ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + currentrow[ x + 1 ].height + currentrow[ x + 1 ].normal[ 2 ] * 16.0f );
01080
01081 qglVertex3f( x1, y2, pm->origin[ 2 ] + nextrow[ x ].height );
01082 qglVertex3f( x1 + nextrow[ x ].normal[ 0 ] * 16.0f, y2 + nextrow[ x ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + nextrow[ x ].height + nextrow[ x ].normal[ 2 ] * 16.0f );
01083
01084 qglVertex3f( x2, y2, pm->origin[ 2 ] + nextrow[ x + 1 ].height );
01085 qglVertex3f( x2 + nextrow[ x + 1 ].normal[ 0 ] * 16.0f, y2 + nextrow[ x + 1 ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + nextrow[ x + 1 ].height + nextrow[ x + 1 ].normal[ 2 ] * 16.0f );
01086 }
01087 }
01088
01089 qglEnd ();
01090 qglEnable( GL_TEXTURE_2D );
01091 #endif
01092