#include <osg/MatrixTransform>
#include <osg/Math>
#include <osg/NodeCallback>
+#include <osg/ProxyNode>
#include <osgDB/FileNameUtils>
#include <osgDB/ReaderWriter>
using std::string;
using namespace simgear;
-ModelLoadHelper *TileEntry::_modelLoader=0;
+static ModelLoadHelper *_modelLoader=0;
namespace {
osgDB::RegisterReaderWriterProxy<ReaderWriterSTG> g_readerWriterSTGProxy;
return SGBucket(index);
}
+static bool
+loadStgFile(const std::string& absoluteFileName, osg::Group& group, const osgDB::Options* options)
+{
+ 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<SGReaderWriterOptions> staticOptions;
+ staticOptions = SGReaderWriterOptions::copyOrCreate(options);
+ staticOptions->getDatabasePathList().clear();
+ staticOptions->getDatabasePathList().push_back(filePath);
+ staticOptions->setObjectCacheHint(osgDB::Options::CACHE_NONE);
+
+ osg::ref_ptr<SGReaderWriterOptions> 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);
+
+ bool has_base = false;
+ while ( ! in.eof() ) {
+ std::string token;
+ in >> token;
+
+ // No comment
+ if ( token.empty() || token[0] == '#' ) {
+ in >> ::skipeol;
+ continue;
+ }
+
+ // Then there is always a name
+ std::string name;
+ in >> name;
+
+ SGPath path = filePath;
+ path.append(name);
+
+ osg::ref_ptr<osg::Node> node;
+ if ( token == "OBJECT_BASE" ) {
+ // Load only once (first found)
+ SG_LOG( SG_TERRAIN, SG_BULK, " " << token << " " << name );
+
+ has_base = true;
+ node = osgDB::readRefNodeFile(path.str(),
+ staticOptions.get());
+
+ if (!node.valid()) {
+ SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName
+ << ": Failed to load OBJECT_BASE '"
+ << name << "'" );
+ }
+
+ } else if ( token == "OBJECT" ) {
+ 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" ) {
+ /// Hmm, the findDataFile should happen downstream
+ std::string absName = osgDB::findDataFile(name,
+ staticOptions.get());
+ if(_modelLoader) {
+ node = _modelLoader->loadTileModel(absName, false);
+ } else {
+ osg::ref_ptr<SGReaderWriterOptions> opt;
+ opt = new SGReaderWriterOptions(*staticOptions);
+ if (SGPath(absName).lower_extension() == "ac")
+ opt->setInstantiateEffects(true);
+ else
+ opt->setInstantiateEffects(false);
+ node = osgDB::readRefNodeFile(absName, opt.get());
+ }
+
+ if (!node.valid()) {
+ SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName
+ << ": Failed to load OBJECT_STATIC '"
+ << name << "'" );
+ }
+
+ } else if ( token == "OBJECT_SHARED" ) {
+ if(_modelLoader) {
+ node = _modelLoader->loadTileModel(name, true);
+ } else {
+ osg::ref_ptr<SGReaderWriterOptions> opt;
+ opt = new SGReaderWriterOptions(*sharedOptions);
+
+ /// Hmm, the findDataFile should happen in the downstream readers
+ std::string absName = osgDB::findDataFile(name, opt.get());
+
+ osg::ProxyNode* proxyNode = new osg::ProxyNode;
+ proxyNode->setLoadingExternalReferenceMode(osg::ProxyNode::DEFER_LOADING_TO_DATABASE_PAGER);
+ proxyNode->setFileName(0, absName);
+ if (SGPath(absName).lower_extension() == "ac")
+ 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_SHARED '"
+ << name << "'" );
+ }
+
+ } else if ( token == "OBJECT_SIGN" ) {
+ node = SGMakeSign(staticOptions->getMaterialLib(), name);
+
+ } else if ( token == "OBJECT_RUNWAY_SIGN" ) {
+ node = SGMakeRunwaySign(staticOptions->getMaterialLib(), name);
+
+ } else {
+ SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName
+ << ": Unknown token '" << token << "'" );
+ }
+
+ if (node.valid() && token != "OBJECT") {
+ osg::Matrix matrix;
+ matrix = makeZUpFrame(SGGeod::fromDegM(lon, lat, elev));
+ matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(hdg),
+ osg::Vec3(0, 0, 1)));
+
+ osg::MatrixTransform* matrixTransform;
+ matrixTransform = new osg::MatrixTransform(matrix);
+ matrixTransform->setDataVariance(osg::Object::STATIC);
+ matrixTransform->addChild(node.get());
+ node = matrixTransform;
+ }
+ }
+
+ if (node.valid())
+ group.addChild(node.get());
+
+ in >> ::skipeol;
+ }
+
+ return has_base;
+}
+
+void
+TileEntry::setModelLoadHelper(ModelLoadHelper *m)
+{
+ _modelLoader=m;
+}
+
// Constructor
TileEntry::TileEntry ( const SGBucket& b )
: tile_bucket( b ),
{
SG_LOG(SG_TERRAIN, SG_INFO, "Loading tile " << fileName);
- // Space for up to two stg file names.
- // There is usually one in the Terrain and one in the Objects subdirectory.
- std::string absoluteFileName[2];
-
// 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.
// files spread across the scenery directories.
std::string simpleFileName = osgDB::getSimpleFileName(fileName);
SGBucket bucket = getBucketFromFileName(simpleFileName);
- bool file_mode = false;
- if (simpleFileName == fileName && options) {
- // This is considered a meta file, so apply the scenery path search
- const osgDB::FilePathList& filePathList = options->getDatabasePathList();
- std::string basePath = bucket.gen_base_path();
- for (osgDB::FilePathList::const_iterator i = filePathList.begin();
- i != filePathList.end(); ++i) {
- SGPath terrain(*i);
- terrain.append("Terrain");
- terrain.append(basePath);
- terrain.append(simpleFileName);
-
- SGPath objects(*i);
- objects.append("Objects");
- objects.append(basePath);
- objects.append(simpleFileName);
-
- if (terrain.isFile() || objects.isFile()) {
- absoluteFileName[0] = terrain.str();
- absoluteFileName[1] = objects.str();
- break;
- }
- }
- } else {
+ osg::ref_ptr<osg::Group> group = new osg::Group;
+ if (simpleFileName != fileName || !options) {
// This is considered a real existing file.
// We still apply the search path algorithms for relative files.
- absoluteFileName[0] = osgDB::findDataFile(fileName, options);
- // Do not generate an ocean tile if we have no btg
- file_mode = true;
+ loadStgFile(osgDB::findDataFile(fileName, options), *group, options);
+ return group.release();
}
- std::string fg_root = options->getPluginStringData("SimGear::FG_ROOT");
- osg::ref_ptr<SGReaderWriterOptions> opt;
- opt = SGReaderWriterOptions::copyOrCreate(options);
-
- bool found_tile_base = false;
- osg::ref_ptr<osg::Group> group = new osg::Group;
- for (unsigned i = 0; i < 2; ++i) {
-
- if (absoluteFileName[i].empty())
- continue;
-
- sg_gzifstream in( absoluteFileName[i] );
- if ( !in.is_open() )
- continue;
-
- SG_LOG(SG_TERRAIN, SG_INFO, "Loading stg file " << absoluteFileName[i]);
-
- std::string filePath = osgDB::getFilePath(absoluteFileName[i]);
-
- osg::ref_ptr<SGReaderWriterOptions> staticOptions;
- staticOptions = SGReaderWriterOptions::copyOrCreate(options);
- staticOptions->getDatabasePathList().clear();
- staticOptions->getDatabasePathList().push_back(filePath);
- staticOptions->setObjectCacheHint(osgDB::Options::CACHE_NONE);
-
- osg::ref_ptr<SGReaderWriterOptions> sharedOptions;
- sharedOptions = SGReaderWriterOptions::copyOrCreate(options);
- sharedOptions->getDatabasePathList().clear();
-
- SGPath path = filePath;
- path.append(".."); path.append(".."); path.append("..");
- sharedOptions->getDatabasePathList().push_back(path.str());
- sharedOptions->getDatabasePathList().push_back(fg_root);
-
- bool has_base = false;
- while ( ! in.eof() ) {
- std::string token;
- in >> token;
-
- // No comment
- if ( token.empty() || token[0] == '#' ) {
- in >> ::skipeol;
- continue;
- }
-
- // Then there is always a name
- std::string name;
- in >> name;
-
- SGPath path = filePath;
- path.append(name);
-
- osg::ref_ptr<osg::Node> node;
- if ( token == "OBJECT_BASE" ) {
- // Load only once (first found)
- SG_LOG( SG_TERRAIN, SG_BULK, " " << token << " " << name );
-
- if (!found_tile_base) {
- found_tile_base = true;
- has_base = true;
-
- node = osgDB::readRefNodeFile(path.str(),
- staticOptions.get());
-
- if (!node.valid()) {
- SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName[i]
- << ": Failed to load OBJECT_BASE '"
- << name << "'" );
- }
- } else
- SG_LOG(SG_TERRAIN, SG_BULK, " (skipped)");
-
- } else if ( token == "OBJECT" ) {
- // Load only if base is not in another file
- if (!found_tile_base || has_base) {
- node = osgDB::readRefNodeFile(path.str(),
- staticOptions.get());
-
- if (!node.valid()) {
- SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName[i]
- << ": Failed to load OBJECT '"
- << name << "'" );
- }
- } else {
- SG_LOG(SG_TERRAIN, SG_BULK, " " << token << " "
- << name << " (skipped)");
- }
-
- } else {
- double lon, lat, elev, hdg;
- in >> lon >> lat >> elev >> hdg;
-
- // Always OK to load
- if ( token == "OBJECT_STATIC" ) {
- /// Hmm, the findDataFile should happen downstream
- std::string absName = osgDB::findDataFile(name,
- staticOptions.get());
- if(_modelLoader) {
- node = _modelLoader->loadTileModel(absName, false);
- } else {
- node = osgDB::readRefNodeFile(absName,
- staticOptions.get());
- }
-
- if (!node.valid()) {
- SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName[i]
- << ": Failed to load OBJECT_STATIC '"
- << name << "'" );
- }
-
- } else if ( token == "OBJECT_SHARED" ) {
- if(_modelLoader) {
- node = _modelLoader->loadTileModel(name, true);
- } else {
- /// Hmm, the findDataFile should happen in the downstream readers
- std::string absName = osgDB::findDataFile(name,
- sharedOptions.get());
- node = osgDB::readRefNodeFile(absName,
- sharedOptions.get());
- }
-
- if (!node.valid()) {
- SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName[i]
- << ": Failed to load OBJECT_SHARED '"
- << name << "'" );
- }
-
- } else if ( token == "OBJECT_SIGN" ) {
- node = SGMakeSign(opt->getMaterialLib(), name);
-
- } else if ( token == "OBJECT_RUNWAY_SIGN" ) {
- node = SGMakeRunwaySign(opt->getMaterialLib(), name);
-
- } else {
- SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName[i]
- << ": Unknown token '" << token << "'" );
- }
-
- if (node.valid() && token != "OBJECT") {
- osg::Matrix matrix;
- matrix = makeZUpFrame(SGGeod::fromDegM(lon, lat, elev));
- matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(hdg),
- osg::Vec3(0, 0, 1)));
-
- osg::MatrixTransform* matrixTransform;
- matrixTransform = new osg::MatrixTransform(matrix);
- matrixTransform->setDataVariance(osg::Object::STATIC);
- matrixTransform->addChild(node.get());
- node = matrixTransform;
- }
- }
-
- if (node.valid())
- group->addChild(node.get());
-
- in >> ::skipeol;
- }
+ // This is considered a meta file, so apply the scenery path search
+ const osgDB::FilePathList& filePathList = options->getDatabasePathList();
+ std::string basePath = bucket.gen_base_path();
+ // Stop scanning once an object base is found
+ bool foundBase = false;
+ for (osgDB::FilePathList::const_iterator i = filePathList.begin();
+ i != filePathList.end() && !foundBase; ++i) {
+ SGPath objects(*i);
+ objects.append("Objects");
+ objects.append(basePath);
+ objects.append(simpleFileName);
+ if (loadStgFile(objects.str(), *group, options))
+ foundBase = true;
+
+ SGPath terrain(*i);
+ terrain.append("Terrain");
+ terrain.append(basePath);
+ terrain.append(simpleFileName);
+ if (loadStgFile(terrain.str(), *group, options))
+ foundBase = true;
}
-
- if (!found_tile_base && !file_mode) {
- // ... or generate an ocean tile on the fly
+
+ // ... or generate an ocean tile on the fly
+ if (!foundBase) {
SG_LOG(SG_TERRAIN, SG_INFO, " Generating ocean tile");
-
+
+ osg::ref_ptr<SGReaderWriterOptions> opt;
+ opt = SGReaderWriterOptions::copyOrCreate(options);
osg::Node* node = SGOceanTile(bucket, opt->getMaterialLib());
if ( node ) {
group->addChild(node);
"Warning: failed to generate ocean tile!" );
}
}
-
return group.release();
}