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 
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                 // FIXME: need to not do loop lookups inside here
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         // draw the textured polys
01231         DrawTerrain( pm, pm->bSelected, true );
01232 
01233         // if selected, draw the red tint on the polys
01234         if( pm->bSelected ) { // && ( g_qeglobals.d_savedinfo.include & INCLUDE_CAMERATINT ) ) {
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         // draw the backside poly outlines
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         //FIXME
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     //if ( numselfaces || selected_brushes.next == &selected_brushes )
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     //if ( numselfaces || selected_brushes.next == &selected_brushes )
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     //brush_t *pb;
01318     //terrainMesh_t *p;
01319     //int i;
01320     //int j;
01321 
01322 //  g_qeglobals.d_numpoints = 0;
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     // find the point closest to the ray
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     //for( pb = selected_brushes.next; pb != &selected_brushes; pb = pb->next ) {
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 //  for( pb = selected_brushes.next; pb != &selected_brushes; pb = pb->next ) {
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     // begin calculating determinant - also used to calculate U parameter
01567     CrossProduct( dir, edge2, pvec );
01568 
01569     // if determinant is near zero, ray lies in plane of triangle
01570     det = DotProduct( edge1, pvec );
01571     if ( det < EPSILON ) {
01572         return false;
01573     }
01574 
01575     // calculate distance from vert1 to ray origin
01576     VectorSubtract( orig, vert1, tvec );
01577 
01578     // calculate U parameter and test bounds
01579     u = DotProduct( tvec, pvec );
01580     if ( ( u < 0.0f ) || ( u > det ) ) {
01581         return false;
01582     }
01583 
01584     // prepare to test V parameter
01585     CrossProduct( tvec, edge1, qvec );
01586 
01587     // calculate V parameter and test bounds
01588     v = DotProduct( dir, qvec );
01589     if ( ( v < 0.0f ) || ( u + v > det ) ) {
01590         return false;
01591     }
01592 
01593     // calculate t, scale parameters, ray intersects triangle
01594     *t = DotProduct( edge2, qvec ) / det;
01595 
01596     return true;
01597 }
01598 
01599 /*
01600 ==============
01601 Terrain_Ray
01602 
01603 Itersects a ray with a terrain
01604 Returns the face hit and the distance along the ray the intersection occured at
01605 Returns NULL and 0 if not hit at all
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 Select_TerrainFace
01668 
01669 Select the face
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     //Terrain_AddTexture( face->texture );
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     //g_qeglobals.d_terrainFalloff  = TERRAIN_FALLOFF_LINEAR;
01732     g_qeglobals.d_terrainFalloff    = TERRAIN_FALLOFF_CURVED;
01733     g_qeglobals.d_terrainBrush      = TERRAIN_BRUSH_CIRCLE;
01734     //g_qeglobals.d_terrainBrush        = TERRAIN_BRUSH_SQUARE;
01735 }

Generated on Thu Aug 25 12:38:40 2005 for Quake III Arena by  doxygen 1.3.9.1