00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef TERRAIN_MESH_INCLUDED
00023 #define TERRAIN_MESH_INCLUDED
00024
00025 #ifdef _MSC_VER
00026 #pragma warning( disable : 4786 ) // Debugger truncating names.
00027 #endif
00028
00029 #include "../grinliz/gldebug.h"
00030 #include "../grinliz/gltypes.h"
00031 #include "../grinliz/glrandom.h"
00032 #include "../grinliz/glgeometry.h"
00033 #include "../grinliz/glpublisher.h"
00034 #include "../grinliz/glbitarray.h"
00035 #include "../grinliz/glcolor.h"
00036 #include "../micropather/micropather.h"
00037 #include "meshgroup.h"
00038 #include "weather.h"
00039 #include "worlddefine.h"
00040 #include "meshnode.h"
00041 #include "shader.h"
00042 #include "SDL.h"
00043
00044 #include <set>
00045 #include <vector>
00046
00047
00048 namespace lilith3d
00049 {
00050
00051 class Texture;
00052 struct PathNode;
00053 struct PathSurfaceInstance;
00054 class StaticResource;
00055 class BuildingMesh;
00056 class LilithObject;
00057 struct L3State;
00058
00059 typedef grinliz::BitArray< VERTEXSIZE, VERTEXSIZE > VertexBitArray;
00060 typedef grinliz::BitArray< MAPSIZE/2, MAPSIZE/2 > PatchBitArray;
00061 typedef grinliz::BitArray< MAPSIZE, MAPSIZE > MapBitArray;
00062
00063 class TerrainListener : public grinliz::Listener< TerrainListener >
00064 {
00065 public:
00066 virtual void TerrainChange( const grinliz::Rectangle2I& vertexBounds ) = 0;
00067 };
00068
00069
00075 class TerrainMesh : public micropather::Graph
00076 {
00077 public:
00078 enum
00079 {
00080
00081 EAST, NORTHEAST, NORTH, NORTHWEST, WEST, SOUTHWEST, SOUTH, SOUTHEAST,
00082 BIT_E = 0x01,
00083 BIT_NE = 0x02,
00084 BIT_N = 0x04,
00085 BIT_NW = 0x08,
00086 BIT_W = 0x10,
00087 BIT_SW = 0x20,
00088 BIT_S = 0x40,
00089 BIT_SE = 0x80,
00090
00091
00092
00093
00094 MAX_LOD = MAP_POWER-1,
00095 MAX_NEIGHBORS = ( MAPSIZE >> MIN_LOD ) * 4,
00096
00097 PATCHSIZE = MAPSIZE / 2,
00098 WATER_SIZE = 4,
00099
00100 WATER_VERTEXSIZE = ( MAPSIZE / WATER_SIZE ) + 1,
00101 WATER_PATCHSIZE = ( MAPSIZE / WATER_SIZE ),
00102 WATER_INDEX_COUNT = (WATER_VERTEXSIZE-1) * (WATER_VERTEXSIZE-1) * 4,
00103 };
00104
00105 TerrainMesh();
00106 virtual ~TerrainMesh();
00107
00108 grinliz::Publisher< TerrainListener > publish;
00109
00110 virtual void DoCulling();
00111 void StreamOut();
00112 void StreamOutWater();
00113 void StreamOutMap();
00114 void StreamOutShadowed();
00115
00119 void LoadHeightMap( const char* filename );
00120
00123 void RandomHeightMap( U32 seed );
00124
00132 int IntersectRay( const grinliz::Vector3F& point,
00133 const grinliz::Vector3F& dir,
00134 grinliz::Vector3F* intersect,
00135 void** state );
00136
00143 float CalcHeight( float x, float y, grinliz::Vector3F* at=0, bool* inWater=0 );
00144
00145 inline static bool VertexInRange( int x, int y ) { return ( x >= 0 && x < (int)VERTEXSIZE && y >= 0 && y < (int)VERTEXSIZE ); }
00146
00153 void PointToPoly( float x, float y,
00154 int vind[],
00155 grinliz::Vector3F vertex[],
00156 bool *passable )
00157 {
00158 QuadNode* pNode;
00159 U32 poly;
00160
00161 PointToPoly( x, y, vind, vertex, passable, &pNode, &poly );
00162 }
00163
00164
00165 void TerrainMesh::RenderDecal( const grinliz::Rectangle2F& coord, bool suppressVState = false );
00166
00167
00171 float Height( int x, int y ) { GLASSERT( grinliz::InRange( x, 0, (int)VERTEXSIZE-1 ) );
00172 GLASSERT( grinliz::InRange( y, 0, (int)VERTEXSIZE-1 ) );
00173 return tvertex[y*VERTEXSIZE+x].pos.z; }
00174
00177 void StartHeightChange() { heightChange = true;
00178 heightChangeInit = false;
00179 }
00181 void SetHeight( int x, int y, float height );
00183 void SetHeightDelta( int x, int y, float delta ) { SetHeight( x, y, tvertex[y*VERTEXSIZE+x].pos.z + delta ); }
00187 void SetHeightFiltered( int x, int y, float height );
00188
00190 void EndHeightChange( bool callListeners=true );
00191
00192 bool IsHeightChanging() { return heightChange; }
00193
00198 void LockHeight( const grinliz::Rectangle2I& bounds );
00200 void UnLockHeight( const grinliz::Rectangle2I& bounds );
00201
00202
00208 std::vector< grinliz::Vector2F >* FindPath( float startX, float startY, float endX, float endY );
00209
00215 std::vector< grinliz::Vector2F >* FindPath( const LilithObject& start, const LilithObject& end );
00216
00217 bool Passable( float x, float y )
00218 {
00219 int vindex[3];
00220 grinliz::Vector3F vertex[3];
00221 bool passable;
00222
00223 PointToPoly( x, y, vindex, vertex, &passable );
00224 return passable;
00225 }
00226
00227
00228
00229
00230 float CalcCost( const grinliz::Vector3F& pos, float zSlope );
00231
00236 bool CanPlaceBuilding( int x, int y, const StaticResource* meshResource, grinliz::Rectangle2I* outVertexBounds );
00237
00242 BuildingMesh* CreateBuilding( int x, int y, const StaticResource* meshResource );
00243
00244
00245 const MapBitArray& GetMapPatherReserved() { return mapPatherReserved; }
00246
00247
00248 void PatchInfo( int patchX, int patchY, bool* level, float* z );
00249
00250
00251
00252
00253 bool ReservePather( const grinliz::Rectangle2I& map );
00254 void ReleasePather( const grinliz::Rectangle2I& map );
00255
00256 inline static int VINDX( int x, int y )
00257 {
00258 GLASSERT( grinliz::InRange( x, 0, VERTEXSIZE-1 ) );
00259 GLASSERT( grinliz::InRange( y, 0, VERTEXSIZE-1 ) );
00260 return y*VERTEXSIZE+x;
00261 }
00262 inline static int PINDX( int x, int y )
00263 {
00264 GLASSERT( grinliz::InRange( x, 0, PATCHSIZE-1 ) );
00265 GLASSERT( grinliz::InRange( y, 0, PATCHSIZE-1 ) );
00266 return y*PATCHSIZE+x;
00267 }
00268 inline static void INV_PINDX( int index, int* x, int* y )
00269 {
00270 *y = index / PATCHSIZE;
00271 *x = index - (*y) * PATCHSIZE;
00272
00273 GLASSERT( *x >= 0 && *x < PATCHSIZE );
00274 GLASSERT( *y >= 0 && *y < PATCHSIZE );
00275 }
00276 inline static int WVINDX( int x, int y )
00277 {
00278 GLASSERT( x >= 0 && x < WATER_VERTEXSIZE );
00279 GLASSERT( y >= 0 && y < WATER_VERTEXSIZE );
00280 return y*WATER_VERTEXSIZE + x;
00281 }
00282
00283 inline static void INV_VINDX( U32 index, grinliz::Vector2I* vertex )
00284 {
00285 vertex->y = index / lilith3d::VERTEXSIZE;
00286 vertex->x = index - vertex->y * lilith3d::VERTEXSIZE;
00287 }
00288 inline void INV_VINDX( U32 index, grinliz::Vector3F* vertex )
00289 {
00290 U32 iy = index / lilith3d::VERTEXSIZE;
00291 vertex->y = float( iy );
00292 vertex->x = float( index - iy * lilith3d::VERTEXSIZE );
00293 vertex->z = tvertex[ index ].pos.z;
00294 }
00295 inline static void INV_VINDX( U32 index, U32* x, U32* y )
00296 {
00297
00298
00299
00300
00301 *y = index / lilith3d::VERTEXSIZE;
00302 *x = index - (*y) * lilith3d::VERTEXSIZE;
00303
00304 GLASSERT( *x >= 0 && *x < (U32)lilith3d::VERTEXSIZE );
00305 GLASSERT( *y >= 0 && *y < (U32)lilith3d::VERTEXSIZE );
00306 }
00307 inline static void INV_VINDX( U32 index, float* x, float* y )
00308 {
00309 U32 iy = index / lilith3d::VERTEXSIZE;
00310 *y = float( iy );
00311 *x = float( index - iy * lilith3d::VERTEXSIZE );
00312 }
00313 static bool VertexToMap( const grinliz::Rectangle2I& vertex, grinliz::Rectangle2I* map )
00314 {
00315 GLASSERT( vertex.min.x >= 0 && vertex.max.x < VERTEXSIZE );
00316 GLASSERT( vertex.min.y >= 0 && vertex.max.y < VERTEXSIZE );
00317
00318 if ( vertex.Width() > 1 && vertex.Height() > 1 ) {
00319 *map = vertex;
00320 --map->max.x;
00321 --map->max.y;
00322 return true;
00323 }
00324 return false;
00325 }
00326 static void MapToVertex( const grinliz::Rectangle2I& map, grinliz::Rectangle2I* vertex )
00327 {
00328 GLASSERT( map.min.x >= 0 && map.max.x < MAPSIZE );
00329 GLASSERT( map.min.y >= 0 && map.max.y < MAPSIZE );
00330
00331 *vertex = map;
00332 ++vertex->max.x;
00333 ++vertex->max.y;
00334 }
00335
00336
00337 static void VertexToPatchExcl( const grinliz::Rectangle2I& vertex, grinliz::Rectangle2I* patch )
00338 {
00339 patch->min.x = vertex.min.x / 2;
00340 patch->min.y = vertex.min.y / 2;
00341 patch->max.x = ( vertex.max.x - 1 ) / 2;
00342 patch->max.y = ( vertex.max.y - 1 ) / 2;
00343 }
00344
00345
00346 static void VertexToPatchInc( const grinliz::Rectangle2I& vertex, grinliz::Rectangle2I* patch )
00347 {
00348 patch->min.x = (vertex.min.x-1) / 2;
00349 patch->min.y = (vertex.min.y-1) / 2;
00350 patch->max.x = ( vertex.max.x ) / 2;
00351 patch->max.y = ( vertex.max.y ) / 2;
00352 if ( patch->max.x == PATCHSIZE ) patch->max.x = PATCHSIZE-1;
00353 if ( patch->max.y == PATCHSIZE ) patch->max.y = PATCHSIZE-1;
00354 }
00355 static void PatchToVertex( const grinliz::Rectangle2I& patch, grinliz::Rectangle2I* vertex )
00356 {
00357
00358 GLASSERT( patch.min.x >= 0 );
00359 GLASSERT( patch.max.x < PATCHSIZE );
00360 GLASSERT( patch.min.y >= 0 );
00361 GLASSERT( patch.max.y < PATCHSIZE );
00362
00363 vertex->min.x = patch.min.x * 2;
00364 vertex->min.y = patch.min.y * 2;
00365 vertex->max.x = patch.max.x * 2 + 2;
00366 vertex->max.y = patch.max.y * 2 + 2;
00367
00368 GLASSERT( vertex->min.x >= 0 );
00369 GLASSERT( vertex->max.x < VERTEXSIZE );
00370 GLASSERT( vertex->min.y >= 0 );
00371 GLASSERT( vertex->max.y < VERTEXSIZE );
00372 }
00373
00374 void DisplayInfo( float x, float y );
00375
00376 static void DumpMemUse( FILE* fp );
00377
00378
00379 bool MicroTravel( float speed,
00380 grinliz::Vector3F* pos,
00381 grinliz::Vector3F* dir,
00382 PathSurfaceInstance** psi,
00383 const grinliz::Vector2F* path,
00384 int *pathIndex,
00385 int pathSize );
00386
00387 virtual float LeastCostEstimate( void* stateStart, void* stateEnd );
00388 virtual void AdjacentCost( void* state, std::vector< micropather::StateCost > *adjacent );
00389 virtual void PrintStateInfo( void* state );
00390
00391
00392
00393 void AdjacentState( void* state, void* adjacent[] );
00394
00395 const grinliz::LineLoop& Frustum2D() { return frustum2D; }
00396 void StateToPlane( void* state, grinliz::Plane *plane );
00397
00398 private:
00399
00400 void InitQuadCache();
00401 void InitEdges();
00402 void InitQuadNodes();
00403 void InitNoise();
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413 struct QuadNode;
00414
00415 void StreamOutLand( Lilith3D* lilith );
00416 void StreamOutLandFlat( Lilith3D* lilith, bool shadows );
00417 void StreamOutLandFlatRec( bool shadows );
00418 void StreamOutLandLOD( Lilith3D* lilith );
00419 void StreamOutLandLODRec( const grinliz::Color4F* );
00420 void StreamOutLandPather( Lilith3D* lilith );
00421 void StreamOutLandPatherRec();
00422 void StreamOutSkybox( Lilith3D* lilith );
00423 void StreamOutSkyboxQuads( Lilith3D* lilith, const grinliz::Color3F& color, float alpha, const Texture* const tex[] );
00424 void StreamOutSkydome( Lilith3D* lilith );
00425 void StreamOutSkydomeQuads( Lilith3D* lilith, const grinliz::Color3F& color, float alpha, const Texture* tex );
00426 void StreamOutBottom();
00427
00428 void RandomHeightMapRec( grinliz::Random* random, grinliz::Rectangle2I rect, float range );
00429
00430
00431 void CalcVertexNormals( const grinliz::Rectangle2I vertexBounds );
00432
00433 void RayCastToSun( int x, int y, const grinliz::Vector3F& sunlight, float* output );
00434 const Texture *water;
00435
00436 std::vector< grinliz::Vector3F > skydomeVertex;
00437 std::vector< U32 > skydomeIndex;
00438 std::vector< grinliz::Vector2F > skydomeTex;
00439
00440
00441
00442
00443 enum { QUAD_CACHE_SIZE = 16 };
00444 struct QuadCache
00445 {
00446 #ifdef DEBUG
00447 QuadCache() { GLASSERT( sizeof( QuadCache ) == 128 ); }
00448 #endif
00449
00450
00451 int index[10];
00452 int nIndex;
00453 U8 dVX[10];
00454 U8 dVY[10];
00455
00456
00457 U8 possible[8];
00458 U8 size[8];
00459 struct
00460 {
00461 S8 dx;
00462 S8 dy;
00463 } facing[8][3];
00464 };
00465 QuadCache m_quadCache[QUAD_CACHE_SIZE];
00466
00467
00468
00469 struct QuadNode
00470 {
00471 void Init( unsigned _x, unsigned _y )
00472 {
00473 GLASSERT( _x < 0xffff );
00474 GLASSERT( _y < 0xffff );
00475 this->x = (U16)_x;
00476 this->y = (U16)_y;
00477 hasRender = 0;
00478 }
00479
00480
00481 void CalcCorner( int dir, grinliz::Vector2F* point );
00482
00483 bool Render() { return hasRender ? true : false; }
00484
00485 void CreateRender( int _numVertex )
00486 {
00487 GLASSERT( !hasRender );
00488 GLASSERT( _numVertex >=6 && _numVertex <= 10 );
00489 numVertex = _numVertex;
00490 hasRender = 1;
00491 }
00492
00493 void DeleteRender()
00494 {
00495 hasRender = 0;
00496 }
00497
00498 U32 PatchX() { return x / 2; }
00499 U32 PatchY() { return y / 2; }
00500
00501
00502 bool HasPathing()
00503 {
00504 GLASSERT( hasRender );
00505 if ( passable )
00506 return true;
00507 return false;
00508 }
00509
00510 unsigned NumPoly() { return numVertex-2; }
00511
00512 void GetPoly( U32 i, int* vind )
00513 {
00514 GLASSERT( i < NumPoly() );
00515 vind[0] = fanIndexBase[0] + fanOffset;
00516 vind[1] = fanIndexBase[i+1] + fanOffset;
00517 vind[2] = fanIndexBase[i+2] + fanOffset;
00518 }
00519
00520
00521
00522 int FindPoly( int tailVIndex, int headVIndex );
00523
00524 public:
00525
00526
00527 U16 x;
00528 U16 y;
00529
00530 int* fanIndexBase;
00531 int fanOffset;
00532
00533 unsigned hasRender : 1;
00534 unsigned numVertex : 4;
00535 unsigned flat : 1;
00536 unsigned passable : 8;
00537
00538
00539 unsigned cacheIndex : 4;
00540
00541 };
00542
00543 const QuadCache& GetQuadCache( QuadNode* node ) {
00544 const QuadCache& qc = m_quadCache[ node->cacheIndex ];
00545 GLASSERT( qc.nIndex == (int)node->numVertex );
00546 return qc;
00547 }
00548
00549 bool PolyPassable( QuadNode* node, U32 poly );
00550
00551 void CalcTri( QuadNode* quadNode, int poly, grinliz::Vector3F output[] );
00552
00553 void CalcTriCentroid( const grinliz::Vector3F* tri, grinliz::Vector3F* center )
00554 {
00555 for( int i=0; i<3; ++i )
00556 center->X(i) = ( tri[0].X(i) + tri[1].X(i) + tri[2].X(i) ) / 3.0f;
00557 }
00558
00559 void CalcTriCentroid( QuadNode* quadNode, int poly, grinliz::Vector3F* center );
00560
00561
00562 PathSurfaceInstance* FindBuildingForPather( QuadNode* quadNode, U32 poly );
00563
00564 QuadNode* FindQuadNodeForPather( PathSurfaceInstance* psi, int index, U32* poly );
00565
00566 friend struct QuadNode;
00567
00568 struct QuadNodeInfo
00569 {
00570 QuadNode* node;
00571 int dir;
00572 int x, y, size;
00573 void Set( int _x, int _y, int _size, int _dir ) {
00574 this->x = _x; this->y = _y; this->size = _size; this->dir = _dir;
00575 }
00576 };
00577
00578
00579 void PointToPoly( float x, float y,
00580 int vind[],
00581 grinliz::Vector3F vertex[],
00582 bool *passable,
00583 QuadNode** node,
00584 U32* poly );
00585
00586 void PointToPoly( float x, float y,
00587 QuadNode** node,
00588 U32* poly )
00589 {
00590 int vindex[3];
00591 grinliz::Vector3F vertex[3];
00592 bool passable;
00593 PointToPoly( x, y, vindex, vertex, &passable, node, poly );
00594 }
00595
00596 enum {
00597 NUM_QUADNODES = PATCHSIZE*PATCHSIZE
00598 };
00599
00600
00601
00602
00603 enum { QUADNODE_MEM_SIZE = NUM_QUADNODES*sizeof(QuadNode)+16 };
00604 U8 quadNodeMem[QUADNODE_MEM_SIZE];
00605 QuadNode *quadNodeArr;
00606
00607 VertexBitArray vertexInUse;
00608 MapBitArray mapPatherReserved;
00609
00610 int INV_DIR( int dir ) { return ( dir+4 )%8; }
00611
00612 void InitQuadNodesRec( QuadNode* node, int x, int y, unsigned lod );
00613
00614
00615
00616 void SplitAndMerge( const grinliz::Rectangle2I& patchBounds, grinliz::Rectangle2I* update );
00617
00618
00619
00620 void ClearQuadTree( const grinliz::Rectangle2I& patchBounds );
00621
00622 QuadNode* GetQuadNode( int x, int y )
00623 {
00624 if ( x < 0 || y < 0 || x >= MAPSIZE || y >= MAPSIZE )
00625 return 0;
00626
00627 QuadNode* node = &quadNodeArr[ PINDX( x/2, y/2 ) ];
00628 GLASSERT( grinliz::InRange( x, (int)node->x, (int)node->x+1 ) );
00629 GLASSERT( grinliz::InRange( y, (int)node->y, (int)node->y+1 ) );
00630 return node;
00631 }
00632
00633
00634
00635
00636
00637 QuadNode* GetNeighborNode( QuadNode* origin, int tailVertex, int headVertex, U32* poly );
00638
00639
00640
00641 void CalcQuadRender( QuadNode* node );
00642
00643 #ifdef DEBUG
00644
00645 bool ValidateQuadRender( QuadNode* node );
00646 #endif
00647
00648 void CalcQuadRender( const grinliz::Rectangle2I& patchBounds );
00649
00650
00651 bool IsErrorOverThresh( int x, int y, int size );
00652
00653 void* QuadNodeToState( QuadNode* quadNode, U32 poly ) {
00654 GLASSERT( quadNode != 0 );
00655
00656 GLASSERT( sizeof( QuadNode ) == 16 );
00657 GLASSERT( ( ((UPTR)quadNode) & 0xf ) == 0 );
00658 GLASSERT( poly >= 0 && poly < 16 );
00659 GLASSERT( quadNode->Render() );
00660
00661 void* result = (void*)( ((UPTR)quadNode) | poly );
00662 GLASSERT( result != 0 );
00663 return result;
00664 }
00665
00666 void* TerrainPointToState( float x, float y )
00667 {
00668 QuadNode* quadNode = 0;
00669 U32 poly;
00670 PointToPoly( x, y, &quadNode, &poly );
00671 return QuadNodeToState( quadNode, poly );
00672 }
00673
00674 QuadNode* StateToQuadNode( void* state, U32* poly ) {
00675 GLASSERT( StateIsQuadNode( state ) );
00676 *poly = ((U32)((UPTR)state)) & 0xf;
00677 QuadNode* result = (QuadNode*) ( ((UPTR)state) & (~0xf) );
00678
00679 GLASSERT( result != 0 );
00680
00681 GLASSERT( result->Render() );
00682 return result;
00683 }
00684
00685 bool StateIsQuadNode( void* state ) {
00686 if ( state >= quadNodeMem && state < ((U8*)quadNodeMem+QUADNODE_MEM_SIZE) )
00687 return true;
00688 return false;
00689 }
00690
00691 QuadNode* StateToQuadNode( void* state ) {
00692 GLASSERT( StateIsQuadNode( state ) );
00693 QuadNode* result = (QuadNode*) ( ((UPTR)state) & (~0xf) );
00694 GLASSERT( result != 0 );
00695 GLASSERT( result->Render() );
00696 return result;
00697 }
00698
00699
00700 void FilterPath( void **states, unsigned size );
00701
00702 void FilterTerrainPath( void **states, unsigned size );
00703
00704 void StreamOutLandRec( Lilith3D* lilith,
00705 QuadNode* node,
00706 int frustum );
00707
00708 float OceanIntensity( float eyeX, float eyeY, float vX, float vY )
00709 {
00710 float len = grinliz::Clamp( grinliz::Length( eyeX - vX, eyeY - vY ), 0.0f, FAR_PLANE_DISTANCE );
00711 return 0.5f + 0.5f * ( 1.0f - len / FAR_PLANE_DISTANCE );
00712 }
00713
00714 enum {
00715 NORMAL_DIVISIONS = 31,
00716 NUM_LAYERS = 4,
00717 };
00718
00719 grinliz::LineLoop frustum2D;
00720
00721
00722
00723 struct Range {
00724 int start;
00725 int end;
00726
00727 int Length() { return end-start+1; }
00728 void Init( int s, int e ) { start = s; end = e; }
00729 };
00730
00731
00732
00733
00734
00735
00736 Range vertexRange[ VERTEXSIZE ];
00737 Range patchRange[ PATCHSIZE ];
00738 Range waterPatchRange[ WATER_PATCHSIZE ];
00739
00740
00741 grinliz::Rectangle2I looseVertexBounds;
00742 grinliz::Rectangle2I looseWaterVertexBounds;
00743
00744 #ifdef DEBUG
00745
00746 grinliz::BitArray< PATCHSIZE, PATCHSIZE > quadsDrawn;
00747 #endif
00748
00749
00750 grinliz::Rectangle3F corners;
00751
00752
00753 unsigned int waterStrip[ WATER_VERTEXSIZE*2 ];
00754
00755 struct TVertex
00756 {
00757 grinliz::Vector3F pos;
00758 grinliz::Vector3F normal;
00759 };
00760 TVertex tvertex[ VERTEXSIZE * VERTEXSIZE ];
00761
00762 struct WVertex
00763 {
00764 grinliz::Vector3F pos;
00765 grinliz::Vector2F tex;
00766 };
00767 WVertex wvertex[WATER_VERTEXSIZE*2];
00768
00769 U32 vboTVertex;
00770 U32 vboWVertex;
00771
00772 int waterPoly;
00773 int landPoly;
00774 int landQuad;
00775 int overPoly;
00776
00777 bool heightChange;
00778 bool heightChangeInit;
00779 grinliz::Rectangle2I heightChangeBounds;
00780 grinliz::BitArray< VERTEXSIZE, VERTEXSIZE > heightLockArray;
00781 bool regenHeightArray;
00782 std::list< grinliz::Rectangle2I > heightLock;
00783 micropather::MicroPather pather;
00784
00785
00786 enum { FUZZ_3D_COUNT = 64 };
00787 float fuzz3D[ FUZZ_3D_COUNT ];
00788
00789
00790
00791 float TextureZ( float z, int index ) {
00792 const float SPLIT = 0.35f;
00793 const float SPLITM1 = ( 1.0f - SPLIT );
00794 if ( z > 0.0f )
00795 return z / TERRAIN_MAX * SPLITM1 + SPLIT + fuzz3D[index&(FUZZ_3D_COUNT-1)];
00796 else
00797 return ( z - TERRAIN_MIN ) / (-TERRAIN_MIN) * SPLIT;
00798 }
00799
00800
00801 enum {
00802 INDEX_BUFFER_SIZE = 1000,
00803 };
00804 U32 triIndexBuffer[INDEX_BUFFER_SIZE];
00805
00806 grinliz::Vector3F _eye;
00807 Lilith3D* _lilith;
00808 const Texture* _terrainTex[NUM_LAYERS];
00809 };
00810 };
00811 #endif
00812