]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_init.cxx
21f0624b5b89c7169925f128ab30c9d0b65d1ac4
[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 <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>             // strcmp()
31
32 #if defined( unix ) || defined( __CYGWIN__ )
33 #  include <unistd.h>           // for gethostname()
34 #endif
35 #ifdef _WIN32
36 #  include <direct.h>           // for getcwd()
37 #  define getcwd _getcwd
38 #  include <io.h>               // isatty()
39 #  define isatty _isatty
40 #  include "winsock2.h"         // for gethostname()
41 #endif
42
43 // work around a stdc++ lib bug in some versions of linux, but doesn't
44 // seem to hurt to have this here for all versions of Linux.
45 #ifdef linux
46 #  define _G_NO_EXTERN_TEMPLATES
47 #endif
48
49 #include <simgear/compiler.h>
50
51 #include <string>
52 #include <boost/algorithm/string/compare.hpp>
53 #include <boost/algorithm/string/predicate.hpp>
54
55 #include <simgear/constants.h>
56 #include <simgear/debug/logstream.hxx>
57 #include <simgear/structure/exception.hxx>
58 #include <simgear/structure/event_mgr.hxx>
59 #include <simgear/structure/SGPerfMon.hxx>
60 #include <simgear/misc/sg_path.hxx>
61 #include <simgear/misc/sg_dir.hxx>
62 #include <simgear/misc/sgstream.hxx>
63 #include <simgear/misc/strutils.hxx>
64 #include <simgear/props/props_io.hxx>
65
66 #include <simgear/misc/interpolator.hxx>
67 #include <simgear/scene/material/matlib.hxx>
68 #include <simgear/scene/model/particles.hxx>
69 #include <simgear/sound/soundmgr_openal.hxx>
70
71 #include <Aircraft/controls.hxx>
72 #include <Aircraft/replay.hxx>
73 #include <Airports/apt_loader.hxx>
74 #include <Airports/runways.hxx>
75 #include <Airports/simple.hxx>
76 #include <Airports/dynamics.hxx>
77
78 #include <AIModel/AIManager.hxx>
79
80 #include <ATCDCL/ATCmgr.hxx>
81 #include <ATC/atc_mgr.hxx>
82
83 #include <Autopilot/route_mgr.hxx>
84 #include <Autopilot/autopilotgroup.hxx>
85
86 #include <Cockpit/panel.hxx>
87 #include <Cockpit/panel_io.hxx>
88
89 #include <GUI/new_gui.hxx>
90 #include <Input/input.hxx>
91 #include <Instrumentation/instrument_mgr.hxx>
92 #include <Model/acmodel.hxx>
93 #include <Model/modelmgr.hxx>
94 #include <AIModel/submodel.hxx>
95 #include <AIModel/AIManager.hxx>
96 #include <Navaids/navdb.hxx>
97 #include <Navaids/navlist.hxx>
98 #include <Navaids/fix.hxx>
99 #include <Navaids/fixlist.hxx>
100 #include <Navaids/airways.hxx>
101 #include <Scenery/scenery.hxx>
102 #include <Scenery/tilemgr.hxx>
103 #include <Scripting/NasalSys.hxx>
104 #include <Sound/voice.hxx>
105 #include <Systems/system_mgr.hxx>
106 #include <Time/light.hxx>
107 #include <Traffic/TrafficMgr.hxx>
108 #include <MultiPlayer/multiplaymgr.hxx>
109 #include <FDM/fdm_shell.hxx>
110 #include <Environment/ephemeris.hxx>
111 #include <Environment/environment_mgr.hxx>
112
113 #include "fg_init.hxx"
114 #include "fg_io.hxx"
115 #include "fg_commands.hxx"
116 #include "fg_props.hxx"
117 #include "options.hxx"
118 #include "globals.hxx"
119 #include "logger.hxx"
120 #include "renderer.hxx"
121 #include "viewmgr.hxx"
122 #include "main.hxx"
123
124
125 using std::string;
126 using namespace boost::algorithm;
127
128
129 // Return the current base package version
130 string fgBasePackageVersion() {
131     SGPath base_path( globals->get_fg_root() );
132     base_path.append("version");
133
134     sg_gzifstream in( base_path.str() );
135     if ( !in.is_open() ) {
136         SGPath old_path( globals->get_fg_root() );
137         old_path.append( "Thanks" );
138         sg_gzifstream old( old_path.str() );
139         if ( !old.is_open() ) {
140             return "[none]";
141         } else {
142             return "[old version]";
143         }
144     }
145
146     string version;
147     in >> version;
148
149     return version;
150 }
151
152
153 template <class T>
154 bool fgFindAircraftInDir(const SGPath& dirPath, T* obj, bool (T::*pred)(const SGPath& p))
155 {
156   if (!dirPath.exists()) {
157     SG_LOG(SG_GENERAL, SG_WARN, "fgFindAircraftInDir: no such path:" << dirPath.str());
158     return false;
159   }
160     
161   bool recurse = true;
162   simgear::Dir dir(dirPath);
163   simgear::PathList setFiles(dir.children(simgear::Dir::TYPE_FILE, "-set.xml"));
164   simgear::PathList::iterator p;
165   for (p = setFiles.begin(); p != setFiles.end(); ++p) {
166     // check file name ends with -set.xml
167     
168     // if we found a -set.xml at this level, don't recurse any deeper
169     recurse = false;
170     
171     bool done = (obj->*pred)(*p);
172     if (done) {
173       return true;
174     }
175   } // of -set.xml iteration
176   
177   if (!recurse) {
178     return false;
179   }
180   
181   simgear::PathList subdirs(dir.children(simgear::Dir::TYPE_DIR | simgear::Dir::NO_DOT_OR_DOTDOT));
182   for (p = subdirs.begin(); p != subdirs.end(); ++p) {
183     if (p->file() == "CVS") {
184       continue;
185     }
186     
187     if (fgFindAircraftInDir(*p, obj, pred)) {
188       return true;
189     }
190   } // of subdirs iteration
191   
192   return false;
193 }
194
195 template <class T>
196 void fgFindAircraft(T* obj, bool (T::*pred)(const SGPath& p))
197 {
198   const string_list& paths(globals->get_aircraft_paths());
199   string_list::const_iterator it = paths.begin();
200   for (; it != paths.end(); ++it) {
201     bool done = fgFindAircraftInDir(SGPath(*it), obj, pred);
202     if (done) {
203       return;
204     }
205   } // of aircraft paths iteration
206   
207   // if we reach this point, search the default location (always last)
208   SGPath rootAircraft(globals->get_fg_root());
209   rootAircraft.append("Aircraft");
210   fgFindAircraftInDir(rootAircraft, obj, pred);
211 }
212
213 class FindAndCacheAircraft
214 {
215 public:
216   FindAndCacheAircraft(SGPropertyNode* autoSave)
217   {
218     _cache = autoSave->getNode("sim/startup/path-cache", true);
219   }
220   
221   bool loadAircraft()
222   {
223     std::string aircraft = fgGetString( "/sim/aircraft", "");
224     if (aircraft.empty()) {
225       SG_LOG(SG_GENERAL, SG_ALERT, "no aircraft specified");
226       return false;
227     }
228     
229     _searchAircraft = aircraft + "-set.xml";
230     std::string aircraftDir = fgGetString("/sim/aircraft-dir", "");
231     if (!aircraftDir.empty()) {
232       // aircraft-dir was set, skip any searching at all, if it's valid
233       simgear::Dir acPath(aircraftDir);
234       SGPath setFile = acPath.file(_searchAircraft);
235       if (setFile.exists()) {
236         SG_LOG(SG_GENERAL, SG_INFO, "found aircraft in dir: " << aircraftDir );
237         
238         try {
239           readProperties(setFile.str(), globals->get_props());
240         } catch ( const sg_exception &e ) {
241           SG_LOG(SG_INPUT, SG_ALERT, "Error reading aircraft: " << e.getFormattedMessage());
242           return false;
243         }
244         
245         return true;
246       } else {
247         SG_LOG(SG_GENERAL, SG_ALERT, "aircraft '" << _searchAircraft << 
248                "' not found in specified dir:" << aircraftDir);
249         return false;
250       }
251     }
252     
253     if (!checkCache()) {
254       // prepare cache for re-scan
255       SGPropertyNode *n = _cache->getNode("fg-root", true);
256       n->setStringValue(globals->get_fg_root().c_str());
257       n->setAttribute(SGPropertyNode::USERARCHIVE, true);
258       n = _cache->getNode("fg-aircraft", true);
259       n->setStringValue(getAircraftPaths().c_str());
260       n->setAttribute(SGPropertyNode::USERARCHIVE, true);
261       _cache->removeChildren("aircraft");
262   
263       fgFindAircraft(this, &FindAndCacheAircraft::checkAircraft);
264     }
265     
266     if (_foundPath.str().empty()) {
267       SG_LOG(SG_GENERAL, SG_ALERT, "Cannot find specified aircraft: " << aircraft );
268       return false;
269     }
270     
271     SG_LOG(SG_GENERAL, SG_INFO, "Loading aircraft -set file from:" << _foundPath.str());
272     fgSetString( "/sim/aircraft-dir", _foundPath.dir().c_str());
273     if (!_foundPath.exists()) {
274       SG_LOG(SG_GENERAL, SG_ALERT, "Unable to find -set file:" << _foundPath.str());
275       return false;
276     }
277     
278     try {
279       readProperties(_foundPath.str(), globals->get_props());
280     } catch ( const sg_exception &e ) {
281       SG_LOG(SG_INPUT, SG_ALERT, "Error reading aircraft: " << e.getFormattedMessage());
282       return false;
283     }
284     
285     return true;
286   }
287   
288 private:
289   SGPath getAircraftPaths() {
290     string_list pathList = globals->get_aircraft_paths();
291     SGPath aircraftPaths;
292     string_list::const_iterator it = pathList.begin();
293     if (it != pathList.end()) {
294         aircraftPaths.set(*it);
295         it++;
296     }
297     for (; it != pathList.end(); ++it) {
298         aircraftPaths.add(*it);
299     }
300     return aircraftPaths;
301   }
302   
303   bool checkCache()
304   {
305     if (globals->get_fg_root() != _cache->getStringValue("fg-root", "")) {
306       return false; // cache mismatch
307     }
308
309     if (getAircraftPaths().str() != _cache->getStringValue("fg-aircraft", "")) {
310       return false; // cache mismatch
311     }
312     
313     vector<SGPropertyNode_ptr> cache = _cache->getChildren("aircraft");
314     for (unsigned int i = 0; i < cache.size(); i++) {
315       const char *name = cache[i]->getStringValue("file", "");
316       if (!boost::equals(_searchAircraft, name, is_iequal())) {
317         continue;
318       }
319       
320       SGPath xml(cache[i]->getStringValue("path", ""));
321       xml.append(name);
322       if (xml.exists()) {
323         _foundPath = xml;
324         return true;
325       } 
326       
327       return false;
328     } // of aircraft in cache iteration
329     
330     return false;
331   }
332   
333   bool checkAircraft(const SGPath& p)
334   {
335     // create cache node
336     int i = 0;
337     while (1) {
338         if (!_cache->getChild("aircraft", i++, false))
339             break;
340     }
341     
342     SGPropertyNode *n, *entry = _cache->getChild("aircraft", --i, true);
343
344     std::string fileName(p.file());
345     n = entry->getNode("file", true);
346     n->setStringValue(fileName);
347     n->setAttribute(SGPropertyNode::USERARCHIVE, true);
348
349     n = entry->getNode("path", true);
350     n->setStringValue(p.dir());
351     n->setAttribute(SGPropertyNode::USERARCHIVE, true);
352
353     if ( boost::equals(fileName, _searchAircraft.c_str(), is_iequal()) ) {
354         _foundPath = p;
355         return true;
356     }
357
358     return false;
359   }
360   
361   std::string _searchAircraft;
362   SGPath _foundPath;
363   SGPropertyNode* _cache;
364 };
365
366 #ifdef _WIN32
367 static SGPath platformDefaultDataPath()
368 {
369   char *envp = ::getenv( "APPDATA" );
370   SGPath config( envp );
371   config.append( "flightgear.org" );
372   return config;
373 }
374 #elif __APPLE__
375
376 #include <CoreServices/CoreServices.h>
377
378 static SGPath platformDefaultDataPath()
379 {
380   FSRef ref;
381   OSErr err = FSFindFolder(kUserDomain, kApplicationSupportFolderType, false, &ref);
382   if (err) {
383     return SGPath();
384   }
385   
386   unsigned char path[1024];
387   if (FSRefMakePath(&ref, path, 1024) != noErr) {
388     return SGPath();
389   }
390   
391   SGPath appData;
392   appData.set((const char*) path);
393   appData.append("FlightGear");
394   return appData;
395 }
396 #else
397 static SGPath platformDefaultDataPath()
398 {
399   SGPath config( homedir );
400   config.append( ".fgfs" );
401   return config;
402 }
403 #endif
404
405 // Read in configuration (file and command line)
406 bool fgInitConfig ( int argc, char **argv )
407 {
408     SGPath dataPath = platformDefaultDataPath();
409     
410     const char *fg_home = getenv("FG_HOME");
411     if (fg_home)
412       dataPath = fg_home;
413     
414     simgear::Dir exportDir(simgear::Dir(dataPath).file("Export"));
415     if (!exportDir.exists()) {
416       exportDir.create(0777);
417     }
418     
419     // Set /sim/fg-home and don't allow malign code to override it until
420     // Nasal security is set up.  Use FG_HOME if necessary.
421     SGPropertyNode *home = fgGetNode("/sim", true);
422     home->removeChild("fg-home", 0, false);
423     home = home->getChild("fg-home", 0, true);
424     home->setStringValue(dataPath.c_str());
425     home->setAttribute(SGPropertyNode::WRITE, false);
426   
427     flightgear::Options::sharedInstance()->init(argc, argv, dataPath);
428   
429     // Read global preferences from $FG_ROOT/preferences.xml
430     SG_LOG(SG_INPUT, SG_INFO, "Reading global preferences");
431     fgLoadProps("preferences.xml", globals->get_props());
432     SG_LOG(SG_INPUT, SG_INFO, "Finished Reading global preferences");
433
434     globals->loadUserSettings(dataPath);
435
436     // Scan user config files and command line for a specified aircraft.
437     flightgear::Options::sharedInstance()->initAircraft();
438
439     FindAndCacheAircraft f(globals->get_props());
440     if (!f.loadAircraft()) {
441       return false;
442     }
443
444     // parse options after loading aircraft to ensure any user
445     // overrides of defaults are honored.
446     flightgear::Options::sharedInstance()->processOptions();
447       
448     return true;
449 }
450
451 // Set current tower position lon/lat given an airport id
452 static bool fgSetTowerPosFromAirportID( const string& id) {
453     const FGAirport *a = fgFindAirportID( id);
454     if (a) {
455         SGGeod tower = a->getTowerLocation();
456         fgSetDouble("/sim/tower/longitude-deg",  tower.getLongitudeDeg());
457         fgSetDouble("/sim/tower/latitude-deg",  tower.getLatitudeDeg());
458         fgSetDouble("/sim/tower/altitude-ft", tower.getElevationFt());
459         return true;
460     } else {
461         return false;
462     }
463
464 }
465
466 struct FGTowerLocationListener : SGPropertyChangeListener {
467     void valueChanged(SGPropertyNode* node) {
468         string id(node->getStringValue());
469         if (fgGetBool("/sim/tower/auto-position",true))
470         {
471             // enforce using closest airport when auto-positioning is enabled 
472             const char* closest_airport = fgGetString("/sim/airport/closest-airport-id", "");
473             if (closest_airport && (id != closest_airport))
474             {
475                 id = closest_airport;
476                 node->setStringValue(id);
477             }
478         }
479         fgSetTowerPosFromAirportID(id);
480     }
481 };
482
483 struct FGClosestTowerLocationListener : SGPropertyChangeListener
484 {
485     void valueChanged(SGPropertyNode* )
486     {
487         // closest airport has changed
488         if (fgGetBool("/sim/tower/auto-position",true))
489         {
490             // update tower position
491             const char* id = fgGetString("/sim/airport/closest-airport-id", "");
492             if (id && *id!=0)
493                 fgSetString("/sim/tower/airport-id", id);
494         }
495     }
496 };
497
498 void fgInitTowerLocationListener() {
499     fgGetNode("/sim/tower/airport-id",  true)
500         ->addChangeListener( new FGTowerLocationListener(), true );
501     FGClosestTowerLocationListener* ntcl = new FGClosestTowerLocationListener();
502     fgGetNode("/sim/airport/closest-airport-id", true)
503         ->addChangeListener(ntcl , true );
504     fgGetNode("/sim/tower/auto-position", true)
505            ->addChangeListener(ntcl, true );
506 }
507
508 static void fgApplyStartOffset(const SGGeod& aStartPos, double aHeading, double aTargetHeading = HUGE_VAL)
509 {
510   SGGeod startPos(aStartPos);
511   if (aTargetHeading == HUGE_VAL) {
512     aTargetHeading = aHeading;
513   }
514   
515   if ( fabs( fgGetDouble("/sim/presets/offset-distance-nm") ) > SG_EPSILON ) {
516     double offsetDistance = fgGetDouble("/sim/presets/offset-distance-nm");
517     offsetDistance *= SG_NM_TO_METER;
518     double offsetAzimuth = aHeading;
519     if ( fabs(fgGetDouble("/sim/presets/offset-azimuth-deg")) > SG_EPSILON ) {
520       offsetAzimuth = fgGetDouble("/sim/presets/offset-azimuth-deg");
521       aHeading = aTargetHeading;
522     }
523
524     SGGeod offset;
525     double az2; // dummy
526     SGGeodesy::direct(startPos, offsetAzimuth + 180, offsetDistance, offset, az2);
527     startPos = offset;
528   }
529
530   // presets
531   fgSetDouble("/sim/presets/longitude-deg", startPos.getLongitudeDeg() );
532   fgSetDouble("/sim/presets/latitude-deg", startPos.getLatitudeDeg() );
533   fgSetDouble("/sim/presets/heading-deg", aHeading );
534
535   // other code depends on the actual values being set ...
536   fgSetDouble("/position/longitude-deg",  startPos.getLongitudeDeg() );
537   fgSetDouble("/position/latitude-deg",  startPos.getLatitudeDeg() );
538   fgSetDouble("/orientation/heading-deg", aHeading );
539 }
540
541 // Set current_options lon/lat given an airport id and heading (degrees)
542 bool fgSetPosFromAirportIDandHdg( const string& id, double tgt_hdg ) {
543     if ( id.empty() )
544         return false;
545
546     // set initial position from runway and heading
547     SG_LOG( SG_GENERAL, SG_INFO,
548             "Attempting to set starting position from airport code "
549             << id << " heading " << tgt_hdg );
550
551     const FGAirport* apt = fgFindAirportID(id);
552     if (!apt) return false;
553     FGRunway* r = apt->findBestRunwayForHeading(tgt_hdg);
554     fgSetString("/sim/atc/runway", r->ident().c_str());
555
556     SGGeod startPos = r->pointOnCenterline(fgGetDouble("/sim/airport/runways/start-offset-m", 5.0));
557           fgApplyStartOffset(startPos, r->headingDeg(), tgt_hdg);
558     return true;
559 }
560
561 // Set current_options lon/lat given an airport id and parkig position name
562 static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& parkpos ) {
563     if ( id.empty() )
564         return false;
565
566     // can't see an easy way around this const_cast at the moment
567     FGAirport* apt = const_cast<FGAirport*>(fgFindAirportID(id));
568     if (!apt) {
569         SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find airport " << id );
570         return false;
571     }
572     FGAirportDynamics* dcs = apt->getDynamics();
573     if (!dcs) {
574         SG_LOG( SG_GENERAL, SG_ALERT,
575                 "Airport " << id << "does not appear to have parking information available");
576         return false;
577     }
578     
579     int park_index = dcs->getNrOfParkings() - 1;
580     bool succes;
581     double radius = fgGetDouble("/sim/dimensions/radius-m");
582     if ((parkpos == string("AVAILABLE")) && (radius > 0)) {
583         double lat, lon, heading;
584         string fltType;
585         string acOperator;
586         SGPath acData;
587         try {
588             acData = fgGetString("/sim/fg-home");
589             acData.append("aircraft-data");
590             string acfile = fgGetString("/sim/aircraft") + string(".xml");
591             acData.append(acfile);
592             SGPropertyNode root;
593             readProperties(acData.str(), &root);
594             SGPropertyNode * node = root.getNode("sim");
595             fltType    = node->getStringValue("aircraft-class", "NONE"     );
596             acOperator = node->getStringValue("aircraft-operator", "NONE"     );
597         } catch (const sg_exception &) {
598             SG_LOG(SG_GENERAL, SG_INFO,
599                 "Could not load aircraft aircrat type and operator information from: " << acData.str() << ". Using defaults");
600
601        // cout << path.str() << endl;
602         }
603         if (fltType.empty() || fltType == "NONE") {
604             SG_LOG(SG_GENERAL, SG_INFO,
605                 "Aircraft type information not found in: " << acData.str() << ". Using default value");
606                 fltType = fgGetString("/sim/aircraft-class"   );
607         }
608         if (acOperator.empty() || fltType == "NONE") {
609             SG_LOG(SG_GENERAL, SG_INFO,
610                 "Aircraft operator information not found in: " << acData.str() << ". Using default value");
611                 acOperator = fgGetString("/sim/aircraft-operator"   );
612         }
613
614         cerr << "Running aircraft " << fltType << " of livery " << acOperator << endl;
615         string acType; // Currently not used by findAvailable parking, so safe to leave empty. 
616         succes = dcs->getAvailableParking(&lat, &lon, &heading, &park_index, radius, fltType, acType, acOperator);
617         if (succes) {
618             fgGetString("/sim/presets/parkpos");
619             fgSetString("/sim/presets/parkpos", dcs->getParking(park_index)->getName());
620         } else {
621             SG_LOG( SG_GENERAL, SG_ALERT,
622                     "Failed to find a suitable parking at airport " << id );
623             return false;
624         }
625     } else {
626         //cerr << "We shouldn't get here when AVAILABLE" << endl;
627         while (park_index >= 0 && dcs->getParkingName(park_index) != parkpos) park_index--;
628         if (park_index < 0) {
629             SG_LOG( SG_GENERAL, SG_ALERT,
630                     "Failed to find parking position " << parkpos <<
631                     " at airport " << id );
632             return false;
633         }
634     }
635     FGParking* parking = dcs->getParking(park_index);
636     parking->setAvailable(false);
637     fgApplyStartOffset(
638       SGGeod::fromDeg(parking->getLongitude(), parking->getLatitude()),
639       parking->getHeading());
640     return true;
641 }
642
643
644 // Set current_options lon/lat given an airport id and runway number
645 static bool fgSetPosFromAirportIDandRwy( const string& id, const string& rwy, bool rwy_req ) {
646     if ( id.empty() )
647         return false;
648
649     // set initial position from airport and runway number
650     SG_LOG( SG_GENERAL, SG_INFO,
651             "Attempting to set starting position for "
652             << id << ":" << rwy );
653
654     const FGAirport* apt = fgFindAirportID(id);
655     if (!apt) {
656       SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find airport:" << id);
657       return false;
658     }
659     
660     if (!apt->hasRunwayWithIdent(rwy)) {
661       SG_LOG( SG_GENERAL, rwy_req ? SG_ALERT : SG_INFO,
662                 "Failed to find runway " << rwy <<
663                 " at airport " << id << ". Using default runway." );
664       return false;
665     }
666     
667     FGRunway* r(apt->getRunwayByIdent(rwy));
668     fgSetString("/sim/atc/runway", r->ident().c_str());
669     SGGeod startPos = r->pointOnCenterline( fgGetDouble("/sim/airport/runways/start-offset-m", 5.0));
670           fgApplyStartOffset(startPos, r->headingDeg());
671     return true;
672 }
673
674
675 static void fgSetDistOrAltFromGlideSlope() {
676     // cout << "fgSetDistOrAltFromGlideSlope()" << endl;
677     string apt_id = fgGetString("/sim/presets/airport-id");
678     double gs = fgGetDouble("/sim/presets/glideslope-deg")
679         * SG_DEGREES_TO_RADIANS ;
680     double od = fgGetDouble("/sim/presets/offset-distance-nm");
681     double alt = fgGetDouble("/sim/presets/altitude-ft");
682
683     double apt_elev = 0.0;
684     if ( ! apt_id.empty() ) {
685         apt_elev = fgGetAirportElev( apt_id );
686         if ( apt_elev < -9990.0 ) {
687             apt_elev = 0.0;
688         }
689     } else {
690         apt_elev = 0.0;
691     }
692
693     if( fabs(gs) > 0.01 && fabs(od) > 0.1 && alt < -9990 ) {
694         // set altitude from glideslope and offset-distance
695         od *= SG_NM_TO_METER * SG_METER_TO_FEET;
696         alt = fabs(od*tan(gs)) + apt_elev;
697         fgSetDouble("/sim/presets/altitude-ft", alt);
698         fgSetBool("/sim/presets/onground", false);
699         SG_LOG( SG_GENERAL, SG_INFO, "Calculated altitude as: "
700                 << alt  << " ft" );
701     } else if( fabs(gs) > 0.01 && alt > 0 && fabs(od) < 0.1) {
702         // set offset-distance from glideslope and altitude
703         od  = (alt - apt_elev) / tan(gs);
704         od *= -1*SG_FEET_TO_METER * SG_METER_TO_NM;
705         fgSetDouble("/sim/presets/offset-distance-nm", od);
706         fgSetBool("/sim/presets/onground", false);
707         SG_LOG( SG_GENERAL, SG_INFO, "Calculated offset distance as: " 
708                 << od  << " nm" );
709     } else if( fabs(gs) > 0.01 ) {
710         SG_LOG( SG_GENERAL, SG_ALERT,
711                 "Glideslope given but not altitude or offset-distance." );
712         SG_LOG( SG_GENERAL, SG_ALERT, "Resetting glideslope to zero" );
713         fgSetDouble("/sim/presets/glideslope-deg", 0);
714         fgSetBool("/sim/presets/onground", true);
715     }
716 }
717
718
719 // Set current_options lon/lat given an airport id and heading (degrees)
720 static bool fgSetPosFromNAV( const string& id, const double& freq, FGPositioned::Type type ) {
721
722     const nav_list_type navlist
723         = globals->get_navlist()->findByIdentAndFreq( id.c_str(), freq, type );
724
725     if (navlist.size() == 0 ) {
726         SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate NAV = "
727             << id << ":" << freq );
728         return false;
729     }
730
731     if( navlist.size() > 1 ) {
732         ostringstream buf;
733         buf << "Ambigous NAV-ID: '" << id << "'. Specify id and frequency. Available stations:" << endl;
734         for( nav_list_type::const_iterator it = navlist.begin(); it != navlist.end(); ++it ) {
735             // NDB stored in kHz, VOR stored in MHz * 100 :-P
736             double factor = (*it)->type() == FGPositioned::NDB ? 1.0 : 1/100.0;
737             string unit = (*it)->type() == FGPositioned::NDB ? "kHz" : "MHz";
738             buf << (*it)->ident() << " "
739                 << setprecision(5) << (double)((*it)->get_freq() * factor) << " "
740                 << (*it)->get_lat() << "/" << (*it)->get_lon()
741                 << endl;
742         }
743
744         SG_LOG( SG_GENERAL, SG_ALERT, buf.str() );
745         return false;
746     }
747
748     FGNavRecord *nav = navlist[0];
749     fgApplyStartOffset(nav->geod(), fgGetDouble("/sim/presets/heading-deg"));
750     return true;
751 }
752
753 // Set current_options lon/lat given an aircraft carrier id
754 static bool fgSetPosFromCarrier( const string& carrier, const string& posid ) {
755
756     // set initial position from runway and heading
757     SGGeod geodPos;
758     double heading;
759     SGVec3d uvw;
760     if (FGAIManager::getStartPosition(carrier, posid, geodPos, heading, uvw)) {
761         double lon = geodPos.getLongitudeDeg();
762         double lat = geodPos.getLatitudeDeg();
763         double alt = geodPos.getElevationFt();
764
765         SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position for "
766                 << carrier << " at lat = " << lat << ", lon = " << lon
767                 << ", alt = " << alt << ", heading = " << heading);
768
769         fgSetDouble("/sim/presets/longitude-deg",  lon);
770         fgSetDouble("/sim/presets/latitude-deg",  lat);
771         fgSetDouble("/sim/presets/altitude-ft", alt);
772         fgSetDouble("/sim/presets/heading-deg", heading);
773         fgSetDouble("/position/longitude-deg",  lon);
774         fgSetDouble("/position/latitude-deg",  lat);
775         fgSetDouble("/position/altitude-ft", alt);
776         fgSetDouble("/orientation/heading-deg", heading);
777
778         fgSetString("/sim/presets/speed-set", "UVW");
779         fgSetDouble("/velocities/uBody-fps", uvw(0));
780         fgSetDouble("/velocities/vBody-fps", uvw(1));
781         fgSetDouble("/velocities/wBody-fps", uvw(2));
782         fgSetDouble("/sim/presets/uBody-fps", uvw(0));
783         fgSetDouble("/sim/presets/vBody-fps", uvw(1));
784         fgSetDouble("/sim/presets/wBody-fps", uvw(2));
785
786         fgSetBool("/sim/presets/onground", true);
787
788         return true;
789     } else {
790         SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate aircraft carrier = "
791                 << carrier );
792         return false;
793     }
794 }
795  
796 // Set current_options lon/lat given an airport id and heading (degrees)
797 static bool fgSetPosFromFix( const string& id )
798 {
799   FGPositioned::TypeFilter fixFilter(FGPositioned::FIX);
800   FGPositioned* fix = FGPositioned::findNextWithPartialId(NULL, id, &fixFilter);
801   if (!fix) {
802     SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate fix = " << id );
803     return false;
804   }
805   
806   fgApplyStartOffset(fix->geod(), fgGetDouble("/sim/presets/heading-deg"));
807   return true;
808 }
809
810 /**
811  * Initialize vor/ndb/ils/fix list management and query systems (as
812  * well as simple airport db list)
813  */
814 bool
815 fgInitNav ()
816 {
817     SG_LOG(SG_GENERAL, SG_INFO, "Loading Airport Database ...");
818
819     SGPath aptdb( globals->get_fg_root() );
820     aptdb.append( "Airports/apt.dat" );
821
822     SGPath p_metar( globals->get_fg_root() );
823     p_metar.append( "Airports/metar.dat" );
824
825     fgAirportDBLoad( aptdb.str(), p_metar.str() );
826     FGAirport::installPropertyListener();
827     FGPositioned::installCommands();
828     
829     FGNavList *navlist = new FGNavList;
830     FGNavList *loclist = new FGNavList;
831     FGNavList *gslist = new FGNavList;
832     FGNavList *dmelist = new FGNavList;
833     FGNavList *tacanlist = new FGNavList;
834     FGNavList *carrierlist = new FGNavList;
835     FGTACANList *channellist = new FGTACANList;
836
837     globals->set_navlist( navlist );
838     globals->set_loclist( loclist );
839     globals->set_gslist( gslist );
840     globals->set_dmelist( dmelist );
841     globals->set_tacanlist( tacanlist );
842     globals->set_carrierlist( carrierlist );
843     globals->set_channellist( channellist );
844
845     if ( !fgNavDBInit(navlist, loclist, gslist, dmelist, tacanlist, carrierlist, channellist) ) {
846         SG_LOG( SG_GENERAL, SG_ALERT,
847                 "Problems loading one or more navigational database" );
848     }
849     
850     SG_LOG(SG_GENERAL, SG_INFO, "  Fixes");
851     SGPath p_fix( globals->get_fg_root() );
852     p_fix.append( "Navaids/fix.dat" );
853     FGFixList fixlist;
854     fixlist.init( p_fix );  // adds fixes to the DB in positioned.cxx
855
856     SG_LOG(SG_GENERAL, SG_INFO, "  Airways");
857     flightgear::Airway::load();
858     
859     return true;
860 }
861
862
863 // Set the initial position based on presets (or defaults)
864 bool fgInitPosition() {
865     // cout << "fgInitPosition()" << endl;
866     double gs = fgGetDouble("/sim/presets/glideslope-deg")
867         * SG_DEGREES_TO_RADIANS ;
868     double od = fgGetDouble("/sim/presets/offset-distance-nm");
869     double alt = fgGetDouble("/sim/presets/altitude-ft");
870
871     bool set_pos = false;
872
873     // If glideslope is specified, then calculate offset-distance or
874     // altitude relative to glide slope if either of those was not
875     // specified.
876     if ( fabs( gs ) > 0.01 ) {
877         fgSetDistOrAltFromGlideSlope();
878     }
879
880
881     // If we have an explicit, in-range lon/lat, don't change it, just use it.
882     // If not, check for an airport-id and use that.
883     // If not, default to the middle of the KSFO field.
884     // The default values for lon/lat are deliberately out of range
885     // so that the airport-id can take effect; valid lon/lat will
886     // override airport-id, however.
887     double lon_deg = fgGetDouble("/sim/presets/longitude-deg");
888     double lat_deg = fgGetDouble("/sim/presets/latitude-deg");
889     if ( lon_deg >= -180.0 && lon_deg <= 180.0
890          && lat_deg >= -90.0 && lat_deg <= 90.0 )
891     {
892         set_pos = true;
893     }
894
895     string apt = fgGetString("/sim/presets/airport-id");
896     string rwy_no = fgGetString("/sim/presets/runway");
897     bool rwy_req = fgGetBool("/sim/presets/runway-requested");
898     string vor = fgGetString("/sim/presets/vor-id");
899     double vor_freq = fgGetDouble("/sim/presets/vor-freq");
900     string ndb = fgGetString("/sim/presets/ndb-id");
901     double ndb_freq = fgGetDouble("/sim/presets/ndb-freq");
902     string carrier = fgGetString("/sim/presets/carrier");
903     string parkpos = fgGetString("/sim/presets/parkpos");
904     string fix = fgGetString("/sim/presets/fix");
905     SGPropertyNode *hdg_preset = fgGetNode("/sim/presets/heading-deg", true);
906     double hdg = hdg_preset->getDoubleValue();
907
908     // save some start parameters, so that we can later say what the
909     // user really requested. TODO generalize that and move it to options.cxx
910     static bool start_options_saved = false;
911     if (!start_options_saved) {
912         start_options_saved = true;
913         SGPropertyNode *opt = fgGetNode("/sim/startup/options", true);
914
915         opt->setDoubleValue("latitude-deg", lat_deg);
916         opt->setDoubleValue("longitude-deg", lon_deg);
917         opt->setDoubleValue("heading-deg", hdg);
918         opt->setStringValue("airport", apt.c_str());
919         opt->setStringValue("runway", rwy_no.c_str());
920     }
921
922     if (hdg > 9990.0)
923         hdg = fgGetDouble("/environment/config/boundary/entry/wind-from-heading-deg", 270);
924
925     if ( !set_pos && !apt.empty() && !parkpos.empty() ) {
926         // An airport + parking position is requested
927         if ( fgSetPosFromAirportIDandParkpos( apt, parkpos ) ) {
928             // set tower position
929             fgSetString("/sim/airport/closest-airport-id",  apt.c_str());
930             fgSetString("/sim/tower/airport-id",  apt.c_str());
931             set_pos = true;
932         }
933     }
934
935     if ( !set_pos && !apt.empty() && !rwy_no.empty() ) {
936         // An airport + runway is requested
937         if ( fgSetPosFromAirportIDandRwy( apt, rwy_no, rwy_req ) ) {
938             // set tower position (a little off the heading for single
939             // runway airports)
940             fgSetString("/sim/airport/closest-airport-id",  apt.c_str());
941             fgSetString("/sim/tower/airport-id",  apt.c_str());
942             set_pos = true;
943         }
944     }
945
946     if ( !set_pos && !apt.empty() ) {
947         // An airport is requested (find runway closest to hdg)
948         if ( fgSetPosFromAirportIDandHdg( apt, hdg ) ) {
949             // set tower position (a little off the heading for single
950             // runway airports)
951             fgSetString("/sim/airport/closest-airport-id",  apt.c_str());
952             fgSetString("/sim/tower/airport-id",  apt.c_str());
953             set_pos = true;
954         }
955     }
956
957     if (hdg_preset->getDoubleValue() > 9990.0)
958         hdg_preset->setDoubleValue(hdg);
959
960     if ( !set_pos && !vor.empty() ) {
961         // a VOR is requested
962         if ( fgSetPosFromNAV( vor, vor_freq, FGPositioned::VOR ) ) {
963             set_pos = true;
964         }
965     }
966
967     if ( !set_pos && !ndb.empty() ) {
968         // an NDB is requested
969         if ( fgSetPosFromNAV( ndb, ndb_freq, FGPositioned::NDB ) ) {
970             set_pos = true;
971         }
972     }
973
974     if ( !set_pos && !carrier.empty() ) {
975         // an aircraft carrier is requested
976         if ( fgSetPosFromCarrier( carrier, parkpos ) ) {
977             set_pos = true;
978         }
979     }
980
981     if ( !set_pos && !fix.empty() ) {
982         // a Fix is requested
983         if ( fgSetPosFromFix( fix ) ) {
984             set_pos = true;
985         }
986     }
987
988     if ( !set_pos ) {
989         // No lon/lat specified, no airport specified, default to
990         // middle of KSFO field.
991         fgSetDouble("/sim/presets/longitude-deg", -122.374843);
992         fgSetDouble("/sim/presets/latitude-deg", 37.619002);
993     }
994
995     fgSetDouble( "/position/longitude-deg",
996                  fgGetDouble("/sim/presets/longitude-deg") );
997     fgSetDouble( "/position/latitude-deg",
998                  fgGetDouble("/sim/presets/latitude-deg") );
999     fgSetDouble( "/orientation/heading-deg", hdg_preset->getDoubleValue());
1000
1001     // determine if this should be an on-ground or in-air start
1002     if ((fabs(gs) > 0.01 || fabs(od) > 0.1 || alt > 0.1) && carrier.empty()) {
1003         fgSetBool("/sim/presets/onground", false);
1004     } else {
1005         fgSetBool("/sim/presets/onground", true);
1006     }
1007
1008     return true;
1009 }
1010
1011
1012 // General house keeping initializations
1013 bool fgInitGeneral() {
1014     string root;
1015
1016     SG_LOG( SG_GENERAL, SG_INFO, "General Initialization" );
1017     SG_LOG( SG_GENERAL, SG_INFO, "======= ==============" );
1018
1019     root = globals->get_fg_root();
1020     if ( ! root.length() ) {
1021         // No root path set? Then bail ...
1022         SG_LOG( SG_GENERAL, SG_ALERT,
1023                 "Cannot continue without a path to the base package "
1024                 << "being defined." );
1025         exit(-1);
1026     }
1027     SG_LOG( SG_GENERAL, SG_INFO, "FG_ROOT = " << '"' << root << '"' << endl );
1028
1029     globals->set_browser(fgGetString("/sim/startup/browser-app", "firefox %u"));
1030
1031     char buf[512], *cwd = getcwd(buf, 511);
1032     buf[511] = '\0';
1033     SGPropertyNode *curr = fgGetNode("/sim", true);
1034     curr->removeChild("fg-current", 0, false);
1035     curr = curr->getChild("fg-current", 0, true);
1036     curr->setStringValue(cwd ? cwd : "");
1037     curr->setAttribute(SGPropertyNode::WRITE, false);
1038
1039     fgSetBool("/sim/startup/stdout-to-terminal", isatty(1) != 0 );
1040     fgSetBool("/sim/startup/stderr-to-terminal", isatty(2) != 0 );
1041     return true;
1042 }
1043
1044 // This is the top level init routine which calls all the other
1045 // initialization routines.  If you are adding a subsystem to flight
1046 // gear, its initialization call should located in this routine.
1047 // Returns non-zero if a problem encountered.
1048 bool fgInitSubsystems() {
1049
1050     SG_LOG( SG_GENERAL, SG_INFO, "Initialize Subsystems");
1051     SG_LOG( SG_GENERAL, SG_INFO, "========== ==========");
1052
1053     ////////////////////////////////////////////////////////////////////
1054     // Initialize the sound subsystem.
1055     ////////////////////////////////////////////////////////////////////
1056     // Sound manager uses an own subsystem group "SOUND" which is the last
1057     // to be updated in every loop.
1058     // Sound manager is updated last so it can use the CPU while the GPU
1059     // is processing the scenery (doubled the frame-rate for me) -EMH-
1060     globals->add_subsystem("sound", new SGSoundMgr, SGSubsystemMgr::SOUND);
1061
1062     ////////////////////////////////////////////////////////////////////
1063     // Initialize the event manager subsystem.
1064     ////////////////////////////////////////////////////////////////////
1065
1066     globals->get_event_mgr()->init();
1067     globals->get_event_mgr()->setRealtimeProperty(fgGetNode("/sim/time/delta-realtime-sec", true));
1068
1069     ////////////////////////////////////////////////////////////////////
1070     // Initialize the property interpolator subsystem. Put into the INIT
1071     // group because the "nasal" subsystem may need it at GENERAL take-down.
1072     ////////////////////////////////////////////////////////////////////
1073     globals->add_subsystem("interpolator", new SGInterpolator, SGSubsystemMgr::INIT);
1074
1075
1076     ////////////////////////////////////////////////////////////////////
1077     // Add the FlightGear property utilities.
1078     ////////////////////////////////////////////////////////////////////
1079     globals->add_subsystem("properties", new FGProperties);
1080
1081
1082     ////////////////////////////////////////////////////////////////////
1083     // Add the performance monitoring system.
1084     ////////////////////////////////////////////////////////////////////
1085     globals->add_subsystem("performance-mon",
1086             new SGPerformanceMonitor(globals->get_subsystem_mgr(),
1087                                      fgGetNode("/sim/performance-monitor", true)));
1088
1089     ////////////////////////////////////////////////////////////////////
1090     // Initialize the material property subsystem.
1091     ////////////////////////////////////////////////////////////////////
1092
1093     SGPath mpath( globals->get_fg_root() );
1094     mpath.append( fgGetString("/sim/rendering/materials-file") );
1095     if ( ! globals->get_matlib()->load(globals->get_fg_root(), mpath.str(),
1096             globals->get_props()) ) {
1097         SG_LOG( SG_GENERAL, SG_ALERT,
1098                 "Error loading materials file " << mpath.str() );
1099         exit(-1);
1100     }
1101
1102
1103     ////////////////////////////////////////////////////////////////////
1104     // Initialize the scenery management subsystem.
1105     ////////////////////////////////////////////////////////////////////
1106
1107     globals->get_scenery()->get_scene_graph()
1108         ->addChild(simgear::Particles::getCommonRoot());
1109     simgear::GlobalParticleCallback::setSwitch(fgGetNode("/sim/rendering/particles", true));
1110
1111     ////////////////////////////////////////////////////////////////////
1112     // Initialize the flight model subsystem.
1113     ////////////////////////////////////////////////////////////////////
1114
1115     globals->add_subsystem("flight", new FDMShell, SGSubsystemMgr::FDM);
1116
1117     ////////////////////////////////////////////////////////////////////
1118     // Initialize the weather subsystem.
1119     ////////////////////////////////////////////////////////////////////
1120
1121     // Initialize the weather modeling subsystem
1122     globals->add_subsystem("environment", new FGEnvironmentMgr);
1123     globals->add_subsystem("ephemeris", new Ephemeris);
1124     
1125     ////////////////////////////////////////////////////////////////////
1126     // Initialize the aircraft systems and instrumentation (before the
1127     // autopilot.)
1128     ////////////////////////////////////////////////////////////////////
1129
1130     globals->add_subsystem("instrumentation", new FGInstrumentMgr, SGSubsystemMgr::FDM);
1131     globals->add_subsystem("systems", new FGSystemMgr, SGSubsystemMgr::FDM);
1132
1133     ////////////////////////////////////////////////////////////////////
1134     // Initialize the XML Autopilot subsystem.
1135     ////////////////////////////////////////////////////////////////////
1136
1137     globals->add_subsystem( "xml-autopilot", FGXMLAutopilotGroup::createInstance("autopilot"), SGSubsystemMgr::FDM );
1138     globals->add_subsystem( "xml-proprules", FGXMLAutopilotGroup::createInstance("property-rule"), SGSubsystemMgr::GENERAL );
1139     globals->add_subsystem( "route-manager", new FGRouteMgr );
1140
1141     ////////////////////////////////////////////////////////////////////
1142     // Initialize the Input-Output subsystem
1143     ////////////////////////////////////////////////////////////////////
1144     globals->add_subsystem( "io", new FGIO );
1145
1146     ////////////////////////////////////////////////////////////////////
1147     // Create and register the logger.
1148     ////////////////////////////////////////////////////////////////////
1149     
1150     globals->add_subsystem("logger", new FGLogger);
1151
1152     ////////////////////////////////////////////////////////////////////
1153     // Create and register the XML GUI.
1154     ////////////////////////////////////////////////////////////////////
1155
1156     globals->add_subsystem("gui", new NewGUI, SGSubsystemMgr::INIT);
1157
1158     //////////////////////////////////////////////////////////////////////
1159     // Initialize the 2D cloud subsystem.
1160     ////////////////////////////////////////////////////////////////////
1161     fgGetBool("/sim/rendering/bump-mapping", false);
1162
1163
1164
1165     ////////////////////////////////////////////////////////////////////
1166     // Initialise the ATC Manager
1167     // Note that this is old stuff, but might be necessesary for the 
1168     // current ATIS implementation. Therefore, leave it in here
1169     // until the ATIS system is ported over to make use of the ATIS 
1170     // sub system infrastructure.
1171     ////////////////////////////////////////////////////////////////////
1172
1173     globals->add_subsystem("ATC-old", new FGATCMgr, SGSubsystemMgr::INIT);
1174
1175     ////////////////////////////////////////////////////////////////////
1176    // Initialize the ATC subsystem
1177     ////////////////////////////////////////////////////////////////////
1178     globals->add_subsystem("ATC", new FGATCManager, SGSubsystemMgr::POST_FDM);
1179     ////////////////////////////////////////////////////////////////////
1180     // Initialise the ATIS Subsystem
1181     ////////////////////////////////////////////////////////////////////
1182     //globals->add_subsystem("atis", new FGAtisManager, SGSubsystemMgr::POST_FDM);
1183
1184
1185     ////////////////////////////////////////////////////////////////////
1186     // Initialize multiplayer subsystem
1187     ////////////////////////////////////////////////////////////////////
1188
1189     globals->add_subsystem("mp", new FGMultiplayMgr, SGSubsystemMgr::POST_FDM);
1190
1191     ////////////////////////////////////////////////////////////////////
1192     // Initialise the AI Model Manager
1193     ////////////////////////////////////////////////////////////////////
1194     SG_LOG(SG_GENERAL, SG_INFO, "  AI Model Manager");
1195     globals->add_subsystem("ai-model", new FGAIManager, SGSubsystemMgr::POST_FDM);
1196     globals->add_subsystem("submodel-mgr", new FGSubmodelMgr, SGSubsystemMgr::POST_FDM);
1197
1198
1199     // It's probably a good idea to initialize the top level traffic manager
1200     // After the AI and ATC systems have been initialized properly.
1201     // AI Traffic manager
1202     globals->add_subsystem("traffic-manager", new FGTrafficManager, SGSubsystemMgr::POST_FDM);
1203
1204     ////////////////////////////////////////////////////////////////////
1205     // Add a new 2D panel.
1206     ////////////////////////////////////////////////////////////////////
1207
1208     string panel_path(fgGetString("/sim/panel/path"));
1209     if (!panel_path.empty()) {
1210       FGPanel* p = fgReadPanel(panel_path);
1211       if (p) {
1212         globals->set_current_panel(p);
1213         p->init();
1214         p->bind();
1215         SG_LOG( SG_INPUT, SG_INFO, "Loaded new panel from " << panel_path );
1216       } else {
1217         SG_LOG( SG_INPUT, SG_ALERT,
1218                 "Error reading new panel from " << panel_path );
1219       }
1220     }
1221
1222     ////////////////////////////////////////////////////////////////////
1223     // Initialize the controls subsystem.
1224     ////////////////////////////////////////////////////////////////////
1225
1226     globals->get_controls()->init();
1227     globals->get_controls()->bind();
1228
1229
1230     ////////////////////////////////////////////////////////////////////
1231     // Initialize the input subsystem.
1232     ////////////////////////////////////////////////////////////////////
1233
1234     globals->add_subsystem("input", new FGInput);
1235
1236
1237     ////////////////////////////////////////////////////////////////////
1238     // Initialize the replay subsystem
1239     ////////////////////////////////////////////////////////////////////
1240     globals->add_subsystem("replay", new FGReplay);
1241
1242 #ifdef ENABLE_AUDIO_SUPPORT
1243     ////////////////////////////////////////////////////////////////////
1244     // Initialize the sound-effects subsystem.
1245     ////////////////////////////////////////////////////////////////////
1246     globals->add_subsystem("voice", new FGVoiceMgr, SGSubsystemMgr::DISPLAY);
1247 #endif
1248
1249     ////////////////////////////////////////////////////////////////////
1250     // Initialize the lighting subsystem.
1251     ////////////////////////////////////////////////////////////////////
1252
1253     globals->add_subsystem("lighting", new FGLight, SGSubsystemMgr::DISPLAY);
1254     
1255     // ordering here is important : Nasal (via events), then models, then views
1256     globals->add_subsystem("events", globals->get_event_mgr(), SGSubsystemMgr::DISPLAY);
1257     
1258     FGAircraftModel* acm = new FGAircraftModel;
1259     globals->set_aircraft_model(acm);
1260     globals->add_subsystem("aircraft-model", acm, SGSubsystemMgr::DISPLAY);
1261
1262     FGModelMgr* mm = new FGModelMgr;
1263     globals->set_model_mgr(mm);
1264     globals->add_subsystem("model-manager", mm, SGSubsystemMgr::DISPLAY);
1265
1266     FGViewMgr *viewmgr = new FGViewMgr;
1267     globals->set_viewmgr( viewmgr );
1268     globals->add_subsystem("view-manager", viewmgr, SGSubsystemMgr::DISPLAY);
1269
1270     globals->add_subsystem("tile-manager", globals->get_tile_mgr(), 
1271       SGSubsystemMgr::DISPLAY);
1272       
1273     ////////////////////////////////////////////////////////////////////
1274     // Bind and initialize subsystems.
1275     ////////////////////////////////////////////////////////////////////
1276
1277     globals->get_subsystem_mgr()->bind();
1278     globals->get_subsystem_mgr()->init();
1279
1280     ////////////////////////////////////////////////////////////////////////
1281     // Initialize the Nasal interpreter.
1282     // Do this last, so that the loaded scripts see initialized state
1283     ////////////////////////////////////////////////////////////////////////
1284     FGNasalSys* nasal = new FGNasalSys();
1285     globals->add_subsystem("nasal", nasal, SGSubsystemMgr::INIT);
1286     nasal->init();
1287
1288     // initialize methods that depend on other subsystems.
1289     globals->get_subsystem_mgr()->postinit();
1290
1291     ////////////////////////////////////////////////////////////////////////
1292     // End of subsystem initialization.
1293     ////////////////////////////////////////////////////////////////////
1294
1295     fgSetBool("/sim/crashed", false);
1296     fgSetBool("/sim/initialized", true);
1297
1298     SG_LOG( SG_GENERAL, SG_INFO, endl);
1299
1300                                 // Save the initial state for future
1301                                 // reference.
1302     globals->saveInitialState();
1303     
1304     return true;
1305 }
1306
1307 // Reset: this is what the 'reset' command (and hence, GUI) is attached to
1308 void fgReInitSubsystems()
1309 {
1310     static const SGPropertyNode *master_freeze
1311         = fgGetNode("/sim/freeze/master");
1312
1313     SG_LOG( SG_GENERAL, SG_INFO, "fgReInitSubsystems()");
1314
1315 // setup state to begin re-init
1316     bool freeze = master_freeze->getBoolValue();
1317     if ( !freeze ) {
1318         fgSetBool("/sim/freeze/master", true);
1319     }
1320     
1321     fgSetBool("/sim/signals/reinit", true);
1322     fgSetBool("/sim/crashed", false);
1323
1324 // do actual re-init steps
1325     globals->get_subsystem("flight")->unbind();
1326     
1327   // reset control state, before restoring initial state; -set or config files
1328   // may specify values for flaps, trim tabs, magnetos, etc
1329     globals->get_controls()->reset_all();
1330         
1331     globals->restoreInitialState();
1332
1333     // update our position based on current presets
1334     fgInitPosition();
1335     
1336     // Force reupdating the positions of the ai 3d models. They are used for
1337     // initializing ground level for the FDM.
1338     globals->get_subsystem("ai-model")->reinit();
1339
1340     // Initialize the FDM
1341     globals->get_subsystem("flight")->reinit();
1342
1343     // reset replay buffers
1344     globals->get_subsystem("replay")->reinit();
1345     
1346     // reload offsets from config defaults
1347     globals->get_viewmgr()->reinit();
1348
1349     globals->get_subsystem("time")->reinit();
1350
1351     // need to bind FDMshell again, since we manually unbound it above...
1352     globals->get_subsystem("flight")->bind();
1353
1354 // setup state to end re-init
1355     fgSetBool("/sim/signals/reinit", false);
1356     if ( !freeze ) {
1357         fgSetBool("/sim/freeze/master", false);
1358     }
1359     fgSetBool("/sim/sceneryloaded",false);
1360 }
1361
1362
1363 ///////////////////////////////////////////////////////////////////////////////
1364 // helper object to implement the --show-aircraft command.
1365 // resides here so we can share the fgFindAircraftInDir template above,
1366 // and hence ensure this command lists exectly the same aircraft as the normal
1367 // loading path.
1368 class ShowAircraft 
1369 {
1370 public:
1371   ShowAircraft()
1372   {
1373     _minStatus = getNumMaturity(fgGetString("/sim/aircraft-min-status", "all"));
1374   }
1375   
1376   
1377   void show(const SGPath& path)
1378   {
1379     fgFindAircraftInDir(path, this, &ShowAircraft::processAircraft);
1380   
1381     std::sort(_aircraft.begin(), _aircraft.end(), ciLessLibC());
1382     SG_LOG( SG_GENERAL, SG_ALERT, "" ); // To popup the console on Windows
1383     cout << "Available aircraft:" << endl;
1384     for ( unsigned int i = 0; i < _aircraft.size(); i++ ) {
1385         cout << _aircraft[i] << endl;
1386     }
1387   }
1388   
1389 private:
1390   bool processAircraft(const SGPath& path)
1391   {
1392     SGPropertyNode root;
1393     try {
1394        readProperties(path.str(), &root);
1395     } catch (sg_exception& ) {
1396        return false;
1397     }
1398   
1399     int maturity = 0;
1400     string descStr("   ");
1401     descStr += path.file();
1402   // trim common suffix from file names
1403     int nPos = descStr.rfind("-set.xml");
1404     if (nPos == (int)(descStr.size() - 8)) {
1405       descStr.resize(nPos);
1406     }
1407     
1408     SGPropertyNode *node = root.getNode("sim");
1409     if (node) {
1410       SGPropertyNode* desc = node->getNode("description");
1411       // if a status tag is found, read it in
1412       if (node->hasValue("status")) {
1413         maturity = getNumMaturity(node->getStringValue("status"));
1414       }
1415       
1416       if (desc) {
1417         if (descStr.size() <= 27+3) {
1418           descStr.append(29+3-descStr.size(), ' ');
1419         } else {
1420           descStr += '\n';
1421           descStr.append( 32, ' ');
1422         }
1423         descStr += desc->getStringValue();
1424       }
1425     } // of have 'sim' node
1426     
1427     if (maturity < _minStatus) {
1428       return false;
1429     }
1430
1431     _aircraft.push_back(descStr);
1432     return false;
1433   }
1434
1435
1436   int getNumMaturity(const char * str) 
1437   {
1438     // changes should also be reflected in $FG_ROOT/data/options.xml & 
1439     // $FG_ROOT/data/Translations/string-default.xml
1440     const char* levels[] = {"alpha","beta","early-production","production"}; 
1441
1442     if (!strcmp(str, "all")) {
1443       return 0;
1444     }
1445
1446     for (size_t i=0; i<(sizeof(levels)/sizeof(levels[0]));i++) 
1447       if (strcmp(str,levels[i])==0)
1448         return i;
1449
1450     return 0;
1451   }
1452
1453   // recommended in Meyers, Effective STL when internationalization and embedded
1454   // NULLs aren't an issue.  Much faster than the STL or Boost lex versions.
1455   struct ciLessLibC : public std::binary_function<string, string, bool>
1456   {
1457     bool operator()(const std::string &lhs, const std::string &rhs) const
1458     {
1459       return strcasecmp(lhs.c_str(), rhs.c_str()) < 0 ? 1 : 0;
1460     }
1461   };
1462
1463   int _minStatus;
1464   string_list _aircraft;
1465 };
1466
1467 void fgShowAircraft(const SGPath &path)
1468 {
1469     ShowAircraft s;
1470     s.show(path);
1471         
1472 #ifdef _MSC_VER
1473     cout << "Hit a key to continue..." << endl;
1474     cin.get();
1475 #endif
1476 }
1477
1478