Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

terrain.cpp

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 /*
00023 
00024 Todo:
00025 
00026 immediate:
00027 Texture placement
00028 New map format
00029 q3map
00030 
00031 
00032 later:
00033 Smoothing brush
00034 Stitching terrains together
00035 Cross terrain selection
00036 
00037 
00038 
00039 
00040 
00041 Terrain_ApplyMatrix
00042 UpdateTerrainInspector
00043 
00044 */
00045 
00046 #include "stdafx.h"
00047 #include "qe3.h"
00048 #include "DialogInfo.h"
00049 #include "assert.h"
00050 
00051 //random in the range [0, 1]
00052 #define random()            ((rand () & 0x7fff) / ((float)0x7fff))
00053 
00054 //random in the range [-1, 1]
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 Terrain_SetEpair
00067 sets an epair for the given patch
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 Terrain_GetKeyValue
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 Terrain_MemorySize
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         // first tri
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         // second tri
00128         *b0 = *a2;
00129         Terrain_GetVert( pm, x + 1, y, 0.0f, 1.0f, b1, texture );
00130         *b2 = *a0;
00131     } else {
00132         // first tri
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         // second tri
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             // first tri
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             // first tri
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         // shift all textures down to remove the texture from the list
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     // calculate the face normals
00285     Terrain_CalcNormals( pm );
00286    
00287     // find the farthest points in x,y,z
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         // copy the texdef to the brush faces texdef
00301         f->texdef = pm->heightmap->tri.texdef;
00302     }
00303 
00304     // FIXME: this entire type of linkage needs to be fixed
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     // read the texturename
00388     GetToken( false );
00389     f->texdef.SetName( token );
00390 
00391     // Load the texture, and set the face to that texture's defaults
00392     f->texture = Texture_ForName( f->texdef.Name() );
00393 
00394     // read the texturedef
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     // the flags and value field aren't necessarily present
00407     //f->texture = Texture_ForName( f->texdef.Name() );
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     // get width
00436     GetToken( false );
00437     w = atoi( token );
00438 
00439     // get height
00440     GetToken( false );
00441     h = atoi( token );
00442 
00443     pm = MakeNewTerrain( w, h );
00444 
00445     // get scale_x
00446     GetToken( false );
00447     pm->scale_x = atoi( token );
00448 
00449     // get scale_y
00450     GetToken( false );
00451     pm->scale_y = atoi( token );
00452 
00453     // get origin
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     // get the height map
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     // only output flags and value if not default
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     // not written yet
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     //for( x = 0; x < num; x++, vert++ ) {
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         //FIXME
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     // if we are scaling in the same dimension the terrain has no depth
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     // abs of both should always be equal
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     // first tri
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     //int           n;
00924     //float         x1;
00925     //float         y1;
00926     float           scale_x;
00927     float           scale_y;
00928     //vec3_t        pSelectedPoints[ MAX_TERRA_POINTS ];
00929     //int           nIndex;
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                     // first tri
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                     // second tri
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                     // first tri
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                     // second tri
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     // Draw normals
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             // normals
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