X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FScenery%2Ftilemgr.cxx;h=54fe7988e30c78dc08d93038d9fbd4f59b94857b;hb=070dba29f9390806457206c2660f2daebd3d847c;hp=e5cd08bbb281bd8b9358b71f0cd468d831bbde06;hpb=9604908a8d38767345410447b75a13582158128e;p=flightgear.git diff --git a/src/Scenery/tilemgr.cxx b/src/Scenery/tilemgr.cxx index e5cd08bbb..54fe7988e 100644 --- a/src/Scenery/tilemgr.cxx +++ b/src/Scenery/tilemgr.cxx @@ -29,141 +29,207 @@ #include #include +#include #include #include #include #include -#include +#include +#include +#include +#include #include
#include
-#include
-#include
+#include +#include #include +#include #include "scenery.hxx" #include "SceneryPager.hxx" #include "tilemgr.hxx" -using std::for_each; using flightgear::SceneryPager; -using simgear::SGModelLib; -using simgear::TileEntry; -using simgear::TileCache; + +class FGTileMgr::TileManagerListener : public SGPropertyChangeListener +{ +public: + TileManagerListener(FGTileMgr* manager) : + _manager(manager) + { + fgGetNode("/sim/rendering/use-vbos", true)->addChangeListener(this, true); + } + + ~TileManagerListener() + { + fgGetNode("/sim/rendering/use-vbos")->removeChangeListener(this); + } + + virtual void valueChanged(SGPropertyNode* prop) + { + bool useVBOs = prop->getBoolValue(); + _manager->_options->setPluginStringData("SimGear::USE_VBOS", + useVBOs ? "ON" : "OFF"); + } + +private: + FGTileMgr* _manager; +}; FGTileMgr::FGTileMgr(): state( Start ), - vis( 16000 ) + last_state( Running ), + scheduled_visibility(100.0), + _terra_sync(NULL), + _listener(NULL), + _visibilityMeters(fgGetNode("/environment/visibility-m", true)), + _maxTileRangeM(fgGetNode("/sim/rendering/static-lod/bare", true)), + _disableNasalHooks(fgGetNode("/sim/temp/disable-scenery-nasal", true)), + _scenery_loaded(fgGetNode("/sim/sceneryloaded", true)), + _scenery_override(fgGetNode("/sim/sceneryloaded-override", true)), + _pager(FGScenery::getPagerSingleton()) { } -FGTileMgr::~FGTileMgr() { +FGTileMgr::~FGTileMgr() +{ + delete _listener; + // remove all nodes we might have left behind osg::Group* group = globals->get_scenery()->get_terrain_branch(); group->removeChildren(0, group->getNumChildren()); + // clear OSG cache + osgDB::Registry::instance()->clearObjectCache(); } // Initialize the Tile Manager subsystem -int FGTileMgr::init() { +void FGTileMgr::init() { SG_LOG( SG_TERRAIN, SG_INFO, "Initializing Tile Manager subsystem." ); - _options = new SGReaderWriterBTGOptions; - _options->setMatlib(globals->get_matlib()); - _options->setUseRandomObjects(fgGetBool("/sim/rendering/random-objects", true)); - _options->setUseRandomVegetation(fgGetBool("/sim/rendering/random-vegetation", true)); + _options = new simgear::SGReaderWriterOptions; + _listener = new TileManagerListener(this); + + materialLibChanged(); + _options->setPropertyNode(globals->get_props()); + osgDB::FilePathList &fp = _options->getDatabasePathList(); const string_list &sc = globals->get_fg_scenery(); fp.clear(); std::copy(sc.begin(), sc.end(), back_inserter(fp)); + _options->setPluginStringData("SimGear::FG_ROOT", globals->get_fg_root()); + + if (globals->get_subsystem("terrasync")) { + _options->setPluginStringData("SimGear::TERRASYNC_ROOT", fgGetString("/sim/terrasync/scenery-dir")); + } + + if (!_disableNasalHooks->getBoolValue()) + _options->setModelData(new FGNasalModelDataProxy); - TileEntry::setModelLoadHelper(this); + reinit(); +} +void FGTileMgr::reinit() +{ + _terra_sync = static_cast (globals->get_subsystem("terrasync")); + + // protect against multiple scenery reloads and properly reset flags, + // otherwise aircraft fall through the ground while reloading scenery + if (!fgGetBool("/sim/sceneryloaded",true)) + return; + fgSetBool("/sim/sceneryloaded",false); + fgSetDouble("/sim/startup/splash-alpha", 1.0); + + materialLibChanged(); + + // remove all old scenery nodes from scenegraph and clear cache + osg::Group* group = globals->get_scenery()->get_terrain_branch(); + group->removeChildren(0, group->getNumChildren()); tile_cache.init(); - + + // clear OSG cache, except on initial start-up + if (state != Start) + { + osgDB::Registry::instance()->clearObjectCache(); + } + state = Inited; - + previous_bucket.make_bad(); current_bucket.make_bad(); + scheduled_visibility = 100.0; - longitude = latitude = -1000.0; + // force an update now + update(0.0); +} - return 1; +void FGTileMgr::materialLibChanged() +{ + _options->setMaterialLib(globals->get_matlib()); + _options->getMaterialLib()->refreshActiveMaterials(); } -// schedule a tile for loading -void FGTileMgr::sched_tile( const SGBucket& b, const bool is_inner_ring ) { +/* schedule a tile for loading, keep request for given amount of time. + * Returns true if tile is already loaded. */ +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 ); - - if ( !t ) { - // make space in the cache - SceneryPager* pager = FGScenery::getPagerSingleton(); - while ( (int)tile_cache.get_size() > tile_cache.get_max_cache_size() ) { - long index = tile_cache.get_oldest_tile(); - if ( index >= 0 ) { - TileEntry *old = tile_cache.get_tile( index ); - tile_cache.clear_entry( index ); - osg::ref_ptr subgraph = old->getNode(); - old->removeFromSceneGraph(); - delete old; - // zeros out subgraph ref_ptr, so subgraph is owned by - // the pager and will be deleted in the pager thread. - pager->queueDeleteRequest(subgraph); - } else { - // nothing to free ?!? forge ahead - break; - } - } - + if (!t) + { // create a new entry - TileEntry *e = new TileEntry( b ); - - // insert the tile into the cache - if ( tile_cache.insert_tile( e ) ) { - // update_queues will generate load request - } else { + t = new TileEntry( b ); + // insert the tile into the cache, update will generate load request + if ( tile_cache.insert_tile( t ) ) + { + // Attach to scene graph + + t->addToSceneGraph(globals->get_scenery()->get_terrain_branch()); + } else + { // insert failed (cache full with no available entries to // delete.) Try again later - delete e; + delete t; + return false; } - // Attach to scene graph - e->addToSceneGraph(globals->get_scenery()->get_terrain_branch()); - } else { - t->set_inner_ring( is_inner_ring ); + + SG_LOG( SG_TERRAIN, SG_DEBUG, " New tile cache size " << (int)tile_cache.get_size() ); } -} + // update tile's properties + tile_cache.request_tile(t,priority,current_view,duration); + + return t->is_loaded(); +} -// schedule a needed buckets for loading -void FGTileMgr::schedule_needed( double vis, const SGBucket& curr_bucket) { +/* schedule needed buckets for the current view position for loading, + * keep request for given amount of time */ +void FGTileMgr::schedule_needed(const SGBucket& curr_bucket, double vis) +{ // sanity check (unfortunately needed!) - if ( longitude < -180.0 || longitude > 180.0 - || latitude < -90.0 || latitude > 90.0 ) + if (!curr_bucket.isValid() ) { SG_LOG( SG_TERRAIN, SG_ALERT, - "Attempting to schedule tiles for bogus lon and lat = (" - << longitude << "," << latitude << ")" ); - return; // FIXME - SG_LOG( SG_TERRAIN, SG_ALERT, - "This is a FATAL error. Exiting!" ); - exit(-1); + "Attempting to schedule tiles for invalid bucket" ); + return; } - SG_LOG( SG_TERRAIN, SG_INFO, - "scheduling needed tiles for " << longitude << " " << latitude ); - - // vis = fgGetDouble("/environment/visibility-m"); - double tile_width = curr_bucket.get_width_m(); double tile_height = curr_bucket.get_height_m(); + SG_LOG( SG_TERRAIN, SG_INFO, + "scheduling needed tiles for " << curr_bucket + << ", tile-width-m:" << tile_width << ", tile-height-m:" << tile_height); + + // cout << "tile width = " << tile_width << " tile_height = " // << tile_height << endl; - xrange = (int)(vis / tile_width) + 1; - yrange = (int)(vis / tile_height) + 1; + double tileRangeM = std::min(vis,_maxTileRangeM->getDoubleValue()); + int xrange = (int)(tileRangeM / tile_width) + 1; + int yrange = (int)(tileRangeM / tile_height) + 1; if ( xrange < 1 ) { xrange = 1; } if ( yrange < 1 ) { yrange = 1; } @@ -174,283 +240,285 @@ void FGTileMgr::schedule_needed( double vis, const SGBucket& curr_bucket) { // cout << "max cache size = " << tile_cache.get_max_cache_size() // << " current cache size = " << tile_cache.get_size() << endl; - // clear the inner ring flags so we can set them below. This - // prevents us from having "true" entries we aren't able to find - // to get rid of if we teleport a long ways away from the current - // location. - tile_cache.clear_inner_ring_flags(); + // clear flags of all tiles belonging to the previous view set + tile_cache.clear_current_view(); - SGBucket b; + // update timestamps, so all tiles scheduled now are *newer* than any tile previously loaded + osg::FrameStamp* framestamp + = globals->get_renderer()->getViewer()->getFrameStamp(); + tile_cache.set_current_time(framestamp->getReferenceTime()); - // schedule center tile first so it can be loaded first - b = sgBucketOffset( longitude, latitude, 0, 0 ); - sched_tile( b, true ); + SGBucket b; int x, y; - // schedule next ring of 8 tiles - for ( x = -1; x <= 1; ++x ) { - for ( y = -1; y <= 1; ++y ) { - if ( x != 0 || y != 0 ) { - b = sgBucketOffset( longitude, latitude, x, y ); - sched_tile( b, true ); + /* schedule all tiles, use distance-based loading priority, + * so tiles are loaded in innermost-to-outermost sequence. */ + for ( x = -xrange; x <= xrange; ++x ) + { + for ( y = -yrange; y <= yrange; ++y ) + { + SGBucket b = curr_bucket.sibling(x, y); + if (!b.isValid()) { + continue; } - } - } - - // schedule remaining tiles - for ( x = -xrange; x <= xrange; ++x ) { - for ( y = -yrange; y <= yrange; ++y ) { - if ( x < -1 || x > 1 || y < -1 || y > 1 ) { - SGBucket b = sgBucketOffset( longitude, latitude, x, y ); - sched_tile( b, false ); + + float priority = (-1.0) * (x*x+y*y); + sched_tile( b, priority, true, 0.0 ); + + if (_terra_sync) { + _terra_sync->scheduleTile(b); } } } } - -void FGTileMgr::initialize_queue() +/** + * Update the various queues maintained by the tilemagr (private + * internal function, do not call directly.) + */ +void FGTileMgr::update_queues(bool& isDownloadingScenery) { - // First time through or we have teleported, initialize the - // system and load all relavant tiles - - SG_LOG( SG_TERRAIN, SG_INFO, "Initialize_queue(): Updating Tile list for " - << current_bucket ); - // cout << "tile cache size = " << tile_cache.get_size() << endl; - - // wipe/initialize tile cache - // tile_cache.init(); - previous_bucket.make_bad(); - - // build the local area list and schedule tiles for loading - - // start with the center tile and work out in concentric - // "rings" - - double visibility_meters = fgGetDouble("/environment/visibility-m"); - schedule_needed(visibility_meters, current_bucket); -} + osg::FrameStamp* framestamp + = globals->get_renderer()->getViewer()->getFrameStamp(); + double current_time = framestamp->getReferenceTime(); + double vis = _visibilityMeters->getDoubleValue(); + TileEntry *e; + int loading=0; + int sz=0; + bool didRefreshMaterialCache = false; + + tile_cache.set_current_time( current_time ); + tile_cache.reset_traversal(); -osg::Node* -FGTileMgr::loadTileModel(const string& modelPath, bool cacheModel) -{ - SGPath fullPath; - if (fgGetBool("/sim/paths/use-custom-scenery-data") == true) { - string_list sc = globals->get_fg_scenery(); - - for (string_list_iterator it = sc.begin(); it != sc.end(); ++it) { - SGPath tmpPath(*it); - tmpPath.append(modelPath); - if (tmpPath.exists()) { - fullPath = tmpPath; - break; - } + while ( ! tile_cache.at_end() ) + { + e = tile_cache.get_current(); + if ( e ) + { + // Prepare the ssg nodes corresponding to each tile. + // Set the ssg transform and update it's range selector + // based on current visibilty + e->prep_ssg_node(vis); + + if (!e->is_loaded()) { + if (!didRefreshMaterialCache) { + didRefreshMaterialCache = true; + globals->get_matlib()->refreshActiveMaterials(); + } + + bool nonExpiredOrCurrent = !e->is_expired(current_time) || e->is_current_view(); + bool downloading = isTileDirSyncing(e->tileFileName); + isDownloadingScenery |= downloading; + if ( !downloading && nonExpiredOrCurrent) { + // schedule tile for loading with osg pager + _pager->queueRequest(e->tileFileName, + e->getNode(), + e->get_priority(), + framestamp, + e->getDatabaseRequest(), + _options.get()); + loading++; + } + } // of tile not loaded case + } else { + SG_LOG(SG_TERRAIN, SG_ALERT, "Warning: empty tile in cache!"); } - } else { - fullPath.append(modelPath); - } - osg::Node* result = 0; - try { - if(cacheModel) - result = - SGModelLib::loadModel(fullPath.str(), globals->get_props(), - new FGNasalModelData); - else - result= - SGModelLib::loadPagedModel(modelPath, globals->get_props(), - new FGNasalModelData); - } catch (const sg_io_exception& exc) { - string m(exc.getMessage()); - m += " "; - m += exc.getLocation().asString(); - SG_LOG( SG_ALL, SG_ALERT, m ); - } catch (const sg_exception& exc) { // XXX may be redundant - SG_LOG( SG_ALL, SG_ALERT, exc.getMessage()); + tile_cache.next(); + sz++; } - return result; -} -// Helper class for STL fun -class TileLoad : public std::unary_function -{ -public: - TileLoad(SceneryPager *pager, osg::FrameStamp* framestamp, - osg::Group* terrainBranch, osgDB::ReaderWriter::Options* options) : - _pager(pager), _framestamp(framestamp), _options(options) {} - - TileLoad(const TileLoad& rhs) : - _pager(rhs._pager), _framestamp(rhs._framestamp), - _options(rhs._options) {} - - void operator()(TileCache::tile_map::value_type& tilePair) + int drop_count = sz - tile_cache.get_max_cache_size(); + if (( drop_count > 0 )&& + ((loading==0)||(drop_count > 10))) { - TileEntry* entry = tilePair.second; - if (entry->getNode()->getNumChildren() == 0) { - _pager->queueRequest(entry->tileFileName, - entry->getNode(), - entry->get_inner_ring() ? 10.0f : 1.0f, - _framestamp, - entry->getDatabaseRequest(), - _options); + long drop_index = tile_cache.get_drop_tile(); + while ( drop_index > -1 ) + { + // schedule tile for deletion with osg pager + TileEntry* old = tile_cache.get_tile(drop_index); + tile_cache.clear_entry(drop_index); + + osg::ref_ptr subgraph = old->getNode(); + old->removeFromSceneGraph(); + delete old; + // zeros out subgraph ref_ptr, so subgraph is owned by + // the pager and will be deleted in the pager thread. + _pager->queueDeleteRequest(subgraph); + + if (--drop_count > 0) + drop_index = tile_cache.get_drop_tile(); + else + drop_index = -1; } } -private: - SceneryPager* _pager; - osg::FrameStamp* _framestamp; - osgDB::ReaderWriter::Options* _options; -}; - -/** - * Update the various queues maintained by the tilemagr (private - * internal function, do not call directly.) - */ -void FGTileMgr::update_queues() -{ - SceneryPager* pager = FGScenery::getPagerSingleton(); - osg::FrameStamp* framestamp - = globals->get_renderer()->getViewer()->getFrameStamp(); - tile_cache.set_current_time(framestamp->getReferenceTime()); - for_each(tile_cache.begin(), tile_cache.end(), - TileLoad(pager, - framestamp, - globals->get_scenery()->get_terrain_branch(), _options.get())); } - // given the current lon/lat (in degrees), fill in the array of local // chunks. If the chunk isn't already in the cache, then read it from // disk. -int FGTileMgr::update( double visibility_meters ) +void FGTileMgr::update(double) { - SGVec3d viewPos = globals->get_current_view()->get_view_pos(); - return update(SGGeod::fromCart(viewPos), visibility_meters); + double vis = _visibilityMeters->getDoubleValue(); + schedule_tiles_at(globals->get_view_position(), vis); + + bool waitingOnTerrasync = false; + update_queues(waitingOnTerrasync); + + // scenery loading check, triggers after each sim (tile manager) reinit + if (!_scenery_loaded->getBoolValue()) + { + bool fdmInited = fgGetBool("sim/fdm-initialized"); + bool positionFinalized = fgGetBool("sim/position-finalized"); + bool sceneryOverride = _scenery_override->getBoolValue(); + + + // we are done if final position is set and the scenery & FDM are done. + // scenery-override can ignore the last two, but not position finalization. + if (positionFinalized && (sceneryOverride || (isSceneryLoaded() && fdmInited))) + { + _scenery_loaded->setBoolValue(true); + fgSplashProgress(""); + } + else + { + if (!positionFinalized) { + fgSplashProgress("finalize-position"); + } else if (waitingOnTerrasync) { + fgSplashProgress("downloading-scenery"); + } else { + fgSplashProgress("loading-scenery"); + } + + // be nice to loader threads while waiting for initial scenery, reduce to 20fps + SGTimeStamp::sleepForMSec(50); + } + } } -int FGTileMgr::update( const SGGeod& location, double visibility_meters) +// schedule tiles for the viewer bucket +// (FDM/AI/groundcache/... should use "schedule_scenery" instead) +void FGTileMgr::schedule_tiles_at(const SGGeod& location, double range_m) { - SG_LOG( SG_TERRAIN, SG_DEBUG, "FGTileMgr::update()" ); + // SG_LOG( SG_TERRAIN, SG_DEBUG, "FGTileMgr::update() for " + // << longitude << " " << latitude ); - longitude = location.getLongitudeDeg(); - latitude = location.getLatitudeDeg(); + current_bucket = SGBucket( location ); - // SG_LOG( SG_TERRAIN, SG_DEBUG, "FGTileMgr::update() for " - // << longitude << " " << latatitude ); + // schedule more tiles when visibility increased considerably + // TODO Calculate tile size - instead of using fixed value (5000m) + if (range_m - scheduled_visibility > 5000.0) + previous_bucket.make_bad(); - current_bucket.set_bucket( location ); // SG_LOG( SG_TERRAIN, SG_DEBUG, "Updating tile list for " // << current_bucket ); fgSetInt( "/environment/current-tile-id", current_bucket.gen_index() ); - // do tile load scheduling. + // do tile load scheduling. // Note that we need keep track of both viewer buckets and fdm buckets. if ( state == Running ) { - SG_LOG( SG_TERRAIN, SG_DEBUG, "State == Running" ); + if (last_state != state) + { + SG_LOG( SG_TERRAIN, SG_DEBUG, "State == Running" ); + } if (current_bucket != previous_bucket) { // We've moved to a new bucket, we need to schedule any // needed tiles for loading. - SG_LOG( SG_TERRAIN, SG_INFO, "FGTileMgr::update()" ); - schedule_needed(visibility_meters, current_bucket); + SG_LOG( SG_TERRAIN, SG_INFO, "FGTileMgr: at " << location << ", scheduling needed for:" << current_bucket + << ", visbility=" << range_m); + scheduled_visibility = range_m; + schedule_needed(current_bucket, range_m); } + + // save bucket + previous_bucket = current_bucket; } else if ( state == Start || state == Inited ) { - SG_LOG( SG_TERRAIN, SG_INFO, "State == Start || Inited" ); -// initialize_queue(); + SG_LOG( SG_TERRAIN, SG_DEBUG, "State == Start || Inited" ); + // do not update bucket yet (position not valid in initial loop) state = Running; - if (current_bucket != previous_bucket - && current_bucket.get_chunk_lon() != -1000) { - SG_LOG( SG_TERRAIN, SG_INFO, "FGTileMgr::update()" ); - schedule_needed(visibility_meters, current_bucket); - } + previous_bucket.make_bad(); } - - update_queues(); - - // save bucket... - previous_bucket = current_bucket; - - return 1; + last_state = state; } -void FGTileMgr::prep_ssg_nodes(float vis) { - - // traverse the potentially viewable tile list and update range - // selector and transform - - TileEntry *e; - tile_cache.reset_traversal(); +/** Schedules scenery for given position. Load request remains valid for given duration + * (duration=0.0 => nothing is loaded). + * Used for FDM/AI/groundcache/... requests. Viewer uses "schedule_tiles_at" instead. + * Returns true when all tiles for the given position are already loaded, false otherwise. + */ +bool FGTileMgr::schedule_scenery(const SGGeod& position, double range_m, double duration) +{ + // sanity check (unfortunately needed!) + if (!position.isValid()) + return false; + const float priority = 0.0; + bool available = true; - while ( ! tile_cache.at_end() ) { - // cout << "processing a tile" << endl; - if ( (e = tile_cache.get_current()) ) { - e->prep_ssg_node(vis); - } else { - SG_LOG(SG_INPUT, SG_ALERT, "warning ... empty tile in cache"); + SGBucket bucket(position); + available = sched_tile( bucket, priority, false, duration ); + + if ((!available)&&(duration==0.0)) + return false; + + SGVec3d cartPos = SGVec3d::fromGeod(position); + + // Traverse all tiles required to be there for the given visibility. + double tile_width = bucket.get_width_m(); + double tile_height = bucket.get_height_m(); + double tile_r = 0.5*sqrt(tile_width*tile_width + tile_height*tile_height); + double max_dist = tile_r + range_m; + double max_dist2 = max_dist*max_dist; + + int xrange = (int)fabs(range_m / tile_width) + 1; + int yrange = (int)fabs(range_m / tile_height) + 1; + + for ( int x = -xrange; x <= xrange; ++x ) + { + for ( int y = -yrange; y <= yrange; ++y ) + { + // We have already checked for the center tile. + if ( x != 0 || y != 0 ) + { + SGBucket b = bucket.sibling(x, y ); + if (!b.isValid()) { + continue; + } + + double distance2 = distSqr(cartPos, SGVec3d::fromGeod(b.get_center())); + // Do not ask if it is just the next tile but way out of range. + if (distance2 <= max_dist2) + { + available &= sched_tile( b, priority, false, duration ); + if ((!available)&&(duration==0.0)) + return false; + } + } } - tile_cache.next(); } + + return available; } -bool FGTileMgr::scenery_available(const SGGeod& position, double range_m) +// Returns true if tiles around current view position have been loaded +bool FGTileMgr::isSceneryLoaded() { - // sanity check (unfortunately needed!) - if (position.getLongitudeDeg() < -180 || position.getLongitudeDeg() > 180 || - position.getLatitudeDeg() < -90 || position.getLatitudeDeg() > 90) - return false; - - SGBucket bucket(position); - TileEntry *te = tile_cache.get_tile(bucket); - if (!te || !te->is_loaded()) - return false; - - SGVec3d cartPos = SGVec3d::fromGeod(position); - - // Traverse all tiles required to be there for the given visibility. - // This uses exactly the same algorithm like the tile scheduler. - double tile_width = bucket.get_width_m(); - double tile_height = bucket.get_height_m(); - double tile_r = 0.5*sqrt(tile_width*tile_width + tile_height*tile_height); - double max_dist = tile_r + range_m; - double max_dist2 = max_dist*max_dist; - - int xrange = (int)fabs(range_m / tile_width) + 1; - int yrange = (int)fabs(range_m / tile_height) + 1; - - for ( int x = -xrange; x <= xrange; ++x ) { - for ( int y = -yrange; y <= yrange; ++y ) { - // We have already checked for the center tile. - if ( x != 0 || y != 0 ) { - SGBucket b = sgBucketOffset( position.getLongitudeDeg(), - position.getLatitudeDeg(), x, y ); - // Do not ask if it is just the next tile but way out of range. - if (max_dist2 < distSqr(cartPos, SGVec3d::fromGeod(b.get_center()))) - continue; - TileEntry *te = tile_cache.get_tile(b); - if (!te || !te->is_loaded()) - return false; - } - } - } + double range_m = 100.0; + if (scheduled_visibility < range_m) + range_m = scheduled_visibility; - // Survived all tests. - return true; + return schedule_scenery(globals->get_view_position(), range_m, 0.0); } -namespace +bool FGTileMgr::isTileDirSyncing(const std::string& tileFileName) const { -struct IsTileLoaded : - public std::unary_function -{ - bool operator()(const TileCache::tile_map::value_type& tilePair) const - { - return tilePair.second->is_loaded(); + if (!_terra_sync) { + return false; } -}; + + std::string nameWithoutExtension = tileFileName.substr(0, tileFileName.size() - 4); + long int bucketIndex = simgear::strutils::to_int(nameWithoutExtension); + SGBucket bucket(bucketIndex); + + return _terra_sync->isTileDirPending(bucket.gen_base_path()); } -bool FGTileMgr::isSceneryLoaded() -{ - return (std::find_if(tile_cache.begin(), tile_cache.end(), - std::not1(IsTileLoaded())) - == tile_cache.end()); -}