scene: Reorganize stg loading.

This is in preparation loading the non btg objects
in a seperate page node. Reorganize this code again.
This commit is contained in:
Mathias Froehlich
2012-08-25 08:43:12 +02:00
parent 68dd50ecbc
commit f1201eaebc
3 changed files with 291 additions and 267 deletions

View File

@@ -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);

View File

@@ -40,14 +40,12 @@
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/scene/util/RenderConstants.hxx>
#include <simgear/scene/util/OsgMath.hxx>
#include <simgear/scene/material/mat.hxx>
#include <simgear/scene/material/matlib.hxx>
#include <simgear/scene/tgdb/apt_signs.hxx>
#include <simgear/scene/tgdb/obj.hxx>
#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<SGReaderWriterOptions> _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<SGReaderWriterOptions> _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<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);
return sharedOptions.release();
}
if ( isdigit(in.peek()) || (in.peek() == '-') ){
SGReaderWriterOptions* staticOptions(const std::string& filePath, const osgDB::Options* options)
{
osg::ref_ptr<SGReaderWriterOptions> 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<SGReaderWriterOptions> 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<SGReaderWriterOptions> 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<SGReaderWriterOptions> options;
options = SGReaderWriterOptions::copyOrCreate(opt);
osg::ref_ptr<osg::Group> 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<osg::Node> 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<osg::Node> node;
if (i->_proxy) {
osg::ref_ptr<osg::ProxyNode> 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<osg::Group> 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;
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;
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");
SG_LOG(SG_TERRAIN, SG_INFO, "Loading tile " << fileName);
osg::ref_ptr<SGReaderWriterOptions> 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!" );
std::string basePath = bucket.gen_base_path();
// 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);
SGPath terrain(*i);
terrain.append("Terrain");
terrain.append(basePath);
terrain.append(fileName);
modelBin.read(terrain.str(), options);
}
}
return group.get();
return modelBin.load(bucket, options);
}
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<osg::Group> 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<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);
// 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;
}
// 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;
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 << "'" );
}
}
} 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<SGReaderWriterOptions> 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<SGReaderWriterOptions> 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;
}
}
if (node.valid())
group.addChild(node.get());
in >> ::skipeol;
}
if (signBuilder.getSignsGroup())
group.addChild(signBuilder.getSignsGroup());
return has_base;
}

View File

@@ -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;
};
}