]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_init.cxx
834c2dc6cf7536591a80375ad5f86104c0f1a88a
[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., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 //
22 // $Id$
23
24
25 #ifdef HAVE_CONFIG_H
26 #  include <config.h>
27 #endif
28
29 // For BC 5.01 this must be included before OpenGL includes.
30 #ifdef SG_MATH_EXCEPTION_CLASH
31 #  include <math.h>
32 #endif
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>             // strcmp()
37
38 #if defined( unix ) || defined( __CYGWIN__ )
39 #  include <unistd.h>           // for gethostname()
40 #endif
41
42 // work around a stdc++ lib bug in some versions of linux, but doesn't
43 // seem to hurt to have this here for all versions of Linux.
44 #ifdef linux
45 #  define _G_NO_EXTERN_TEMPLATES
46 #endif
47
48 #include <simgear/compiler.h>
49
50 #include STL_STRING
51
52 #include <simgear/constants.h>
53 #include <simgear/debug/logstream.hxx>
54 #include <simgear/structure/exception.hxx>
55 #include <simgear/structure/event_mgr.hxx>
56 #include <simgear/math/point3d.hxx>
57 #include <simgear/math/polar3d.hxx>
58 #include <simgear/math/sg_geodesy.hxx>
59 #include <simgear/misc/sg_path.hxx>
60 #include <simgear/misc/interpolator.hxx>
61 #include <simgear/scene/material/matlib.hxx>
62 #include <simgear/timing/sg_time.hxx>
63 #include <simgear/timing/lowleveltime.h>
64
65 #include <Aircraft/aircraft.hxx>
66 #include <Aircraft/replay.hxx>
67 #include <Airports/apt_loader.hxx>
68 #include <Airports/runways.hxx>
69 #include <Airports/simple.hxx>
70 #include <AIModel/AIManager.hxx>
71 #include <ATC/ATCdisplay.hxx>
72 #include <ATC/ATCmgr.hxx>
73 #include <ATC/AIMgr.hxx>
74 #include <Autopilot/auto_gui.hxx>
75 #include <Autopilot/route_mgr.hxx>
76 #include <Autopilot/xmlauto.hxx>
77 #include <Cockpit/cockpit.hxx>
78 #include <Cockpit/panel.hxx>
79 #include <Cockpit/panel_io.hxx>
80 #ifdef ENABLE_SP_FMDS
81 #include <FDM/SP/ADA.hxx>
82 #include <FDM/SP/ACMS.hxx>
83 #endif
84 #include <FDM/Balloon.h>
85 #include <FDM/ExternalNet/ExternalNet.hxx>
86 #include <FDM/ExternalPipe/ExternalPipe.hxx>
87 #include <FDM/JSBSim/JSBSim.hxx>
88 #include <FDM/LaRCsim/LaRCsim.hxx>
89 #include <FDM/MagicCarpet.hxx>
90 #include <FDM/UFO.hxx>
91 #include <FDM/NullFDM.hxx>
92 #include <FDM/YASim/YASim.hxx>
93 #include <GUI/new_gui.hxx>
94 #include <Include/general.hxx>
95 #include <Input/input.hxx>
96 #include <Instrumentation/instrument_mgr.hxx>
97 #include <Model/acmodel.hxx>
98 #include <AIModel/submodel.hxx>
99 #include <AIModel/AIManager.hxx>
100 #include <Navaids/navdb.hxx>
101 #include <Navaids/navlist.hxx>
102 #include <Scenery/scenery.hxx>
103 #include <Scenery/tilemgr.hxx>
104 #include <Scripting/NasalSys.hxx>
105 #include <Sound/fg_fx.hxx>
106 #include <Sound/beacon.hxx>
107 #include <Sound/morse.hxx>
108 #include <Systems/system_mgr.hxx>
109 #include <Time/light.hxx>
110 #include <Time/sunsolver.hxx>
111 #include <Time/tmp.hxx>
112 #include <Traffic/TrafficMgr.hxx>
113
114 #ifdef FG_MPLAYER_AS
115 #include <MultiPlayer/multiplaymgr.hxx>
116 #endif
117
118 #include <Environment/environment_mgr.hxx>
119
120 #include "fg_init.hxx"
121 #include "fg_io.hxx"
122 #include "fg_commands.hxx"
123 #include "fg_props.hxx"
124 #include "options.hxx"
125 #include "globals.hxx"
126 #include "logger.hxx"
127 #include "viewmgr.hxx"
128 #include "main.hxx"
129
130 #if defined(FX) && defined(XMESA)
131 #include <GL/xmesa.h>
132 #endif
133
134 SG_USING_STD(string);
135
136
137 class Sound;
138 extern const char *default_root;
139 float init_volume;
140
141
142 // Scan the command line options for the specified option and return
143 // the value.
144 static string fgScanForOption( const string& option, int argc, char **argv ) {
145     int i = 1;
146
147     if (hostname == NULL)
148     {
149         char _hostname[256];
150         gethostname(_hostname, 256);
151         hostname = strdup(_hostname);
152         free_hostname = true;
153     }
154
155     SG_LOG(SG_GENERAL, SG_INFO, "Scanning command line for: " << option );
156
157     int len = option.length();
158
159     while ( i < argc ) {
160         SG_LOG( SG_GENERAL, SG_DEBUG, "argv[" << i << "] = " << argv[i] );
161
162         string arg = argv[i];
163         if ( arg.find( option ) == 0 ) {
164             return arg.substr( len );
165         }
166
167         i++;
168     }
169
170     return "";
171 }
172
173
174 // Scan the user config files for the specified option and return
175 // the value.
176 static string fgScanForOption( const string& option, const string& path ) {
177     sg_gzifstream in( path );
178     if ( !in.is_open() ) {
179         return "";
180     }
181
182     SG_LOG( SG_GENERAL, SG_INFO, "Scanning " << path << " for: " << option );
183
184     int len = option.length();
185
186     in >> skipcomment;
187 #ifndef __MWERKS__
188     while ( ! in.eof() ) {
189 #else
190     char c = '\0';
191     while ( in.get(c) && c != '\0' ) {
192         in.putback(c);
193 #endif
194         string line;
195
196 #if defined( macintosh )
197         getline( in, line, '\r' );
198 #else
199         getline( in, line, '\n' );
200 #endif
201
202         // catch extraneous (DOS) line ending character
203         if ( line[line.length() - 1] < 32 ) {
204             line = line.substr( 0, line.length()-1 );
205         }
206
207         if ( line.find( option ) == 0 ) {
208             return line.substr( len );
209         }
210
211         in >> skipcomment;
212     }
213
214     return "";
215 }
216
217 // Scan the user config files for the specified option and return
218 // the value.
219 static string fgScanForOption( const string& option ) {
220     string arg("");
221
222 #if defined( unix ) || defined( __CYGWIN__ )
223     // Next check home directory for .fgfsrc.hostname file
224     if ( arg.empty() ) {
225         if ( homedir != NULL ) {
226             SGPath config( homedir );
227             config.append( ".fgfsrc" );
228             config.concat( "." );
229             config.concat( hostname );
230             arg = fgScanForOption( option, config.str() );
231         }
232     }
233 #endif
234
235     // Next check home directory for .fgfsrc file
236     if ( arg.empty() ) {
237         if ( homedir != NULL ) {
238             SGPath config( homedir );
239             config.append( ".fgfsrc" );
240             arg = fgScanForOption( option, config.str() );
241         }
242     }
243
244     if ( arg.empty() ) {
245         // Check for $fg_root/system.fgfsrc
246         SGPath config( globals->get_fg_root() );
247         config.append( "system.fgfsrc" );
248         arg = fgScanForOption( option, config.str() );
249     }
250
251     return arg;
252 }
253
254
255 // Read in configuration (files and command line options) but only set
256 // fg_root
257 bool fgInitFGRoot ( int argc, char **argv ) {
258     string root;
259
260     // First parse command line options looking for --fg-root=, this
261     // will override anything specified in a config file
262     root = fgScanForOption( "--fg-root=", argc, argv);
263
264     // Check in one of the user configuration files.
265     if (root.empty() )
266         root = fgScanForOption( "--fg-root=" );
267     
268     // Next check if fg-root is set as an env variable
269     if ( root.empty() ) {
270         char *envp = ::getenv( "FG_ROOT" );
271         if ( envp != NULL ) {
272             root = envp;
273         }
274     }
275
276     // Otherwise, default to a random compiled-in location if we can't
277     // find fg-root any other way.
278     if ( root.empty() ) {
279 #if defined( __CYGWIN__ )
280         root = "/FlightGear";
281 #elif defined( WIN32 )
282         root = "\\FlightGear";
283 #elif defined(OSX_BUNDLE) 
284         /* the following code looks for the base package directly inside
285             the application bundle. This can be changed fairly easily by
286             fiddling with the code below. And yes, I know it's ugly and verbose.
287         */
288         CFBundleRef appBundle = CFBundleGetMainBundle();
289         CFURLRef appUrl = CFBundleCopyBundleURL(appBundle);
290         CFRelease(appBundle);
291
292         // look for a 'data' subdir directly inside the bundle : is there
293         // a better place? maybe in Resources? I don't know ...
294         CFURLRef dataDir = CFURLCreateCopyAppendingPathComponent(NULL, appUrl, CFSTR("data"), true);
295
296         // now convert down to a path, and the a c-string
297         CFStringRef path = CFURLCopyFileSystemPath(dataDir, kCFURLPOSIXPathStyle);
298         root = CFStringGetCStringPtr(path, CFStringGetSystemEncoding());
299
300         // tidy up.
301         CFRelease(appBundle);
302         CFRelease(dataDir);
303         CFRelease(path);
304 #else
305         root = PKGLIBDIR;
306 #endif
307     }
308
309     SG_LOG(SG_INPUT, SG_INFO, "fg_root = " << root );
310     globals->set_fg_root(root);
311
312     return true;
313 }
314
315
316 // Read in configuration (files and command line options) but only set
317 // aircraft
318 bool fgInitFGAircraft ( int argc, char **argv ) {
319     string aircraft;
320
321     // First parse command line options looking for --aircraft=, this
322     // will override anything specified in a config file
323     aircraft = fgScanForOption( "--aircraft=", argc, argv );
324
325     // Check in one of the user configuration files.
326     if ( aircraft.empty() )
327         aircraft = fgScanForOption( "--aircraft=" );
328
329     // if an aircraft was specified, set the property name
330     if ( !aircraft.empty() ) {
331         SG_LOG(SG_INPUT, SG_INFO, "aircraft = " << aircraft );
332         fgSetString("/sim/aircraft", aircraft.c_str() );
333     } else {
334         SG_LOG(SG_INPUT, SG_INFO, "No user specified aircraft, using default" );
335     }
336
337     return true;
338 }
339
340
341 // Return the current base package version
342 string fgBasePackageVersion() {
343     SGPath base_path( globals->get_fg_root() );
344     base_path.append("version");
345
346     sg_gzifstream in( base_path.str() );
347     if ( !in.is_open() ) {
348         SGPath old_path( globals->get_fg_root() );
349         old_path.append( "Thanks" );
350         sg_gzifstream old( old_path.str() );
351         if ( !old.is_open() ) {
352             return "[none]";
353         } else {
354             return "[old version]";
355         }
356     }
357
358     string version;
359     in >> version;
360
361     return version;
362 }
363
364
365 // Initialize the localization
366 SGPropertyNode *fgInitLocale(const char *language) {
367    SGPropertyNode *c_node = NULL, *d_node = NULL;
368    SGPropertyNode *intl = fgGetNode("/sim/intl");
369
370    SG_LOG(SG_GENERAL, SG_INFO, "Selecting language: " << language );
371
372    // localization not defined
373    if (!intl)
374       return NULL;
375
376    //
377    // Select the proper language from the list
378    //
379    vector<SGPropertyNode_ptr> locale = intl->getChildren("locale");
380    for (unsigned int i = 0; i < locale.size(); i++) {
381
382       vector<SGPropertyNode_ptr> lang = locale[i]->getChildren("lang");
383       for (unsigned int j = 0; j < lang.size(); j++) {
384
385          if (!strcmp(lang[j]->getStringValue(), language)) {
386             c_node = locale[i];
387             break;
388          }
389       }
390    }
391
392
393    // Get the defaults
394    d_node = intl->getChild("locale");
395    if (!c_node)
396       c_node = d_node;
397
398    // Check for localized font
399    SGPropertyNode *font_n = c_node->getNode("font", true);
400    if ( !strcmp(font_n->getStringValue(), "") )
401       font_n->setStringValue(d_node->getStringValue("font", "typewriter.txf"));
402
403
404    //
405    // Load the default strings
406    //
407    SGPath d_path( globals->get_fg_root() );
408
409    const char *d_path_str = d_node->getStringValue("strings");
410    if (!d_path_str) {
411       SG_LOG(SG_GENERAL, SG_ALERT, "Incorrect path in configuration file.");
412       return NULL;
413    }
414
415    d_path.append(d_path_str);
416    SG_LOG(SG_GENERAL, SG_INFO, "Reading localized strings from "
417                                   << d_path.str());
418
419    SGPropertyNode *strings = c_node->getNode("strings");
420    try {
421       readProperties(d_path.str(), strings);
422    } catch (const sg_exception &e) {
423       SG_LOG(SG_GENERAL, SG_ALERT, "Unable to read the localized strings");
424       return NULL;
425    }
426
427    //
428    // Load the language specific strings
429    //
430    if (c_node != d_node) {
431       SGPath c_path( globals->get_fg_root() );
432
433       const char *c_path_str = c_node->getStringValue("strings");
434       if (!c_path_str) {
435          SG_LOG(SG_GENERAL, SG_ALERT, "Incorrect path in configuration file.");
436          return NULL;
437       }
438
439       c_path.append(c_path_str);
440       SG_LOG(SG_GENERAL, SG_INFO, "Reading localized strings from "
441                                      << c_path.str());
442
443       try {
444          readProperties(c_path.str(), strings);
445       } catch (const sg_exception &e) {
446          SG_LOG(SG_GENERAL, SG_ALERT, "Unable to read the localized strings");
447          return NULL;
448       }
449    }
450
451    return c_node;
452 }
453
454
455
456 // Initialize the localization routines
457 bool fgDetectLanguage() {
458     char *language = ::getenv("LANG");
459
460     if (language == NULL) {
461         SG_LOG(SG_GENERAL, SG_INFO, "Unable to detect the language" );
462         language = "C";
463     }
464
465     SGPropertyNode *locale = fgInitLocale(language);
466     if (!locale) {
467        SG_LOG(SG_GENERAL, SG_ALERT,
468               "No internationalization settings specified in preferences.xml" );
469
470        return false;
471     }
472
473     globals->set_locale( locale );
474
475     return true;
476 }
477
478 // Attempt to locate and parse the various non-XML config files in order
479 // from least precidence to greatest precidence
480 static void
481 do_options (int argc, char ** argv)
482 {
483     // Check for $fg_root/system.fgfsrc
484     SGPath config( globals->get_fg_root() );
485     config.append( "system.fgfsrc" );
486     fgParseOptions(config.str());
487
488 #if defined( unix ) || defined( __CYGWIN__ )
489     config.concat( "." );
490     config.concat( hostname );
491     fgParseOptions(config.str());
492 #endif
493
494     // Check for ~/.fgfsrc
495     if ( homedir != NULL ) {
496         config.set( homedir );
497         config.append( ".fgfsrc" );
498         fgParseOptions(config.str());
499     }
500
501 #if defined( unix ) || defined( __CYGWIN__ )
502     // Check for ~/.fgfsrc.hostname
503     config.concat( "." );
504     config.concat( hostname );
505     fgParseOptions(config.str());
506 #endif
507
508     // Parse remaining command line options
509     // These will override anything specified in a config file
510     fgParseArgs(argc, argv);
511 }
512
513
514 static string fgFindAircraftPath( const SGPath &path, const string &aircraft ) {
515     ulDirEnt* dire;
516     ulDir *dirp = ulOpenDir(path.str().c_str());
517     if (dirp == NULL) {
518         cerr << "Unable to open aircraft directory '" << path.str() << '\'' << endl;
519         exit(-1);
520     }
521
522     while ((dire = ulReadDir(dirp)) != NULL) {
523         if (dire->d_isdir) {
524             if ( strcmp("CVS", dire->d_name) && strcmp(".", dire->d_name)
525                  && strcmp("..", dire->d_name) )
526             {
527                 SGPath next = path;
528                 next.append(dire->d_name);
529
530                 string result = fgFindAircraftPath( next, aircraft );
531                 if ( ! result.empty() ) {
532                     return result;
533                 }
534             }
535         } else if ( !strcmp(dire->d_name, aircraft.c_str()) ) {
536             return path.str();
537         }
538     }
539
540     ulCloseDir(dirp);
541
542     return "";
543 }
544
545
546 // Read in configuration (file and command line)
547 bool fgInitConfig ( int argc, char **argv ) {
548
549     // First, set some sane default values
550     fgSetDefaults();
551
552     // Read global preferences from $FG_ROOT/preferences.xml
553     SG_LOG(SG_INPUT, SG_INFO, "Reading global preferences");
554     fgLoadProps("preferences.xml", globals->get_props());
555     SG_LOG(SG_INPUT, SG_INFO, "Finished Reading global preferences");
556
557     // Detect the required language as early as possible
558     if ( !fgDetectLanguage() ) {
559         return false;
560     }
561
562     // Scan user config files and command line for a specified aircraft.
563     fgInitFGAircraft(argc, argv);
564
565     string aircraft = fgGetString( "/sim/aircraft", "" );
566     if ( aircraft.size() > 0 ) {
567         SGPath aircraft_search( globals->get_fg_root() );
568         aircraft_search.append( "Aircraft" );
569
570         string aircraft_set = aircraft + "-set.xml";
571
572         string result = fgFindAircraftPath( aircraft_search, aircraft_set );
573         if ( !result.empty() ) {
574             fgSetString( "/sim/aircraft-dir", result.c_str() );
575             SGPath full_name( result );
576             full_name.append( aircraft_set );
577
578             SG_LOG(SG_INPUT, SG_INFO, "Reading default aircraft: " << aircraft
579                    << " from " << full_name.str());
580             try {
581                 readProperties( full_name.str(), globals->get_props() );
582             } catch ( const sg_exception &e ) {
583                 string message = "Error reading default aircraft: ";
584                 message += e.getFormattedMessage();
585                 SG_LOG(SG_INPUT, SG_ALERT, message);
586                 exit(2);
587             }
588         } else {
589             SG_LOG( SG_INPUT, SG_ALERT, "Cannot find specified aircraft: "
590                     << aircraft );
591             return false;
592         }
593
594     } else {
595         SG_LOG( SG_INPUT, SG_ALERT, "No default aircraft specified" );
596     }
597
598 #ifdef _MSC_VER
599     char *envp = ::getenv( "APPDATA" );
600     if (envp != NULL ) {
601         SGPath config( envp );
602         config.append( "flightgear.org" );
603 #else
604     if ( homedir != NULL ) {
605         SGPath config( homedir );
606         config.append( ".fgfs" );
607 #endif
608         config.append( "preferences.xml" );
609         SG_LOG(SG_INPUT, SG_INFO, "Reading user preferences");
610         try {
611             fgLoadProps(config.str().c_str(), globals->get_props(), false,
612                         SGPropertyNode::USERARCHIVE);
613         } catch (...) {
614             SG_LOG(SG_INPUT, SG_BULK, "First time reading user preferences.");
615         }
616         SG_LOG(SG_INPUT, SG_BULK, "Finished Reading user preferences");
617     }
618
619     // parse options after loading aircraft to ensure any user
620     // overrides of defaults are honored.
621     do_options(argc, argv);
622
623     return true;
624 }
625
626
627
628
629
630 #if 0 
631   // 
632   // This function is never used, but maybe useful in the future ???
633   //
634
635 // Preset lon/lat given an airport id
636 static bool fgSetPosFromAirportID( const string& id ) {
637     FGAirport *a;
638     // double lon, lat;
639
640     SG_LOG( SG_GENERAL, SG_INFO,
641             "Attempting to set starting position from airport code " << id );
642
643     if ( fgFindAirportID( id, &a ) ) {
644         // presets
645         fgSetDouble("/sim/presets/longitude-deg", a->longitude );
646         fgSetDouble("/sim/presets/latitude-deg", a->latitude );
647
648         // other code depends on the actual postition being set so set
649         // that as well
650         fgSetDouble("/position/longitude-deg", a->longitude );
651         fgSetDouble("/position/latitude-deg", a->latitude );
652
653         SG_LOG( SG_GENERAL, SG_INFO,
654                 "Position for " << id << " is (" << a->longitude
655                 << ", " << a->latitude << ")" );
656
657         return true;
658     } else {
659         return false;
660     }
661 }
662 #endif
663
664
665 // Set current tower position lon/lat given an airport id
666 static bool fgSetTowerPosFromAirportID( const string& id, double hdg ) {
667     
668     // tower height hard coded for now...
669     float towerheight=50.0f;
670
671     // make a little off the heading for 1 runway airports...
672     float fudge_lon = fabs(sin(hdg)) * .003f;
673     float fudge_lat = .003f - fudge_lon;
674
675     const FGAirport *a = fgFindAirportID( id);
676     if ( a) {
677         fgSetDouble("/sim/tower/longitude-deg",  a->getLongitude() + fudge_lon);
678         fgSetDouble("/sim/tower/latitude-deg",  a->getLatitude() + fudge_lat);
679         fgSetDouble("/sim/tower/altitude-ft", a->getElevation() + towerheight);
680         return true;
681     } else {
682         return false;
683     }
684
685 }
686
687 struct FGTowerLocationListener : SGPropertyChangeListener {
688     void valueChanged(SGPropertyNode* node) {
689         const double hdg = fgGetDouble( "/orientation/heading-deg", 0);
690         const string id(node->getStringValue());
691         fgSetTowerPosFromAirportID(id, hdg);
692     }
693 };
694
695 static void fgInitTowerLocationListener() {
696     fgGetNode("/sim/tower/airport-id",  true)
697         ->addChangeListener( new FGTowerLocationListener() );
698 }
699
700 // Set current_options lon/lat given an airport id and heading (degrees)
701 static bool fgSetPosFromAirportIDandHdg( const string& id, double tgt_hdg ) {
702     FGRunway r;
703
704     if ( id.length() ) {
705         // set initial position from runway and heading
706
707         SG_LOG( SG_GENERAL, SG_INFO,
708                 "Attempting to set starting position from airport code "
709                 << id << " heading " << tgt_hdg );
710                 
711         if ( ! globals->get_runways()->search( id, (int)tgt_hdg, &r ) ) {
712             SG_LOG( SG_GENERAL, SG_ALERT,
713                     "Failed to find a good runway for " << id << '\n' );
714             return false;
715         }       
716     } else {
717         return false;
718     }
719
720     double lat2, lon2, az2;
721     double heading = r._heading;
722     double azimuth = heading + 180.0;
723     while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
724
725     SG_LOG( SG_GENERAL, SG_INFO,
726             "runway =  " << r._lon << ", " << r._lat
727             << " length = " << r._length * SG_FEET_TO_METER 
728             << " heading = " << azimuth );
729             
730     geo_direct_wgs_84 ( 0, r._lat, r._lon, azimuth, 
731                         r._length * SG_FEET_TO_METER * 0.5 - 5.0,
732                         &lat2, &lon2, &az2 );
733
734     if ( fabs( fgGetDouble("/sim/presets/offset-distance") ) > SG_EPSILON ) {
735         double olat, olon;
736         double odist = fgGetDouble("/sim/presets/offset-distance");
737         odist *= SG_NM_TO_METER;
738         double oaz = azimuth;
739         if ( fabs(fgGetDouble("/sim/presets/offset-azimuth")) > SG_EPSILON ) {
740             oaz = fgGetDouble("/sim/presets/offset-azimuth") + 180;
741             heading = tgt_hdg;
742         }
743         while ( oaz >= 360.0 ) { oaz -= 360.0; }
744         geo_direct_wgs_84 ( 0, lat2, lon2, oaz, odist, &olat, &olon, &az2 );
745         lat2=olat;
746         lon2=olon;
747     }
748
749     // presets
750     fgSetDouble("/sim/presets/longitude-deg",  lon2 );
751     fgSetDouble("/sim/presets/latitude-deg",  lat2 );
752     fgSetDouble("/sim/presets/heading-deg", heading );
753
754     // other code depends on the actual values being set ...
755     fgSetDouble("/position/longitude-deg",  lon2 );
756     fgSetDouble("/position/latitude-deg",  lat2 );
757     fgSetDouble("/orientation/heading-deg", heading );
758
759     SG_LOG( SG_GENERAL, SG_INFO,
760             "Position for " << id << " is ("
761             << lon2 << ", "
762             << lat2 << ") new heading is "
763             << heading );
764             
765     return true;
766 }
767
768
769 // Set current_options lon/lat given an airport id and runway number
770 static bool fgSetPosFromAirportIDandRwy( const string& id, const string& rwy ) {
771     FGRunway r;
772
773     if ( id.length() ) {
774         // set initial position from airport and runway number
775
776         SG_LOG( SG_GENERAL, SG_INFO,
777                 "Attempting to set starting position for "
778                 << id << ":" << rwy );
779
780         if ( ! globals->get_runways()->search( id, rwy, &r ) ) {
781             SG_LOG( SG_GENERAL, SG_ALERT,
782                     "Failed to find runway " << rwy << 
783                     " at airport " << id );
784             return false;
785         }
786     } else {
787         return false;
788     }
789
790     double lat2, lon2, az2;
791     double heading = r._heading;
792     double azimuth = heading + 180.0;
793     while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
794     
795     SG_LOG( SG_GENERAL, SG_INFO,
796     "runway =  " << r._lon << ", " << r._lat
797     << " length = " << r._length * SG_FEET_TO_METER 
798     << " heading = " << azimuth );
799     
800     geo_direct_wgs_84 ( 0, r._lat, r._lon, 
801     azimuth,
802     r._length * SG_FEET_TO_METER * 0.5 - 5.0,
803     &lat2, &lon2, &az2 );
804     
805     if ( fabs( fgGetDouble("/sim/presets/offset-distance") ) > SG_EPSILON )
806     {
807         double olat, olon;
808         double odist = fgGetDouble("/sim/presets/offset-distance");
809         odist *= SG_NM_TO_METER;
810         double oaz = azimuth;
811         if ( fabs(fgGetDouble("/sim/presets/offset-azimuth")) > SG_EPSILON )
812         {
813             oaz = fgGetDouble("/sim/presets/offset-azimuth") + 180;
814             heading = fgGetDouble("/sim/presets/heading-deg");
815         }
816         while ( oaz >= 360.0 ) { oaz -= 360.0; }
817         geo_direct_wgs_84 ( 0, lat2, lon2, oaz, odist, &olat, &olon, &az2 );
818         lat2=olat;
819         lon2=olon;
820     }
821     
822     // presets
823     fgSetDouble("/sim/presets/longitude-deg",  lon2 );
824     fgSetDouble("/sim/presets/latitude-deg",  lat2 );
825     fgSetDouble("/sim/presets/heading-deg", heading );
826     
827     // other code depends on the actual values being set ...
828     fgSetDouble("/position/longitude-deg",  lon2 );
829     fgSetDouble("/position/latitude-deg",  lat2 );
830     fgSetDouble("/orientation/heading-deg", heading );
831     
832     SG_LOG( SG_GENERAL, SG_INFO,
833     "Position for " << id << " is ("
834     << lon2 << ", "
835     << lat2 << ") new heading is "
836     << heading );
837     
838     return true;
839 }
840
841
842 static void fgSetDistOrAltFromGlideSlope() {
843     // cout << "fgSetDistOrAltFromGlideSlope()" << endl;
844     string apt_id = fgGetString("/sim/presets/airport-id");
845     double gs = fgGetDouble("/sim/presets/glideslope-deg")
846         * SG_DEGREES_TO_RADIANS ;
847     double od = fgGetDouble("/sim/presets/offset-distance");
848     double alt = fgGetDouble("/sim/presets/altitude-ft");
849
850     double apt_elev = 0.0;
851     if ( ! apt_id.empty() ) {
852         apt_elev = fgGetAirportElev( apt_id );
853         if ( apt_elev < -9990.0 ) {
854             apt_elev = 0.0;
855         }
856     } else {
857         apt_elev = 0.0;
858     }
859
860     if( fabs(gs) > 0.01 && fabs(od) > 0.1 && alt < -9990 ) {
861         // set altitude from glideslope and offset-distance
862         od *= SG_NM_TO_METER * SG_METER_TO_FEET;
863         alt = fabs(od*tan(gs)) + apt_elev;
864         fgSetDouble("/sim/presets/altitude-ft", alt);
865         fgSetBool("/sim/presets/onground", false);
866         SG_LOG( SG_GENERAL, SG_INFO, "Calculated altitude as: "
867                 << alt  << " ft" );
868     } else if( fabs(gs) > 0.01 && alt > 0 && fabs(od) < 0.1) {
869         // set offset-distance from glideslope and altitude
870         od  = (alt - apt_elev) / tan(gs);
871         od *= -1*SG_FEET_TO_METER * SG_METER_TO_NM;
872         fgSetDouble("/sim/presets/offset-distance", od);
873         fgSetBool("/sim/presets/onground", false);
874         SG_LOG( SG_GENERAL, SG_INFO, "Calculated offset distance as: " 
875                 << od  << " nm" );
876     } else if( fabs(gs) > 0.01 ) {
877         SG_LOG( SG_GENERAL, SG_ALERT,
878                 "Glideslope given but not altitude or offset-distance." );
879         SG_LOG( SG_GENERAL, SG_ALERT, "Resetting glideslope to zero" );
880         fgSetDouble("/sim/presets/glideslope-deg", 0);
881         fgSetBool("/sim/presets/onground", true);
882     }                              
883 }
884
885
886 // Set current_options lon/lat given an airport id and heading (degrees)
887 static bool fgSetPosFromNAV( const string& id, const double& freq ) {
888     FGNavRecord *nav
889         = globals->get_navlist()->findByIdentAndFreq( id.c_str(), freq );
890
891     // set initial position from runway and heading
892     if ( nav != NULL ) {
893         SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position for "
894                 << id << ":" << freq );
895
896         double lon = nav->get_lon();
897         double lat = nav->get_lat();
898
899         if ( fabs( fgGetDouble("/sim/presets/offset-distance") ) > SG_EPSILON )
900         {
901             double odist = fgGetDouble("/sim/presets/offset-distance")
902                 * SG_NM_TO_METER;
903             double oaz = fabs(fgGetDouble("/sim/presets/offset-azimuth"))
904                 + 180.0;
905             while ( oaz >= 360.0 ) { oaz -= 360.0; }
906             double olat, olon, az2;
907             geo_direct_wgs_84 ( 0, lat, lon, oaz, odist, &olat, &olon, &az2 );
908
909             lat = olat;
910             lon = olon;
911         }
912
913         // presets
914         fgSetDouble("/sim/presets/longitude-deg",  lon );
915         fgSetDouble("/sim/presets/latitude-deg",  lat );
916
917         // other code depends on the actual values being set ...
918         fgSetDouble("/position/longitude-deg",  lon );
919         fgSetDouble("/position/latitude-deg",  lat );
920         fgSetDouble("/orientation/heading-deg", 
921                     fgGetDouble("/sim/presets/heading-deg") );
922
923         SG_LOG( SG_GENERAL, SG_INFO,
924                 "Position for " << id << ":" << freq << " is ("
925                 << lon << ", "<< lat << ")" );
926
927         return true;
928     } else {
929         SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate NAV = "
930                 << id << ":" << freq );
931         return false;
932     }
933 }
934
935 // Set current_options lon/lat given an aircraft carrier id
936 static bool fgSetPosFromCarrier( const string& carrier, const string& posid ) {
937
938     // set initial position from runway and heading
939     Point3D geodPos;
940     double heading;
941     sgdVec3 uvw;
942     if (FGAIManager::getStartPosition(carrier, posid, geodPos, heading, uvw)) {
943         double lon = geodPos.lon() * SGD_RADIANS_TO_DEGREES;
944         double lat = geodPos.lat() * SGD_RADIANS_TO_DEGREES;
945         double alt = geodPos.elev() * SG_METER_TO_FEET;
946
947         SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position for "
948                 << carrier << " at lat = " << lat << ", lon = " << lon
949                 << ", alt = " << alt << ", heading = " << heading);
950
951         fgSetDouble("/sim/presets/longitude-deg",  lon);
952         fgSetDouble("/sim/presets/latitude-deg",  lat);
953         fgSetDouble("/sim/presets/altitude-ft", alt);
954         fgSetDouble("/sim/presets/heading-deg", heading);
955         fgSetDouble("/position/longitude-deg",  lon);
956         fgSetDouble("/position/latitude-deg",  lat);
957         fgSetDouble("/position/altitude-ft", alt);
958         fgSetDouble("/orientation/heading-deg", heading);
959
960         fgSetString("/sim/presets/speed-set", "UVW");
961         fgSetDouble("/velocities/uBody-fps", uvw[0]);
962         fgSetDouble("/velocities/vBody-fps", uvw[1]);
963         fgSetDouble("/velocities/wBody-fps", uvw[2]);
964         fgSetDouble("/sim/presets/uBody-fps", uvw[0]);
965         fgSetDouble("/sim/presets/vBody-fps", uvw[1]);
966         fgSetDouble("/sim/presets/wBody-fps", uvw[2]);
967
968         fgSetBool("/sim/presets/onground", true);
969
970         return true;
971     } else {
972         SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate aircraft carrier = "
973                 << carrier );
974         return false;
975     }
976 }
977  
978 // Set current_options lon/lat given an airport id and heading (degrees)
979 static bool fgSetPosFromFix( const string& id ) {
980     FGFix fix;
981
982     // set initial position from runway and heading
983     if ( globals->get_fixlist()->query( id.c_str(), &fix ) ) {
984         SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position for "
985                 << id );
986
987         double lon = fix.get_lon();
988         double lat = fix.get_lat();
989
990         if ( fabs( fgGetDouble("/sim/presets/offset-distance") ) > SG_EPSILON )
991         {
992             double odist = fgGetDouble("/sim/presets/offset-distance")
993                 * SG_NM_TO_METER;
994             double oaz = fabs(fgGetDouble("/sim/presets/offset-azimuth"))
995                 + 180.0;
996             while ( oaz >= 360.0 ) { oaz -= 360.0; }
997             double olat, olon, az2;
998             geo_direct_wgs_84 ( 0, lat, lon, oaz, odist, &olat, &olon, &az2 );
999
1000             lat = olat;
1001             lon = olon;
1002         }
1003
1004         // presets
1005         fgSetDouble("/sim/presets/longitude-deg",  lon );
1006         fgSetDouble("/sim/presets/latitude-deg",  lat );
1007
1008         // other code depends on the actual values being set ...
1009         fgSetDouble("/position/longitude-deg",  lon );
1010         fgSetDouble("/position/latitude-deg",  lat );
1011         fgSetDouble("/orientation/heading-deg", 
1012                     fgGetDouble("/sim/presets/heading-deg") );
1013
1014         SG_LOG( SG_GENERAL, SG_INFO,
1015                 "Position for " << id << " is ("
1016                 << lon << ", "<< lat << ")" );
1017
1018         return true;
1019     } else {
1020         SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate NAV = "
1021                 << id );
1022         return false;
1023     }
1024 }
1025  
1026 static void parseWaypoints() {
1027     string_list *waypoints = globals->get_initial_waypoints();
1028     if (waypoints) {
1029         vector<string>::iterator i;
1030         for (i = waypoints->begin(); 
1031              i  != waypoints->end();
1032              i++)
1033         {
1034             NewWaypoint(*i);
1035         }
1036         // Now were done using the way points we can deallocate the
1037         // memory they used
1038         while (waypoints->begin() != waypoints->end()) {
1039             waypoints->pop_back();
1040         }
1041         delete waypoints;
1042         globals->set_initial_waypoints(0);
1043     }
1044 }
1045
1046  
1047  
1048
1049
1050 /**
1051  * Initialize vor/ndb/ils/fix list management and query systems (as
1052  * well as simple airport db list)
1053  */
1054 bool
1055 fgInitNav ()
1056 {
1057     SG_LOG(SG_GENERAL, SG_INFO, "Loading Airport Database ...");
1058
1059     SGPath aptdb( globals->get_fg_root() );
1060     aptdb.append( "Airports/apt.dat" );
1061
1062     SGPath p_metar( globals->get_fg_root() );
1063     p_metar.append( "Airports/metar.dat" );
1064
1065     FGAirportList *airports = new FGAirportList();
1066     globals->set_airports( airports );
1067     FGRunwayList *runways = new FGRunwayList();
1068     globals->set_runways( runways );
1069
1070     fgAirportDBLoad( airports, runways, aptdb.str(), p_metar.str() );
1071
1072     FGNavList *navlist = new FGNavList;
1073     FGNavList *loclist = new FGNavList;
1074     FGNavList *gslist = new FGNavList;
1075     FGNavList *dmelist = new FGNavList;
1076     FGNavList *mkrlist = new FGNavList;
1077     FGNavList *tacanlist = new FGNavList;
1078     FGNavList *carrierlist = new FGNavList;
1079     FGTACANList *channellist = new FGTACANList;
1080
1081     globals->set_navlist( navlist );
1082     globals->set_loclist( loclist );
1083     globals->set_gslist( gslist );
1084     globals->set_dmelist( dmelist );
1085     globals->set_mkrlist( mkrlist );
1086     globals->set_tacanlist( tacanlist );
1087     globals->set_carrierlist( carrierlist );
1088     globals->set_channellist( channellist );
1089
1090     if ( !fgNavDBInit(airports, navlist, loclist, gslist, dmelist, mkrlist, tacanlist, carrierlist, channellist) ) {
1091         SG_LOG( SG_GENERAL, SG_ALERT,
1092                 "Problems loading one or more navigational database" );
1093     }
1094
1095     if ( fgGetBool("/sim/navdb/localizers/auto-align", true) ) {
1096         // align all the localizers with their corresponding runways
1097         // since data sources are good for cockpit navigation
1098         // purposes, but not always to the error tolerances needed to
1099         // exactly place these items.
1100         double threshold
1101             = fgGetDouble( "/sim/navdb/localizers/auto-align-threshold-deg",
1102                            5.0 );
1103         fgNavDBAlignLOCwithRunway( runways, loclist, threshold );
1104     }
1105
1106     SG_LOG(SG_GENERAL, SG_INFO, "  Fixes");
1107     SGPath p_fix( globals->get_fg_root() );
1108     p_fix.append( "Navaids/fix.dat" );
1109     FGFixList *fixlist = new FGFixList;
1110     fixlist->init( p_fix );
1111     globals->set_fixlist( fixlist );
1112
1113     return true;
1114 }
1115
1116
1117 // Set the initial position based on presets (or defaults)
1118 bool fgInitPosition() {
1119     // cout << "fgInitPosition()" << endl;
1120     double gs = fgGetDouble("/sim/presets/glideslope-deg")
1121         * SG_DEGREES_TO_RADIANS ;
1122     double od = fgGetDouble("/sim/presets/offset-distance");
1123     double alt = fgGetDouble("/sim/presets/altitude-ft");
1124
1125     bool set_pos = false;
1126
1127     // If glideslope is specified, then calculate offset-distance or
1128     // altitude relative to glide slope if either of those was not
1129     // specified.
1130     if ( fabs( gs ) > 0.01 ) {
1131         fgSetDistOrAltFromGlideSlope();
1132     }
1133
1134
1135     // If we have an explicit, in-range lon/lat, don't change it, just use it.
1136     // If not, check for an airport-id and use that.
1137     // If not, default to the middle of the KSFO field.
1138     // The default values for lon/lat are deliberately out of range
1139     // so that the airport-id can take effect; valid lon/lat will
1140     // override airport-id, however.
1141     double lon_deg = fgGetDouble("/sim/presets/longitude-deg");
1142     double lat_deg = fgGetDouble("/sim/presets/latitude-deg");
1143     if ( lon_deg >= -180.0 && lon_deg <= 180.0
1144          && lat_deg >= -90.0 && lat_deg <= 90.0 )
1145     {
1146         set_pos = true;
1147     }
1148
1149     string apt = fgGetString("/sim/presets/airport-id");
1150     string rwy_no = fgGetString("/sim/presets/runway");
1151     double hdg = fgGetDouble("/sim/presets/heading-deg");
1152     string vor = fgGetString("/sim/presets/vor-id");
1153     double vor_freq = fgGetDouble("/sim/presets/vor-freq");
1154     string ndb = fgGetString("/sim/presets/ndb-id");
1155     double ndb_freq = fgGetDouble("/sim/presets/ndb-freq");
1156     string carrier = fgGetString("/sim/presets/carrier");
1157     string parkpos = fgGetString("/sim/presets/parkpos");
1158     string fix = fgGetString("/sim/presets/fix");
1159
1160     fgSetDouble( "/orientation/heading-deg", hdg );
1161     fgInitTowerLocationListener();
1162
1163     if ( !set_pos && !apt.empty() && !rwy_no.empty() ) {
1164         // An airport + runway is requested
1165         if ( fgSetPosFromAirportIDandRwy( apt, rwy_no ) ) {
1166             // set tower position (a little off the heading for single
1167             // runway airports)
1168             fgSetString("/sim/tower/airport-id",  apt.c_str());
1169             set_pos = true;
1170         }
1171     }
1172
1173     if ( !set_pos && !apt.empty() ) {
1174         // An airport is requested (find runway closest to hdg)
1175         if ( fgSetPosFromAirportIDandHdg( apt, hdg ) ) {
1176             // set tower position (a little off the heading for single
1177             // runway airports)
1178             fgSetString("/sim/tower/airport-id",  apt.c_str());
1179             set_pos = true;
1180         }
1181     }
1182
1183     if ( !set_pos && !vor.empty() ) {
1184         // a VOR is requested
1185         if ( fgSetPosFromNAV( vor, vor_freq ) ) {
1186             set_pos = true;
1187         }
1188     }
1189
1190     if ( !set_pos && !ndb.empty() ) {
1191         // an NDB is requested
1192         if ( fgSetPosFromNAV( ndb, ndb_freq ) ) {
1193             set_pos = true;
1194         }
1195     }
1196
1197     if ( !set_pos && !carrier.empty() ) {
1198         // an aircraft carrier is requested
1199         if ( fgSetPosFromCarrier( carrier, parkpos ) ) {
1200             set_pos = true;
1201         }
1202     }
1203
1204     if ( !set_pos && !fix.empty() ) {
1205         // a Fix is requested
1206         if ( fgSetPosFromFix( fix ) ) {
1207             set_pos = true;
1208         }
1209     }
1210
1211     if ( !set_pos ) {
1212         // No lon/lat specified, no airport specified, default to
1213         // middle of KSFO field.
1214         fgSetDouble("/sim/presets/longitude-deg", -122.374843);
1215         fgSetDouble("/sim/presets/latitude-deg", 37.619002);
1216     }
1217
1218     fgSetDouble( "/position/longitude-deg",
1219                  fgGetDouble("/sim/presets/longitude-deg") );
1220     fgSetDouble( "/position/latitude-deg",
1221                  fgGetDouble("/sim/presets/latitude-deg") );
1222
1223     // determine if this should be an on-ground or in-air start
1224     if ((fabs(gs) > 0.01 || fabs(od) > 0.1 || alt > 0.1) && carrier.empty()) {
1225         fgSetBool("/sim/presets/onground", false);
1226     } else {
1227         fgSetBool("/sim/presets/onground", true);
1228     }                              
1229
1230     return true;
1231 }
1232
1233
1234 // General house keeping initializations
1235 bool fgInitGeneral() {
1236     string root;
1237
1238 #if defined(FX) && defined(XMESA)
1239     char *mesa_win_state;
1240 #endif
1241
1242     SG_LOG( SG_GENERAL, SG_INFO, "General Initialization" );
1243     SG_LOG( SG_GENERAL, SG_INFO, "======= ==============" );
1244
1245     root = globals->get_fg_root();
1246     if ( ! root.length() ) {
1247         // No root path set? Then bail ...
1248         SG_LOG( SG_GENERAL, SG_ALERT,
1249                 "Cannot continue without a path to the base package "
1250                 << "being defined." );
1251         exit(-1);
1252     }
1253     SG_LOG( SG_GENERAL, SG_INFO, "FG_ROOT = " << '"' << root << '"' << endl );
1254
1255 #if defined(FX) && defined(XMESA)
1256     // initialize full screen flag
1257     globals->set_fullscreen(false);
1258     if ( strstr ( general.get_glRenderer(), "Glide" ) ) {
1259         // Test for the MESA_GLX_FX env variable
1260         if ( (mesa_win_state = getenv( "MESA_GLX_FX" )) != NULL) {
1261             // test if we are fullscreen mesa/glide
1262             if ( (mesa_win_state[0] == 'f') ||
1263                  (mesa_win_state[0] == 'F') ) {
1264                 globals->set_fullscreen(true);
1265             }
1266         }
1267     }
1268 #endif
1269
1270     return true;
1271 }
1272
1273
1274 // Initialize the flight model subsystem.  This just creates the
1275 // object.  The actual fdm initialization is delayed until we get a
1276 // proper scenery elevation hit.  This is checked for in main.cxx
1277
1278 void fgInitFDM() {
1279
1280     if ( cur_fdm_state ) {
1281         delete cur_fdm_state;
1282         cur_fdm_state = 0;
1283     }
1284
1285     double dt = 1.0 / fgGetInt("/sim/model-hz");
1286     string model = fgGetString("/sim/flight-model");
1287
1288     try {
1289         if ( model == "larcsim" ) {
1290             cur_fdm_state = new FGLaRCsim( dt );
1291         } else if ( model == "jsb" ) {
1292             cur_fdm_state = new FGJSBsim( dt );
1293 #if ENABLE_SP_FDMS
1294         } else if ( model == "ada" ) {
1295             cur_fdm_state = new FGADA( dt );
1296         } else if ( model == "acms" ) {
1297             cur_fdm_state = new FGACMS( dt );
1298 #endif
1299         } else if ( model == "balloon" ) {
1300             cur_fdm_state = new FGBalloonSim( dt );
1301         } else if ( model == "magic" ) {
1302             cur_fdm_state = new FGMagicCarpet( dt );
1303         } else if ( model == "ufo" ) {
1304             cur_fdm_state = new FGUFO( dt );
1305         } else if ( model == "external" ) {
1306             // external is a synonym for "--fdm=null" and is
1307             // maintained here for backwards compatibility
1308             cur_fdm_state = new FGNullFDM( dt );
1309         } else if ( model.find("network") == 0 ) {
1310             string host = "localhost";
1311             int port1 = 5501;
1312             int port2 = 5502;
1313             int port3 = 5503;
1314             string net_options = model.substr(8);
1315             string::size_type begin, end;
1316             begin = 0;
1317             // host
1318             end = net_options.find( ",", begin );
1319             if ( end != string::npos ) {
1320                 host = net_options.substr(begin, end - begin);
1321                 begin = end + 1;
1322             }
1323             // port1
1324             end = net_options.find( ",", begin );
1325             if ( end != string::npos ) {
1326                 port1 = atoi( net_options.substr(begin, end - begin).c_str() );
1327                 begin = end + 1;
1328             }
1329             // port2
1330             end = net_options.find( ",", begin );
1331             if ( end != string::npos ) {
1332                 port2 = atoi( net_options.substr(begin, end - begin).c_str() );
1333                 begin = end + 1;
1334             }
1335             // port3
1336             end = net_options.find( ",", begin );
1337             if ( end != string::npos ) {
1338                 port3 = atoi( net_options.substr(begin, end - begin).c_str() );
1339                 begin = end + 1;
1340             }
1341             cur_fdm_state = new FGExternalNet( dt, host, port1, port2, port3 );
1342         } else if ( model.find("pipe") == 0 ) {
1343             // /* old */ string pipe_path = model.substr(5);
1344             // /* old */ cur_fdm_state = new FGExternalPipe( dt, pipe_path );
1345             string pipe_path = "";
1346             string pipe_protocol = "";
1347             string pipe_options = model.substr(5);
1348             string::size_type begin, end;
1349             begin = 0;
1350             // pipe file path
1351             end = pipe_options.find( ",", begin );
1352             if ( end != string::npos ) {
1353                 pipe_path = pipe_options.substr(begin, end - begin);
1354                 begin = end + 1;
1355             }
1356             // protocol (last option)
1357             pipe_protocol = pipe_options.substr(begin);
1358             cur_fdm_state = new FGExternalPipe( dt, pipe_path, pipe_protocol );
1359         } else if ( model == "null" ) {
1360             cur_fdm_state = new FGNullFDM( dt );
1361         } else if ( model == "yasim" ) {
1362             cur_fdm_state = new YASim( dt );
1363         } else {
1364             SG_LOG(SG_GENERAL, SG_ALERT,
1365                    "Unrecognized flight model '" << model
1366                    << "', cannot init flight dynamics model.");
1367             exit(-1);
1368         }
1369     } catch ( ... ) {
1370         SG_LOG(SG_GENERAL, SG_ALERT, "FlightGear aborting\n\n");
1371         exit(-1);
1372     }
1373 }
1374
1375 static void printMat(const sgVec4 *mat, char *name="")
1376 {
1377     int i;
1378     SG_LOG(SG_GENERAL, SG_BULK, name );
1379     for(i=0; i<4; i++) {
1380         SG_LOG(SG_GENERAL, SG_BULK, "  " << mat[i][0] << " " << mat[i][1]
1381                                     << " " << mat[i][2] << " " << mat[i][3] );
1382     }
1383 }
1384
1385 // Initialize view parameters
1386 void fgInitView() {
1387   // force update of model so that viewer can get some data...
1388   globals->get_aircraft_model()->update(0);
1389   // run update for current view so that data is current...
1390   globals->get_viewmgr()->update(0);
1391
1392   printMat(globals->get_current_view()->get_VIEW(),"VIEW");
1393   printMat(globals->get_current_view()->get_UP(),"UP");
1394   // printMat(globals->get_current_view()->get_LOCAL(),"LOCAL");
1395   
1396 }
1397
1398
1399 SGTime *fgInitTime() {
1400     // Initialize time
1401     static const SGPropertyNode *longitude
1402         = fgGetNode("/position/longitude-deg");
1403     static const SGPropertyNode *latitude
1404         = fgGetNode("/position/latitude-deg");
1405     static const SGPropertyNode *cur_time_override
1406         = fgGetNode("/sim/time/cur-time-override", true);
1407
1408     SGPath zone( globals->get_fg_root() );
1409     zone.append( "Timezone" );
1410     SGTime *t = new SGTime( longitude->getDoubleValue()
1411                               * SGD_DEGREES_TO_RADIANS,
1412                             latitude->getDoubleValue()
1413                               * SGD_DEGREES_TO_RADIANS,
1414                             zone.str(),
1415                             cur_time_override->getLongValue() );
1416
1417     globals->set_warp_delta( 0 );
1418
1419     t->update( 0.0, 0.0,
1420                cur_time_override->getLongValue(),
1421                globals->get_warp() );
1422
1423     return t;
1424 }
1425
1426
1427 // set up a time offset (aka warp) if one is specified
1428 void fgInitTimeOffset() {
1429     static const SGPropertyNode *longitude
1430         = fgGetNode("/position/longitude-deg");
1431     static const SGPropertyNode *latitude
1432         = fgGetNode("/position/latitude-deg");
1433     static const SGPropertyNode *cur_time_override
1434         = fgGetNode("/sim/time/cur-time-override", true);
1435
1436     // Handle potential user specified time offsets
1437     int orig_warp = globals->get_warp();
1438     SGTime *t = globals->get_time_params();
1439     time_t cur_time = t->get_cur_time();
1440     time_t currGMT = sgTimeGetGMT( gmtime(&cur_time) );
1441     time_t systemLocalTime = sgTimeGetGMT( localtime(&cur_time) );
1442     time_t aircraftLocalTime = 
1443         sgTimeGetGMT( fgLocaltime(&cur_time, t->get_zonename() ) );
1444
1445     // Okay, we now have several possible scenarios
1446     int offset = fgGetInt("/sim/startup/time-offset");
1447     string offset_type = fgGetString("/sim/startup/time-offset-type");
1448
1449     int warp = 0;
1450     if ( offset_type == "real" ) {
1451         warp = 0;
1452     } else if ( offset_type == "dawn" ) {
1453         warp = fgTimeSecondsUntilSunAngle( cur_time,
1454                                            longitude->getDoubleValue()
1455                                              * SGD_DEGREES_TO_RADIANS,
1456                                            latitude->getDoubleValue()
1457                                              * SGD_DEGREES_TO_RADIANS,
1458                                            90.0, true ); 
1459     } else if ( offset_type == "morning" ) {
1460         warp = fgTimeSecondsUntilSunAngle( cur_time,
1461                                            longitude->getDoubleValue()
1462                                              * SGD_DEGREES_TO_RADIANS,
1463                                            latitude->getDoubleValue()
1464                                              * SGD_DEGREES_TO_RADIANS,
1465                                            75.0, true ); 
1466     } else if ( offset_type == "noon" ) {
1467         warp = fgTimeSecondsUntilSunAngle( cur_time,
1468                                            longitude->getDoubleValue()
1469                                              * SGD_DEGREES_TO_RADIANS,
1470                                            latitude->getDoubleValue()
1471                                              * SGD_DEGREES_TO_RADIANS,
1472                                            0.0, true ); 
1473     } else if ( offset_type == "afternoon" ) {
1474         warp = fgTimeSecondsUntilSunAngle( cur_time,
1475                                            longitude->getDoubleValue()
1476                                              * SGD_DEGREES_TO_RADIANS,
1477                                            latitude->getDoubleValue()
1478                                              * SGD_DEGREES_TO_RADIANS,
1479                                            60.0, false ); 
1480      } else if ( offset_type == "dusk" ) {
1481         warp = fgTimeSecondsUntilSunAngle( cur_time,
1482                                            longitude->getDoubleValue()
1483                                              * SGD_DEGREES_TO_RADIANS,
1484                                            latitude->getDoubleValue()
1485                                              * SGD_DEGREES_TO_RADIANS,
1486                                            90.0, false ); 
1487      } else if ( offset_type == "evening" ) {
1488         warp = fgTimeSecondsUntilSunAngle( cur_time,
1489                                            longitude->getDoubleValue()
1490                                              * SGD_DEGREES_TO_RADIANS,
1491                                            latitude->getDoubleValue()
1492                                              * SGD_DEGREES_TO_RADIANS,
1493                                            100.0, false ); 
1494     } else if ( offset_type == "midnight" ) {
1495         warp = fgTimeSecondsUntilSunAngle( cur_time,
1496                                            longitude->getDoubleValue()
1497                                              * SGD_DEGREES_TO_RADIANS,
1498                                            latitude->getDoubleValue()
1499                                              * SGD_DEGREES_TO_RADIANS,
1500                                            180.0, false ); 
1501     } else if ( offset_type == "system-offset" ) {
1502         warp = offset;
1503     } else if ( offset_type == "gmt-offset" ) {
1504         warp = offset - (currGMT - systemLocalTime);
1505     } else if ( offset_type == "latitude-offset" ) {
1506         warp = offset - (aircraftLocalTime - systemLocalTime);
1507     } else if ( offset_type == "system" ) {
1508         warp = offset - cur_time;
1509     } else if ( offset_type == "gmt" ) {
1510         warp = offset - currGMT;
1511     } else if ( offset_type == "latitude" ) {
1512         warp = offset - (aircraftLocalTime - systemLocalTime) - cur_time; 
1513     } else {
1514         SG_LOG( SG_GENERAL, SG_ALERT,
1515                 "FG_TIME::Unsupported offset type " << offset_type );
1516         exit( -1 );
1517     }
1518     globals->set_warp( orig_warp + warp );
1519     t->update( longitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS,
1520                latitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS,
1521                cur_time_override->getLongValue(),
1522                globals->get_warp() );
1523
1524     SG_LOG( SG_GENERAL, SG_INFO, "After fgInitTimeOffset(): warp = " 
1525             << globals->get_warp() );
1526 }
1527
1528
1529 // This is the top level init routine which calls all the other
1530 // initialization routines.  If you are adding a subsystem to flight
1531 // gear, its initialization call should located in this routine.
1532 // Returns non-zero if a problem encountered.
1533 bool fgInitSubsystems() {
1534     // static const SGPropertyNode *longitude
1535     //     = fgGetNode("/sim/presets/longitude-deg");
1536     // static const SGPropertyNode *latitude
1537     //     = fgGetNode("/sim/presets/latitude-deg");
1538     // static const SGPropertyNode *altitude
1539     //     = fgGetNode("/sim/presets/altitude-ft");
1540     SG_LOG( SG_GENERAL, SG_INFO, "Initialize Subsystems");
1541     SG_LOG( SG_GENERAL, SG_INFO, "========== ==========");
1542
1543     ////////////////////////////////////////////////////////////////////
1544     // Initialize the event manager subsystem.
1545     ////////////////////////////////////////////////////////////////////
1546
1547     globals->get_event_mgr()->init();
1548     globals->get_event_mgr()->setRealtimeProperty(fgGetNode("/sim/time/delta-realtime-sec", true));
1549
1550     ////////////////////////////////////////////////////////////////////
1551     // Initialize the property interpolator subsystem
1552     ////////////////////////////////////////////////////////////////////
1553     globals->add_subsystem("interpolator", new SGInterpolator);
1554
1555
1556     ////////////////////////////////////////////////////////////////////
1557     // Add the FlightGear property utilities.
1558     ////////////////////////////////////////////////////////////////////
1559     globals->add_subsystem("properties", new FGProperties);
1560
1561     ////////////////////////////////////////////////////////////////////
1562     // Initialize the material property subsystem.
1563     ////////////////////////////////////////////////////////////////////
1564
1565     SGPath mpath( globals->get_fg_root() );
1566     mpath.append( "materials.xml" );
1567     string season = fgGetString("/sim/startup/season", "summer");
1568     if ( ! globals->get_matlib()->load(globals->get_fg_root(), mpath.str(), season.c_str()) ) {
1569         SG_LOG( SG_GENERAL, SG_ALERT, "Error loading material lib!" );
1570         exit(-1);
1571     }
1572
1573
1574     ////////////////////////////////////////////////////////////////////
1575     // Initialize the scenery management subsystem.
1576     ////////////////////////////////////////////////////////////////////
1577
1578     if ( globals->get_tile_mgr()->init() ) {
1579         // Load the local scenery data
1580         double visibility_meters = fgGetDouble("/environment/visibility-m");
1581                 
1582         globals->get_tile_mgr()->update( visibility_meters );
1583     } else {
1584         SG_LOG( SG_GENERAL, SG_ALERT, "Error in Tile Manager initialization!" );
1585         exit(-1);
1586     }
1587
1588     // cause refresh of viewer scenery timestamps every 15 seconds...
1589     globals->get_event_mgr()->addTask( "FGTileMgr::refresh_view_timestamps()",
1590                                        globals->get_tile_mgr(),
1591                                        &FGTileMgr::refresh_view_timestamps,
1592                                        15 );
1593
1594
1595     ////////////////////////////////////////////////////////////////////
1596     // Initialize the flight model subsystem.
1597     ////////////////////////////////////////////////////////////////////
1598
1599     fgInitFDM();
1600         
1601     // allocates structures so must happen before any of the flight
1602     // model or control parameters are set
1603     fgAircraftInit();   // In the future this might not be the case.
1604
1605
1606     ////////////////////////////////////////////////////////////////////
1607     // Initialize the XML Autopilot subsystem.
1608     ////////////////////////////////////////////////////////////////////
1609
1610     globals->add_subsystem( "xml-autopilot", new FGXMLAutopilot );
1611     globals->add_subsystem( "route-manager", new FGRouteMgr );
1612
1613   
1614     ////////////////////////////////////////////////////////////////////
1615     // Initialize the view manager subsystem.
1616     ////////////////////////////////////////////////////////////////////
1617
1618     fgInitView();
1619
1620     ////////////////////////////////////////////////////////////////////
1621     // Create and register the logger.
1622     ////////////////////////////////////////////////////////////////////
1623     
1624     globals->add_subsystem("logger", new FGLogger);
1625
1626     ////////////////////////////////////////////////////////////////////
1627     // Create and register the XML GUI.
1628     ////////////////////////////////////////////////////////////////////
1629
1630     globals->add_subsystem("gui", new NewGUI, SGSubsystemMgr::INIT);
1631
1632
1633     ////////////////////////////////////////////////////////////////////
1634     // Initialize the local time subsystem.
1635     ////////////////////////////////////////////////////////////////////
1636
1637     // update the current timezone each 30 minutes
1638     globals->get_event_mgr()->addTask( "fgUpdateLocalTime()",
1639                                        &fgUpdateLocalTime, 30*60 );
1640     fgInitTimeOffset();         // the environment subsystem needs this
1641
1642
1643     ////////////////////////////////////////////////////////////////////
1644     // Initialize the weather subsystem.
1645     ////////////////////////////////////////////////////////////////////
1646
1647     // Initialize the weather modeling subsystem
1648     globals->add_subsystem("environment", new FGEnvironmentMgr);
1649
1650
1651     ////////////////////////////////////////////////////////////////////
1652     // Initialize the lighting subsystem.
1653     ////////////////////////////////////////////////////////////////////
1654
1655     globals->add_subsystem("lighting", new FGLight);
1656
1657     //////////////////////////////////////////////////////////////////////
1658     // Initialize the 2D cloud subsystem.
1659     ////////////////////////////////////////////////////////////////////
1660     fgGetBool("/sim/rendering/bump-mapping", false);
1661
1662 #ifdef ENABLE_AUDIO_SUPPORT
1663     ////////////////////////////////////////////////////////////////////
1664     // Initialize the sound subsystem.
1665     ////////////////////////////////////////////////////////////////////
1666
1667     init_volume = fgGetFloat("/sim/sound/volume");
1668     fgSetFloat("/sim/sound/volume", 0.0f);
1669     globals->set_soundmgr(new SGSoundMgr);
1670     globals->get_soundmgr()->init();
1671     globals->get_soundmgr()->bind();
1672
1673
1674     ////////////////////////////////////////////////////////////////////
1675     // Initialize the sound-effects subsystem.
1676     ////////////////////////////////////////////////////////////////////
1677
1678     globals->add_subsystem("fx", new FGFX);
1679     
1680 #endif
1681
1682     ////////////////////////////////////////////////////////////////////
1683     // Initialise ATC display system
1684     ////////////////////////////////////////////////////////////////////
1685
1686     SG_LOG(SG_GENERAL, SG_INFO, "  ATC Display");
1687     globals->set_ATC_display(new FGATCDisplay);
1688     globals->get_ATC_display()->init(); 
1689
1690     ////////////////////////////////////////////////////////////////////
1691     // Initialise the ATC Manager 
1692     ////////////////////////////////////////////////////////////////////
1693
1694     SG_LOG(SG_GENERAL, SG_INFO, "  ATC Manager");
1695     globals->set_ATC_mgr(new FGATCMgr);
1696     globals->get_ATC_mgr()->init(); 
1697     
1698     ////////////////////////////////////////////////////////////////////
1699     // Initialise the AI Manager 
1700     ////////////////////////////////////////////////////////////////////
1701
1702     SG_LOG(SG_GENERAL, SG_INFO, "  AI Manager");
1703     globals->set_AI_mgr(new FGAIMgr);
1704     globals->get_AI_mgr()->init();
1705
1706     ////////////////////////////////////////////////////////////////////
1707     // Initialise the AI Model Manager
1708     ////////////////////////////////////////////////////////////////////
1709     SG_LOG(SG_GENERAL, SG_INFO, "  AI Model Manager");
1710     globals->add_subsystem("ai_model", new FGAIManager);
1711     globals->add_subsystem("submodel_mgr", new FGSubmodelMgr);
1712
1713
1714      // It's probably a good idea to initialize the top level traffic manager
1715      // After the AI and ATC systems have been initialized properly.
1716      // AI Traffic manager
1717      globals->add_subsystem("Traffic Manager", new FGTrafficManager);
1718              FGTrafficManager *dispatcher = 
1719              (FGTrafficManager*) globals->get_subsystem("Traffic Manager");
1720              SGPath path = globals->get_fg_root();
1721              path.append("/Traffic/fgtraffic.xml");
1722      readXML(path.str(),
1723         *dispatcher);
1724              //globals->get_subsystem("Traffic Manager")->init();
1725
1726     globals->add_subsystem("instrumentation", new FGInstrumentMgr);
1727     globals->add_subsystem("systems", new FGSystemMgr);
1728
1729
1730
1731     ////////////////////////////////////////////////////////////////////
1732     // Initialize the cockpit subsystem
1733     ////////////////////////////////////////////////////////////////////
1734     if( fgCockpitInit( &current_aircraft )) {
1735         // Cockpit initialized ok.
1736     } else {
1737         SG_LOG( SG_GENERAL, SG_ALERT, "Error in Cockpit initialization!" );
1738         exit(-1);
1739     }
1740
1741
1742     ////////////////////////////////////////////////////////////////////
1743     // Initialize the autopilot subsystem.
1744     ////////////////////////////////////////////////////////////////////
1745
1746                                 // FIXME: these should go in the
1747                                 // GUI initialization code, not here.
1748     // fgAPAdjustInit();
1749     NewTgtAirportInit();
1750     NewHeadingInit();
1751     NewAltitudeInit();
1752
1753     ////////////////////////////////////////////////////////////////////
1754     // Initialize I/O subsystem.
1755     ////////////////////////////////////////////////////////////////////
1756
1757     globals->get_io()->init();
1758     globals->get_io()->bind();
1759
1760
1761     ////////////////////////////////////////////////////////////////////
1762     // Add a new 2D panel.
1763     ////////////////////////////////////////////////////////////////////
1764
1765     string panel_path = fgGetString("/sim/panel/path",
1766                                     "Panels/Default/default.xml");
1767
1768     globals->set_current_panel( fgReadPanel(panel_path) );
1769     if (globals->get_current_panel() == 0) {
1770         SG_LOG( SG_INPUT, SG_ALERT, 
1771                 "Error reading new panel from " << panel_path );
1772     } else {
1773         SG_LOG( SG_INPUT, SG_INFO, "Loaded new panel from " << panel_path );
1774         globals->get_current_panel()->init();
1775         globals->get_current_panel()->bind();
1776     }
1777
1778     
1779     ////////////////////////////////////////////////////////////////////
1780     // Initialize the controls subsystem.
1781     ////////////////////////////////////////////////////////////////////
1782
1783     globals->get_controls()->init();
1784     globals->get_controls()->bind();
1785
1786
1787     ////////////////////////////////////////////////////////////////////
1788     // Initialize the input subsystem.
1789     ////////////////////////////////////////////////////////////////////
1790
1791     globals->add_subsystem("input", new FGInput);
1792
1793
1794     ////////////////////////////////////////////////////////////////////
1795     // Initialize the replay subsystem
1796     ////////////////////////////////////////////////////////////////////
1797     globals->add_subsystem("replay", new FGReplay);
1798
1799     ////////////////////////////////////////////////////////////////////
1800     // Bind and initialize subsystems.
1801     ////////////////////////////////////////////////////////////////////
1802
1803     globals->get_subsystem_mgr()->bind();
1804     globals->get_subsystem_mgr()->init();
1805
1806 #ifdef FG_MPLAYER_AS
1807     ////////////////////////////////////////////////////////////////////
1808     // Initialize multiplayer subsystem
1809     ////////////////////////////////////////////////////////////////////
1810
1811     globals->set_multiplayer_mgr(new FGMultiplayMgr);
1812     globals->get_multiplayer_mgr()->init();
1813 #endif
1814
1815     ////////////////////////////////////////////////////////////////////////
1816     // Initialize the Nasal interpreter.
1817     // Do this last, so that the loaded scripts see initialized state
1818     ////////////////////////////////////////////////////////////////////////
1819     FGNasalSys* nasal = new FGNasalSys();
1820     globals->add_subsystem("nasal", nasal);
1821     nasal->init();
1822
1823     ////////////////////////////////////////////////////////////////////
1824     // At this point we could try and parse the waypoint options
1825     ///////////////////////////////////////////////////////////////////
1826     parseWaypoints();
1827
1828     // initialize methods that depend on other subsystems.
1829     globals->get_subsystem_mgr()->postinit();
1830
1831     ////////////////////////////////////////////////////////////////////////
1832     // End of subsystem initialization.
1833     ////////////////////////////////////////////////////////////////////
1834
1835     SG_LOG( SG_GENERAL, SG_INFO, endl);
1836
1837                                 // Save the initial state for future
1838                                 // reference.
1839     globals->saveInitialState();
1840     
1841     return true;
1842 }
1843
1844
1845 void fgReInitSubsystems()
1846 {
1847     // static const SGPropertyNode *longitude
1848     //     = fgGetNode("/sim/presets/longitude-deg");
1849     // static const SGPropertyNode *latitude
1850     //     = fgGetNode("/sim/presets/latitude-deg");
1851     static const SGPropertyNode *altitude
1852         = fgGetNode("/sim/presets/altitude-ft");
1853     static const SGPropertyNode *master_freeze
1854         = fgGetNode("/sim/freeze/master");
1855
1856     SG_LOG( SG_GENERAL, SG_INFO,
1857             "fgReInitSubsystems(): /position/altitude = "
1858             << altitude->getDoubleValue() );
1859
1860     bool freeze = master_freeze->getBoolValue();
1861     if ( !freeze ) {
1862         fgSetBool("/sim/freeze/master", true);
1863     }
1864     fgSetBool("/sim/crashed", false);
1865
1866     // Force reupdating the positions of the ai 3d models. They are used for
1867     // initializing ground level for the FDM.
1868     globals->get_subsystem("ai_model")->reinit();
1869
1870     // Initialize the FDM
1871     fgInitFDM();
1872     
1873     // allocates structures so must happen before any of the flight
1874     // model or control parameters are set
1875     fgAircraftInit();   // In the future this might not be the case.
1876
1877     // reload offsets from config defaults
1878     globals->get_viewmgr()->reinit();
1879
1880     fgInitView();
1881
1882     globals->get_controls()->reset_all();
1883
1884     fgUpdateLocalTime();
1885
1886     // re-init to proper time of day setting
1887     fgInitTimeOffset();
1888
1889     if ( !freeze ) {
1890         fgSetBool("/sim/freeze/master", false);
1891     }
1892     fgSetBool("/sim/sceneryloaded",false);
1893 }
1894