]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_init.cxx
One more Mac helper moved into CocoaHelpers.mm
[flightgear.git] / src / Main / fg_init.cxx
1 // fg_init.cxx -- Flight Gear top level initialization routines
2 //
3 // Written by Curtis Olson, started August 1997.
4 //
5 // Copyright (C) 1997  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
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #include <simgear/compiler.h>
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>             // strcmp()
33
34 #if defined(SG_WINDOWS)
35 #  include <io.h>               // isatty()
36 #  include <process.h>          // _getpid()
37 #  include <Windows.h>
38 #  define isatty _isatty
39 #else
40 // for open() and options
41 #  include <sys/types.h>        
42 #  include <sys/stat.h>
43 #  include <fcntl.h>
44 #endif
45
46 #include <string>
47 #include <boost/algorithm/string/compare.hpp>
48 #include <boost/algorithm/string/predicate.hpp>
49
50 #include <simgear/constants.h>
51 #include <simgear/debug/logstream.hxx>
52 #include <simgear/structure/exception.hxx>
53 #include <simgear/structure/event_mgr.hxx>
54 #include <simgear/structure/SGPerfMon.hxx>
55 #include <simgear/misc/sg_path.hxx>
56 #include <simgear/misc/sg_dir.hxx>
57 #include <simgear/misc/sgstream.hxx>
58 #include <simgear/misc/strutils.hxx>
59 #include <simgear/props/props_io.hxx>
60
61 #include <simgear/scene/material/matlib.hxx>
62 #include <simgear/scene/model/particles.hxx>
63 #include <simgear/scene/tsync/terrasync.hxx>
64
65 #include <Aircraft/controls.hxx>
66 #include <Aircraft/replay.hxx>
67 #include <Aircraft/FlightHistory.hxx>
68 #include <Airports/runways.hxx>
69 #include <Airports/airport.hxx>
70 #include <Airports/dynamics.hxx>
71
72 #include <AIModel/AIManager.hxx>
73
74 #include <ATCDCL/ATISmgr.hxx>
75 #include <ATC/atc_mgr.hxx>
76
77 #include <Autopilot/route_mgr.hxx>
78 #include <Autopilot/autopilotgroup.hxx>
79
80 #include <Cockpit/panel.hxx>
81 #include <Cockpit/panel_io.hxx>
82
83 #include <Canvas/canvas_mgr.hxx>
84 #include <Canvas/gui_mgr.hxx>
85 #include <GUI/new_gui.hxx>
86 #include <GUI/MessageBox.hxx>
87 #include <Input/input.hxx>
88 #include <Instrumentation/instrument_mgr.hxx>
89 #include <Model/acmodel.hxx>
90 #include <Model/modelmgr.hxx>
91 #include <AIModel/submodel.hxx>
92 #include <AIModel/AIManager.hxx>
93 #include <Navaids/navdb.hxx>
94 #include <Navaids/navlist.hxx>
95 #include <Scenery/scenery.hxx>
96 #include <Scenery/tilemgr.hxx>
97 #include <Scripting/NasalSys.hxx>
98 #include <Sound/voice.hxx>
99 #include <Sound/soundmanager.hxx>
100 #include <Systems/system_mgr.hxx>
101 #include <Time/light.hxx>
102 #include <Traffic/TrafficMgr.hxx>
103 #include <MultiPlayer/multiplaymgr.hxx>
104 #include <FDM/fdm_shell.hxx>
105 #include <Environment/ephemeris.hxx>
106 #include <Environment/environment_mgr.hxx>
107 #include <Viewer/renderer.hxx>
108 #include <Viewer/viewmgr.hxx>
109 #include <Navaids/NavDataCache.hxx>
110 #include <Instrumentation/HUD/HUD.hxx>
111 #include <Cockpit/cockpitDisplayManager.hxx>
112 #include <Network/HTTPClient.hxx>
113 #include <Network/fgcom.hxx>
114
115 #include "fg_init.hxx"
116 #include "fg_io.hxx"
117 #include "fg_commands.hxx"
118 #include "fg_props.hxx"
119 #include "FGInterpolator.hxx"
120 #include "options.hxx"
121 #include "globals.hxx"
122 #include "logger.hxx"
123 #include "main.hxx"
124 #include "positioninit.hxx"
125 #include "util.hxx"
126 #include "AircraftDirVisitorBase.hxx"
127
128 #if defined(SG_MAC)
129 #include <GUI/CocoaHelpers.h> // for Mac impl of platformDefaultDataPath()
130 #endif
131
132 using std::string;
133 using std::endl;
134 using std::cerr;
135 using std::cout;
136 using namespace boost::algorithm;
137
138
139 // Return the current base package version
140 string fgBasePackageVersion() {
141     SGPath base_path( globals->get_fg_root() );
142     base_path.append("version");
143     if (!base_path.exists()) {
144         return string();
145     }
146     
147     sg_gzifstream in( base_path.str() );
148     if (!in.is_open()) {
149         return string();
150     }
151
152     string version;
153     in >> version;
154
155     return version;
156 }
157
158 class FindAndCacheAircraft : public AircraftDirVistorBase
159 {
160 public:
161   FindAndCacheAircraft(SGPropertyNode* autoSave)
162   {
163     _cache = autoSave->getNode("sim/startup/path-cache", true);
164   }
165   
166   bool loadAircraft()
167   {
168     std::string aircraft = fgGetString( "/sim/aircraft", "");
169     if (aircraft.empty()) {
170         flightgear::fatalMessageBox("No aircraft", "No aircraft was specified");
171       SG_LOG(SG_GENERAL, SG_ALERT, "no aircraft specified");
172       return false;
173     }
174     
175     _searchAircraft = aircraft + "-set.xml";
176     std::string aircraftDir = fgGetString("/sim/aircraft-dir", "");
177     if (!aircraftDir.empty()) {
178       // aircraft-dir was set, skip any searching at all, if it's valid
179       simgear::Dir acPath(aircraftDir);
180       SGPath setFile = acPath.file(_searchAircraft);
181       if (setFile.exists()) {
182         SG_LOG(SG_GENERAL, SG_INFO, "found aircraft in dir: " << aircraftDir );
183         
184         try {
185           readProperties(setFile.str(), globals->get_props());
186         } catch ( const sg_exception &e ) {
187           SG_LOG(SG_INPUT, SG_ALERT, "Error reading aircraft: " << e.getFormattedMessage());
188             flightgear::fatalMessageBox("Error reading aircraft",
189                                         "An error occured reading the requested aircraft (" + aircraft + ")",
190                                         e.getFormattedMessage());
191           return false;
192         }
193         
194         return true;
195       } else {
196         SG_LOG(SG_GENERAL, SG_ALERT, "aircraft '" << _searchAircraft << 
197                "' not found in specified dir:" << aircraftDir);
198           flightgear::fatalMessageBox("Aircraft not found",
199                                       "The requested aircraft '" + aircraft + "' could not be found in the specified location.",
200                                       aircraftDir);
201         return false;
202       }
203     }
204     
205     if (!checkCache()) {
206       // prepare cache for re-scan
207       SGPropertyNode *n = _cache->getNode("fg-root", true);
208       n->setStringValue(globals->get_fg_root().c_str());
209       n->setAttribute(SGPropertyNode::USERARCHIVE, true);
210       n = _cache->getNode("fg-aircraft", true);
211       n->setStringValue(getAircraftPaths().c_str());
212       n->setAttribute(SGPropertyNode::USERARCHIVE, true);
213       _cache->removeChildren("aircraft");
214   
215         visitAircraftPaths();
216     }
217     
218     if (_foundPath.str().empty()) {
219       SG_LOG(SG_GENERAL, SG_ALERT, "Cannot find specified aircraft: " << aircraft );
220         flightgear::fatalMessageBox("Aircraft not found",
221                                     "The requested aircraft '" + aircraft + "' could not be found in any of the search paths");
222
223       return false;
224     }
225     
226     SG_LOG(SG_GENERAL, SG_INFO, "Loading aircraft -set file from:" << _foundPath.str());
227     fgSetString( "/sim/aircraft-dir", _foundPath.dir().c_str());
228     if (!_foundPath.exists()) {
229       SG_LOG(SG_GENERAL, SG_ALERT, "Unable to find -set file:" << _foundPath.str());
230       return false;
231     }
232     
233     try {
234       readProperties(_foundPath.str(), globals->get_props());
235     } catch ( const sg_exception &e ) {
236       SG_LOG(SG_INPUT, SG_ALERT, "Error reading aircraft: " << e.getFormattedMessage());
237         flightgear::fatalMessageBox("Error reading aircraft",
238                                     "An error occured reading the requested aircraft (" + aircraft + ")",
239                                     e.getFormattedMessage());
240       return false;
241     }
242     
243     return true;
244   }
245   
246 private:
247   SGPath getAircraftPaths() {
248     string_list pathList = globals->get_aircraft_paths();
249     SGPath aircraftPaths;
250     string_list::const_iterator it = pathList.begin();
251     if (it != pathList.end()) {
252         aircraftPaths.set(*it);
253         it++;
254     }
255     for (; it != pathList.end(); ++it) {
256         aircraftPaths.add(*it);
257     }
258     return aircraftPaths;
259   }
260   
261   bool checkCache()
262   {
263     if (globals->get_fg_root() != _cache->getStringValue("fg-root", "")) {
264       return false; // cache mismatch
265     }
266
267     if (getAircraftPaths().str() != _cache->getStringValue("fg-aircraft", "")) {
268       return false; // cache mismatch
269     }
270     
271     vector<SGPropertyNode_ptr> cache = _cache->getChildren("aircraft");
272     for (unsigned int i = 0; i < cache.size(); i++) {
273       const char *name = cache[i]->getStringValue("file", "");
274       if (!boost::equals(_searchAircraft, name, is_iequal())) {
275         continue;
276       }
277       
278       SGPath xml(cache[i]->getStringValue("path", ""));
279       xml.append(name);
280       if (xml.exists()) {
281         _foundPath = xml;
282         return true;
283       } 
284       
285       return false;
286     } // of aircraft in cache iteration
287     
288     return false;
289   }
290   
291   virtual VisitResult visit(const SGPath& p)
292   {
293     // create cache node
294     int i = 0;
295     while (1) {
296         if (!_cache->getChild("aircraft", i++, false))
297             break;
298     }
299     
300     SGPropertyNode *n, *entry = _cache->getChild("aircraft", --i, true);
301
302     std::string fileName(p.file());
303     n = entry->getNode("file", true);
304     n->setStringValue(fileName);
305     n->setAttribute(SGPropertyNode::USERARCHIVE, true);
306
307     n = entry->getNode("path", true);
308     n->setStringValue(p.dir());
309     n->setAttribute(SGPropertyNode::USERARCHIVE, true);
310
311     if ( boost::equals(fileName, _searchAircraft.c_str(), is_iequal()) ) {
312         _foundPath = p;
313         return VISIT_DONE;
314     }
315
316     return VISIT_CONTINUE;
317   }
318   
319   std::string _searchAircraft;
320   SGPath _foundPath;
321   SGPropertyNode* _cache;
322 };
323
324 #ifdef _WIN32
325 static SGPath platformDefaultDataPath()
326 {
327   char *envp = ::getenv( "APPDATA" );
328   SGPath config( envp );
329   config.append( "flightgear.org" );
330   return config;
331 }
332
333 #elif defined(SG_MAC)
334
335 // platformDefaultDataPath defined in GUI/CocoaHelpers.h
336
337 #else
338 static SGPath platformDefaultDataPath()
339 {
340   return SGPath::home() / ".fgfs";
341 }
342 #endif
343
344 bool fgInitHome()
345 {
346   SGPath dataPath = SGPath::fromEnv("FG_HOME", platformDefaultDataPath());
347   globals->set_fg_home(dataPath.c_str());
348     
349     simgear::Dir fgHome(dataPath);
350     if (!fgHome.exists()) {
351         fgHome.create(0755);
352     }
353     
354     if (!fgHome.exists()) {
355         flightgear::fatalMessageBox("Problem setting up user data",
356                                     "Unable to create the user-data storage folder at: '"
357                                     + dataPath.str() + "'");
358         return false;
359     }
360     
361     if (fgGetBool("/sim/fghome-readonly", false)) {
362         // user / config forced us into readonly mode, fine
363         SG_LOG(SG_GENERAL, SG_INFO, "Running with FG_HOME readonly");
364         return true;
365     }
366     
367 // write our PID, and check writeability
368     SGPath pidPath(dataPath, "fgfs.pid");
369     if (pidPath.exists()) {
370         SG_LOG(SG_GENERAL, SG_INFO, "flightgear instance already running, switching to FG_HOME read-only.");
371         // set a marker property so terrasync/navcache don't try to write
372         // from secondary instances
373         fgSetBool("/sim/fghome-readonly", true);
374         return true;
375     }
376     
377     char buf[16];
378     bool result = false;
379 #if defined(SG_WINDOWS)
380     size_t len = snprintf(buf, 16, "%d", _getpid());
381
382     HANDLE f = CreateFileA(pidPath.c_str(), GENERIC_READ | GENERIC_WRITE, 
383                                                    FILE_SHARE_READ, /* sharing */
384                            NULL, /* security attributes */
385                            CREATE_NEW, /* error if already exists */
386                            FILE_FLAG_DELETE_ON_CLOSE,
387                                                    NULL /* template */);
388     
389     result = (f != INVALID_HANDLE_VALUE);
390     if (result) {
391                 DWORD written;
392         WriteFile(f, buf, len, &written, NULL /* overlapped */);
393     }
394 #else
395     // POSIX, do open+unlink trick to the file is deleted on exit, even if we
396     // crash or exit(-1)
397     size_t len = snprintf(buf, 16, "%d", getpid());
398     int fd = ::open(pidPath.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0644);
399     if (fd >= 0) {
400         ::write(fd, buf, len);
401         ::unlink(pidPath.c_str()); // delete file when app quits
402         result = true;
403     }
404     
405     fgSetBool("/sim/fghome-readonly", false);
406 #endif
407     if (!result) {
408         flightgear::fatalMessageBox("File permissions problem",
409                                     "Can't write to user-data storage folder, check file permissions and FG_HOME.",
410                                     "User-data at:" + dataPath.str());
411     }
412     return result;
413 }
414
415 // Read in configuration (file and command line)
416 int fgInitConfig ( int argc, char **argv )
417 {
418     SGPath dataPath = globals->get_fg_home();
419     
420     simgear::Dir exportDir(simgear::Dir(dataPath).file("Export"));
421     if (!exportDir.exists()) {
422       exportDir.create(0777);
423     }
424     
425     // Set /sim/fg-home and don't allow malign code to override it until
426     // Nasal security is set up.  Use FG_HOME if necessary.
427     SGPropertyNode *home = fgGetNode("/sim", true);
428     home->removeChild("fg-home", 0, false);
429     home = home->getChild("fg-home", 0, true);
430     home->setStringValue(dataPath.c_str());
431     home->setAttribute(SGPropertyNode::WRITE, false);
432   
433     fgSetDefaults();
434     flightgear::Options* options = flightgear::Options::sharedInstance();
435     options->init(argc, argv, dataPath);
436     bool loadDefaults = flightgear::Options::sharedInstance()->shouldLoadDefaultConfig();
437     if (loadDefaults) {
438       // Read global preferences from $FG_ROOT/preferences.xml
439       SG_LOG(SG_INPUT, SG_INFO, "Reading global preferences");
440       fgLoadProps("preferences.xml", globals->get_props());
441       SG_LOG(SG_INPUT, SG_INFO, "Finished Reading global preferences");
442         
443       // do not load user settings when reset to default is requested, or if
444       // told to explicitly ignore
445       if (options->isOptionSet("restore-defaults") || options->isOptionSet("ignore-autosave"))
446       {
447           SG_LOG(SG_ALL, SG_ALERT, "Ignoring user settings. Restoring defaults.");
448       }
449       else
450       {
451           globals->loadUserSettings(dataPath);
452       }
453     } else {
454       SG_LOG(SG_GENERAL, SG_INFO, "not reading default configuration files");
455     }// of no-default-config selected
456   
457     // Scan user config files and command line for a specified aircraft.
458     options->initAircraft();
459
460     FindAndCacheAircraft f(globals->get_props());
461     if (!f.loadAircraft()) {
462       return flightgear::FG_OPTIONS_ERROR;
463     }
464
465     // parse options after loading aircraft to ensure any user
466     // overrides of defaults are honored.
467     return options->processOptions();
468 }
469
470
471
472 /**
473  * Initialize vor/ndb/ils/fix list management and query systems (as
474  * well as simple airport db list)
475  * This is called multiple times in the case of a cache rebuild,
476  * to allow lengthy caching to take place in the background, without
477  * blocking the main/UI thread.
478  */
479 bool
480 fgInitNav ()
481 {
482   flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
483   static bool doingRebuild = false;
484   if (doingRebuild || cache->isRebuildRequired()) {
485     doingRebuild = true;
486     bool finished = cache->rebuild();
487     if (!finished) {
488       // sleep to give the rebuild thread more time
489       SGTimeStamp::sleepForMSec(50);
490       return false;
491     }
492   }
493   
494   FGTACANList *channellist = new FGTACANList;
495   globals->set_channellist( channellist );
496   
497   SGPath path(globals->get_fg_root());
498   path.append( "Navaids/TACAN_freq.dat" );
499   flightgear::loadTacan(path, channellist);
500   
501   return true;
502 }
503
504 // General house keeping initializations
505 bool fgInitGeneral() {
506     string root;
507
508     SG_LOG( SG_GENERAL, SG_INFO, "General Initialization" );
509     SG_LOG( SG_GENERAL, SG_INFO, "======= ==============" );
510
511     root = globals->get_fg_root();
512     if ( ! root.length() ) {
513         // No root path set? Then bail ...
514         SG_LOG( SG_GENERAL, SG_ALERT,
515                 "Cannot continue without a path to the base package "
516                 << "being defined." );
517         return false;
518     }
519     SG_LOG( SG_GENERAL, SG_INFO, "FG_ROOT = " << '"' << root << '"' << endl );
520
521     // Note: browser command is hard-coded for Mac/Windows, so this only affects other platforms
522     globals->set_browser(fgGetString("/sim/startup/browser-app", WEB_BROWSER));
523     fgSetString("/sim/startup/browser-app", globals->get_browser());
524
525     simgear::Dir cwd(simgear::Dir::current());
526     SGPropertyNode *curr = fgGetNode("/sim", true);
527     curr->removeChild("fg-current", 0, false);
528     curr = curr->getChild("fg-current", 0, true);
529     curr->setStringValue(cwd.path().str());
530     curr->setAttribute(SGPropertyNode::WRITE, false);
531
532     fgSetBool("/sim/startup/stdout-to-terminal", isatty(1) != 0 );
533     fgSetBool("/sim/startup/stderr-to-terminal", isatty(2) != 0 );
534     return true;
535 }
536
537 // Write various configuraton values out to the logs
538 void fgOutputSettings()
539 {    
540     SG_LOG( SG_GENERAL, SG_INFO, "Configuration State" );
541     SG_LOG( SG_GENERAL, SG_INFO, "======= ==============" );
542     
543     SG_LOG( SG_GENERAL, SG_INFO, "aircraft-dir = " << '"' << fgGetString("/sim/aircraft-dir") << '"' );
544     SG_LOG( SG_GENERAL, SG_INFO, "fghome-dir = " << '"' << globals->get_fg_home() << '"');
545     SG_LOG( SG_GENERAL, SG_INFO, "aircraft-dir = " << '"' << fgGetString("/sim/aircraft-dir") << '"');
546     
547     SG_LOG( SG_GENERAL, SG_INFO, "aircraft-search-paths = \n\t" << simgear::strutils::join(globals->get_aircraft_paths(), "\n\t") );
548     SG_LOG( SG_GENERAL, SG_INFO, "scenery-search-paths = \n\t" << simgear::strutils::join(globals->get_fg_scenery(), "\n\t") );
549 }
550
551 // This is the top level init routine which calls all the other
552 // initialization routines.  If you are adding a subsystem to flight
553 // gear, its initialization call should located in this routine.
554 // Returns non-zero if a problem encountered.
555 void fgCreateSubsystems() {
556
557     SG_LOG( SG_GENERAL, SG_INFO, "Creating Subsystems");
558     SG_LOG( SG_GENERAL, SG_INFO, "========== ==========");
559
560     ////////////////////////////////////////////////////////////////////
561     // Initialize the sound subsystem.
562     ////////////////////////////////////////////////////////////////////
563     // Sound manager uses an own subsystem group "SOUND" which is the last
564     // to be updated in every loop.
565     // Sound manager is updated last so it can use the CPU while the GPU
566     // is processing the scenery (doubled the frame-rate for me) -EMH-
567     globals->add_subsystem("sound", new FGSoundManager, SGSubsystemMgr::SOUND);
568
569     ////////////////////////////////////////////////////////////////////
570     // Initialize the event manager subsystem.
571     ////////////////////////////////////////////////////////////////////
572
573     globals->get_event_mgr()->init();
574     globals->get_event_mgr()->setRealtimeProperty(fgGetNode("/sim/time/delta-realtime-sec", true));
575
576     ////////////////////////////////////////////////////////////////////
577     // Initialize the property interpolator subsystem. Put into the INIT
578     // group because the "nasal" subsystem may need it at GENERAL take-down.
579     ////////////////////////////////////////////////////////////////////
580     FGInterpolator* interp = new FGInterpolator;
581     interp->setRealtimeProperty(fgGetNode("/sim/time/delta-realtime-sec", true));
582     globals->add_subsystem("prop-interpolator", interp, SGSubsystemMgr::INIT);
583     SGPropertyNode::setInterpolationMgr(interp);
584
585     ////////////////////////////////////////////////////////////////////
586     // Add the FlightGear property utilities.
587     ////////////////////////////////////////////////////////////////////
588     globals->add_subsystem("properties", new FGProperties);
589
590
591     ////////////////////////////////////////////////////////////////////
592     // Add the performance monitoring system.
593     ////////////////////////////////////////////////////////////////////
594     globals->add_subsystem("performance-mon",
595             new SGPerformanceMonitor(globals->get_subsystem_mgr(),
596                                      fgGetNode("/sim/performance-monitor", true)));
597
598     ////////////////////////////////////////////////////////////////////
599     // Initialize the material property subsystem.
600     ////////////////////////////////////////////////////////////////////
601
602     SGPath mpath( globals->get_fg_root() );
603     mpath.append( fgGetString("/sim/rendering/materials-file") );
604     if ( ! globals->get_matlib()->load(globals->get_fg_root(), mpath.str(),
605             globals->get_props()) ) {
606         throw sg_io_exception("Error loading materials file", mpath);
607     }
608
609     globals->add_subsystem( "http", new FGHTTPClient );
610     
611     ////////////////////////////////////////////////////////////////////
612     // Initialize the scenery management subsystem.
613     ////////////////////////////////////////////////////////////////////
614
615     globals->get_scenery()->get_scene_graph()
616         ->addChild(simgear::Particles::getCommonRoot());
617     simgear::GlobalParticleCallback::setSwitch(fgGetNode("/sim/rendering/particles", true));
618
619     ////////////////////////////////////////////////////////////////////
620     // Initialize the flight model subsystem.
621     ////////////////////////////////////////////////////////////////////
622
623     globals->add_subsystem("flight", new FDMShell, SGSubsystemMgr::FDM);
624
625     ////////////////////////////////////////////////////////////////////
626     // Initialize the weather subsystem.
627     ////////////////////////////////////////////////////////////////////
628
629     // Initialize the weather modeling subsystem
630     globals->add_subsystem("environment", new FGEnvironmentMgr);
631     globals->add_subsystem("ephemeris", new Ephemeris);
632     
633     ////////////////////////////////////////////////////////////////////
634     // Initialize the aircraft systems and instrumentation (before the
635     // autopilot.)
636     ////////////////////////////////////////////////////////////////////
637
638     globals->add_subsystem("systems", new FGSystemMgr, SGSubsystemMgr::FDM);
639     globals->add_subsystem("instrumentation", new FGInstrumentMgr, SGSubsystemMgr::FDM);
640     globals->add_subsystem("hud", new HUD, SGSubsystemMgr::DISPLAY);
641     globals->add_subsystem("cockpit-displays", new flightgear::CockpitDisplayManager, SGSubsystemMgr::DISPLAY);
642   
643     ////////////////////////////////////////////////////////////////////
644     // Initialize the XML Autopilot subsystem.
645     ////////////////////////////////////////////////////////////////////
646
647     globals->add_subsystem( "xml-autopilot", FGXMLAutopilotGroup::createInstance("autopilot"), SGSubsystemMgr::FDM );
648     globals->add_subsystem( "xml-proprules", FGXMLAutopilotGroup::createInstance("property-rule"), SGSubsystemMgr::GENERAL );
649     globals->add_subsystem( "route-manager", new FGRouteMgr );
650
651     ////////////////////////////////////////////////////////////////////
652     // Initialize the Input-Output subsystem
653     ////////////////////////////////////////////////////////////////////
654     globals->add_subsystem( "io", new FGIO );
655   
656     ////////////////////////////////////////////////////////////////////
657     // Create and register the logger.
658     ////////////////////////////////////////////////////////////////////
659     
660     globals->add_subsystem("logger", new FGLogger);
661
662     ////////////////////////////////////////////////////////////////////
663     // Create and register the XML GUI.
664     ////////////////////////////////////////////////////////////////////
665
666     globals->add_subsystem("gui", new NewGUI, SGSubsystemMgr::INIT);
667
668     //////////////////////////////////////////////////////////////////////
669     // Initialize the 2D cloud subsystem.
670     ////////////////////////////////////////////////////////////////////
671     fgGetBool("/sim/rendering/bump-mapping", false);
672
673     ////////////////////////////////////////////////////////////////////
674     // Initialize the canvas 2d drawing subsystem.
675     ////////////////////////////////////////////////////////////////////
676     globals->add_subsystem("Canvas", new CanvasMgr, SGSubsystemMgr::DISPLAY);
677     globals->add_subsystem("CanvasGUI", new GUIMgr, SGSubsystemMgr::DISPLAY);
678
679     ////////////////////////////////////////////////////////////////////
680     // Initialise the ATIS Manager
681     // Note that this is old stuff, but is necessary for the
682     // current ATIS implementation. Therefore, leave it in here
683     // until the ATIS system is ported over to make use of the ATIS 
684     // sub system infrastructure.
685     ////////////////////////////////////////////////////////////////////
686
687     globals->add_subsystem("ATIS", new FGATISMgr, SGSubsystemMgr::INIT, 0.4);
688
689     ////////////////////////////////////////////////////////////////////
690    // Initialize the ATC subsystem
691     ////////////////////////////////////////////////////////////////////
692     globals->add_subsystem("ATC", new FGATCManager, SGSubsystemMgr::POST_FDM);
693
694     ////////////////////////////////////////////////////////////////////
695     // Initialize multiplayer subsystem
696     ////////////////////////////////////////////////////////////////////
697
698     globals->add_subsystem("mp", new FGMultiplayMgr, SGSubsystemMgr::POST_FDM);
699
700     ////////////////////////////////////////////////////////////////////
701     // Initialise the AI Model Manager
702     ////////////////////////////////////////////////////////////////////
703     SG_LOG(SG_GENERAL, SG_INFO, "  AI Model Manager");
704     globals->add_subsystem("ai-model", new FGAIManager, SGSubsystemMgr::POST_FDM);
705     globals->add_subsystem("submodel-mgr", new FGSubmodelMgr, SGSubsystemMgr::POST_FDM);
706
707
708     // It's probably a good idea to initialize the top level traffic manager
709     // After the AI and ATC systems have been initialized properly.
710     // AI Traffic manager
711     globals->add_subsystem("traffic-manager", new FGTrafficManager, SGSubsystemMgr::POST_FDM);
712
713     ////////////////////////////////////////////////////////////////////
714     // Add a new 2D panel.
715     ////////////////////////////////////////////////////////////////////
716
717     fgSetArchivable("/sim/panel/visibility");
718     fgSetArchivable("/sim/panel/x-offset");
719     fgSetArchivable("/sim/panel/y-offset");
720     fgSetArchivable("/sim/panel/jitter");
721   
722     ////////////////////////////////////////////////////////////////////
723     // Initialize the controls subsystem.
724     ////////////////////////////////////////////////////////////////////
725     
726     globals->add_subsystem("controls", new FGControls, SGSubsystemMgr::GENERAL);
727
728     ////////////////////////////////////////////////////////////////////
729     // Initialize the input subsystem.
730     ////////////////////////////////////////////////////////////////////
731
732     globals->add_subsystem("input", new FGInput, SGSubsystemMgr::GENERAL);
733
734
735     ////////////////////////////////////////////////////////////////////
736     // Initialize the replay subsystem
737     ////////////////////////////////////////////////////////////////////
738     globals->add_subsystem("replay", new FGReplay);
739     globals->add_subsystem("history", new FGFlightHistory);
740     
741 #ifdef ENABLE_AUDIO_SUPPORT
742     ////////////////////////////////////////////////////////////////////
743     // Initialize the sound-effects subsystem.
744     ////////////////////////////////////////////////////////////////////
745     globals->add_subsystem("voice", new FGVoiceMgr, SGSubsystemMgr::DISPLAY);
746 #endif
747
748 #ifdef ENABLE_IAX
749     ////////////////////////////////////////////////////////////////////
750     // Initialize the FGCom subsystem.
751     ////////////////////////////////////////////////////////////////////
752     globals->add_subsystem("fgcom", new FGCom);
753 #endif
754
755     ////////////////////////////////////////////////////////////////////
756     // Initialize the lighting subsystem.
757     ////////////////////////////////////////////////////////////////////
758
759     globals->add_subsystem("lighting", new FGLight, SGSubsystemMgr::DISPLAY);
760     
761     // ordering here is important : Nasal (via events), then models, then views
762     globals->add_subsystem("events", globals->get_event_mgr(), SGSubsystemMgr::DISPLAY);
763
764     globals->add_subsystem("aircraft-model", new FGAircraftModel, SGSubsystemMgr::DISPLAY);
765     globals->add_subsystem("model-manager", new FGModelMgr, SGSubsystemMgr::DISPLAY);
766
767     globals->add_subsystem("view-manager", new FGViewMgr, SGSubsystemMgr::DISPLAY);
768
769     globals->add_subsystem("tile-manager", globals->get_tile_mgr(), 
770       SGSubsystemMgr::DISPLAY);
771 }
772
773 void fgPostInitSubsystems()
774 {
775     SGTimeStamp st;
776     st.stamp();
777   
778     ////////////////////////////////////////////////////////////////////////
779     // Initialize the Nasal interpreter.
780     // Do this last, so that the loaded scripts see initialized state
781     ////////////////////////////////////////////////////////////////////////
782     FGNasalSys* nasal = new FGNasalSys();
783     globals->add_subsystem("nasal", nasal, SGSubsystemMgr::INIT);
784     nasal->init();
785     SG_LOG(SG_GENERAL, SG_INFO, "Nasal init took:" << st.elapsedMSec());
786
787     // Ensure IOrules and path validation are working properly by trying to
788     // access a folder/file which should never be accessible.
789     const char* no_access_path =
790 #ifdef _WIN32
791       "Z:"
792 #endif
793       "/do-not-access";
794
795     if( fgValidatePath(no_access_path, true) )
796       SG_LOG
797       (
798         SG_GENERAL,
799         SG_ALERT,
800         "Check your IOrules! (write to '" << no_access_path << "' is allowed)"
801       );
802     if( fgValidatePath(no_access_path, false) )
803       SG_LOG
804       (
805         SG_GENERAL,
806         SG_ALERT,
807         "Check your IOrules! (read from '" << no_access_path << "' is allowed)"
808       );
809   
810     // initialize methods that depend on other subsystems.
811     st.stamp();
812     globals->get_subsystem_mgr()->postinit();
813     SG_LOG(SG_GENERAL, SG_INFO, "Subsystems postinit took:" << st.elapsedMSec());
814   
815     ////////////////////////////////////////////////////////////////////////
816     // End of subsystem initialization.
817     ////////////////////////////////////////////////////////////////////
818
819     fgSetBool("/sim/crashed", false);
820     fgSetBool("/sim/initialized", true);
821
822     SG_LOG( SG_GENERAL, SG_INFO, endl);
823
824                                 // Save the initial state for future
825                                 // reference.
826     globals->saveInitialState();
827 }
828
829 // Reset: this is what the 'reset' command (and hence, GUI) is attached to
830 void fgReInitSubsystems()
831 {
832     SGPropertyNode *master_freeze = fgGetNode("/sim/freeze/master");
833
834     SG_LOG( SG_GENERAL, SG_INFO, "fgReInitSubsystems()");
835
836 // setup state to begin re-init
837     bool freeze = master_freeze->getBoolValue();
838     if ( !freeze ) {
839         master_freeze->setBoolValue(true);
840     }
841     
842     fgSetBool("/sim/signals/reinit", true);
843     fgSetBool("/sim/crashed", false);
844
845 // do actual re-init steps
846     globals->get_subsystem("flight")->unbind();
847     
848   // reset control state, before restoring initial state; -set or config files
849   // may specify values for flaps, trim tabs, magnetos, etc
850     globals->get_controls()->reset_all();
851         
852     globals->restoreInitialState();
853
854     // update our position based on current presets
855     // this will mark position as needed finalized which we'll do in the
856     // main-loop
857     flightgear::initPosition();
858     
859     simgear::SGTerraSync* terraSync =
860         static_cast<simgear::SGTerraSync*>(globals->get_subsystem("terrasync"));
861     if (terraSync) {
862         terraSync->reposition();
863     }
864     
865     // Force reupdating the positions of the ai 3d models. They are used for
866     // initializing ground level for the FDM.
867     globals->get_subsystem("ai-model")->reinit();
868
869     // Initialize the FDM
870     globals->get_subsystem("flight")->reinit();
871
872     // reset replay buffers
873     globals->get_subsystem("replay")->reinit();
874     
875     // reload offsets from config defaults
876     globals->get_viewmgr()->reinit();
877
878     // ugly: finalizePosition waits for METAR to arrive for the new airport.
879     // we don't re-init the environment manager here, since historically we did
880     // not, and doing so seems to have other issues. All that's needed is to
881     // schedule METAR fetch immediately, so it's available for finalizePosition.
882     // So we manually extract the METAR-fetching component inside the environment
883     // manager, and re-init that.
884     SGSubsystemGroup* envMgr = static_cast<SGSubsystemGroup*>(globals->get_subsystem("environment"));
885     if (envMgr) {
886       envMgr->get_subsystem("realwx")->reinit();
887     }
888   
889     globals->get_subsystem("time")->reinit();
890
891     // need to bind FDMshell again, since we manually unbound it above...
892     globals->get_subsystem("flight")->bind();
893
894     // need to reset aircraft (systems/instruments) so they can adapt to current environment
895     globals->get_subsystem("systems")->reinit();
896     globals->get_subsystem("instrumentation")->reinit();
897
898     globals->get_subsystem("ATIS")->reinit();
899
900 // setup state to end re-init
901     fgSetBool("/sim/signals/reinit", false);
902     if ( !freeze ) {
903         master_freeze->setBoolValue(false);
904     }
905     fgSetBool("/sim/sceneryloaded",false);
906 }
907
908