terrainmesh.h

00001 /*--License:
00002         Lilith 3D Engine
00003         Copyright Lee Thomason (Grinning Lizard Software) 2002-2007
00004         www.grinninglizard.com/lilith
00005 
00006         This program is free software; you can redistribute it and/or
00007         modify it under the terms of the GNU General Public License
00008         as published by the Free Software Foundation; either version 2
00009         of the License, or (at your option) any later version.
00010 
00011         This program is distributed in the hope that it will be useful,
00012         but WITHOUT ANY WARRANTY; without even the implied warranty of
00013         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014         GNU General Public License for more details.
00015 
00016         You should have received a copy of the GNU General Public License
00017         along with this program; if not, write to the Free Software
00018         Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00019 
00020         The full text of the license can be found in license.txt
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                 // To reverse a direction: (dir+4)%8
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                 // For a mapsize of 4, LOD=0, 4x4       2^MAX = MAPSIZE
00092                 //                                         LOD=1, 2x2
00093                 //                                         LOD=2, 1x1
00094                 MAX_LOD = MAP_POWER-1,
00095                 MAX_NEIGHBORS = ( MAPSIZE >> MIN_LOD ) * 4,
00096 
00097                 PATCHSIZE = MAPSIZE / 2,
00098                 WATER_SIZE = 4,
00099                 // The water vertex size doesn't include the edges.
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,               // x, y point [in]
00154                                                 int vind[],                             // array of 3 vertex indices [out]
00155                                                 grinliz::Vector3F vertex[],             // array of 3 vertices that match indices [out]
00156                                                 bool *passable )                // set to true or false indicating whether the terrain is passable [out]
00157         {
00158                 QuadNode* pNode;
00159                 U32 poly;  
00160 
00161                 PointToPoly( x, y, vind, vertex, passable, &pNode, &poly );
00162         }
00163 
00164         // Internal. Renders a decal. ONLY vertex & texture coordinates written to "state"
00165         void TerrainMesh::RenderDecal( const grinliz::Rectangle2F& coord, bool suppressVState = false );
00166 
00167         // --- Morphing functionality --- //
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         // -- The pather -- //
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                 Cost to cover a terrain. Cost of 1.0 moves at normal speed, 2.0 half speed, etc.
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         // [Internal]
00245         const MapBitArray& GetMapPatherReserved()       { return mapPatherReserved; }
00246 
00247         // [Internal]
00248         void PatchInfo( int patchX, int patchY, bool* level, float* z );
00249 
00250         // Removes "map" from the pather. Used by building so they don't get pathed through.
00251         // Note that the pather is reserved in map (grid) coordinates. Return true if area
00252         // could be reserved.
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         }       // vertex
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         }       // water
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                 *y = index / lilith3d::VERTEXSIZE;
00299                 *x = index - ((*y)<<<MAP_POWER) - *y;
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         // A more conservatve converter. 
00336         // Vertex x=2 -> x=4, would convert to patch 1.
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         // A more inclusive converter.
00345         // vertex x=2 -> x=4 would convert to patch 0, 1, & 2
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                 // Patch (0,0)-(0,0) covers vertex (0,0)-(2,2)
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         // Travel along the path. Returns 'true' if stuck.
00379         bool MicroTravel(       float speed,                                    // speed on a flat surface
00380                                                 grinliz::Vector3F* pos,                 // in/out: position of the walker
00381                                                 grinliz::Vector3F* dir,                 // in/out: direction of the walker
00382                                                 PathSurfaceInstance** psi,              // in/out: psi (null implies terrain)
00383                                                 const grinliz::Vector2F* path,  // pointer to the path to be followed
00384                                                 int *pathIndex,                                 // current index into the path
00385                                                 int pathSize );                                 // length of the path
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         // Gets the cost of all the adjacent states, in edge order. 
00392         // adjacent is a 4 element array.
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         // Initialization (from constructor)
00400         void InitQuadCache();
00401         void InitEdges();
00402         void InitQuadNodes();
00403         void InitNoise();               // creates 2 noise textures
00404 
00405         /*
00406         // called by MicroTravel for travel across a single quad or tri
00407         void* MicroSubTravel(   const grinliz::Vector2F& start, 
00408                                                         const grinliz::Vector2F& dir,
00409                                                         void* state,
00410                                                         bool* reachedEnd );
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         // In vertex coordinates:
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         // There are 16 possible patch configurations, identified 
00441         // by the bits SENW. Use 16 for the VSIZE to optimize array indexing.
00442         // The origin is in the lower left.
00443         enum { QUAD_CACHE_SIZE = 16 };
00444         struct QuadCache
00445         {
00446                 #ifdef DEBUG
00447                 QuadCache()     { GLASSERT( sizeof( QuadCache ) == 128 ); }
00448                 #endif
00449 
00450                 // INDEX traits
00451                 int                                     index[10];              // 40 bytes:    6->10 indices (first and last the same)
00452                 int                                     nIndex;                 // 4 bytes
00453                 U8                                      dVX[10];                // 10 bytes:    vertex coord for each index
00454                 U8                                      dVY[10];                // 10 bytes
00455 
00456                 // TRI traits
00457                 U8                                      possible[8];    // 8 bytes:             maps 8 possible-tris to the 4-8 tri-in-use
00458                 U8                                      size[8];                // 8 bytes:             size of each tri-in-use (1 or 2)
00459                 struct 
00460                 {
00461                         S8                              dx;
00462                         S8                              dy;
00463                 } facing[8][3];                                         // 48 bytes:    facing of each edge. +1,0,-1. CCW from center.
00464         };
00465         QuadCache m_quadCache[QUAD_CACHE_SIZE];
00466 
00467 
00468         // Quad Ordering
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                 // x and y location of the node in the given direction.
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                 // Can this path at all?
00502                 bool HasPathing() 
00503                 {
00504                         GLASSERT( hasRender );
00505                         if ( passable ) // something is set...
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                 // Find a poly, by index, that has the 2 vindex's given.
00521                 // Returns < 0 if none found.
00522                 int FindPoly( int tailVIndex, int headVIndex );
00523 
00524         public:
00525                 // Want to fit the following into an intel cache line - 128 bits = 16 bytes = 4 dword
00526 
00527                 U16 x;
00528                 U16 y;
00529 
00530                 int*    fanIndexBase;                   // locations of the fan corners, for rendering
00531                 int             fanOffset;
00532 
00533                 unsigned hasRender              : 1;    // is the render state valid?
00534                 unsigned numVertex              : 4;    // 4-8 vertices
00535                 unsigned flat                   : 1;    // 1: the quad is flat: all passable, little terrain variance
00536                 unsigned passable               : 8;    // bitmap of whether a *polygon* is passable or not. There were
00537                                                                                 // a lot of rules for this, but now it is just based on whether
00538                                                                                 // the polygon is underwater.
00539                 unsigned cacheIndex             : 4;    // index into the quadCache
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         // From the terrain, the pather needs a building.
00562         PathSurfaceInstance* FindBuildingForPather( QuadNode* quadNode, U32 poly );
00563         // From a building, the pather needs terrain.
00564         QuadNode* FindQuadNodeForPather( PathSurfaceInstance* psi, int index, U32* poly );
00565 
00566         friend struct QuadNode;
00567 
00568         struct QuadNodeInfo
00569         {
00570                 QuadNode* node;         // null for virtual nodes
00571                 int dir;                        // NORTH, SOUTH, EAST, WEST
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,                       // x, y point [in]
00580                                                 int vind[],                                     // array of 3 vertex indices [out]
00581                                                 grinliz::Vector3F vertex[],     // array of 3 vertices that match indices [out]
00582                                                 bool *passable,                         // set to true or false indicating whether the terrain is passable [out]
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         // These structures are kept to 16 bytes, and are meant to be align for very
00601         // fast access, and to take advanage of the intel cache. Also, the pather
00602         // uses memory tricks, so they *must* be 16 byte aligned.
00603         enum { QUADNODE_MEM_SIZE = NUM_QUADNODES*sizeof(QuadNode)+16 };
00604         U8                      quadNodeMem[QUADNODE_MEM_SIZE];
00605         QuadNode        *quadNodeArr;
00606 
00607         VertexBitArray vertexInUse;                     // Set if a vertex is used by the LOD system
00608         MapBitArray        mapPatherReserved;   // Set if reserved for a building
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         // Divides up the terrain mesh until the polygons are as large as possible,
00615         // while still beneath the error threshhold. Called when a height change ends.
00616         void SplitAndMerge(     const grinliz::Rectangle2I& patchBounds, grinliz::Rectangle2I* update );
00617         
00618         // Clears out stuff in the quad tree for a change. QuadRender, MeshNodes, etc.
00619         // Be sure to follow with a call to CalcAllQuadRender and RestoreMeshNodes as appropriate.
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         // Get a node's neighbor - very useful for pathing. The 'head' and 'tail' are both 
00634         // on the *outside* of the quad. They are ordered (positive), so the left side is the 
00635         // current node, and the right side is the neighbor. This also allows the neighbor 
00636         // poly to be found.
00637         QuadNode* GetNeighborNode( QuadNode* origin, int tailVertex, int headVertex, U32* poly );
00638 
00639         // Compute a particular render node. Can get called at odd times,
00640         // and during EndHeightChange/CalcQuadRenderRec
00641         void CalcQuadRender( QuadNode* node );
00642 
00643         #ifdef DEBUG
00644         // Debug check to see if the state of this object is consistent.
00645         bool ValidateQuadRender( QuadNode* node );
00646         #endif
00647 
00648         void CalcQuadRender( const grinliz::Rectangle2I& patchBounds );
00649 
00650         // For the x, y, and size, would 2 triangles be over the error thresh hold?
00651         bool IsErrorOverThresh( int x, int y, int size );
00652 
00653         void* QuadNodeToState( QuadNode* quadNode, U32 poly ) {
00654                 GLASSERT( quadNode != 0 );      // 0,0 underwater
00655                 // depends on the quadnode being 16-byte aligned
00656                 GLASSERT( sizeof( QuadNode ) == 16 );
00657                 GLASSERT( ( ((UPTR)quadNode) & 0xf ) == 0 );
00658                 GLASSERT( poly >= 0 && poly < 16 );
00659                 GLASSERT( quadNode->Render() );         // and have a render established
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 //              GLASSERT( result->Leaf() );             // should always be a terminal node
00681                 GLASSERT( result->Render() );           // and have a render established
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() );           // and have a render established
00696                 return result;
00697         }
00698 
00699         // filter a path
00700         void FilterPath( void **states, unsigned size );                
00701         // firter a path of all QuadNode (called by FilterPath)
00702         void FilterTerrainPath( void **states, unsigned size );
00703 
00704         void StreamOutLandRec(  Lilith3D* lilith, 
00705                                                         QuadNode* node, 
00706                                                         int frustum );  // positive (fully inside) or intersecting
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,  // works better odd
00716                 NUM_LAYERS = 4,
00717         };
00718         
00719         grinliz::LineLoop frustum2D;
00720 
00721         // When culling is complete, the start and end [start,end] are computed.
00722         // The culling bounds are computed mathematically, and stored here.
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         // Subtle behavior here: a vertex is a mathematical point, which is or isn't visible.
00731         //                                           a patch is a square - if any part is visible, all is
00732         // The vertices are computed, but the patch is usually what is queried for occlusion -
00733         // or even color computation since colors are interpolated between vertices that may
00734         // not be visible.
00735         //
00736         Range vertexRange[ VERTEXSIZE ];
00737         Range patchRange[ PATCHSIZE ];
00738         Range waterPatchRange[ WATER_PATCHSIZE ];
00739 
00740         // At culling, compute the bounds of all the vertices, +1 extra row for color interpolation
00741         grinliz::Rectangle2I looseVertexBounds;
00742         grinliz::Rectangle2I looseWaterVertexBounds;
00743 
00744         #ifdef DEBUG
00745         // For debugging, which quads were rendered.
00746         grinliz::BitArray< PATCHSIZE, PATCHSIZE > quadsDrawn;
00747         #endif
00748 
00749         // The un-clipped terrain dimensions
00750         grinliz::Rectangle3F corners;   
00751 
00752         // Vertex strip used to render
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;           // actual unique triangles sent
00774         int landQuad;           // the number of quads (not subdivided) sent
00775         int overPoly;           // tris sent counting overdraw
00776 
00777         bool heightChange;
00778         bool heightChangeInit;
00779         grinliz::Rectangle2I heightChangeBounds;                // vertex bounds
00780         grinliz::BitArray< VERTEXSIZE, VERTEXSIZE > heightLockArray;
00781         bool regenHeightArray;
00782         std::list< grinliz::Rectangle2I > heightLock;
00783         micropather::MicroPather pather;
00784 
00785         // Used to add randomness to the 3D texturing.
00786         enum { FUZZ_3D_COUNT = 64 };    // power of 2
00787         float fuzz3D[ FUZZ_3D_COUNT ];
00788 
00789         //              TERRAIN_MIN-->0.0 maps to 0.0-->SPLIT
00790         //              0.0-->TERRAIN_MAX maps to SPLIT-->1.0
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         // Buffers used by the drawing routine.
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 

Generated on Fri Mar 23 19:36:22 2007 for Lilith3D by  doxygen 1.5.1-p1