/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2006 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main programmer: Marco Biasini */ #ifndef TERRAIN_PAGE_H #define TERRAIN_PAGE_H #define USE_VBO #include "terrain_quad.h" #include class TerrainPage; class Terrain; typedef TerrainPage *pTerrainPage; struct Vertex { TexCoord t; Triple p; }; typedef Vertex *pVertex; typedef struct { Triple correct; Triple real; float diff; } LODError, *pLODError; class TerrainPage : public TerrainQuad { public: enum { TP_LEFT = 0, TP_RIGHT = 1, TP_BOTTOM = 2, TP_TOP = 3 }; const static int MAX_LODS = 5; /** * Creates a new terrain page with its lower left corner set * to C = ( _xOffset, _zOffset ), where the two values specify * the offset in the height-map. * The size of the page, as well as the scaling factors are read * from the _owner terrain page. */ TerrainPage( Terrain *_owner, int _xOffset, int _zOffset ); /** * This is used only internally for communication between the TerrainPage and * the Terrain class itself. */ inline bool isActive() { return active; } ~TerrainPage( ) { if ( isVisible ) hide(); } /** * @brief Makes the terrain look as if it were created with the given level of * detail. */ void mimick( int _level ) {} /** * @brief Draws a box around the TerrainPage. For debugging purposes. */ void drawBox(); /** * @brief Calculates the smallest fitting axis aligned bounding box for this TerrainPage. */ virtual void calculateBounds(); /** * @brief Sets the visibility to _flag. If the visibility changed, the vertex and index * arrays are allocated or freed, respectively. */ inline void setVisibility( bool _flag ); /** * @brief Prepares the page for rendering. */ void show( ); /** * @brief Frees most of the memory for economomical reasons. */ void hide( ); /** * @brief Updates the tesselation if necessary. */ void updateTesselation( ); /** * @return The current tesselation level. */ int getLOD() { return currentLOD; } /** * @return The curren tween factor. This is a floating point value between 0.0f and 1.0f */ float getTween() { return 0.0f; } /** * @brief Determines the new LOD which should be used by this terrain page based on * the distance from the camera. * * No geometry is updated in this method. You need to call * updateTesselation() in order to see a change in geometry. This method is * just a recommondation for the LOD. It might be invalid due to outer * constraints. */ int chooseLOD(); /** * If the terrain pages tesselation level changed between the last and the * current frame, this function returns true, else you'll get false as the * return value. * @return True if the page needs an update and false if not. */ bool isDirty() { return forceTesselation; } /** * @brief Calculates the maximal errors for every LOD. */ void calculateErrors(); /** * @brief Calculates the error for the given LOD. We just need to know the "worst" * vertex for choosing an appropriate LOD. */ void calculateError( int _lod ); /** * Tests if the terrain page would cull against the viewing frustum. */ bool cull( ); bool needsRetesselation(); /** * Sets the neighbors of this terrain page. pass null if a neighbor if this * pages is at the border. */ inline void setNeighbors( pTerrainPage _left, pTerrainPage _right, pTerrainPage _top, pTerrainPage _bottom ) { left = _left; right = _right; top = _top; bottom = _bottom; } /** * Sets the position of the TerrainPage. Is this needed? */ inline void setPosition( const Triple& _pos ) { position.x = _pos.x; position.y = _pos.y; position.z = _pos.z; } pTerrainPage getLeft() { return left; } pTerrainPage getRight() { return right; } pTerrainPage getBottom() { return bottom; } pTerrainPage getTop() { return top; } /** * Does what exactly what the name says and nothing more. */ void draw( ); /** * @return the next active page */ inline pTerrainPage getNext() { return next; } /** * Returns the previous active page */ inline pTerrainPage getPrevious() { return previous; } inline int getCurrentLOD() { return currentLOD; } /** * @return Returns the wanted LOD. Make sure you call this method after a call to * chooseLOD() or you will get screwed values. */ inline int getWantedLOD() { return wantedLOD; } /** * @brief Removes the page from the active page list. */ void deactivate(); /** * @brief Inserts the page into the active page list. */ void activate(); inline bool hasMaterial( int _i ) { return true; } inline void setWantedLOD( int _lod ) { if ( _lod >= TerrainPage::MAX_LODS ) wantedLOD = TerrainPage::MAX_LODS-1; else if ( _lod < 0 ) wantedLOD = 0; else wantedLOD = _lod; } protected: /** * @brief Tesselates one row of the terrain page. * @param _z The z-offset of the row * @param _xStride Determines the step-size horizontally * @param _zStride Determines the step-size vertically. * @param _adaptRight True if the right neighbor has a coarser * tesselation level. * @param _adaptLeft True if the left neighbor has a coarser * tesselation level. */ void tesselateRow( int _z, int _xStride, int _zStride, bool _adaptLeft, bool _adaptRight ); /** * @brief Returns four boolean values in the oder */ void determineBorderAdaption( bool _adapt[] ); /** * @brief Adds the given index to the index-array */ inline void addIndex( unsigned short _index ); /** * @brief We programmers are very lazy :) This method just adds the last added index * again. */ inline void addAgain(); void getCoord( int _x, int _z, TexCoord& _coord) const; /** * Fills _vertex with the vertex information at index. */ void getVertex( int _x, int _z, Triple& _vertex ) const; /** * Use this method to safely get a vertex at location ( _x, _z ). If it wasn't * created before, this method does that for you. */ short getIndex( int _x, int _z ); void tesselateLevelFourPatch( bool _adapt[] ); /** * Generates the tesselation for the given level of detail. */ void tesselate( int _lod ); float getAltitude( int _x, int _z ) const; int currentLOD, wantedLOD; float tween; pTerrainPage left, right, top, bottom; bool forceTesselation; bool active; pVertex vertices; unsigned short *indices; unsigned short *indexHash; int numIndices; int numVertices; #ifdef USE_VBO GLuint ibIdentifier, vbIdentifier; #endif bool isVisible; pTerrainPage next; pTerrainPage previous; LODError *errors; Triple position; }; inline void TerrainPage::setVisibility( bool _flag ) { if ( _flag ) { if ( !isVisible ) { isVisible = true; show( ); } active = true; } else { if ( isVisible ) { isVisible = false; hide( ); } } } inline void TerrainPage::addIndex( unsigned short _index ) { indices[numIndices] = _index; numIndices++; } inline void TerrainPage::addAgain() { indices[numIndices] = indices[numIndices-1]; numIndices++; } #endif