]> git.mxchange.org Git - flightgear.git/blob - src/Main/globals.cxx
Merge branch 'next' of git://gitorious.org/fg/flightgear into next
[flightgear.git] / src / Main / globals.cxx
1 // globals.cxx -- Global state that needs to be shared among the sim modules
2 //
3 // Written by Curtis Olson, started July 2000.
4 //
5 // Copyright (C) 2000  Curtis L. Olson - http://www.flightgear.org/~curt
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software Foundation,
19 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23 #ifdef HAVE_CONFIG_H
24 #  include <config.h>
25 #endif
26
27 #include <simgear/structure/commands.hxx>
28 #include <simgear/misc/sg_path.hxx>
29 #include <simgear/misc/sg_dir.hxx>
30 #include <simgear/timing/sg_time.hxx>
31 #include <simgear/ephemeris/ephemeris.hxx>
32 #include <simgear/magvar/magvar.hxx>
33 #include <simgear/scene/material/matlib.hxx>
34 #include <simgear/structure/subsystem_mgr.hxx>
35 #include <simgear/structure/event_mgr.hxx>
36 #include <simgear/sound/soundmgr_openal.hxx>
37 #include <simgear/misc/ResourceManager.hxx>
38
39 #include <Aircraft/controls.hxx>
40 #include <Airports/runways.hxx>
41 #include <ATCDCL/ATCmgr.hxx>
42 #include <Autopilot/route_mgr.hxx>
43 #include <Cockpit/panel.hxx>
44 #include <GUI/new_gui.hxx>
45 #include <Model/acmodel.hxx>
46 #include <Model/modelmgr.hxx>
47 #include <MultiPlayer/multiplaymgr.hxx>
48 #include <Navaids/awynet.hxx>
49 #include <Scenery/scenery.hxx>
50 #include <Scenery/tilemgr.hxx>
51 #include <Navaids/navlist.hxx>
52
53 #include "globals.hxx"
54 #include "renderer.hxx"
55 #include "viewmgr.hxx"
56
57 #include "fg_props.hxx"
58 #include "fg_io.hxx"
59
60 \fclass AircraftResourceProvider : public simgear::ResourceProvider
61 {
62 public:
63   AircraftResourceProvider() :
64     simgear::ResourceProvider(simgear::ResourceManager::PRIORITY_HIGH)
65   {
66   }
67   
68   virtual SGPath resolve(const std::string& aResource, SGPath&) const
69   {
70     string_list pieces(sgPathBranchSplit(aResource));
71     if ((pieces.size() < 3) || (pieces.front() != "Aircraft")) {
72       return SGPath(); // not an Aircraft path
73     }
74     
75   // test against the aircraft-dir property
76     const char* aircraftDir = fgGetString("/sim/aircraft-dir");
77     string_list aircraftDirPieces(sgPathBranchSplit(aircraftDir));
78     if (aircraftDirPieces.empty() || (aircraftDirPieces.back() != pieces[1])) {
79       return SGPath(); // current aircraft-dir does not match resource aircraft
80     }
81     
82     SGPath r(aircraftDir);
83     for (unsigned int i=2; i<pieces.size(); ++i) {
84       r.append(pieces[i]);
85     }
86     
87     if (r.exists()) {
88       SG_LOG(SG_IO, SG_INFO, "found path:" << aResource << " via /sim/aircraft-dir: " << r.str());
89       return r;
90     }
91   
92   // try each aircaft dir in turn
93     std::string res(aResource, 9); // resource path with 'Aircraft/' removed
94     const string_list& dirs(globals->get_aircraft_paths());
95     string_list::const_iterator it = dirs.begin();
96     for (; it != dirs.end(); ++it) {
97       SGPath p(*it, res);
98       if (p.exists()) {
99         SG_LOG(SG_IO, SG_INFO, "found path:" << aResource << " in aircraft dir: " << r.str());
100         return p;
101       }
102     } // of aircraft path iteration
103     
104     return SGPath(); // not found
105   }
106 };
107
108 ////////////////////////////////////////////////////////////////////////
109 // Implementation of FGGlobals.
110 ////////////////////////////////////////////////////////////////////////
111
112 // global global :-)
113 FGGlobals *globals;
114
115
116 // Constructor
117 FGGlobals::FGGlobals() :
118     props( new SGPropertyNode ),
119     initial_state( NULL ),
120     locale( NULL ),
121     renderer( new FGRenderer ),
122     subsystem_mgr( new SGSubsystemMgr ),
123     event_mgr( new SGEventMgr ),
124     soundmgr( new SGSoundMgr ),
125     sim_time_sec( 0.0 ),
126     fg_root( "" ),
127     warp( 0 ),
128     warp_delta( 0 ),
129     time_params( NULL ),
130     ephem( NULL ),
131     mag( NULL ),
132     matlib( NULL ),
133     route_mgr( NULL ),
134     current_panel( NULL ),
135     ATC_mgr( NULL ),
136     controls( NULL ),
137     viewmgr( NULL ),
138     commands( SGCommandMgr::instance() ),
139     acmodel( NULL ),
140     model_mgr( NULL ),
141     channel_options_list( NULL ),
142     initial_waypoints( NULL ),
143     scenery( NULL ),
144     tile_mgr( NULL ),
145     fontcache ( new FGFontCache ),
146     navlist( NULL ),
147     loclist( NULL ),
148     gslist( NULL ),
149     dmelist( NULL ),
150     tacanlist( NULL ),
151     carrierlist( NULL ),
152     channellist( NULL ),
153     airwaynet( NULL ),
154     multiplayer_mgr( NULL )
155 {
156   simgear::ResourceManager::instance()->addProvider(new AircraftResourceProvider());
157 }
158
159
160 // Destructor
161 FGGlobals::~FGGlobals() 
162 {
163     delete renderer;
164 // The AIModels manager performs a number of actions upon
165     // Shutdown that implicitly assume that other subsystems
166     // are still operational (Due to the dynamic allocation and
167     // deallocation of AIModel objects. To ensure we can safely
168     // shut down all subsystems, make sure we take down the 
169     // AIModels system first.
170     subsystem_mgr->get_group(SGSubsystemMgr::GENERAL)->remove_subsystem("ai_model");
171     // FGInput (FGInputEvent) and FGDialog calls get_subsystem() in their destructors, 
172     // which is not safe since some subsystem are already deleted but can be referred.
173     // So these subsystems must be deleted prior to deleting subsystem_mgr unless
174     // ~SGSubsystemGroup and SGSubsystemMgr::get_subsystem are changed not to refer to
175     // deleted subsystems.
176     subsystem_mgr->get_group(SGSubsystemMgr::GENERAL)->remove_subsystem("input");
177     subsystem_mgr->get_group(SGSubsystemMgr::GENERAL)->remove_subsystem("gui");
178     subsystem_mgr->unbind();
179     delete subsystem_mgr;
180     delete event_mgr;
181     delete time_params;
182     delete mag;
183     delete matlib;
184     delete route_mgr;
185     delete current_panel;
186
187     delete ATC_mgr;
188     delete controls;
189     delete viewmgr;
190
191 //     delete commands;
192     delete acmodel;
193     delete model_mgr;
194     delete channel_options_list;
195     delete initial_waypoints;
196     delete scenery;
197     delete fontcache;
198
199     delete navlist;
200     delete loclist;
201     delete gslist;
202     delete dmelist;
203     delete tacanlist;
204     delete carrierlist;
205     delete channellist;
206     delete airwaynet;
207     delete multiplayer_mgr;
208
209     soundmgr->unbind();
210     delete soundmgr;
211 }
212
213
214 // set the fg_root path
215 void FGGlobals::set_fg_root (const string &root) {
216     fg_root = root;
217
218     // append /data to root if it exists
219     SGPath tmp( fg_root );
220     tmp.append( "data" );
221     tmp.append( "version" );
222     if ( ulFileExists( tmp.c_str() ) ) {
223         fgGetNode("BAD_FG_ROOT", true)->setStringValue(fg_root);
224         fg_root += "/data";
225         fgGetNode("GOOD_FG_ROOT", true)->setStringValue(fg_root);
226         SG_LOG(SG_GENERAL, SG_ALERT, "***\n***\n*** Warning: changing bad FG_ROOT/--fg-root to '"
227                 << fg_root << "'\n***\n***");
228     }
229
230     // remove /sim/fg-root before writing to prevent hijacking
231     SGPropertyNode *n = fgGetNode("/sim", true);
232     n->removeChild("fg-root", 0, false);
233     n = n->getChild("fg-root", 0, true);
234     n->setStringValue(fg_root.c_str());
235     n->setAttribute(SGPropertyNode::WRITE, false);
236     
237     simgear::ResourceManager::instance()->addBasePath(fg_root, 
238       simgear::ResourceManager::PRIORITY_DEFAULT);
239 }
240
241 void FGGlobals::set_fg_scenery (const string &scenery)
242 {
243     SGPath s;
244     if (scenery.empty()) {
245         s.set( fg_root );
246         s.append( "Scenery" );
247     } else
248         s.set( scenery );
249
250     string_list path_list = sgPathSplit( s.str() );
251     fg_scenery.clear();
252
253     for (unsigned i = 0; i < path_list.size(); i++) {
254         SGPath path(path_list[i]);
255         if (!path.exists()) {
256           SG_LOG(SG_GENERAL, SG_WARN, "scenery path not found:" << path.str());
257           continue;
258         }
259
260         simgear::Dir dir(path);
261         SGPath terrainDir(dir.file("Terrain"));
262         SGPath objectsDir(dir.file("Objects"));
263         
264       // this code used to add *either* the base dir, OR add the 
265       // Terrain and Objects subdirs, but the conditional logic was commented
266       // out, such that all three dirs are added. Unfortunately there's
267       // no information as to why the change was made.
268         fg_scenery.push_back(path.str());
269         
270         if (terrainDir.exists()) {
271           fg_scenery.push_back(terrainDir.str());
272         }
273         
274         if (objectsDir.exists()) {
275           fg_scenery.push_back(objectsDir.str());
276         }
277         
278         // insert a marker for FGTileEntry::load(), so that
279         // FG_SCENERY=A:B becomes list ["A/Terrain", "A/Objects", "",
280         // "B/Terrain", "B/Objects", ""]
281         fg_scenery.push_back("");
282     } // of path list iteration
283 }
284
285 void FGGlobals::append_aircraft_path(const std::string& path)
286 {
287   SGPath dirPath(path);
288   if (!dirPath.exists()) {
289     SG_LOG(SG_GENERAL, SG_WARN, "aircraft path not found:" << path);
290     return;
291   }
292   
293   unsigned int index = fg_aircraft_dirs.size();  
294   fg_aircraft_dirs.push_back(path);
295   
296 // make aircraft dirs available to Nasal
297   SGPropertyNode* sim = fgGetNode("/sim", true);
298   sim->removeChild("fg-aircraft", index, false);
299   SGPropertyNode* n = sim->getChild("fg-aircraft", index, true);
300   n->setStringValue(path);
301   n->setAttribute(SGPropertyNode::WRITE, false);
302 }
303
304 void FGGlobals::append_aircraft_paths(const std::string& path)
305 {
306   string_list paths = sgPathSplit(path);
307   for (unsigned int p = 0; p<paths.size(); ++p) {
308     append_aircraft_path(paths[p]);
309   }
310 }
311
312 SGPath FGGlobals::resolve_aircraft_path(const std::string& branch) const
313 {
314   return simgear::ResourceManager::instance()->findPath(branch);
315 }
316
317 SGPath FGGlobals::resolve_maybe_aircraft_path(const std::string& branch) const
318 {
319   return simgear::ResourceManager::instance()->findPath(branch);
320 }
321
322 FGRenderer *
323 FGGlobals::get_renderer () const
324 {
325    return renderer;
326 }
327
328 SGSubsystemMgr *
329 FGGlobals::get_subsystem_mgr () const
330 {
331     return subsystem_mgr;
332 }
333
334 SGSubsystem *
335 FGGlobals::get_subsystem (const char * name)
336 {
337     return subsystem_mgr->get_subsystem(name);
338 }
339
340 void
341 FGGlobals::add_subsystem (const char * name,
342                           SGSubsystem * subsystem,
343                           SGSubsystemMgr::GroupType type,
344                           double min_time_sec)
345 {
346     subsystem_mgr->add(name, subsystem, type, min_time_sec);
347 }
348
349 SGSoundMgr *
350 FGGlobals::get_soundmgr () const
351 {
352     return soundmgr;
353 }
354
355 SGEventMgr *
356 FGGlobals::get_event_mgr () const
357 {
358     return event_mgr;
359 }
360
361
362 // Save the current state as the initial state.
363 void
364 FGGlobals::saveInitialState ()
365 {
366   initial_state = new SGPropertyNode();
367
368   if (!copyProperties(props, initial_state))
369     SG_LOG(SG_GENERAL, SG_ALERT, "Error saving initial state");
370     
371   // delete various properties from the initial state, since we want to
372   // preserve their values even if doing a restore
373   
374   SGPropertyNode* sim = initial_state->getChild("sim");
375   sim->removeChild("presets");
376   SGPropertyNode* simStartup = sim->getChild("startup");
377   simStartup->removeChild("xsize");
378   simStartup->removeChild("ysize");
379   
380   SGPropertyNode* cameraGroupNode = sim->getNode("rendering/camera-group");
381   if (cameraGroupNode) {
382     cameraGroupNode->removeChild("camera");
383     cameraGroupNode->removeChild("gui");
384   }
385 }
386
387
388 // Restore the saved initial state, if any
389 void
390 FGGlobals::restoreInitialState ()
391 {
392     if ( initial_state == 0 ) {
393         SG_LOG(SG_GENERAL, SG_ALERT,
394                "No initial state available to restore!!!");
395         return;
396     }
397
398     if ( copyProperties(initial_state, props) ) {
399         SG_LOG( SG_GENERAL, SG_INFO, "Initial state restored successfully" );
400     } else {
401         SG_LOG( SG_GENERAL, SG_INFO,
402                 "Some errors restoring initial state (read-only props?)" );
403     }
404
405 }
406
407 FGViewer *
408 FGGlobals::get_current_view () const
409 {
410   return viewmgr->get_current_view();
411 }
412
413 // end of globals.cxx