]> 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 tile_mgr;
197     delete scenery;
198     delete fontcache;
199
200     delete navlist;
201     delete loclist;
202     delete gslist;
203     delete dmelist;
204     delete tacanlist;
205     delete carrierlist;
206     delete channellist;
207     delete airwaynet;
208     delete multiplayer_mgr;
209
210     soundmgr->unbind();
211     delete soundmgr;
212 }
213
214
215 // set the fg_root path
216 void FGGlobals::set_fg_root (const string &root) {
217     fg_root = root;
218
219     // append /data to root if it exists
220     SGPath tmp( fg_root );
221     tmp.append( "data" );
222     tmp.append( "version" );
223     if ( ulFileExists( tmp.c_str() ) ) {
224         fgGetNode("BAD_FG_ROOT", true)->setStringValue(fg_root);
225         fg_root += "/data";
226         fgGetNode("GOOD_FG_ROOT", true)->setStringValue(fg_root);
227         SG_LOG(SG_GENERAL, SG_ALERT, "***\n***\n*** Warning: changing bad FG_ROOT/--fg-root to '"
228                 << fg_root << "'\n***\n***");
229     }
230
231     // remove /sim/fg-root before writing to prevent hijacking
232     SGPropertyNode *n = fgGetNode("/sim", true);
233     n->removeChild("fg-root", 0, false);
234     n = n->getChild("fg-root", 0, true);
235     n->setStringValue(fg_root.c_str());
236     n->setAttribute(SGPropertyNode::WRITE, false);
237     
238     simgear::ResourceManager::instance()->addBasePath(fg_root, 
239       simgear::ResourceManager::PRIORITY_DEFAULT);
240 }
241
242 void FGGlobals::set_fg_scenery (const string &scenery)
243 {
244     SGPath s;
245     if (scenery.empty()) {
246         s.set( fg_root );
247         s.append( "Scenery" );
248     } else
249         s.set( scenery );
250
251     string_list path_list = sgPathSplit( s.str() );
252     fg_scenery.clear();
253
254     for (unsigned i = 0; i < path_list.size(); i++) {
255         SGPath path(path_list[i]);
256         if (!path.exists()) {
257           SG_LOG(SG_GENERAL, SG_WARN, "scenery path not found:" << path.str());
258           continue;
259         }
260
261         simgear::Dir dir(path);
262         SGPath terrainDir(dir.file("Terrain"));
263         SGPath objectsDir(dir.file("Objects"));
264         
265       // this code used to add *either* the base dir, OR add the 
266       // Terrain and Objects subdirs, but the conditional logic was commented
267       // out, such that all three dirs are added. Unfortunately there's
268       // no information as to why the change was made.
269         fg_scenery.push_back(path.str());
270         
271         if (terrainDir.exists()) {
272           fg_scenery.push_back(terrainDir.str());
273         }
274         
275         if (objectsDir.exists()) {
276           fg_scenery.push_back(objectsDir.str());
277         }
278         
279         // insert a marker for FGTileEntry::load(), so that
280         // FG_SCENERY=A:B becomes list ["A/Terrain", "A/Objects", "",
281         // "B/Terrain", "B/Objects", ""]
282         fg_scenery.push_back("");
283     } // of path list iteration
284 }
285
286 void FGGlobals::append_aircraft_path(const std::string& path)
287 {
288   SGPath dirPath(path);
289   if (!dirPath.exists()) {
290     SG_LOG(SG_GENERAL, SG_WARN, "aircraft path not found:" << path);
291     return;
292   }
293   
294   unsigned int index = fg_aircraft_dirs.size();  
295   fg_aircraft_dirs.push_back(path);
296   
297 // make aircraft dirs available to Nasal
298   SGPropertyNode* sim = fgGetNode("/sim", true);
299   sim->removeChild("fg-aircraft", index, false);
300   SGPropertyNode* n = sim->getChild("fg-aircraft", index, true);
301   n->setStringValue(path);
302   n->setAttribute(SGPropertyNode::WRITE, false);
303 }
304
305 void FGGlobals::append_aircraft_paths(const std::string& path)
306 {
307   string_list paths = sgPathSplit(path);
308   for (unsigned int p = 0; p<paths.size(); ++p) {
309     append_aircraft_path(paths[p]);
310   }
311 }
312
313 SGPath FGGlobals::resolve_aircraft_path(const std::string& branch) const
314 {
315   return simgear::ResourceManager::instance()->findPath(branch);
316 }
317
318 SGPath FGGlobals::resolve_maybe_aircraft_path(const std::string& branch) const
319 {
320   return simgear::ResourceManager::instance()->findPath(branch);
321 }
322
323 FGRenderer *
324 FGGlobals::get_renderer () const
325 {
326    return renderer;
327 }
328
329 SGSubsystemMgr *
330 FGGlobals::get_subsystem_mgr () const
331 {
332     return subsystem_mgr;
333 }
334
335 SGSubsystem *
336 FGGlobals::get_subsystem (const char * name)
337 {
338     return subsystem_mgr->get_subsystem(name);
339 }
340
341 void
342 FGGlobals::add_subsystem (const char * name,
343                           SGSubsystem * subsystem,
344                           SGSubsystemMgr::GroupType type,
345                           double min_time_sec)
346 {
347     subsystem_mgr->add(name, subsystem, type, min_time_sec);
348 }
349
350 SGSoundMgr *
351 FGGlobals::get_soundmgr () const
352 {
353     return soundmgr;
354 }
355
356 SGEventMgr *
357 FGGlobals::get_event_mgr () const
358 {
359     return event_mgr;
360 }
361
362
363 // Save the current state as the initial state.
364 void
365 FGGlobals::saveInitialState ()
366 {
367   initial_state = new SGPropertyNode();
368
369   if (!copyProperties(props, initial_state))
370     SG_LOG(SG_GENERAL, SG_ALERT, "Error saving initial state");
371     
372   // delete various properties from the initial state, since we want to
373   // preserve their values even if doing a restore
374   
375   SGPropertyNode* sim = initial_state->getChild("sim");
376   sim->removeChild("presets");
377   SGPropertyNode* simStartup = sim->getChild("startup");
378   simStartup->removeChild("xsize");
379   simStartup->removeChild("ysize");
380   
381   SGPropertyNode* cameraGroupNode = sim->getNode("rendering/camera-group");
382   if (cameraGroupNode) {
383     cameraGroupNode->removeChild("camera");
384     cameraGroupNode->removeChild("gui");
385   }
386 }
387
388
389 // Restore the saved initial state, if any
390 void
391 FGGlobals::restoreInitialState ()
392 {
393     if ( initial_state == 0 ) {
394         SG_LOG(SG_GENERAL, SG_ALERT,
395                "No initial state available to restore!!!");
396         return;
397     }
398
399     if ( copyProperties(initial_state, props) ) {
400         SG_LOG( SG_GENERAL, SG_INFO, "Initial state restored successfully" );
401     } else {
402         SG_LOG( SG_GENERAL, SG_INFO,
403                 "Some errors restoring initial state (read-only props?)" );
404     }
405
406 }
407
408 FGViewer *
409 FGGlobals::get_current_view () const
410 {
411   return viewmgr->get_current_view();
412 }
413
414 // end of globals.cxx