From: Mathias Froehlich Date: Thu, 15 Mar 2012 19:56:37 +0000 (+0100) Subject: scenery: Move flightgears paging back into the application. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=1ddb658a706e4d60d60cfce29ffb8f5bc9f71211;p=flightgear.git scenery: Move flightgears paging back into the application. This way of scenery paging is really application code. Now that the simgear stg loader is seperated from the paging code, this appication specific paging can reside here. May be at some time also use the spt stuff here. --- diff --git a/src/Main/fgviewer.cxx b/src/Main/fgviewer.cxx index acf6d9c44..73c3cb2aa 100644 --- a/src/Main/fgviewer.cxx +++ b/src/Main/fgviewer.cxx @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff --git a/src/Scenery/CMakeLists.txt b/src/Scenery/CMakeLists.txt index bb85fc0e6..3a4c9a7ec 100644 --- a/src/Scenery/CMakeLists.txt +++ b/src/Scenery/CMakeLists.txt @@ -4,6 +4,8 @@ set(SOURCES SceneryPager.cxx redout.cxx scenery.cxx + tilecache.cxx + tileentry.cxx tilemgr.cxx ) @@ -11,8 +13,9 @@ set(HEADERS SceneryPager.hxx redout.hxx scenery.hxx + tilecache.hxx + tileentry.hxx tilemgr.hxx ) - -flightgear_component(Scenery "${SOURCES}" "${HEADERS}") +flightgear_component(Scenery "${SOURCES}" "${HEADERS}") diff --git a/src/Scenery/tilecache.cxx b/src/Scenery/tilecache.cxx new file mode 100644 index 000000000..ffe62a744 --- /dev/null +++ b/src/Scenery/tilecache.cxx @@ -0,0 +1,218 @@ +// TileCache.cxx -- routines to handle scenery tile caching +// +// Written by Curtis Olson, started December 2000. +// +// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt +// +// 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 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// $Id$ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "tileentry.hxx" +#include "tilecache.hxx" + +TileCache::TileCache( void ) : + max_cache_size(100), current_time(0.0) +{ + tile_cache.clear(); +} + + +TileCache::~TileCache( void ) { + clear_cache(); +} + + +// Free a tile cache entry +void TileCache::entry_free( long tile_index ) { + SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING CACHE ENTRY = " << tile_index ); + TileEntry *tile = tile_cache[tile_index]; + tile->removeFromSceneGraph(); + tile_cache.erase( tile_index ); + delete tile; +} + + +// Initialize the tile cache subsystem +void TileCache::init( void ) { + SG_LOG( SG_TERRAIN, SG_INFO, "Initializing the tile cache." ); + + SG_LOG( SG_TERRAIN, SG_INFO, " max cache size = " + << max_cache_size ); + SG_LOG( SG_TERRAIN, SG_INFO, " current cache size = " + << tile_cache.size() ); + + clear_cache(); + + SG_LOG( SG_TERRAIN, SG_INFO, " done with init()" ); +} + + +// Search for the specified "bucket" in the cache +bool TileCache::exists( const SGBucket& b ) const { + long tile_index = b.gen_index(); + const_tile_map_iterator it = tile_cache.find( tile_index ); + + return ( it != tile_cache.end() ); +} + + +// Return the index of a tile to be dropped from the cache, return -1 if +// nothing available to be removed. +long TileCache::get_drop_tile() { + long min_index = -1; + double min_time = DBL_MAX; + float priority = FLT_MAX; + + tile_map_iterator current = tile_cache.begin(); + tile_map_iterator end = tile_cache.end(); + + for ( ; current != end; ++current ) { + long index = current->first; + TileEntry *e = current->second; + if (( !e->is_current_view() )&& + ( e->is_expired(current_time) )) + { + if (e->is_expired(current_time - 1.0)&& + !e->is_loaded()) + { + /* Immediately drop "empty" tiles which are no longer used/requested, and were last requested > 1 second ago... + * Allow a 1 second timeout since an empty tiles may just be loaded... + */ + SG_LOG( SG_TERRAIN, SG_DEBUG, " dropping an unused and empty tile"); + break; + } + if (( e->get_time_expired() < min_time )|| + (( e->get_time_expired() == min_time)&& + ( priority > e->get_priority()))) + { + // drop oldest tile with lowest priority + min_time = e->get_time_expired(); + priority = e->get_priority(); + min_index = index; + } + } + } + + SG_LOG( SG_TERRAIN, SG_DEBUG, " index = " << min_index ); + SG_LOG( SG_TERRAIN, SG_DEBUG, " min_time = " << min_time ); + + return min_index; +} + + +// Clear all flags indicating tiles belonging to the current view +void TileCache::clear_current_view() +{ + tile_map_iterator current = tile_cache.begin(); + tile_map_iterator end = tile_cache.end(); + + for ( ; current != end; ++current ) { + TileEntry *e = current->second; + if (e->is_current_view()) + { + // update expiry time for tiles belonging to most recent position + e->update_time_expired( current_time ); + e->set_current_view( false ); + } + } +} + +// Clear a cache entry, note that the cache only holds pointers +// and this does not free the object which is pointed to. +void TileCache::clear_entry( long tile_index ) { + tile_cache.erase( tile_index ); +} + + +// Clear all completely loaded tiles (ignores partially loaded tiles) +void TileCache::clear_cache() { + std::vector indexList; + tile_map_iterator current = tile_cache.begin(); + tile_map_iterator end = tile_cache.end(); + + for ( ; current != end; ++current ) { + long index = current->first; + SG_LOG( SG_TERRAIN, SG_DEBUG, "clearing " << index ); + TileEntry *e = current->second; + if ( e->is_loaded() ) { + e->tile_bucket.make_bad(); + // entry_free modifies tile_cache, so store index and call entry_free() later; + indexList.push_back( index); + } + } + for (unsigned int it = 0; it < indexList.size(); it++) { + entry_free( indexList[ it]); + } +} + +/** + * Create a new tile and schedule it for loading. + */ +bool TileCache::insert_tile( TileEntry *e ) { + // register tile in the cache + long tile_index = e->get_tile_bucket().gen_index(); + tile_cache[tile_index] = e; + e->update_time_expired(current_time); + + return true; +} + +/** + * Reloads a tile when it's already in memory. + */ +void TileCache::refresh_tile(long tile_index) +{ + const_tile_map_iterator it = tile_cache.find( tile_index ); + if ( it == tile_cache.end() ) + return; + + SG_LOG( SG_TERRAIN, SG_DEBUG, "REFRESHING CACHE ENTRY = " << tile_index ); + + if (it->second) + it->second->refresh(); +} + +// update tile's priority and expiry time according to current request +void TileCache::request_tile(TileEntry* t,float priority,bool current_view,double request_time) +{ + if ((!current_view)&&(request_time<=0.0)) + return; + + // update priority when higher - or old request has expired + if ((t->is_expired(current_time))|| + (priority > t->get_priority())) + { + t->set_priority( priority ); + } + + if (current_view) + { + t->update_time_expired( current_time ); + t->set_current_view( true ); + } + else + { + t->update_time_expired( current_time+request_time ); + } +} diff --git a/src/Scenery/tilecache.hxx b/src/Scenery/tilecache.hxx new file mode 100644 index 000000000..eb65696c8 --- /dev/null +++ b/src/Scenery/tilecache.hxx @@ -0,0 +1,134 @@ +// TileCache.hxx -- routines to handle scenery tile caching +// +// Written by Curtis Olson, started December 2000. +// +// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt +// +// 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 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// $Id$ + + +#ifndef _TILECACHE_HXX +#define _TILECACHE_HXX + +#include + +#include +#include "tileentry.hxx" + +using std::map; + +// A class to store and manage a pile of tiles +class TileCache { +public: + typedef map < long, TileEntry * > tile_map; + typedef tile_map::iterator tile_map_iterator; + typedef tile_map::const_iterator const_tile_map_iterator; +private: + // cache storage space + tile_map tile_cache; + + // maximum cache size + int max_cache_size; + + // pointers to allow an external linear traversal of cache entries + tile_map_iterator current; + + double current_time; + + // Free a tile cache entry + void entry_free( long cache_index ); + +public: + tile_map_iterator begin() { return tile_cache.begin(); } + tile_map_iterator end() { return tile_cache.end(); } + const_tile_map_iterator begin() const { return tile_cache.begin(); } + const_tile_map_iterator end() const { return tile_cache.end(); } + + // Constructor + TileCache(); + + // Destructor + ~TileCache(); + + // Initialize the tile cache subsystem + void init( void ); + + // Check if the specified "bucket" exists in the cache + bool exists( const SGBucket& b ) const; + + // Return the index of a tile to be dropped from the cache, return -1 if + // nothing available to be removed. + long get_drop_tile(); + + // Clear all flags indicating tiles belonging to the current view + void clear_current_view(); + + // Clear a cache entry, note that the cache only holds pointers + // and this does not free the object which is pointed to. + void clear_entry( long cache_entry ); + + // Refresh/reload a tile when it's already in memory. + void refresh_tile(long tile_index); + + // Clear all completely loaded tiles (ignores partially loaded tiles) + void clear_cache(); + + // Return a pointer to the specified tile cache entry + inline TileEntry *get_tile( const long tile_index ) const { + const_tile_map_iterator it = tile_cache.find( tile_index ); + if ( it != tile_cache.end() ) { + return it->second; + } else { + return NULL; + } + } + + // Return a pointer to the specified tile cache entry + inline TileEntry *get_tile( const SGBucket& b ) const { + return get_tile( b.gen_index() ); + } + + // Return the cache size + inline size_t get_size() const { return tile_cache.size(); } + + // External linear traversal of cache + inline void reset_traversal() { current = tile_cache.begin(); } + inline bool at_end() { return current == tile_cache.end(); } + inline TileEntry *get_current() const { + // cout << "index = " << current->first << endl; + return current->second; + } + inline void next() { ++current; } + + inline int get_max_cache_size() const { return max_cache_size; } + inline void set_max_cache_size( int m ) { max_cache_size = m; } + + /** + * Create a new tile and enqueue it for loading. + * @param b + * @return success/failure + */ + bool insert_tile( TileEntry* e ); + + void set_current_time(double val) { current_time = val; } + double get_current_time() const { return current_time; } + + // update tile's priority and expiry time according to current request + void request_tile(TileEntry* t,float priority,bool current_view,double requesttime); +}; + +#endif // _TILECACHE_HXX diff --git a/src/Scenery/tileentry.cxx b/src/Scenery/tileentry.cxx new file mode 100644 index 000000000..d85c73926 --- /dev/null +++ b/src/Scenery/tileentry.cxx @@ -0,0 +1,137 @@ +// tileentry.cxx -- routines to handle a scenery tile +// +// Written by Curtis Olson, started May 1998. +// +// Copyright (C) 1998 - 2001 Curtis L. Olson - http://www.flightgear.org/~curt +// +// 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 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include +#include +#include + +#include + +#include +#include + +#include "tileentry.hxx" + +using std::string; + +// Constructor +TileEntry::TileEntry ( const SGBucket& b ) + : tile_bucket( b ), + tileFileName(b.gen_index_str()), + _node( new osg::LOD ), + _priority(-FLT_MAX), + _current_view(false), + _time_expired(-1.0) +{ + tileFileName += ".stg"; + _node->setName(tileFileName); + // Give a default LOD range so that traversals that traverse + // active children (like the groundcache lookup) will work before + // tile manager has had a chance to update this node. + _node->setRange(0, 0.0, 10000.0); +} + +TileEntry::TileEntry( const TileEntry& t ) +: tile_bucket( t.tile_bucket ), + tileFileName(t.tileFileName), + _node( new osg::LOD ), + _priority(t._priority), + _current_view(t._current_view), + _time_expired(t._time_expired) +{ + _node->setName(tileFileName); + // Give a default LOD range so that traversals that traverse + // active children (like the groundcache lookup) will work before + // tile manager has had a chance to update this node. + _node->setRange(0, 0.0, 10000.0); +} + +// Destructor +TileEntry::~TileEntry () +{ +} + +// Update the ssg transform node for this tile so it can be +// properly drawn relative to our (0,0,0) point +void TileEntry::prep_ssg_node(float vis) { + if (!is_loaded()) + return; + // visibility can change from frame to frame so we update the + // range selector cutoff's each time. + float bounding_radius = _node->getChild(0)->getBound().radius(); + _node->setRange( 0, 0, vis + bounding_radius ); +} + +void +TileEntry::addToSceneGraph(osg::Group *terrain_branch) +{ + terrain_branch->addChild( _node.get() ); + + SG_LOG( SG_TERRAIN, SG_DEBUG, + "connected a tile into scene graph. _node = " + << _node.get() ); + SG_LOG( SG_TERRAIN, SG_DEBUG, "num parents now = " + << _node->getNumParents() ); +} + + +void +TileEntry::removeFromSceneGraph() +{ + SG_LOG( SG_TERRAIN, SG_DEBUG, "disconnecting TileEntry nodes" ); + + if (! is_loaded()) { + SG_LOG( SG_TERRAIN, SG_DEBUG, "removing a not-fully loaded tile!" ); + } else { + SG_LOG( SG_TERRAIN, SG_DEBUG, "removing a fully loaded tile! _node = " << _node.get() ); + } + + // find the nodes branch parent + if ( _node->getNumParents() > 0 ) { + // find the first parent (should only be one) + osg::Group *parent = _node->getParent( 0 ) ; + if( parent ) { + parent->removeChild( _node.get() ); + } + } +} + +void +TileEntry::refresh() +{ + osg::Group *parent = NULL; + // find the nodes branch parent + if ( _node->getNumParents() > 0 ) { + // find the first parent (should only be one) + parent = _node->getParent( 0 ) ; + if( parent ) { + parent->removeChild( _node.get() ); + } + } + _node = new osg::LOD; + if (parent) + parent->addChild(_node.get()); +} diff --git a/src/Scenery/tileentry.hxx b/src/Scenery/tileentry.hxx new file mode 100644 index 000000000..54cebe768 --- /dev/null +++ b/src/Scenery/tileentry.hxx @@ -0,0 +1,150 @@ +// tileentry.hxx -- routines to handle an individual scenery tile +// +// Written by Curtis Olson, started May 1998. +// +// Copyright (C) 1998 - 2001 Curtis L. Olson - http://www.flightgear.org/~curt +// +// 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 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// $Id$ + + +#ifndef _TILEENTRY_HXX +#define _TILEENTRY_HXX + + +#ifndef __cplusplus +# error This library requires C++ +#endif + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +/** + * A class to encapsulate everything we need to know about a scenery tile. + */ +class TileEntry { + +public: + // this tile's official location in the world + SGBucket tile_bucket; + std::string tileFileName; + +private: + + // pointer to ssg range selector for this tile + osg::ref_ptr _node; + // Reference to DatabaseRequest object set and used by the + // osgDB::DatabasePager. + osg::ref_ptr _databaseRequest; + + /** + * This value is used by the tile scheduler/loader to load tiles + * in a useful sequence. The priority is set to reflect the tiles + * distance from the center, so all tiles are loaded in an innermost + * to outermost sequence. + */ + float _priority; + /** Flag indicating if tile belongs to current view. */ + bool _current_view; + /** Time when tile expires. */ + double _time_expired; + +public: + + // Constructor + TileEntry( const SGBucket& b ); + TileEntry( const TileEntry& t ); + + // Destructor + ~TileEntry(); + + // Update the ssg transform node for this tile so it can be + // properly drawn relative to our (0,0,0) point + void prep_ssg_node(float vis); + + /** + * Transition to OSG database pager + */ + static osg::Node* loadTileByFileName(const std::string& index_str, + const osgDB::Options*); + /** + * Return true if the tile entry is loaded, otherwise return false + * indicating that the loading thread is still working on this. + */ + inline bool is_loaded() const + { + return _node->getNumChildren() > 0; + } + + /** + * Return the "bucket" for this tile + */ + inline const SGBucket& get_tile_bucket() const { return tile_bucket; } + + /** + * Add terrain mesh and ground lighting to scene graph. + */ + void addToSceneGraph( osg::Group *terrain_branch); + + /** + * disconnect terrain mesh and ground lighting nodes from scene + * graph for this tile. + */ + void removeFromSceneGraph(); + + /** + * Refresh a tile, reload the node from disk. + */ + void refresh(); + + /** + * return the scenegraph node for the terrain + */ + osg::LOD *getNode() const { return _node.get(); } + + inline double get_time_expired() const { return _time_expired; } + inline void update_time_expired( double time_expired ) { if (_time_expired _time_expired); } + + // Get the ref_ptr to the DatabaseRequest object, in order to pass + // this to the pager. + osg::ref_ptr& getDatabaseRequest() + { + return _databaseRequest; + } +}; + +#endif // _TILEENTRY_HXX diff --git a/src/Scenery/tilemgr.cxx b/src/Scenery/tilemgr.cxx index a61aaaae8..20c8d61c2 100644 --- a/src/Scenery/tilemgr.cxx +++ b/src/Scenery/tilemgr.cxx @@ -49,8 +49,6 @@ #include "tilemgr.hxx" using flightgear::SceneryPager; -using simgear::TileEntry; -using simgear::TileCache; FGTileMgr::FGTileMgr(): diff --git a/src/Scenery/tilemgr.hxx b/src/Scenery/tilemgr.hxx index 2d8348658..a218e175a 100644 --- a/src/Scenery/tilemgr.hxx +++ b/src/Scenery/tilemgr.hxx @@ -28,8 +28,8 @@ #include #include -#include -#include +#include "tileentry.hxx" +#include "tilecache.hxx" namespace osg { @@ -78,7 +78,7 @@ private: /** * tile cache */ - simgear::TileCache tile_cache; + TileCache tile_cache; simgear::SGTerraSync* _terra_sync; // Update the various queues maintained by the tilemagr (private diff --git a/utils/fgviewer/fgviewer.cxx b/utils/fgviewer/fgviewer.cxx index d90a91cbb..bbf78822c 100644 --- a/utils/fgviewer/fgviewer.cxx +++ b/utils/fgviewer/fgviewer.cxx @@ -44,7 +44,6 @@ #include #include #include -#include #include #include