1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include <iostream>
6 #include <cstdlib>
7
8 #include <osg/ArgumentParser>
9 #include <osg/Fog>
10 #include <osgDB/ReadFile>
11 #include <osgDB/Registry>
12 #include <osgDB/WriteFile>
13 #include <osgViewer/Renderer>
14 #include <osgViewer/Viewer>
15 #include <osgViewer/ViewerEventHandlers>
16 #include <osgGA/KeySwitchMatrixManipulator>
17 #include <osgGA/TrackballManipulator>
18 #include <osgGA/FlightManipulator>
19 #include <osgGA/DriveManipulator>
20 #include <osgGA/TerrainManipulator>
21 #include <osgGA/StateSetManipulator>
22
23 #include <simgear/props/props.hxx>
24 #include <simgear/props/props_io.hxx>
25 #include <simgear/misc/sg_path.hxx>
26 #include <simgear/scene/material/EffectCullVisitor.hxx>
27 #include <simgear/scene/material/matlib.hxx>
28 #include <simgear/scene/util/SGReaderWriterOptions.hxx>
29 #include <simgear/scene/tgdb/userdata.hxx>
30 #include <simgear/scene/model/ModelRegistry.hxx>
31 #include <simgear/scene/model/modellib.hxx>
32 #include <simgear/structure/exception.hxx>
33
34 #include <Scenery/scenery.hxx>
35
36 #include <Navaids/NavDataCache.hxx>
37 #include <Viewer/renderer_compositor.hxx>
38
39 #include <Main/fg_props.hxx>
40 #include <Main/globals.hxx>
41 #include <Main/options.hxx>
42 #include <Main/fg_init.hxx>
43
44 class GraphDumpHandler : public osgGA::GUIEventHandler
45 {
46 public:
GraphDumpHandler()47 GraphDumpHandler() : _keyDump('d') {}
setKeyDump(int key)48 void setKeyDump(int key) { _keyDump = key; }
getKeyDump() const49 int getKeyDump() const { return _keyDump; }
50 bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);
51
52 /** Get the keyboard and mouse usage of this manipulator.*/
53 virtual void getUsage(osg::ApplicationUsage& usage) const;
54 protected:
55 int _keyDump;
56 };
57
dumpOut(osg::Node * node)58 static void dumpOut(osg::Node* node)
59 {
60 char filename[24];
61 static int count = 1;
62
63 while (count < 1000) {
64 FILE *fp;
65 snprintf(filename, 24, "fgviewer-%03d.osg", count++);
66 if ( (fp = fopen(filename, "r")) == NULL )
67 break;
68 fclose(fp);
69 }
70
71 if (osgDB::writeNodeFile(*node, filename))
72 std::cerr << "Entire scene graph saved to \"" << filename << "\".\n";
73 else
74 std::cerr << "Failed to save to \"" << filename << "\".\n";
75 }
76
handle(const osgGA::GUIEventAdapter & ea,osgGA::GUIActionAdapter & aa)77 bool GraphDumpHandler::handle(const osgGA::GUIEventAdapter& ea,
78 osgGA::GUIActionAdapter& aa)
79 {
80 osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
81 if (!view)
82 return false;
83 if (ea.getHandled())
84 return false;
85 switch(ea.getEventType()) {
86 case osgGA::GUIEventAdapter::KEYUP:
87 if (ea.getKey() == _keyDump) {
88 dumpOut(view->getScene()->getSceneData());
89 return true;
90 }
91 break;
92 default:
93 return false;
94 }
95 return false;
96 }
97
getUsage(osg::ApplicationUsage & usage) const98 void GraphDumpHandler::getUsage(osg::ApplicationUsage& usage) const
99 {
100 std::ostringstream ostr;
101 ostr << char(_keyDump);
102 usage.addKeyboardMouseBinding(ostr.str(),
103 "Dump scene graph to file");
104 }
105
106 int
fgviewerMain(int argc,char ** argv)107 fgviewerMain(int argc, char** argv)
108 {
109
110 sgUserDataInit(0);
111
112 // use an ArgumentParser object to manage the program arguments.
113 osg::ArgumentParser arguments(&argc, argv);
114
115 // construct the viewer.
116 FGRenderer* fgrenderer = new FGRenderer();
117 osgViewer::Viewer* viewer = new osgViewer::Viewer(arguments);
118 fgrenderer->setViewer(viewer);
119 osg::Camera* camera = viewer->getCamera();
120 osgViewer::Renderer* renderer
121 = static_cast<osgViewer::Renderer*>(camera->getRenderer());
122 for (int i = 0; i < 2; ++i) {
123 osgUtil::SceneView* sceneView = renderer->getSceneView(i);
124 sceneView->setCullVisitor(new simgear::EffectCullVisitor);
125 }
126 // Shaders expect valid fog
127 osg::StateSet* cameraSS = camera->getOrCreateStateSet();
128 osg::Fog* fog = new osg::Fog;
129 fog->setMode(osg::Fog::EXP2);
130 fog->setColor(osg::Vec4(1.0, 1.0, 1.0, 1.0));
131 fog->setDensity(.0000001);
132 cameraSS->setAttributeAndModes(fog);
133 // ... for some reason, get rid of that FIXME!
134 viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
135
136 // set up the camera manipulators.
137 osgGA::KeySwitchMatrixManipulator* keyswitchManipulator;
138 keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
139
140 keyswitchManipulator->addMatrixManipulator('1', "Trackball",
141 new osgGA::TrackballManipulator);
142 keyswitchManipulator->addMatrixManipulator('2', "Flight",
143 new osgGA::FlightManipulator);
144 keyswitchManipulator->addMatrixManipulator('3', "Drive",
145 new osgGA::DriveManipulator);
146 keyswitchManipulator->addMatrixManipulator('4', "Terrain",
147 new osgGA::TerrainManipulator);
148 viewer->setCameraManipulator(keyswitchManipulator);
149
150 // Usefull stats
151 viewer->addEventHandler(new osgViewer::HelpHandler);
152 viewer->addEventHandler(new osgViewer::StatsHandler);
153 viewer->addEventHandler( new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()) );
154 // Same FIXME ...
155 // viewer->addEventHandler(new osgViewer::ThreadingHandler);
156 viewer->addEventHandler(new osgViewer::LODScaleHandler);
157 viewer->addEventHandler(new osgViewer::ScreenCaptureHandler);
158
159 viewer->addEventHandler(new GraphDumpHandler);
160
161 // Extract files to load from arguments now; this way fgInitConfig
162 // won't choke on them.
163 string_list dataFiles;
164 for (int i = arguments.argc() - 1; i >= 0; --i) {
165 if (arguments.isOption(i)) {
166 break;
167 } else {
168 dataFiles.insert(dataFiles.begin(), arguments[i]);
169 arguments.remove(i);
170 }
171 }
172
173 // A subset of full flightgear initialization.
174 // Allocate global data structures. This needs to happen before
175 // we parse command line options
176 globals = new FGGlobals;
177 globals->set_renderer(fgrenderer);
178
179 SGPath dataPath = fgHomePath();
180 globals->set_fg_home(dataPath);
181
182 std::string s;
183 if (arguments.read("--fg-scenery", s)) {
184 globals->append_fg_scenery(SGPath::fromLocal8Bit(s.c_str()));
185 }
186 if (std::getenv("FG_SCENERY")) {
187 globals->append_fg_scenery(SGPath::fromEnv("FG_SCENERY"));
188 }
189
190 int configResult = fgInitConfig(arguments.argc(), arguments.argv(), false);
191 if (configResult == flightgear::FG_OPTIONS_ERROR) {
192 return EXIT_FAILURE;
193 } else if (configResult == flightgear::FG_OPTIONS_EXIT) {
194 return EXIT_SUCCESS;
195 }
196
197 osgDB::FilePathList filePathList
198 = osgDB::Registry::instance()->getDataFilePathList();
199 filePathList.push_back(globals->get_fg_root().local8BitStr());
200
201 const PathList& path_list = globals->get_fg_scenery();
202 for (unsigned i = 0; i < path_list.size(); ++i) {
203 filePathList.push_back(path_list[i].local8BitStr());
204 }
205
206 globals->set_matlib( new SGMaterialLib );
207 simgear::SGModelLib::init(globals->get_fg_root().local8BitStr(), globals->get_props());
208
209 // Initialize the material property subsystem.
210
211 SGPath mpath( globals->get_fg_root() );
212 mpath.append( fgGetString("/sim/rendering/materials-file") );
213 if ( ! globals->get_matlib()->load(globals->get_fg_root().local8BitStr(),
214 mpath.local8BitStr(),
215 globals->get_props()) ) {
216 throw sg_io_exception("Error loading materials file", mpath);
217 }
218
219 // The file path list must be set in the registry.
220 osgDB::Registry::instance()->getDataFilePathList() = filePathList;
221
222 simgear::SGReaderWriterOptions* options = new simgear::SGReaderWriterOptions;
223 options->getDatabasePathList() = filePathList;
224 options->setMaterialLib(globals->get_matlib());
225 options->setPropertyNode(globals->get_props());
226 options->setPluginStringData("SimGear::PREVIEW", "ON");
227
228 // Now init the renderer, as we've got all the options, globals etc.
229 fgrenderer->init();
230
231 FGScenery* scenery = globals->add_new_subsystem<FGScenery>(SGSubsystemMgr::DISPLAY);
232 scenery->init();
233 scenery->bind();
234
235 if (! flightgear::NavDataCache::instance()) {
236 flightgear::NavDataCache* cache = flightgear::NavDataCache::createInstance();
237 cache->updateListsOfDatFiles();
238 if (cache->isRebuildRequired()) {
239 while (cache->rebuild() != flightgear::NavDataCache::REBUILD_DONE) {
240 SGTimeStamp::sleepForMSec(1000);
241 std::cerr << "." << std::flush;
242 }
243 }
244 }
245
246 // read the scene from the list of file specified command line args.
247 osg::ref_ptr<osg::Node> loadedModel;
248 loadedModel = osgDB::readNodeFiles(dataFiles, options);
249
250 // if no model has been successfully loaded report failure.
251 if (!loadedModel.valid()) {
252 std::cerr << arguments.getApplicationName()
253 << ": No data loaded" << std::endl;
254 return EXIT_FAILURE;
255 }
256
257 // pass the loaded scene graph to the viewer->
258 viewer->setSceneData(loadedModel.get());
259
260 int result = viewer->run();
261
262 // clear cache now, since it contains SimGear objects. Otherwise SG_LOG
263 // calls during shutdown will cause crashes.
264 osgDB::Registry::instance()->clearObjectCache();
265
266 return result;
267 }
268