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