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