From f1201eaebc3fbb8964e06b7ef158fd34a12901aa Mon Sep 17 00:00:00 2001 From: Mathias Froehlich Date: Sat, 25 Aug 2012 08:43:12 +0200 Subject: [PATCH] scene: Reorganize stg loading. This is in preparation loading the non btg objects in a seperate page node. Reorganize this code again. --- simgear/scene/model/SGReaderWriterXML.cxx | 4 +- simgear/scene/tgdb/ReaderWriterSTG.cxx | 545 ++++++++++++---------- simgear/scene/tgdb/ReaderWriterSTG.hxx | 9 +- 3 files changed, 291 insertions(+), 267 deletions(-) diff --git a/simgear/scene/model/SGReaderWriterXML.cxx b/simgear/scene/model/SGReaderWriterXML.cxx index fc7d67f3..8399a35d 100644 --- a/simgear/scene/model/SGReaderWriterXML.cxx +++ b/simgear/scene/model/SGReaderWriterXML.cxx @@ -77,9 +77,11 @@ const char* SGReaderWriterXML::className() const } osgDB::ReaderWriter::ReadResult -SGReaderWriterXML::readNode(const std::string& fileName, +SGReaderWriterXML::readNode(const std::string& name, const osgDB::Options* options) const { + std::string fileName = osgDB::findDataFile(name, options); + osg::Node *result=0; try { SGPath p = SGModelLib::findDataFile(fileName); diff --git a/simgear/scene/tgdb/ReaderWriterSTG.cxx b/simgear/scene/tgdb/ReaderWriterSTG.cxx index 0f800791..24ac5c14 100644 --- a/simgear/scene/tgdb/ReaderWriterSTG.cxx +++ b/simgear/scene/tgdb/ReaderWriterSTG.cxx @@ -40,14 +40,12 @@ #include #include #include -#include -#include #include #include #include "SGOceanTile.hxx" -using namespace simgear; +namespace simgear { /// Ok, this is a hack - we do not exactly know if it's an airport or not. /// This feature might also vanish again later. This is currently to @@ -79,18 +77,265 @@ static SGBucket bucketIndexFromFileName(const std::string& fileName) return SGBucket(index); } -static bool hasOptionalValue(sg_gzifstream &in) -{ - while ( (in.peek() != '\n') && (in.peek() != '\r') - && isspace(in.peek()) ) { - in.get(); +struct ReaderWriterSTG::_ModelBin { + struct _Object { + std::string _errorLocation; + std::string _token; + std::string _name; + osg::ref_ptr _options; + }; + struct _ObjectStatic { + _ObjectStatic() : _proxy(false), _lon(0), _lat(0), _elev(0), _hdg(0), _pitch(0), _roll(0) { } + std::string _errorLocation; + std::string _token; + std::string _name; + bool _proxy; + double _lon, _lat, _elev; + double _hdg, _pitch, _roll; + osg::ref_ptr _options; + }; + struct _Sign { + _Sign() : _lon(0), _lat(0), _elev(0), _hdg(0), _size(-1) { } + std::string _errorLocation; + std::string _token; + std::string _name; + double _lon, _lat, _elev; + double _hdg; + int _size; + }; + + _ModelBin() : + _foundBase(false) + { } + + SGReaderWriterOptions* sharedOptions(const std::string& filePath, const osgDB::Options* options) + { + osg::ref_ptr sharedOptions; + sharedOptions = SGReaderWriterOptions::copyOrCreate(options); + sharedOptions->getDatabasePathList().clear(); + + SGPath path = filePath; + path.append(".."); path.append(".."); path.append(".."); + sharedOptions->getDatabasePathList().push_back(path.str()); + std::string fg_root = options->getPluginStringData("SimGear::FG_ROOT"); + sharedOptions->getDatabasePathList().push_back(fg_root); + + return sharedOptions.release(); } - if ( isdigit(in.peek()) || (in.peek() == '-') ){ + SGReaderWriterOptions* staticOptions(const std::string& filePath, const osgDB::Options* options) + { + osg::ref_ptr staticOptions; + staticOptions = SGReaderWriterOptions::copyOrCreate(options); + staticOptions->getDatabasePathList().clear(); + + staticOptions->getDatabasePathList().push_back(filePath); + staticOptions->setObjectCacheHint(osgDB::Options::CACHE_NONE); + + return staticOptions.release(); + } + + bool read(const std::string& absoluteFileName, const osgDB::Options* options) + { + if (absoluteFileName.empty()) + return false; + + sg_gzifstream stream(absoluteFileName); + if (!stream.is_open()) + return false; + + SG_LOG(SG_TERRAIN, SG_INFO, "Loading stg file " << absoluteFileName); + + std::string filePath = osgDB::getFilePath(absoluteFileName); + + // do only load airport btg files. + bool onlyAirports = options->getPluginStringData("SimGear::FG_ONLY_AIRPORTS") == "ON"; + // do only load terrain btg files + bool onlyTerrain = options->getPluginStringData("SimGear::FG_ONLY_TERRAIN") == "ON"; + + while (!stream.eof()) { + // read a line + std::string line; + std::getline(stream, line); + + // strip comments + std::string::size_type hash_pos = line.find('#'); + if (hash_pos != std::string::npos) + line.resize(hash_pos); + + // and process further + std::stringstream in(line); + + std::string token; + in >> token; + + // No comment + if (token.empty()) + continue; + + // Then there is always a name + std::string name; + in >> name; + + SGPath path = filePath; + path.append(name); + + if (token == "OBJECT_BASE") { + // Load only once (first found) + SG_LOG( SG_TERRAIN, SG_BULK, " " << token << " " << name ); + _foundBase = true; + if (!onlyAirports || isAirportBtg(name)) { + _Object obj; + obj._errorLocation = absoluteFileName; + obj._token = token; + obj._name = path.str(); + obj._options = staticOptions(filePath, options); + _objectList.push_back(obj); + } + + } else if (token == "OBJECT") { + if (!onlyAirports || isAirportBtg(name)) { + _Object obj; + obj._errorLocation = absoluteFileName; + obj._token = token; + obj._name = path.str(); + obj._options = staticOptions(filePath, options); + _objectList.push_back(obj); + } + + } else { + // Always OK to load + if (token == "OBJECT_STATIC") { + if (!onlyTerrain) { + 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._proxy = true; + in >> obj._lon >> obj._lat >> obj._elev >> obj._hdg >> obj._pitch >> obj._roll; + obj._options = opt; + _objectStaticList.push_back(obj); + } + + } else if (token == "OBJECT_SHARED") { + if (!onlyTerrain) { + 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._proxy = false; + in >> obj._lon >> obj._lat >> obj._elev >> obj._hdg >> obj._pitch >> obj._roll; + obj._options = opt; + _objectStaticList.push_back(obj); + } + + } else if (token == "OBJECT_SIGN") { + if (!onlyTerrain) { + _Sign sign; + sign._token = token; + sign._name = name; + in >> sign._lon >> sign._lat >> sign._elev >> sign._hdg >> sign._size; + _signList.push_back(sign); + } + + } else { + SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName + << ": Unknown token '" << token << "'" ); + } + } + } + return true; - } else { - return false; } -} + + osg::Node* load(const SGBucket& bucket, const osgDB::Options* opt) + { + osg::ref_ptr options; + options = SGReaderWriterOptions::copyOrCreate(opt); + + osg::ref_ptr group = new osg::Group; + group->setDataVariance(osg::Object::STATIC); + + if (_foundBase) { + for (std::list<_Object>::iterator i = _objectList.begin(); i != _objectList.end(); ++i) { + osg::ref_ptr node; + node = osgDB::readRefNodeFile(i->_name, i->_options.get()); + if (!node.valid()) { + SG_LOG(SG_TERRAIN, SG_ALERT, i->_errorLocation << ": Failed to load " + << i->_token << " '" << i->_name << "'"); + continue; + } + group->addChild(node.get()); + } + } else { + SG_LOG(SG_TERRAIN, SG_INFO, " Generating ocean tile"); + + osg::Node* node = SGOceanTile(bucket, options->getMaterialLib()); + if (node) { + group->addChild(node); + } else { + SG_LOG( SG_TERRAIN, SG_ALERT, + "Warning: failed to generate ocean tile!" ); + } + } + + for (std::list<_ObjectStatic>::iterator i = _objectStaticList.begin(); i != _objectStaticList.end(); ++i) { + osg::ref_ptr node; + if (i->_proxy) { + osg::ref_ptr proxy = new osg::ProxyNode; + proxy->setLoadingExternalReferenceMode(osg::ProxyNode::DEFER_LOADING_TO_DATABASE_PAGER); + proxy->setFileName(0, i->_name); + proxy->setDatabaseOptions(i->_options.get()); + node = proxy; + } else { + node = osgDB::readRefNodeFile(i->_name, i->_options.get()); + if (!node.valid()) { + SG_LOG(SG_TERRAIN, SG_ALERT, i->_errorLocation << ": Failed to load " + << i->_token << " '" << i->_name << "'"); + continue; + } + } + if (SGPath(i->_name).lower_extension() == "ac") + node->setNodeMask(~simgear::MODELLIGHT_BIT); + + osg::Matrix matrix; + matrix = makeZUpFrame(SGGeod::fromDegM(i->_lon, i->_lat, i->_elev)); + matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(i->_hdg), osg::Vec3(0, 0, 1))); + matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(i->_pitch), osg::Vec3(0, 1, 0))); + matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(i->_roll), osg::Vec3(1, 0, 0))); + + osg::MatrixTransform* matrixTransform; + matrixTransform = new osg::MatrixTransform(matrix); + matrixTransform->setDataVariance(osg::Object::STATIC); + matrixTransform->addChild(node.get()); + group->addChild(matrixTransform); + } + + simgear::AirportSignBuilder signBuilder(options->getMaterialLib(), bucket.get_center()); + for (std::list<_Sign>::iterator i = _signList.begin(); i != _signList.end(); ++i) + signBuilder.addSign(SGGeod::fromDegM(i->_lon, i->_lat, i->_elev), i->_hdg, i->_name, i->_size); + if (signBuilder.getSignsGroup()) + group->addChild(signBuilder.getSignsGroup()); + + return group.release(); + } + + bool _foundBase; + std::list<_Object> _objectList; + std::list<_ObjectStatic> _objectStaticList; + std::list<_Sign> _signList; +}; ReaderWriterSTG::ReaderWriterSTG() { @@ -109,262 +354,46 @@ const char* ReaderWriterSTG::className() const osgDB::ReaderWriter::ReadResult ReaderWriterSTG::readNode(const std::string& fileName, const osgDB::Options* options) const { + _ModelBin modelBin; + SGBucket bucket(bucketIndexFromFileName(fileName)); + // We treat 123.stg different than ./123.stg. // The difference is that ./123.stg as well as any absolute path // really loads the given stg file and only this. // In contrast 123.stg uses the search paths to load a set of stg // files spread across the scenery directories. - if (osgDB::getSimpleFileName(fileName) != fileName) - return readStgFile(fileName, options); - - // For stg meta files, we need options for the search path. - if (!options) - return ReadResult::FILE_NOT_FOUND; - - - - SG_LOG(SG_TERRAIN, SG_INFO, "Loading tile " << fileName); - - SGBucket bucket(bucketIndexFromFileName(fileName)); - std::string basePath = bucket.gen_base_path(); - - osg::ref_ptr group = new osg::Group; - - // Stop scanning once an object base is found - bool foundBase = false; - // This is considered a meta file, so apply the scenery path search - const osgDB::FilePathList& filePathList = options->getDatabasePathList(); - for (osgDB::FilePathList::const_iterator i = filePathList.begin(); - i != filePathList.end() && !foundBase; ++i) { - SGPath objects(*i); - objects.append("Objects"); - objects.append(basePath); - objects.append(fileName); - if (readStgFile(objects.str(), bucket, *group, options)) - foundBase = true; - - SGPath terrain(*i); - terrain.append("Terrain"); - terrain.append(basePath); - terrain.append(fileName); - if (readStgFile(terrain.str(), bucket, *group, options)) - foundBase = true; - } - - // ... or generate an ocean tile on the fly - if (!foundBase) { - SG_LOG(SG_TERRAIN, SG_INFO, " Generating ocean tile"); - - osg::ref_ptr opt; - opt = SGReaderWriterOptions::copyOrCreate(options); - osg::Node* node = SGOceanTile(bucket, opt->getMaterialLib()); - if ( node ) { - group->addChild(node); - } else { - SG_LOG( SG_TERRAIN, SG_ALERT, - "Warning: failed to generate ocean tile!" ); - } - } - - return group.get(); -} - -osgDB::ReaderWriter::ReadResult -ReaderWriterSTG::readStgFile(const std::string& fileName, const osgDB::Options* options) const -{ - // This is considered a real existing file. - // We still apply the search path algorithms for relative files. - osg::ref_ptr group = new osg::Group; - std::string path = osgDB::findDataFile(fileName, options); - readStgFile(path, bucketIndexFromFileName(path), *group, options); - - return group.get(); -} - -bool -ReaderWriterSTG::readStgFile(const std::string& absoluteFileName, - const SGBucket& bucket, - osg::Group& group, const osgDB::Options* options) const -{ - if (absoluteFileName.empty()) - return false; - - sg_gzifstream in( absoluteFileName ); - if ( !in.is_open() ) - return false; - - SG_LOG(SG_TERRAIN, SG_INFO, "Loading stg file " << absoluteFileName); - - std::string filePath = osgDB::getFilePath(absoluteFileName); - - osg::ref_ptr staticOptions; - staticOptions = SGReaderWriterOptions::copyOrCreate(options); - staticOptions->getDatabasePathList().clear(); - staticOptions->getDatabasePathList().push_back(filePath); - staticOptions->setObjectCacheHint(osgDB::Options::CACHE_NONE); - - osg::ref_ptr sharedOptions; - sharedOptions = SGReaderWriterOptions::copyOrCreate(options); - sharedOptions->getDatabasePathList().clear(); - - SGPath path = filePath; - path.append(".."); path.append(".."); path.append(".."); - sharedOptions->getDatabasePathList().push_back(path.str()); - std::string fg_root = options->getPluginStringData("SimGear::FG_ROOT"); - sharedOptions->getDatabasePathList().push_back(fg_root); - - // do only load airport btg files. - bool onlyAirports = options->getPluginStringData("SimGear::FG_ONLY_AIRPORTS") == "ON"; - // do only load terrain btg files - bool onlyTerrain = options->getPluginStringData("SimGear::FG_ONLY_TERRAIN") == "ON"; - - simgear::AirportSignBuilder signBuilder(staticOptions->getMaterialLib(), bucket.get_center()); - - bool has_base = false; - while ( ! in.eof() ) { - std::string token; - in >> token; - - // No comment - if ( token.empty() || token[0] == '#' ) { - in >> ::skipeol; - continue; - } + if (osgDB::getSimpleFileName(fileName) != fileName) { + if (!modelBin.read(fileName, options)) + return ReadResult::FILE_NOT_FOUND; + } else { + // For stg meta files, we need options for the search path. + if (!options) + return ReadResult::FILE_NOT_FOUND; - // Then there is always a name - std::string name; - in >> name; + SG_LOG(SG_TERRAIN, SG_INFO, "Loading tile " << fileName); - SGPath path = filePath; - path.append(name); + std::string basePath = bucket.gen_base_path(); - osg::ref_ptr node; - if ( token == "OBJECT_BASE" ) { - // Load only once (first found) - SG_LOG( SG_TERRAIN, SG_BULK, " " << token << " " << name ); - - has_base = true; - - if (!onlyAirports || isAirportBtg(name)) { - node = osgDB::readRefNodeFile(path.str(), - staticOptions.get()); - - if (!node.valid()) { - SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName - << ": Failed to load OBJECT_BASE '" - << name << "'" ); - } - } + // Stop scanning once an object base is found + // This is considered a meta file, so apply the scenery path search + const osgDB::FilePathList& filePathList = options->getDatabasePathList(); + for (osgDB::FilePathList::const_iterator i = filePathList.begin(); + i != filePathList.end() && !modelBin._foundBase; ++i) { + SGPath objects(*i); + objects.append("Objects"); + objects.append(basePath); + objects.append(fileName); + modelBin.read(objects.str(), options); - } else if ( token == "OBJECT" ) { - if (!onlyAirports || isAirportBtg(name)) { - node = osgDB::readRefNodeFile(path.str(), - staticOptions.get()); - - if (!node.valid()) { - SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName - << ": Failed to load OBJECT '" - << name << "'" ); - } - } - - } else { - double lon, lat, elev, hdg; - in >> lon >> lat >> elev >> hdg; - - // Always OK to load - if ( token == "OBJECT_STATIC" ) { - if (!onlyTerrain) { - osg::ref_ptr opt; - opt = new SGReaderWriterOptions(*staticOptions); - osg::ProxyNode* proxyNode = new osg::ProxyNode; - proxyNode->setLoadingExternalReferenceMode(osg::ProxyNode::DEFER_LOADING_TO_DATABASE_PAGER); - /// Hmm, the findDataFile should happen downstream - std::string absName = osgDB::findDataFile(name, opt.get()); - proxyNode->setFileName(0, absName); - if (SGPath(absName).lower_extension() == "ac") - { - proxyNode->setNodeMask( ~simgear::MODELLIGHT_BIT ); - opt->setInstantiateEffects(true); - } - else - opt->setInstantiateEffects(false); - proxyNode->setDatabaseOptions(opt.get()); - node = proxyNode; - - if (!node.valid()) { - SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName - << ": Failed to load OBJECT_STATIC '" - << name << "'" ); - } - } - - } else if ( token == "OBJECT_SHARED" ) { - if (!onlyTerrain) { - osg::ref_ptr opt; - opt = new SGReaderWriterOptions(*sharedOptions); - /// Hmm, the findDataFile should happen in the downstream readers - std::string absName = osgDB::findDataFile(name, opt.get()); - if (SGPath(absName).lower_extension() == "ac") - opt->setInstantiateEffects(true); - else - opt->setInstantiateEffects(false); - node = osgDB::readRefNodeFile(absName, opt.get()); - if (SGPath(absName).lower_extension() == "ac") - node->setNodeMask( ~simgear::MODELLIGHT_BIT ); - - if (!node.valid()) { - SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName - << ": Failed to load OBJECT_SHARED '" - << name << "'" ); - } - } - - } else if ( token == "OBJECT_SIGN" ) { - int size(-1); - - if ( hasOptionalValue(in) ){ - in >> size; - } - if (!onlyTerrain) - signBuilder.addSign(SGGeod::fromDegM(lon, lat, elev), hdg, name, size); - } else { - SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName - << ": Unknown token '" << token << "'" ); - } - - if (node.valid()) { - osg::Matrix matrix; - matrix = makeZUpFrame(SGGeod::fromDegM(lon, lat, elev)); - matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(hdg), - osg::Vec3(0, 0, 1))); - - if ( hasOptionalValue(in) ){ - double pitch(0.0), roll(0.0); - in >> pitch >> roll; - - matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(pitch), - osg::Vec3(0, 1, 0))); - matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(roll), - osg::Vec3(1, 0, 0))); - } - - osg::MatrixTransform* matrixTransform; - matrixTransform = new osg::MatrixTransform(matrix); - matrixTransform->setDataVariance(osg::Object::STATIC); - matrixTransform->addChild(node.get()); - node = matrixTransform; - } + SGPath terrain(*i); + terrain.append("Terrain"); + terrain.append(basePath); + terrain.append(fileName); + modelBin.read(terrain.str(), options); } - - if (node.valid()) - group.addChild(node.get()); - - in >> ::skipeol; } - - if (signBuilder.getSignsGroup()) - group.addChild(signBuilder.getSignsGroup()); - return has_base; + return modelBin.load(bucket, options); +} + } diff --git a/simgear/scene/tgdb/ReaderWriterSTG.hxx b/simgear/scene/tgdb/ReaderWriterSTG.hxx index 63c3eb72..8e19578e 100644 --- a/simgear/scene/tgdb/ReaderWriterSTG.hxx +++ b/simgear/scene/tgdb/ReaderWriterSTG.hxx @@ -39,14 +39,7 @@ public: readNode(const std::string&, const osgDB::Options*) const; private: - /// Read an real existing stg file that exists on disk. - ReadResult - readStgFile(const std::string& fileName, const osgDB::Options* options) const; - - /// Read an real existing stg file that exists on disk and return true - /// if a BASE_OBJECT is found. - bool - readStgFile(const std::string&, const SGBucket& bucket, osg::Group&, const osgDB::Options*) const; + struct _ModelBin; }; } -- 2.39.5