From c1fc71066b0150070f98e69b0a4d8fea9ef4e99e Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Wed, 20 Oct 2021 23:39:59 +0100 Subject: [PATCH] WS30 Move VPB tile loading to the tile manager Previously VPB tiles were loaded by the STG file loader. This was not ideal as the VPB tile granularity is 1x1 degree while the STG file loader is 20x20km. This change makes the tile manager load VPB tiles explicitly on range, and allows better prioritization of the underlying terrain. --- src/Scenery/tilecache.cxx | 53 +++++++++++++++++++++++++++++++++++++-- src/Scenery/tilecache.hxx | 24 +++++++++--------- src/Scenery/tileentry.cxx | 33 +++++++++++++++++++++--- src/Scenery/tileentry.hxx | 30 +++++++++++++++++++--- src/Scenery/tilemgr.cxx | 41 ++++++++++++++++++++++++++---- src/Scenery/tilemgr.hxx | 1 + 6 files changed, 155 insertions(+), 27 deletions(-) diff --git a/src/Scenery/tilecache.cxx b/src/Scenery/tilecache.cxx index 69b135757..4a4c907ed 100644 --- a/src/Scenery/tilecache.cxx +++ b/src/Scenery/tilecache.cxx @@ -75,13 +75,21 @@ void TileCache::init( void ) { // Search for the specified "bucket" in the cache -bool TileCache::exists( const SGBucket& b ) const { +bool TileCache::exists_stg( 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() ); } +bool TileCache::exists_vpb( const SGBucket& b ) const { + // VPB tiles are stored with negative index to avoid clash with STG index + long tile_index = - b.gen_vpb_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. @@ -191,7 +199,7 @@ void TileCache::clear_cache() { /** * Create a new tile and schedule it for loading. */ -bool TileCache::insert_tile( TileEntry *e ) { +bool TileCache::insert_tile( STGTileEntry *e ) { // register tile in the cache long tile_index = e->get_tile_bucket().gen_index(); tile_cache[tile_index] = e; @@ -200,6 +208,19 @@ bool TileCache::insert_tile( TileEntry *e ) { return true; } +/** + * Create a new tile and schedule it for loading. VPB version, with negative index. + */ +bool TileCache::insert_tile( VPBTileEntry *e ) { + // register tile in the cache + long tile_index = - e->get_tile_bucket().gen_vpb_index(); + tile_cache[tile_index] = e; + e->update_time_expired(current_time); + + return true; +} + + // 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) { @@ -223,3 +244,31 @@ void TileCache::request_tile(TileEntry* t,float priority,bool current_view,doubl t->update_time_expired( current_time+request_time ); } } + +// Return a pointer to the specified tile cache entry +STGTileEntry* TileCache::get_stg_tile( const SGBucket& b ) const { + + const_tile_map_iterator it = std::find_if(tile_cache.begin(), tile_cache.end(), + [b](auto &t) { + return ((b.gen_index() == t.first) && (t.second->getExtension() == TileEntry::Extension::STG)); + }); + if ( it != tile_cache.end() ) { + return dynamic_cast(it->second); + } else { + return NULL; + } +} + +// Return a pointer to the specified tile cache entry +VPBTileEntry* TileCache::get_vpb_tile( const SGBucket& b ) const { + const_tile_map_iterator it = std::find_if(tile_cache.begin(), tile_cache.end(), + [b](auto &t) { + // Negative indices are used for the VPB tiles. + return (( - b.gen_vpb_index() == t.first) && (t.second->getExtension() == TileEntry::Extension::VPB)); + }); + if ( it != tile_cache.end() ) { + return dynamic_cast(it->second); + } else { + return NULL; + } +} diff --git a/src/Scenery/tilecache.hxx b/src/Scenery/tilecache.hxx index 79fec4170..de127e659 100644 --- a/src/Scenery/tilecache.hxx +++ b/src/Scenery/tilecache.hxx @@ -68,7 +68,8 @@ public: void init( void ); // Check if the specified "bucket" exists in the cache - bool exists( const SGBucket& b ) const; + bool exists_stg( const SGBucket& b ) const; + bool exists_vpb( const SGBucket& b ) const; // Return the index of a tile to be dropped from the cache, return -1 if // nothing available to be removed. @@ -88,18 +89,16 @@ public: // 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; - } + 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() ); - } + STGTileEntry* get_stg_tile( const SGBucket& b ) const; + VPBTileEntry* get_vpb_tile( const SGBucket& b ) const; // Return the cache size inline size_t get_size() const { return tile_cache.size(); } @@ -121,7 +120,8 @@ public: * @param b * @return success/failure */ - bool insert_tile( TileEntry* e ); + bool insert_tile( STGTileEntry* e ); + bool insert_tile( VPBTileEntry* e ); void set_current_time(double val) { current_time = val; } double get_current_time() const { return current_time; } diff --git a/src/Scenery/tileentry.cxx b/src/Scenery/tileentry.cxx index 566af52ba..53ffc40aa 100644 --- a/src/Scenery/tileentry.cxx +++ b/src/Scenery/tileentry.cxx @@ -37,10 +37,9 @@ using std::string; -// Constructor +// Base constructor TileEntry::TileEntry ( const SGBucket& b ) : tile_bucket( b ), - tileFileName(b.gen_index_str()), _node( new osg::LOD ), _priority(-FLT_MAX), _current_view(false), @@ -48,8 +47,6 @@ TileEntry::TileEntry ( const SGBucket& b ) { _create_orthophoto(); - 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. @@ -131,3 +128,31 @@ TileEntry::removeFromSceneGraph() } } +// Constructor - STG Variant +STGTileEntry::STGTileEntry ( const SGBucket& b ) : TileEntry(b) +{ + tileFileName = b.gen_index_str() + ".stg"; + _node->setName(tileFileName); +} + +// Destructor - STG Variant +STGTileEntry::~STGTileEntry () +{ +} + +// Constructur - VPB version +VPBTileEntry::VPBTileEntry ( const SGBucket& b ) : TileEntry(b) +{ + tileFileName = "vpb/" + b.gen_vpb_base() + ".osgb"; + _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, 160000.0); +} + +// Destructor - VPB Variant +VPBTileEntry::~VPBTileEntry () +{ +} + diff --git a/src/Scenery/tileentry.hxx b/src/Scenery/tileentry.hxx index 934e89ffa..1866e33c8 100644 --- a/src/Scenery/tileentry.hxx +++ b/src/Scenery/tileentry.hxx @@ -56,10 +56,11 @@ public: SGBucket tile_bucket; std::string tileFileName; -private: - +protected: // pointer to ssg range selector for this tile osg::ref_ptr _node; + +private: // Reference to DatabaseRequest object set and used by the // osgDB::DatabasePager. osg::ref_ptr _databaseRequest; @@ -82,12 +83,12 @@ private: public: - // Constructor + // Constructor. TileEntry( const SGBucket& b ); TileEntry( const TileEntry& t ); // Destructor - ~TileEntry(); + virtual ~TileEntry() = 0; // Update the ssg transform node for this tile so it can be // properly drawn relative to our (0,0,0) point @@ -148,6 +149,27 @@ public: { return _databaseRequest; } + + enum Extension { + STG, VPB + }; + + virtual TileEntry::Extension getExtension() = 0; }; +class STGTileEntry : public TileEntry { + public: + STGTileEntry ( const SGBucket& b ); + ~STGTileEntry(); + inline TileEntry::Extension getExtension() { return TileEntry::Extension::STG; }; +}; + +class VPBTileEntry : public TileEntry { + public: + VPBTileEntry ( const SGBucket& b ); + ~VPBTileEntry(); + inline TileEntry::Extension getExtension() { return TileEntry::Extension::VPB; }; +}; + + #endif // _TILEENTRY_HXX diff --git a/src/Scenery/tilemgr.cxx b/src/Scenery/tilemgr.cxx index 0918a740e..27f1f8313 100644 --- a/src/Scenery/tilemgr.cxx +++ b/src/Scenery/tilemgr.cxx @@ -146,7 +146,8 @@ FGTileMgr::FGTileMgr(): _scenery_loaded(fgGetNode("/sim/sceneryloaded", true)), _scenery_override(fgGetNode("/sim/sceneryloaded-override", true)), _pager(FGScenery::getPagerSingleton()), - _enableCache(true) + _enableCache(true), + _use_vpb(false) { } @@ -206,6 +207,7 @@ void FGTileMgr::reinit() double rough = fgGetDouble("/sim/rendering/static-lod/rough-delta", SG_OBJECT_RANGE_ROUGH) + detailed; double bare = fgGetDouble("/sim/rendering/static-lod/bare", SG_OBJECT_RANGE_BARE) + rough; double tile_min_expiry = fgGetDouble("/sim/rendering/plod-minimum-expiry-time-secs", SG_TILE_MIN_EXPIRY); + _use_vpb = fgGetBool("/scenery/use-vpb"); _options->setPluginStringData("SimGear::LOD_RANGE_BARE", std::to_string(bare)); _options->setPluginStringData("SimGear::LOD_RANGE_ROUGH", std::to_string(rough)); @@ -275,13 +277,12 @@ void FGTileMgr::materialLibChanged() bool FGTileMgr::sched_tile( const SGBucket& b, double priority, bool current_view, double duration) { // see if tile already exists in the cache - TileEntry *t = tile_cache.get_tile( b ); + STGTileEntry *t = tile_cache.get_stg_tile( b ); if (!t) { // create a new entry - t = new TileEntry( b ); - SG_LOG( SG_TERRAIN, SG_INFO, "sched_tile: new tile entry for:" << b ); - + t = new STGTileEntry( b ); + SG_LOG( SG_TERRAIN, SG_INFO, "sched_tile: new STG tile entry for:" << b ); // insert the tile into the cache, update will generate load request if ( tile_cache.insert_tile( t ) ) @@ -303,6 +304,36 @@ bool FGTileMgr::sched_tile( const SGBucket& b, double priority, bool current_vie // update tile's properties tile_cache.request_tile(t,priority,current_view,duration); + if (_use_vpb) { + VPBTileEntry *v = tile_cache.get_vpb_tile( b ); + + if (!v) + { + // create a new entry + v = new VPBTileEntry( b ); + SG_LOG( SG_TERRAIN, SG_INFO, "sched_tile: new VPB tile entry for:" << b ); + + // insert the tile into the cache, update will generate load request + if ( tile_cache.insert_tile( v ) ) + { + // Attach to scene graph + v->addToSceneGraph(globals->get_scenery()->get_terrain_branch()); + } else { + // insert failed (cache full with no available entries to + // delete.) Try again later + delete v; + return false; + } + + SG_LOG( SG_TERRAIN, SG_DEBUG, " New tile cache size " << (int)tile_cache.get_size() ); + } + + // update tile's properties. We ensure VPB tiles have maximum priority - priority is calcualated as + // _negative_ the square of the distance from the viewer to the tile. + // so by multiplying by 0.1 we increase the number towards 0. + tile_cache.request_tile(v,priority * 0.1,current_view,duration); + } + return t->is_loaded(); } diff --git a/src/Scenery/tilemgr.hxx b/src/Scenery/tilemgr.hxx index 810a1d7dc..5a52c8cac 100644 --- a/src/Scenery/tilemgr.hxx +++ b/src/Scenery/tilemgr.hxx @@ -91,6 +91,7 @@ private: /// is caching of expired tiles enabled or not? bool _enableCache; + bool _use_vpb; public: FGTileMgr(); ~FGTileMgr();