From 6c64e9b36c6a0b70618021ef6afea9456af2a5e9 Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Sat, 21 Jan 2017 22:19:38 +0000 Subject: [PATCH] Add scenery-path-suffix support to terrasync Remove /sim/rendering/building-mesh as it is redundant. Add check that objects are in the correct bounding box of the containing STG file. --- simgear/scene/tgdb/ReaderWriterSTG.cxx | 79 +++++++++++++++----------- simgear/scene/tsync/terrasync.cxx | 37 ++++++++++-- simgear/scene/tsync/terrasync.hxx | 33 +++++------ 3 files changed, 93 insertions(+), 56 deletions(-) diff --git a/simgear/scene/tgdb/ReaderWriterSTG.cxx b/simgear/scene/tgdb/ReaderWriterSTG.cxx index b28b30e8..8f5844c7 100644 --- a/simgear/scene/tgdb/ReaderWriterSTG.cxx +++ b/simgear/scene/tgdb/ReaderWriterSTG.cxx @@ -212,7 +212,6 @@ struct ReaderWriterSTG::_ModelBin { _object_range_bare(SG_OBJECT_RANGE_BARE), _object_range_rough(SG_OBJECT_RANGE_ROUGH), _object_range_detailed(SG_OBJECT_RANGE_DETAILED), - _building_mesh_enabled(false), _foundBase(false) { } @@ -284,6 +283,21 @@ struct ReaderWriterSTG::_ModelBin { return SGGeod::fromCart(cart).getElevationM(); } + void checkInsideBucket(const SGPath& absoluteFileName, float lon, float lat) { + SGBucket bucket = bucketIndexFromFileName(absoluteFileName.file_base().c_str()); + + if ((lon > bucket.get_center_lon() + bucket.get_width()/2.0) || + (lon < bucket.get_center_lon() - bucket.get_width()/2.0) || + (lat > bucket.get_center_lat() + bucket.get_height()/2.0) || + (lat < bucket.get_center_lat() - bucket.get_height()/2.0) ) + { + SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName + << ": Object outside tile bounds " << lon << ", " << lat << + "Center of tile: " << bucket.get_center_lon() << ", " << + bucket.get_center_lat()); + } + } + bool read(const SGPath& absoluteFileName, const osgDB::Options* options) { if (!absoluteFileName.exists()) { @@ -299,8 +313,6 @@ struct ReaderWriterSTG::_ModelBin { _object_range_bare = 1414.0f + atof(options->getPluginStringData("SimGear::LOD_RANGE_BARE").c_str()); _object_range_rough = 1414.0f + atof(options->getPluginStringData("SimGear::LOD_RANGE_ROUGH").c_str()); _object_range_detailed = 1414.0f + atof(options->getPluginStringData("SimGear::LOD_RANGE_DETAILED").c_str()); - _building_mesh_enabled = (options->getPluginStringData("SimGear::RENDER_BUILDING_MESH") == "true"); - SG_LOG(SG_TERRAIN, SG_INFO, "Loading stg file " << absoluteFileName); @@ -392,7 +404,8 @@ struct ReaderWriterSTG::_ModelBin { in >> obj._lon >> obj._lat >> obj._elev >> obj._hdg >> obj._pitch >> obj._roll; obj._range = range; obj._options = opt; - _objectStaticList.push_back(obj); + checkInsideBucket(absoluteFileName, obj._lon, obj._lat); + _objectStaticList.push_back(obj); } else if (token == "OBJECT_SHARED" || token == "OBJECT_SHARED_AGL") { osg::ref_ptr opt; opt = sharedOptions(filePath, options); @@ -409,7 +422,8 @@ struct ReaderWriterSTG::_ModelBin { in >> obj._lon >> obj._lat >> obj._elev >> obj._hdg >> obj._pitch >> obj._roll; obj._range = range; obj._options = opt; - _objectStaticList.push_back(obj); + checkInsideBucket(absoluteFileName, obj._lon, obj._lat); + _objectStaticList.push_back(obj); } else if (token == "OBJECT_SIGN" || token == "OBJECT_SIGN_AGL") { _Sign sign; sign._token = token; @@ -418,35 +432,32 @@ struct ReaderWriterSTG::_ModelBin { in >> sign._lon >> sign._lat >> sign._elev >> sign._hdg >> sign._size; _signList.push_back(sign); } else if (token == "OBJECT_BUILDING_MESH_ROUGH" || token == "OBJECT_BUILDING_MESH_DETAILED") { + osg::ref_ptr opt; + opt = staticOptions(filePath, options); + if (SGPath(name).lower_extension() == "ac") + opt->setInstantiateEffects(true); + else + opt->setInstantiateEffects(false); + _ObjectStatic obj; + obj._errorLocation = absoluteFileName; + obj._token = token; + obj._name = name; + obj._agl = false; + obj._proxy = true; + in >> obj._lon >> obj._lat >> obj._elev >> obj._hdg >> obj._pitch >> obj._roll; - // Only load if building mesh enabled to avoid impacting low-powered systems - if (_building_mesh_enabled) { - osg::ref_ptr opt; - opt = staticOptions(filePath, options); - if (SGPath(name).lower_extension() == "ac") - opt->setInstantiateEffects(true); - else - opt->setInstantiateEffects(false); - _ObjectStatic obj; - obj._errorLocation = absoluteFileName; - obj._token = token; - obj._name = name; - obj._agl = false; - obj._proxy = true; - in >> obj._lon >> obj._lat >> obj._elev >> obj._hdg >> obj._pitch >> obj._roll; + if (token == "OBJECT_BUILDING_MESH_DETAILED") { + // Apply a lower LOD range if this is a detailed building + range = _object_range_detailed; + double lrand = mt_rand(&seed); + if (lrand < 0.1) range = range * 2.0; + else if (lrand < 0.4) range = range * 1.5; + } - if (token == "OBJECT_BUILDING_MESH_DETAILED") { - // Apply a lower LOD range if this is a detailed building - range = _object_range_detailed; - double lrand = mt_rand(&seed); - if (lrand < 0.1) range = range * 2.0; - else if (lrand < 0.4) range = range * 1.5; - } - - obj._range = range; - obj._options = opt; - _objectStaticList.push_back(obj); - } + obj._range = range; + obj._options = opt; + checkInsideBucket(absoluteFileName, obj._lon, obj._lat); + _objectStaticList.push_back(obj); } else { SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName << ": Unknown token '" << token << "'" ); @@ -531,7 +542,8 @@ struct ReaderWriterSTG::_ModelBin { // Objects may end up displayed up to 2x the object range. pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 2.0 * _object_range_rough + SG_TILE_RADIUS); - + SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile PagedLOD Center: " << pagedLOD->getCenter().x() << "," << pagedLOD->getCenter().y() << "," << pagedLOD->getCenter().z() ); + SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile PagedLOD Range: " << (2.0 * _object_range_rough + SG_TILE_RADIUS)); return pagedLOD; } } @@ -539,7 +551,6 @@ struct ReaderWriterSTG::_ModelBin { double _object_range_bare; double _object_range_rough; double _object_range_detailed; - bool _building_mesh_enabled; bool _foundBase; std::list<_Object> _objectList; std::list<_ObjectStatic> _objectStaticList; diff --git a/simgear/scene/tsync/terrasync.cxx b/simgear/scene/tsync/terrasync.cxx index 69c7268d..2d071b06 100644 --- a/simgear/scene/tsync/terrasync.cxx +++ b/simgear/scene/tsync/terrasync.cxx @@ -815,6 +815,7 @@ SGTerraSync::~SGTerraSync() void SGTerraSync::setRoot(SGPropertyNode_ptr root) { _terraRoot = root->getNode("/sim/terrasync",true); + _renderingRoot = root->getNode("/sim/rendering", true); } void SGTerraSync::init() @@ -953,12 +954,33 @@ void SGTerraSync::syncAirportsModels() _workerThread->request( w ); } +string_list SGTerraSync::getSceneryPathSuffixes() const +{ + string_list scenerySuffixes; + + for (auto node : _renderingRoot->getChildren("scenery-path-suffix")) { + if (node->getBoolValue("enabled", true)) { + scenerySuffixes.push_back(node->getStringValue("name")); + } + } + + if (scenerySuffixes.empty()) { + // if preferences didn't load, use some default + scenerySuffixes = {"Objects", "Terrain"}; // defaut values + } + + return scenerySuffixes; +} + + void SGTerraSync::syncAreaByPath(const std::string& aPath) { - const char* terrainobjects[3] = { "Terrain/", "Objects/", 0 }; - for (const char** tree = &terrainobjects[0]; *tree; tree++) + string_list scenerySuffixes = getSceneryPathSuffixes(); + string_list::const_iterator it = scenerySuffixes.begin(); + + for (; it != scenerySuffixes.end(); ++it) { - std::string dir = string(*tree) + aPath; + std::string dir = *it + "/" + aPath; if (_activeTileDirs.find(dir) != _activeTileDirs.end()) { continue; } @@ -982,9 +1004,12 @@ bool SGTerraSync::isTileDirPending(const std::string& sceneryDir) const return false; } - const char* terrainobjects[3] = { "Terrain/", "Objects/", 0 }; - for (const char** tree = &terrainobjects[0]; *tree; tree++) { - string s = *tree + sceneryDir; + string_list scenerySuffixes = getSceneryPathSuffixes(); + string_list::const_iterator it = scenerySuffixes.begin(); + + for (; it != scenerySuffixes.end(); ++it) + { + string s = *it + "/" + sceneryDir; if (_activeTileDirs.find(s) != _activeTileDirs.end()) { return true; } diff --git a/simgear/scene/tsync/terrasync.hxx b/simgear/scene/tsync/terrasync.hxx index 2ee6772b..78a3bd62 100644 --- a/simgear/scene/tsync/terrasync.hxx +++ b/simgear/scene/tsync/terrasync.hxx @@ -42,8 +42,8 @@ public: SGTerraSync(); virtual ~SGTerraSync(); - - virtual void init(); + + virtual void init(); virtual void shutdown(); virtual void reinit(); virtual void bind(); @@ -54,53 +54,54 @@ public: /// us travelling in a direction. Avoid last_lat / last_lon blocking /// certain tiles when we reposition. void reposition(); - + bool isIdle(); - + bool scheduleTile(const SGBucket& bucket); - + void syncAreaByPath(const std::string& aPath); - + void setRoot(SGPropertyNode_ptr root); /// retrive the associated log object, for displaying log /// output somewhere (a UI, presumably) BufferedLogCallback* log() const { return _log; } - + /** * Test if a scenery directory is queued or actively syncing. * File path is the tile name, eg 'e001n52' or 'w003n56'. Will return true * if either the Terrain or Objects variant is being synced. - * + * */ bool isTileDirPending(const std::string& sceneryDir) const; - - + + void scheduleDataDir(const std::string& dataDir); - + bool isDataDirPending(const std::string& dataDir) const; protected: void syncAirportsModels(); - - + string_list getSceneryPathSuffixes() const; + class WorkerThread; private: WorkerThread* _workerThread; SGPropertyNode_ptr _terraRoot; + SGPropertyNode_ptr _renderingRoot; SGPropertyNode_ptr _stalledNode; SGPropertyNode_ptr _cacheHits; - + // we manually bind+init TerraSync during early startup // to get better overlap of slow operations (Shared Models sync // and nav-cache rebuild). As a result we need to track the bind/init // state explicitly to avoid duplicate calls. bool _bound, _inited; - + simgear::TiedPropertyList _tiedProperties; BufferedLogCallback* _log; - + typedef std::set string_set; string_set _activeTileDirs; };