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