--- /dev/null
+#include <iostream>
+#include <cstdlib>
+
+#include <osg/ArgumentParser>
+#include <osg/Fog>
+#include <osgDB/ReadFile>
+#include <osgDB/Registry>
+#include <osgDB/WriteFile>
+#include <osgViewer/Renderer>
+#include <osgViewer/Viewer>
+#include <osgViewer/ViewerEventHandlers>
+#include <osgGA/KeySwitchMatrixManipulator>
+#include <osgGA/TrackballManipulator>
+#include <osgGA/FlightManipulator>
+#include <osgGA/DriveManipulator>
+#include <osgGA/TerrainManipulator>
+#include <osgGA/StateSetManipulator>
+
+#include <simgear/props/props.hxx>
+#include <simgear/props/props_io.hxx>
+#include <simgear/misc/sg_path.hxx>
+#include <simgear/scene/material/EffectCullVisitor.hxx>
+#include <simgear/scene/material/matlib.hxx>
+#include <simgear/scene/tgdb/SGReaderWriterBTGOptions.hxx>
+#include <simgear/scene/tgdb/userdata.hxx>
+#include <simgear/scene/tgdb/TileEntry.hxx>
+#include <simgear/scene/model/ModelRegistry.hxx>
+#include <simgear/scene/model/modellib.hxx>
+
+#include <Scenery/scenery.hxx>
+
+#include "fg_init.hxx"
+#include "fg_props.hxx"
+#include "globals.hxx"
+#include "options.hxx"
+
+class DummyLoadHelper : public simgear::ModelLoadHelper {
+public:
+ virtual osg::Node *loadTileModel(const string& modelPath, bool)
+ {
+ try {
+ SGSharedPtr<SGPropertyNode> prop = new SGPropertyNode;
+ return simgear::SGModelLib::loadModel(modelPath, prop);
+ } catch (...) {
+ std::cerr << "Error loading \"" << modelPath << "\"" << std::endl;
+ return 0;
+ }
+ }
+};
+
+class GraphDumpHandler : public osgGA::GUIEventHandler
+{
+public:
+ GraphDumpHandler() : _keyDump('d') {}
+ void setKeyDump(int key) { _keyDump = key; }
+ int getKeyDump() const { return _keyDump; }
+ bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);
+
+ /** Get the keyboard and mouse usage of this manipulator.*/
+ virtual void getUsage(osg::ApplicationUsage& usage) const;
+protected:
+ int _keyDump;
+};
+
+static void dumpOut(osg::Node* node)
+{
+ char filename[24];
+ static int count = 1;
+
+ FGRenderer *renderer = globals->get_renderer();
+
+ while (count < 1000) {
+ FILE *fp;
+ snprintf(filename, 24, "fgviewer-%03d.osg", count++);
+ if ( (fp = fopen(filename, "r")) == NULL )
+ break;
+ fclose(fp);
+ }
+
+ if (osgDB::writeNodeFile(*node, filename))
+ std::cerr << "Entire scene graph saved to \"" << filename << "\".\n";
+ else
+ std::cerr << "Failed to save to \"" << filename << "\".\n";
+}
+
+bool GraphDumpHandler::handle(const osgGA::GUIEventAdapter& ea,
+ osgGA::GUIActionAdapter& aa)
+{
+ osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
+ if (!view)
+ return false;
+ if (ea.getHandled())
+ return false;
+ switch(ea.getEventType()) {
+ case osgGA::GUIEventAdapter::KEYUP:
+ if (ea.getKey() == _keyDump) {
+ dumpOut(view->getScene()->getSceneData());
+ return true;
+ }
+ break;
+ default:
+ return false;
+ }
+}
+
+void GraphDumpHandler::getUsage(osg::ApplicationUsage& usage) const
+{
+ std::ostringstream ostr;
+ ostr << char(_keyDump);
+ usage.addKeyboardMouseBinding(ostr.str(),
+ "Dump scene graph to file");
+}
+
+int
+fgviewerMain(int argc, char** argv)
+{
+
+ sgUserDataInit(0);
+ DummyLoadHelper dummyLoadHelper;
+ simgear::TileEntry::setModelLoadHelper(&dummyLoadHelper);
+
+ // use an ArgumentParser object to manage the program arguments.
+ osg::ArgumentParser arguments(&argc, argv);
+
+ // construct the viewer.
+ osgViewer::Viewer viewer(arguments);
+ osg::Camera* camera = viewer.getCamera();
+ osgViewer::Renderer* renderer
+ = static_cast<osgViewer::Renderer*>(camera->getRenderer());
+ for (int i = 0; i < 2; ++i) {
+ osgUtil::SceneView* sceneView = renderer->getSceneView(i);
+ sceneView->setCullVisitor(new simgear::EffectCullVisitor);
+ }
+ // Shaders expect valid fog
+ osg::StateSet* cameraSS = camera->getOrCreateStateSet();
+ osg::Fog* fog = new osg::Fog;
+ fog->setMode(osg::Fog::EXP2);
+ fog->setColor(osg::Vec4(1.0, 1.0, 1.0, 1.0));
+ fog->setDensity(.0000001);
+ cameraSS->setAttributeAndModes(fog);
+ // ... for some reason, get rid of that FIXME!
+ viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
+
+ // set up the camera manipulators.
+ osgGA::KeySwitchMatrixManipulator* keyswitchManipulator;
+ keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
+
+ osgGA::MatrixManipulator* mm = new osgGA::TrackballManipulator;
+ keyswitchManipulator->addMatrixManipulator('1', "Trackball", mm);
+ mm = new osgGA::FlightManipulator;
+ keyswitchManipulator->addMatrixManipulator('2', "Flight", mm);
+ mm = new osgGA::DriveManipulator;
+ keyswitchManipulator->addMatrixManipulator('3', "Drive", mm);
+ mm = new osgGA::TerrainManipulator;
+ keyswitchManipulator->addMatrixManipulator('4', "Terrain", mm);
+
+ viewer.setCameraManipulator(keyswitchManipulator);
+
+ // Usefull stats
+ viewer.addEventHandler(new osgViewer::HelpHandler);
+ viewer.addEventHandler(new osgViewer::StatsHandler);
+ viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
+ // Same FIXME ...
+ // viewer.addEventHandler(new osgViewer::ThreadingHandler);
+ viewer.addEventHandler(new osgViewer::LODScaleHandler);
+ viewer.addEventHandler(new osgViewer::ScreenCaptureHandler);
+
+ viewer.addEventHandler(new GraphDumpHandler);
+
+ // Extract files to load from arguments now; this way fgInitConfig
+ // won't choke on them.
+ string_list dataFiles;
+ for (int i = arguments.argc() - 1; i >= 0; --i) {
+ if (arguments.isOption(i)) {
+ break;
+ } else {
+ dataFiles.insert(dataFiles.begin(), arguments[i]);
+ arguments.remove(i);
+ }
+ }
+
+ // A subset of full flightgear initialization.
+ // Allocate global data structures. This needs to happen before
+ // we parse command line options
+
+ globals = new FGGlobals;
+
+ fgInitFGRoot(arguments.argc(), arguments.argv());
+ if ( !fgInitConfig(arguments.argc(), arguments.argv()) ) {
+ SG_LOG( SG_GENERAL, SG_ALERT, "Config option parsing failed ..." );
+ exit(-1);
+ }
+
+ osgDB::FilePathList filePathList
+ = osgDB::Registry::instance()->getDataFilePathList();
+ filePathList.push_back(globals->get_fg_root());
+
+ string_list path_list = globals->get_fg_scenery();
+ for (unsigned i = 0; i < path_list.size(); ++i) {
+ filePathList.push_back(path_list[i]);
+ }
+
+ globals->set_matlib( new SGMaterialLib );
+ simgear::SGModelLib::init(globals->get_fg_root());
+
+ // Initialize the material property subsystem.
+
+ SGPath mpath( globals->get_fg_root() );
+ mpath.append( "materials.xml" );
+ if ( ! globals->get_matlib()->load(globals->get_fg_root(), mpath.str(),
+ globals->get_props()) ) {
+ SG_LOG( SG_GENERAL, SG_ALERT, "Error loading material lib!" );
+ exit(-1);
+ }
+
+ globals->set_scenery( new FGScenery );
+ globals->get_scenery()->init();
+ globals->get_scenery()->bind();
+
+ // The file path list must be set in the registry.
+ osgDB::Registry::instance()->getDataFilePathList() = filePathList;
+
+ SGReaderWriterBTGOptions* btgOptions = new SGReaderWriterBTGOptions;
+ btgOptions->getDatabasePathList() = filePathList;
+ btgOptions->setMatlib(globals->get_matlib());
+
+ // read the scene from the list of file specified command line args.
+ osg::ref_ptr<osg::Node> loadedModel;
+ loadedModel = osgDB::readNodeFiles(dataFiles, btgOptions);
+
+ // if no model has been successfully loaded report failure.
+ if (!loadedModel.valid()) {
+ std::cerr << arguments.getApplicationName()
+ << ": No data loaded" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ // pass the loaded scene graph to the viewer.
+ viewer.setSceneData(loadedModel.get());
+
+ return viewer.run();
+}