From 2ae7fc244b62fc7cec06c72756723db5e52d142b Mon Sep 17 00:00:00 2001 From: Mathias Froehlich Date: Sun, 24 Feb 2013 13:03:06 +0100 Subject: [PATCH] spt: Expose the paging levels to osg options. The levels at which page nodes are built is exposed by an osg database pager option SimGear::SPT_PAGE_LEVELS which could contain a blank separated list of levels where paging occurs. Also the database pagers paths are searched for static lower level of detail tiles in case they are available. --- simgear/scene/tgdb/ReaderWriterSPT.cxx | 118 +++++++++++++++++++------ simgear/scene/tgdb/ReaderWriterSPT.hxx | 10 ++- 2 files changed, 95 insertions(+), 33 deletions(-) diff --git a/simgear/scene/tgdb/ReaderWriterSPT.cxx b/simgear/scene/tgdb/ReaderWriterSPT.cxx index c0ca9745..67977858 100644 --- a/simgear/scene/tgdb/ReaderWriterSPT.cxx +++ b/simgear/scene/tgdb/ReaderWriterSPT.cxx @@ -111,6 +111,58 @@ struct ReaderWriterSPT::CullCallback : public osg::NodeCallback { } }; +struct ReaderWriterSPT::LocalOptions { + LocalOptions(const osgDB::Options* options) : + _options(options) + { + std::string pageLevelsString; + if (_options) + pageLevelsString = _options->getPluginStringData("SimGear::SPT_PAGE_LEVELS"); + + // Get the default if nothing given from outside + if (pageLevelsString.empty()) { + // We want an other level of indirection for paging + // Here we get about 12x12 deg tiles + _pageLevels.push_back(3); + // We want an other level of indirection for paging + // Here we get about 2x2 deg tiles + _pageLevels.push_back(5); + // We want an other level of indirection for paging + // Here we get about 0.5x0.5 deg tiles + _pageLevels.push_back(7); + } else { + // If configured from outside + std::stringstream ss(pageLevelsString); + while (ss.good()) { + unsigned level = ~0u; + ss >> level; + _pageLevels.push_back(level); + } + } + } + + bool isPageLevel(unsigned level) const + { + return std::find(_pageLevels.begin(), _pageLevels.end(), level) != _pageLevels.end(); + } + + std::string getLodPathForBucketBox(const BucketBox& bucketBox) const + { + std::stringstream ss; + ss << "LOD/"; + for (std::vector::const_iterator i = _pageLevels.begin(); i != _pageLevels.end(); ++i) { + if (bucketBox.getStartLevel() <= *i) + break; + ss << bucketBox.getParentBox(*i) << "/"; + } + ss << bucketBox; + return ss.str(); + } + + const osgDB::Options* _options; + std::vector _pageLevels; +}; + ReaderWriterSPT::ReaderWriterSPT() { supportsExtension("spt", "SimGear paged terrain meta database."); @@ -160,10 +212,12 @@ ReaderWriterSPT::readObject(const std::string& fileName, const osgDB::Options* o osgDB::ReaderWriter::ReadResult ReaderWriterSPT::readNode(const std::string& fileName, const osgDB::Options* options) const { + LocalOptions localOptions(options); + // The file name without path and without the spt extension std::string strippedFileName = osgDB::getStrippedName(fileName); if (strippedFileName == "earth") - return ReadResult(createTree(BucketBox(-180, -90, 360, 180), options, true)); + return ReadResult(createTree(BucketBox(-180, -90, 360, 180), localOptions, true)); std::stringstream ss(strippedFileName); BucketBox bucketBox; @@ -177,33 +231,23 @@ ReaderWriterSPT::readNode(const std::string& fileName, const osgDB::Options* opt return ReadResult::FILE_NOT_FOUND; if (bucketBoxListSize == 1) - return ReadResult(createTree(bucketBoxList[0], options, true)); + return ReadResult(createTree(bucketBoxList[0], localOptions, true)); assert(bucketBoxListSize == 2); osg::ref_ptr group = new osg::Group; - group->addChild(createTree(bucketBoxList[0], options, true)); - group->addChild(createTree(bucketBoxList[1], options, true)); + group->addChild(createTree(bucketBoxList[0], localOptions, true)); + group->addChild(createTree(bucketBoxList[1], localOptions, true)); return ReadResult(group); } osg::ref_ptr -ReaderWriterSPT::createTree(const BucketBox& bucketBox, const osgDB::Options* options, bool topLevel) const +ReaderWriterSPT::createTree(const BucketBox& bucketBox, const LocalOptions& options, bool topLevel) const { if (bucketBox.getIsBucketSize()) { std::string fileName; fileName = bucketBox.getBucket().gen_index_str() + std::string(".stg"); - return osgDB::readRefNodeFile(fileName, options); - } else if (!topLevel && bucketBox.getStartLevel() == 3) { - // We want an other level of indirection for paging - // Here we get about 12x12 deg tiles - return createPagedLOD(bucketBox, options); - } else if (!topLevel && bucketBox.getStartLevel() == 5) { - // We want an other level of indirection for paging - // Here we get about 2x2 deg tiles - return createPagedLOD(bucketBox, options); - } else if (!topLevel && bucketBox.getStartLevel() == 7) { - // We want an other level of indirection for paging - // Here we get about 0.5x0.5 deg tiles + return osgDB::readRefNodeFile(fileName, options._options); + } else if (!topLevel && options.isPageLevel(bucketBox.getStartLevel())) { return createPagedLOD(bucketBox, options); } else { BucketBox bucketBoxList[100]; @@ -229,7 +273,7 @@ ReaderWriterSPT::createTree(const BucketBox& bucketBox, const osgDB::Options* op } osg::ref_ptr -ReaderWriterSPT::createPagedLOD(const BucketBox& bucketBox, const osgDB::Options* options) const +ReaderWriterSPT::createPagedLOD(const BucketBox& bucketBox, const LocalOptions& options) const { osg::PagedLOD* pagedLOD = new osg::PagedLOD; @@ -241,20 +285,36 @@ ReaderWriterSPT::createPagedLOD(const BucketBox& bucketBox, const osgDB::Options pagedLOD->setCullCallback(new CullCallback); osg::ref_ptr localOptions; - localOptions = static_cast(options->clone(osg::CopyOp())); + localOptions = static_cast(options._options->clone(osg::CopyOp())); // FIXME: // The particle systems have nodes with culling disabled. // PagedLOD nodes with childnodes like this will never expire. // So, for now switch them off. localOptions->setPluginStringData("SimGear::PARTICLESYSTEM", "OFF"); pagedLOD->setDatabaseOptions(localOptions.get()); - - float range = 3*sphere.getRadius(); - // Add the static sea level textured shell - osg::ref_ptr tile = createSeaLevelTile(bucketBox, options); - if (tile.valid()) - pagedLOD->addChild(tile.get(), range, std::numeric_limits::max()); + // The break point for the low level of detail to the high level of detail + float range = 2*sphere.getRadius(); + + // Look for a low level of detail tile + std::string lodPath = options.getLodPathForBucketBox(bucketBox); + const char* extensions[] = { ".btg.gz", ".flt" }; + for (unsigned i = 0; i < sizeof(extensions)/sizeof(extensions[0]); ++i) { + std::string fileName = osgDB::findDataFile(lodPath + extensions[i], options._options); + if (fileName.empty()) + continue; + osg::ref_ptr node = osgDB::readRefNodeFile(fileName, options._options); + if (!node.valid()) + continue; + pagedLOD->addChild(node.get(), range, std::numeric_limits::max()); + break; + } + // Add the static sea level textured shell if there is nothing found + if (pagedLOD->getNumChildren() == 0) { + osg::ref_ptr node = createSeaLevelTile(bucketBox, options._options); + if (node.valid()) + pagedLOD->addChild(node.get(), range, std::numeric_limits::max()); + } // Add the paged file name that creates the subtrees on demand std::stringstream ss; @@ -266,9 +326,9 @@ ReaderWriterSPT::createPagedLOD(const BucketBox& bucketBox, const osgDB::Options } osg::ref_ptr -ReaderWriterSPT::createSeaLevelTile(const BucketBox& bucketBox, const osgDB::Options* options) const +ReaderWriterSPT::createSeaLevelTile(const BucketBox& bucketBox, const LocalOptions& options) const { - if (options->getPluginStringData("SimGear::FG_EARTH") != "ON") + if (options._options->getPluginStringData("SimGear::FG_EARTH") != "ON") return 0; SGSpheref sphere = bucketBox.getBoundingSphere(); @@ -335,10 +395,10 @@ ReaderWriterSPT::createSeaLevelTile(const BucketBox& bucketBox, const osgDB::Opt } osg::ref_ptr -ReaderWriterSPT::getLowLODStateSet(const osgDB::Options* options) const +ReaderWriterSPT::getLowLODStateSet(const LocalOptions& options) const { osg::ref_ptr localOptions; - localOptions = static_cast(options->clone(osg::CopyOp())); + localOptions = static_cast(options._options->clone(osg::CopyOp())); localOptions->setObjectCacheHint(osgDB::Options::CACHE_ALL); osg::ref_ptr object = osgDB::readRefObjectFile("state.spt", localOptions.get()); diff --git a/simgear/scene/tgdb/ReaderWriterSPT.hxx b/simgear/scene/tgdb/ReaderWriterSPT.hxx index 051e829c..9ba8bf6c 100644 --- a/simgear/scene/tgdb/ReaderWriterSPT.hxx +++ b/simgear/scene/tgdb/ReaderWriterSPT.hxx @@ -37,10 +37,12 @@ public: virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& fileName, const osgDB::Options* options) const; protected: - osg::ref_ptr createTree(const BucketBox& bucketBox, const osgDB::Options* options, bool topLevel) const; - osg::ref_ptr createPagedLOD(const BucketBox& bucketBox, const osgDB::Options* options) const; - osg::ref_ptr createSeaLevelTile(const BucketBox& bucketBox, const osgDB::Options* options) const; - osg::ref_ptr getLowLODStateSet(const osgDB::Options* options) const; + struct LocalOptions; + + osg::ref_ptr createTree(const BucketBox& bucketBox, const LocalOptions& options, bool topLevel) const; + osg::ref_ptr createPagedLOD(const BucketBox& bucketBox, const LocalOptions& options) const; + osg::ref_ptr createSeaLevelTile(const BucketBox& bucketBox, const LocalOptions& options) const; + osg::ref_ptr getLowLODStateSet(const LocalOptions& options) const; private: struct CullCallback; -- 2.39.5