X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FScenery%2Ftilemgr.cxx;h=bfe8c0a7ea0be4f63df36ce7f70271d23cf964f8;hb=239a0007631da53c68ca9c8e7989957c567acac9;hp=dcbe391c9b51413b3c911de6ac5a57e2954e1928;hpb=81c0e0b3df9a742c7bdcae9e0ce1d234b70b4fb0;p=flightgear.git diff --git a/src/Scenery/tilemgr.cxx b/src/Scenery/tilemgr.cxx index dcbe391c9..bfe8c0a7e 100644 --- a/src/Scenery/tilemgr.cxx +++ b/src/Scenery/tilemgr.cxx @@ -29,65 +29,51 @@ #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; - - -// helper: listen to property changes affecting tile loading -class LoaderPropertyWatcher : public SGPropertyChangeListener -{ -public: - LoaderPropertyWatcher(FGTileMgr* pTileMgr) : - _pTileMgr(pTileMgr) - { - } - - virtual void valueChanged(SGPropertyNode*) - { - _pTileMgr->configChanged(); - } - -private: - FGTileMgr* _pTileMgr; -}; FGTileMgr::FGTileMgr(): state( Start ), - vis( 16000 ), - _propListener(new LoaderPropertyWatcher(this)) + last_state( Running ), + scheduled_visibility(100.0), + _terra_sync(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()) { - _randomObjects = fgGetNode("/sim/rendering/random-objects", true); - _randomVegetation = fgGetNode("/sim/rendering/random-vegetation", true); } -FGTileMgr::~FGTileMgr() { +FGTileMgr::~FGTileMgr() +{ // remove all nodes we might have left behind osg::Group* group = globals->get_scenery()->get_terrain_branch(); group->removeChildren(0, group->getNumChildren()); - delete _propListener; - _propListener = NULL; // clear OSG cache osgDB::Registry::instance()->clearObjectCache(); } @@ -97,28 +83,40 @@ FGTileMgr::~FGTileMgr() { void FGTileMgr::init() { SG_LOG( SG_TERRAIN, SG_INFO, "Initializing Tile Manager subsystem." ); - _options = new SGReaderWriterBTGOptions; - _options->setMatlib(globals->get_matlib()); - - _randomObjects.get()->addChangeListener(_propListener, false); - _randomVegetation.get()->addChangeListener(_propListener, false); - configChanged(); + _options = new simgear::SGReaderWriterOptions; + + 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)); - - TileEntry::setModelLoadHelper(this); + _options->setPluginStringData("SimGear::FG_ROOT", globals->get_fg_root()); + + if (globals->get_subsystem("terrasync")) { + _options->setPluginStringData("SimGear::TERRASYNC_ROOT", fgGetString("/sim/terrasync/scenery-dir")); + } - _visibilityMeters = fgGetNode("/environment/visibility-m", true); + if (!_disableNasalHooks->getBoolValue()) + _options->setModelData(new FGNasalModelDataProxy); 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()); @@ -134,16 +132,16 @@ void FGTileMgr::reinit() previous_bucket.make_bad(); current_bucket.make_bad(); - longitude = latitude = -1000.0; - + scheduled_visibility = 100.0; + // force an update now update(0.0); } -void FGTileMgr::configChanged() +void FGTileMgr::materialLibChanged() { - _options->setUseRandomObjects(_randomObjects.get()->getBoolValue()); - _options->setUseRandomVegetation(_randomVegetation.get()->getBoolValue()); + _options->setMaterialLib(globals->get_matlib()); + _options->getMaterialLib()->refreshActiveMaterials(); } /* schedule a tile for loading, keep request for given amount of time. @@ -184,28 +182,26 @@ bool FGTileMgr::sched_tile( const SGBucket& b, double priority, bool current_vie 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 ); - 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; } @@ -234,59 +230,27 @@ void FGTileMgr::schedule_needed(const SGBucket& curr_bucket, double vis) { for ( y = -yrange; y <= yrange; ++y ) { - SGBucket b = sgBucketOffset( longitude, latitude, x, y ); + SGBucket b = curr_bucket.sibling(x, y); + if (!b.isValid()) { + continue; + } + float priority = (-1.0) * (x*x+y*y); sched_tile( b, priority, true, 0.0 ); + + if (_terra_sync) { + _terra_sync->scheduleTile(b); + } } } } -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; - } - } - } 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()); - } - return result; -} - /** * Update the various queues maintained by the tilemagr (private * internal function, do not call directly.) */ -void FGTileMgr::update_queues() +void FGTileMgr::update_queues(bool& isDownloadingScenery) { - SceneryPager* pager = FGScenery::getPagerSingleton(); osg::FrameStamp* framestamp = globals->get_renderer()->getViewer()->getFrameStamp(); double current_time = framestamp->getReferenceTime(); @@ -294,36 +258,43 @@ void FGTileMgr::update_queues() TileEntry *e; int loading=0; int sz=0; - + bool didRefreshMaterialCache = false; + tile_cache.set_current_time( current_time ); tile_cache.reset_traversal(); while ( ! tile_cache.at_end() ) { e = tile_cache.get_current(); - // cout << "processing a tile" << endl; 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() )&& - ( !e->is_expired(current_time) )) - { - // schedule tile for loading with osg pager - pager->queueRequest(e->tileFileName, - e->getNode(), - e->get_priority(), - framestamp, - e->getDatabaseRequest(), - _options.get()); - loading++; - } - } else - { - SG_LOG(SG_INPUT, SG_ALERT, "warning ... empty tile in cache"); + + 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!"); } tile_cache.next(); sz++; @@ -345,7 +316,7 @@ void FGTileMgr::update_queues() 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); + _pager->queueDeleteRequest(subgraph); if (--drop_count > 0) drop_index = tile_cache.get_drop_tile(); @@ -360,56 +331,86 @@ void FGTileMgr::update_queues() // disk. void FGTileMgr::update(double) { - SG_LOG( SG_TERRAIN, SG_DEBUG, "FGTileMgr::update()" ); - SGVec3d viewPos = globals->get_current_view()->get_view_pos(); double vis = _visibilityMeters->getDoubleValue(); - schedule_tiles_at(SGGeod::fromCart(viewPos), vis); + schedule_tiles_at(globals->get_view_position(), vis); + + bool waitingOnTerrasync = false; + update_queues(waitingOnTerrasync); - update_queues(); + // 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); + } + } } -// schedule tiles for the viewer bucket (FDM/AI/groundcache/... use -// "schedule_scenery" instead -int FGTileMgr::schedule_tiles_at(const SGGeod& location, double range_m) +// 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) { - longitude = location.getLongitudeDeg(); - latitude = location.getLatitudeDeg(); - // SG_LOG( SG_TERRAIN, SG_DEBUG, "FGTileMgr::update() for " - // << longitude << " " << latatitude ); + // << longitude << " " << latitude ); current_bucket.set_bucket( location ); // schedule more tiles when visibility increased considerably // TODO Calculate tile size - instead of using fixed value (5000m) - if (range_m-scheduled_visibility > 5000.0) + if (range_m - scheduled_visibility > 5000.0) previous_bucket.make_bad(); // 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()" ); + 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" ); + SG_LOG( SG_TERRAIN, SG_DEBUG, "State == Start || Inited" ); // do not update bucket yet (position not valid in initial loop) state = Running; previous_bucket.make_bad(); } - - return 1; + last_state = state; } /** Schedules scenery for given position. Load request remains valid for given duration @@ -419,16 +420,12 @@ int FGTileMgr::schedule_tiles_at(const SGGeod& location, double range_m) */ bool FGTileMgr::schedule_scenery(const SGGeod& position, double range_m, double duration) { - const float priority = 0.0; - double current_longitude = position.getLongitudeDeg(); - double current_latitude = position.getLatitudeDeg(); - bool available = true; - // sanity check (unfortunately needed!) - if (current_longitude < -180 || current_longitude > 180 || - current_latitude < -90 || current_latitude > 90) + if (!position.isValid()) return false; - + const float priority = 0.0; + bool available = true; + SGBucket bucket(position); available = sched_tile( bucket, priority, false, duration ); @@ -454,8 +451,11 @@ bool FGTileMgr::schedule_scenery(const SGGeod& position, double range_m, double // We have already checked for the center tile. if ( x != 0 || y != 0 ) { - SGBucket b = sgBucketOffset( current_longitude, - current_latitude, x, y ); + 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) @@ -478,5 +478,19 @@ bool FGTileMgr::isSceneryLoaded() if (scheduled_visibility < range_m) range_m = scheduled_visibility; - return schedule_scenery(SGGeod::fromDeg(longitude, latitude), range_m, 0.0); + return schedule_scenery(globals->get_view_position(), range_m, 0.0); } + +bool FGTileMgr::isTileDirSyncing(const std::string& tileFileName) const +{ + 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()); +} +