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