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
01093 #if 0
01094 if ( bPoints && ( g_qeglobals.d_select_mode == sel_terrainpoint || g_qeglobals.d_select_mode == sel_area ) ) {
01095 qglPointSize( 6 );
01096 qglDisable( GL_TEXTURE_2D );
01097 qglDisable( GL_BLEND );
01098
01099 qglBegin( GL_POINTS );
01100
01101 nIndex = 0;
01102
01103 qglColor4f( 1, 0, 1, 1 );
01104
01105 y1 = pm->origin[ 1 ];
01106 for ( y = 0; y < pm->height; y++, y1 += pm->scale_y ) {
01107 x1 = pm->origin[ 0 ];
01108 for( x = 0; x < pm->width; x++, x1 += pm->scale_x ) {
01109
01110 n = Terrain_PointInMoveList( &pm->heightmap[ x + y * pm->width ] );
01111 if ( n >= 0 ) {
01112 VectorSet( pSelectedPoints[ nIndex ], x1, y1, pm->heightmap[ x + y * pm->width ].height + pm->origin[ 2 ] );
01113 nIndex++;
01114 } else {
01115 qglVertex3f( x1, y1, pm->origin[ 2 ] + pm->heightmap[ x + y * pm->width ].height );
01116 }
01117 }
01118 }
01119
01120 qglEnd();
01121
01122 qglEnable( GL_TEXTURE_2D );
01123
01124 if ( nIndex > 0 ) {
01125 qglBegin( GL_POINTS );
01126 qglColor4f( 0, 0, 1, 1 );
01127 while( nIndex-- > 0 ) {
01128 qglVertex3fv( pSelectedPoints[ nIndex ] );
01129 }
01130
01131 qglEnd();
01132 }
01133 }
01134 #endif
01135
01136 if ( g_qeglobals.d_numterrapoints && ( ( g_qeglobals.d_select_mode == sel_terrainpoint ) || ( g_qeglobals.d_select_mode == sel_terraintexture ) ) ) {
01137 #if 0
01138 qglPointSize( 6 );
01139 qglDisable( GL_TEXTURE_2D );
01140 qglDisable( GL_BLEND );
01141
01142 qglBegin( GL_POINTS );
01143
01144 qglColor4f( 1, 0, 1, 1 );
01145
01146 for( i = 0; i < g_qeglobals.d_numterrapoints; i++ ) {
01147 qglVertex3fv( g_qeglobals.d_terrapoints[ i ]->xyz );
01148 }
01149
01150 qglEnd();
01151
01152 qglEnable( GL_TEXTURE_2D );
01153 #endif
01154
01155 brush_t *pb;
01156 terrainMesh_t *pm;
01157
01158 pm = NULL;
01159 for( pb = active_brushes .next; pb != &active_brushes; pb = pb->next ) {
01160 if ( pb->terrainBrush ) {
01161 pm = pb->pTerrain;
01162 break;
01163 }
01164 }
01165
01166 if ( pm ) {
01167 qglDisable( GL_TEXTURE_2D );
01168 qglBegin( GL_TRIANGLES );
01169 qglEnable( GL_BLEND );
01170
01171 qglColor4f( 0.25, 0.5, 1, 0.35 );
01172
01173 for( i = 0; i < g_qeglobals.d_numterrapoints; i++ ) {
01174 terravert_t a0;
01175 terravert_t a1;
01176 terravert_t a2;
01177
01178 qglColor4f( 0.25, 0.5, 1, g_qeglobals.d_terrapoints[ i ]->scale * 0.75 + 0.25 );
01179 Terrain_GetTriangle( pm, g_qeglobals.d_terrapoints[ i ]->tri.index * 2, &a0, &a1, &a2 );
01180
01181 qglVertex3fv( a0.xyz );
01182 qglVertex3fv( a1.xyz );
01183 qglVertex3fv( a2.xyz );
01184
01185 Terrain_GetTriangle( pm, g_qeglobals.d_terrapoints[ i ]->tri.index * 2 + 1, &a0, &a1, &a2 );
01186
01187 qglVertex3fv( a0.xyz );
01188 qglVertex3fv( a1.xyz );
01189 qglVertex3fv( a2.xyz );
01190 }
01191 qglEnd();
01192
01193 qglDisable( GL_BLEND );
01194 qglEnable( GL_TEXTURE_2D );
01195 }
01196 }
01197 }
01198
01199 void Terrain_DrawCam( terrainMesh_t *pm ) {
01200 qglColor3f( 1,1,1 );
01201 qglPushAttrib( GL_ALL_ATTRIB_BITS );
01202
01203 if ( g_bPatchWireFrame ) {
01204 if( pm->bSelected ) {
01205 qglLineWidth( 2 );
01206 } else {
01207 qglLineWidth( 1 );
01208 }
01209
01210 qglDisable( GL_CULL_FACE );
01211 qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
01212 qglDisable( GL_TEXTURE_2D );
01213
01214 if ( g_PrefsDlg.m_bGLLighting ) {
01215 qglDisable( GL_LIGHTING );
01216 }
01217
01218 DrawTerrain( pm, pm->bSelected, true );
01219
01220 if ( g_PrefsDlg.m_bGLLighting ) {
01221 qglEnable( GL_LIGHTING );
01222 }
01223
01224 qglEnable( GL_CULL_FACE );
01225 qglLineWidth( 1 );
01226 } else {
01227 qglEnable( GL_CULL_FACE );
01228 qglCullFace( GL_FRONT );
01229
01230
01231 DrawTerrain( pm, pm->bSelected, true );
01232
01233
01234 if( pm->bSelected ) {
01235 qglColor4f( 1.0, 0.0, 0.0, 0.3 );
01236 qglEnable( GL_BLEND );
01237 qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
01238 qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
01239
01240 DrawTerrain( pm, pm->bSelected );
01241
01242 qglColor3f( 1, 1, 1 );
01243 }
01244
01245
01246 qglCullFace( GL_BACK );
01247 qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
01248 qglDisable( GL_BLEND );
01249 DrawTerrain( pm, pm->bSelected, true );
01250 }
01251
01252 qglPopAttrib();
01253 }
01254
01255 void Terrain_DrawXY( terrainMesh_t *pm, entity_t *owner ) {
01256 qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
01257
01258 if ( pm->bSelected ) {
01259 qglColor3fv( g_qeglobals.d_savedinfo.colors[ COLOR_SELBRUSHES ] );
01260 } else if ( owner != world_entity && _stricmp( owner->eclass->name, "func_group" ) ) {
01261 qglColor3fv( owner->eclass->color );
01262 } else {
01263
01264 qglColor3fv( g_qeglobals.d_savedinfo.colors[ COLOR_BRUSHES ] );
01265 }
01266
01267 qglLineWidth( 1 );
01268
01269 DrawTerrain( pm, pm->bSelected );
01270
01271 qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
01272 }
01273
01274 bool OnlyTerrainSelected( void ) {
01275 brush_t *pb;
01276
01277
01278 if ( selected_brushes.next == &selected_brushes ) {
01279 return false;
01280 }
01281
01282 for( pb = selected_brushes.next; pb != &selected_brushes; pb = pb->next ) {
01283 if ( !pb->terrainBrush ) {
01284 return false;
01285 }
01286 }
01287
01288 return true;
01289 }
01290
01291 bool AnyTerrainSelected( void ) {
01292 brush_t *pb;
01293
01294
01295 if ( selected_brushes.next == &selected_brushes ) {
01296 return false;
01297 }
01298
01299 for( pb = selected_brushes.next; pb != &selected_brushes; pb = pb->next ) {
01300 if ( pb->terrainBrush ) {
01301 return true;
01302 }
01303 }
01304
01305 return false;
01306 }
01307
01308 terrainMesh_t *SingleTerrainSelected( void ) {
01309 if ( selected_brushes.next->terrainBrush ) {
01310 return selected_brushes.next->pTerrain;
01311 }
01312
01313 return NULL;
01314 }
01315
01316 void Terrain_Edit( void ) {
01317
01318
01319
01320
01321
01322
01323 g_qeglobals.d_numterrapoints = 0;
01324 #if 0
01325 for( pb = selected_brushes.next; pb != &selected_brushes ; pb = pb->next ) {
01326 if ( pb->terrainBrush ) {
01327 p = pb->pTerrain;
01328
01329 if ( ( g_qeglobals.d_numpoints + p->width * p->height ) > MAX_POINTS ) {
01330 Warning( "Too many points on terrain\n" );
01331 continue;
01332 }
01333 for( i = 0; i < p->width; i++ ) {
01334 for( j = 0; j < p->height; j++ ) {
01335 Terrain_CalcVertPos( p, i, j, g_qeglobals.d_points[ g_qeglobals.d_numpoints ] );
01336 g_qeglobals.d_numpoints++;
01337 }
01338 }
01339 }
01340 }
01341 #endif
01342
01343 g_qeglobals.d_select_mode = sel_terrainpoint;
01344 }
01345
01346 void Terrain_SelectPointByRay( vec3_t org, vec3_t dir, int buttons ) {
01347 float bestd;
01348 terrainFace_t *face;
01349 terrainFace_t *bestface;
01350 brush_t *pb;
01351 float dist;
01352 vec3_t vec;
01353
01354
01355 bestface = NULL;
01356 bestd = WORLD_SIZE * 4;
01357 for( pb = selected_brushes.next; pb != &selected_brushes; pb = pb->next ) {
01358 if ( pb->terrainBrush ) {
01359 face = Terrain_Ray( org, dir, pb, &dist );
01360 if ( face && ( dist < bestd ) ) {
01361 bestface = face;
01362 bestd = dist;
01363 }
01364 }
01365 }
01366
01367 for( pb = active_brushes .next; pb != &active_brushes; pb = pb->next ) {
01368 if ( pb->terrainBrush ) {
01369 face = Terrain_Ray( org, dir, pb, &dist );
01370 if ( face && ( dist < bestd ) ) {
01371 bestface = face;
01372 bestd = dist;
01373 }
01374 }
01375 }
01376
01377 if ( !bestface ) {
01378 return;
01379 }
01380
01381 VectorMA( org, bestd, dir, vec );
01382 Terrain_AddMovePoint( vec, buttons & MK_CONTROL, buttons & MK_SHIFT, buttons );
01383 }
01384
01385 void Terrain_AddMovePoint( vec3_t v, bool bMulti, bool bFull, int buttons ) {
01386 brush_t *pb;
01387 terrainMesh_t *p;
01388 terrainVert_t *vert;
01389 int x;
01390 int y;
01391 int x1, y1;
01392 float dx, dy;
01393 float dist;
01394 float pd;
01395
01396 if ( !g_bSameView && !bMulti && !bFull ) {
01397 g_bSameView = true;
01398 return;
01399 }
01400
01401 g_qeglobals.d_numterrapoints = 0;
01402 for( pb = active_brushes .next; pb != &active_brushes; pb = pb->next ) {
01403
01404 if ( pb->terrainBrush ) {
01405 p = pb->pTerrain;
01406
01407 x = ( v[ 0 ] - p->origin[ 0 ] ) / p->scale_x;
01408 y = ( v[ 1 ] - p->origin[ 1 ] ) / p->scale_x;
01409 if ( ( x < 0 ) || ( x >= p->width ) || ( y < 0 ) || ( y >= p->height ) ) {
01410 continue;
01411 }
01412
01413 vert = p->heightmap;
01414 for( y1 = 0; y1 < p->height; y1++ ) {
01415 for( x1 = 0; x1 < p->width; x1++, vert++ ) {
01416
01417 if ( g_qeglobals.d_terrainBrush == TERRAIN_BRUSH_CIRCLE ) {
01418 dx = x1 - x;
01419 dy = y1 - y;
01420 dist = sqrt( dx * dx + dy * dy );
01421 } else {
01422 dx = abs( x1 - x );
01423 dy = abs( y1 - y );
01424 if ( dx > dy ) {
01425 dist = dx;
01426 } else {
01427 dist = dy;
01428 }
01429 }
01430
01431 pd = dist * 2.0f / g_qeglobals.d_terrainBrushSize;
01432 if ( fabs( pd ) <= 1.0f ) {
01433 Terrain_AddPoint( p, vert );
01434
01435 if ( ( buttons & MK_LBUTTON ) && ( g_qeglobals.d_select_mode == sel_terraintexture ) ) {
01436 vert->tri.texture = Texture_ForName( g_qeglobals.d_texturewin.texdef.name );
01437 vert->tri.texdef.SetName( vert->tri.texture->name );
01438 Terrain_AddTexture( p, vert->tri.texture );
01439 continue;
01440 }
01441
01442 if ( g_qeglobals.d_terrainFalloff == TERRAIN_FALLOFF_CURVED ) {
01443 if ( g_qeglobals.d_terrainBrush == TERRAIN_BRUSH_CIRCLE ) {
01444 vert->scale = ( 0.5f + cos( pd * M_PI ) * 0.5f );
01445 } else {
01446 vert->scale = ( 0.5f + cos( dx/ g_qeglobals.d_terrainBrushSize * M_PI ) * 0.5f ) * ( 0.5f + cos( dy/ g_qeglobals.d_terrainBrushSize * M_PI ) * 0.5f ) - 0.25;
01447 }
01448 } else {
01449 vert->scale = 1.0f - pd;
01450 }
01451
01452 switch( g_qeglobals.d_terrainNoiseType ) {
01453 case NOISE_PLUS :
01454 vert->scale *= crandom();
01455 break;
01456
01457 case NOISE_PLUSMINUS :
01458 vert->scale *= random();
01459 break;
01460 }
01461 }
01462 }
01463 }
01464 }
01465 }
01466 }
01467
01468 void Terrain_UpdateSelected( vec3_t vMove ) {
01469 int i;
01470 brush_t *pb;
01471 terrainMesh_t *p;
01472 vec3_t vMin;
01473 vec3_t vMax;
01474
01475 if ( g_qeglobals.d_select_mode == sel_terrainpoint ) {
01476 for( i = 0; i < g_qeglobals.d_numterrapoints; i++ ) {
01477 g_qeglobals.d_terrapoints[ i ]->height += vMove[ 2 ] * g_qeglobals.d_terrapoints[ i ]->scale;
01478 }
01479 }
01480
01481 for( pb = active_brushes .next; pb != &active_brushes; pb = pb->next ) {
01482
01483 if ( pb->terrainBrush ) {
01484 p = pb->pTerrain;
01485
01486 Terrain_CalcBounds( p, vMin, vMax );
01487 Terrain_CalcNormals( p );
01488 Brush_RebuildBrush( p->pSymbiot, vMin, vMax );
01489 }
01490 }
01491 }
01492
01493 int Terrain_PointInMoveList( terrainVert_t *pf ) {
01494 int i;
01495
01496 for( i = 0; i < g_qeglobals.d_numterrapoints; i++ ) {
01497 if ( pf == g_qeglobals.d_terrapoints[ i ] ) {
01498 return i;
01499 }
01500 }
01501
01502 return -1;
01503 }
01504
01505 void Terrain_RemovePointFromMoveList( terrainVert_t *v ) {
01506 int n;
01507 int i;
01508
01509 while( ( n = Terrain_PointInMoveList( v ) ) >= 0 ) {
01510 for( i = n; i < g_qeglobals.d_numterrapoints - 1; i++ ) {
01511 g_qeglobals.d_terrapoints[ i ] = g_qeglobals.d_terrapoints[ i + 1 ];
01512 }
01513
01514 g_qeglobals.d_numterrapoints--;
01515 }
01516 }
01517
01518 void Terrain_AddPoint( terrainMesh_t *p, terrainVert_t *v ) {
01519 if ( g_qeglobals.d_numterrapoints < MAX_TERRA_POINTS ) {
01520 g_qeglobals.d_terrapoints[ g_qeglobals.d_numterrapoints++ ] = v;
01521 }
01522 }
01523
01524 void Terrain_SelectAreaPoints( void ) {
01525 brush_t *pb;
01526 terrainMesh_t *p;
01527 int x;
01528 int y;
01529 vec3_t vec;
01530
01531 g_qeglobals.d_numterrapoints = 0;
01532 g_nPatchClickedView = -1;
01533
01534 for( pb = selected_brushes.next; pb != &selected_brushes; pb = pb->next ) {
01535 if ( pb->terrainBrush ) {
01536 p = pb->pTerrain;
01537 for( x = 0; x < p->width; x++ ) {
01538 for( y = 0; y < p->height; y++ ) {
01539 Terrain_CalcVertPos( p, x, y, vec );
01540 if ( within( vec, g_qeglobals.d_vAreaTL, g_qeglobals.d_vAreaBR ) ) {
01541 if ( g_qeglobals.d_numterrapoints < MAX_TERRA_POINTS ) {
01542 g_qeglobals.d_terrapoints[ g_qeglobals.d_numterrapoints++ ] = &p->heightmap[ x + y * p->width ];
01543 }
01544 }
01545 }
01546 }
01547 }
01548 }
01549 }
01550
01551 #define EPSILON 0.0001
01552
01553 bool RayTriangleIntersect( vec3_t orig, vec3_t dir, vec3_t vert1, vec3_t vert2, vec3_t vert3, float *t ) {
01554 float u;
01555 float v;
01556 vec3_t edge1;
01557 vec3_t edge2;
01558 vec3_t tvec;
01559 vec3_t pvec;
01560 vec3_t qvec;
01561 float det;
01562
01563 VectorSubtract( vert2, vert1, edge1 );
01564 VectorSubtract( vert3, vert1, edge2 );
01565
01566
01567 CrossProduct( dir, edge2, pvec );
01568
01569
01570 det = DotProduct( edge1, pvec );
01571 if ( det < EPSILON ) {
01572 return false;
01573 }
01574
01575
01576 VectorSubtract( orig, vert1, tvec );
01577
01578
01579 u = DotProduct( tvec, pvec );
01580 if ( ( u < 0.0f ) || ( u > det ) ) {
01581 return false;
01582 }
01583
01584
01585 CrossProduct( tvec, edge1, qvec );
01586
01587
01588 v = DotProduct( dir, qvec );
01589 if ( ( v < 0.0f ) || ( u + v > det ) ) {
01590 return false;
01591 }
01592
01593
01594 *t = DotProduct( edge2, qvec ) / det;
01595
01596 return true;
01597 }
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608 terrainFace_t *Terrain_Ray( vec3_t origin, vec3_t dir, brush_t *b, float *dist ) {
01609 terrainMesh_t *pm;
01610 int h;
01611 int w;
01612 int x;
01613 int y;
01614 float best_t;
01615 float t;
01616 terravert_t a0;
01617 terravert_t a1;
01618 terravert_t a2;
01619 terravert_t b0;
01620 terravert_t b1;
01621 terravert_t b2;
01622 terrainVert_t *vert;
01623 terrainFace_t *best;
01624
01625 best = NULL;
01626 best_t = WORLD_SIZE * 2;
01627
01628 pm = b->pTerrain;
01629 h = pm->height - 1;
01630 w = pm->width - 1;
01631
01632 vert = pm->heightmap;
01633 for( y = 0; y < h; y++, vert++ ) {
01634 for( x = 0; x < w; x++, vert++ ) {
01635 Terrain_GetTriangles( pm, x, y, &a0, &a1, &a2, &b0, &b1, &b2, NULL );
01636
01637 t = WORLD_SIZE * 2;
01638 if ( RayTriangleIntersect( origin, dir, a2.xyz, a1.xyz, a0.xyz, &t ) ) {
01639 if ( ( t >= 0 ) && ( t < best_t ) ) {
01640 best = &vert->tri;
01641 best_t = t;
01642 }
01643 }
01644
01645 t = WORLD_SIZE * 2;
01646 if ( RayTriangleIntersect( origin, dir, b2.xyz, b1.xyz, b0.xyz, &t ) ) {
01647 if ( ( t >= 0 ) && ( t < best_t ) ) {
01648 best = &vert->tri;
01649 best_t = t;
01650 }
01651 }
01652 }
01653 }
01654
01655 if ( !best ) {
01656 *dist = 0;
01657 return NULL;
01658 }
01659
01660 *dist = best_t;
01661
01662 return best;
01663 }
01664
01665
01666
01667
01668
01669
01670
01671
01672 void Select_TerrainFace ( brush_t * brush, terrainFace_t *terraface ) {
01673 #if 0
01674 UnSelect_Brush( brush );
01675
01676 if( numselfaces < MAX_SEL_FACES ) {
01677 selfaces[numselfaces].face = NULL;
01678 selfaces[numselfaces].brush = brush;
01679 selfaces[numselfaces].terraface = terraface;
01680 numselfaces++;
01681 }
01682 #endif
01683 }
01684
01685 void Select_TerrainFacesFromBrush( brush_t *brush ) {
01686 terrainMesh_t *pm;
01687 int h;
01688 int w;
01689 int x;
01690 int y;
01691
01692 pm = brush->pTerrain;
01693 h = pm->height - 1;
01694 w = pm->width - 1;
01695
01696 for( y = 0; y < h; y++ ) {
01697 for( x = 0; x < w; x++ ) {
01698 Select_TerrainFace( brush, &brush->pTerrain->heightmap[ x + y * pm->width ].tri );
01699 }
01700 }
01701 }
01702
01703 void SetTerrainTexdef( brush_t *brush, terrainFace_t *face, texdef_t *texdef ) {
01704 int oldFlags;
01705 int oldContents;
01706
01707 oldFlags = face->texdef.flags;
01708 oldContents = face->texdef.contents;
01709
01710 face->texdef = *texdef;
01711
01712 face->texdef.flags = ( face->texdef.flags & ~SURF_KEEP ) | ( oldFlags & SURF_KEEP );
01713 face->texdef.contents = ( face->texdef.contents & ~CONTENTS_KEEP ) | ( oldContents & CONTENTS_KEEP );
01714
01715 face->texture = Texture_ForName( texdef->name );
01716
01717
01718 }
01719
01720 void RotateTerrainFaceTexture( terrainFace_t *vert, int nAxis, float fDeg ) {
01721 }
01722
01723 void TerrainFace_FitTexture( terrainFace_t *vert ) {
01724 }
01725
01726 void Terrain_Init( void ) {
01727 g_qeglobals.d_terrainWidth = 64;
01728 g_qeglobals.d_terrainHeight = 64;
01729 g_qeglobals.d_terrainBrushSize = 12;
01730 g_qeglobals.d_terrainNoiseType = NOISE_NONE;
01731
01732 g_qeglobals.d_terrainFalloff = TERRAIN_FALLOFF_CURVED;
01733 g_qeglobals.d_terrainBrush = TERRAIN_BRUSH_CIRCLE;
01734
01735 }